我想在内核空间使用串口,我发现了一些在用户空间的代码,我试着把这些代码转换为内核空间的代码... ...
这是我的代码
#include <linux/termios.h>
#include <linux/unistd.h>
#include <linux/signal.h>
#include <linux/fcntl.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/in.h>
struct file * fp;
...
struct termios termAttr;
struct sigaction saio;
oldfs = get_fs();
set_fs(KERNEL_DS);
fp = filp_open("/dev/ttymxc0", O_RDWR | O_NOCTTY | O_NDELAY,0);
if(fp == NULL)
printk(KERN_ALERT "Serial openning error!!.\n");
else{
saio.sa_handler = signal_handler_IO;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);
fcntl(fp, F_SETFL, O_NDELAY|FASYNC);
fcntl(fp, F_SETOWN, THIS_MODULE);
tcgetattr(fp,&termAttr);
cfsetispeed(&termAttr,B115200);
cfsetospeed(&termAttr,B115200);
termAttr.c_cflag &= ~PARENB;
termAttr.c_cflag &= ~CSTOPB;
termAttr.c_cflag &= ~CSIZE;
termAttr.c_cflag |= CS8;
termAttr.c_cflag |= (CLOCAL | CREAD);
termAttr.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
termAttr.c_iflag &= ~(IXON | IXOFF | IXANY);
termAttr.c_oflag &= ~OPOST;
tcsetattr(fp,TCSANOW,&termAttr);
printk(KERN_ALERT "Serial configured....\n");
vfs_write(fp, "HI",2, NULL);
filp_close(fp, NULL);
set_fs(oldfs);
}
在编译时,我得到了以下错误。
note: each undeclared identifier is reported only once for each function it appears in
error: implicit declaration of function 'sigaction' [-Werror=implicit-function-declaration]
sigaction(SIGIO,&saio,NULL);
^
error: implicit declaration of function 'fcntl' [-Werror=implicit-function-declaration]
fcntl(fp, F_SETFL, O_NDELAY|FASYNC);
^
error: implicit declaration of function 'tcgetattr' [-Werror=implicit-function-declaration]
tcgetattr(fp,&termAttr);
^
error: implicit declaration of function 'cfsetispeed' [-Werror=implicit-function-declaration]
cfsetispeed(&termAttr,B115200);
^
error: implicit declaration of function 'cfsetospeed' [-Werror=implicit-function-declaration]
cfsetospeed(&termAttr,B115200);
^
error: implicit declaration of function 'tcsetattr' [-Werror=implicit-function-declaration]
我正在交叉编译这个驱动,而我已经编译了Linux源代码,我在我的Linux源代码中搜索了这个函数,但我没有找到任何这个函数!我应该用什么来代替这个函数?
编辑1:
我把我的代码改成了这样
//serial
struct ktermios termAttr;
struct sigaction saio;
loff_t pos =0;
struct tty_struct *tty;
serialfp = file_open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NDELAY,0);
if(serialfp == NULL)
printk(KERN_ALERT "ARIO RMG Serial openning error!!.\n");
else{
tty = (struct tty_struct *)serialfp->private_data;
tty_termios_encode_baud_rate(&tty->termios,B115200,B115200 );
printk(KERN_ALERT "ARIO RMG Serial configured....\n");
pos = serialfp->f_pos;
file_write(serialfp, "\n\n\n\n\nThis is first test of sending serial data from kernel module\n\n\n\n\n",70,&pos);
serialfp->f_pos=pos;
serial_thread_condition = 1;
mutex_init(&serial_mutex);
task1 = kthread_create(&thread_function, (void *)&pid1, "pradeep");
wake_up_process(task1);
printk(KERN_ALERT "data received:%s\n\n\n\n\n\n\n\n",rmg_drvstruct[0].RxSerial);
}
我现在可以向串口发送数据了 我还创建了一个线程来从串口读取数据 用下面的代码。
static int thread_function(void *data){
loff_t pos;
while(serial_thread_condition){
mutex_lock(&serial_mutex);
if (IS_ERR(serialfp)) {
mutex_unlock(&serial_mutex);
serial_thread_condition=0;
return 0;
}
pos = serialfp->f_pos;
printk(KERN_INFO "try to read from serial\r\n");
if(file_read(serialfp, rmg_drvstruct[0].RxSerial, 100, &pos)>0)
{
printk(KERN_INFO "Data: %s\r\n", rmg_drvstruct[0].RxSerial);
serialfp->f_pos = pos;
serial_thread_condition = 0;
mutex_unlock(&serial_mutex);
break;
}
mutex_unlock(&serial_mutex);
}
}
int file_read(struct file *file, unsigned long long offset, unsigned char *data, unsigned int size)
{
mm_segment_t oldfs;
int ret;
oldfs = get_fs();
set_fs(get_ds());
ret = vfs_read(file, data, size, &offset);
set_fs(oldfs);
return ret;
}
但我的线程在串口中什么都没有 我想用中断来接收新的字节,但是... ... irq_request()
函数使内核恐慌,计算机冻结,那么我应该怎么做才能正确地用中断或线程接收数据?
所以经过一段时间的搜索和测试,我用了 此代码 与串口通信,但我已经改变了一点。
在使用这段代码之前,请阅读我的编辑
我使用了一个线程从串口读取数据,因为使用中断(request_irq)会让我的内核向自己的脑袋开枪!所以这是我的代码,大家可能想在内核模块中使用串口。
所以这是我的代码,供任何想在内核模块中使用串口的人参考。
#include <linux/tty.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include<linux/mutex.h>
MODULE_LICENSE("GPL");
struct file * serialfp;
struct task_struct *task1;
int pid1 = 1;
....
static struct file *file_open(const char *path, int flags, int rights)
{
struct file *filp = NULL;
mm_segment_t oldfs;
int err = 0;
oldfs = get_fs();
set_fs(get_ds());
filp = filp_open(path, flags, rights);
set_fs(oldfs);
if (IS_ERR(filp)) {
err = PTR_ERR(filp);
return NULL;
}
return filp;
}
static void file_close(struct file *file)
{
filp_close(file, NULL);
}
static int file_read(struct file *file, unsigned long long *offset, unsigned char *data, unsigned int size)
{
mm_segment_t oldfs;
int ret;
oldfs = get_fs();
set_fs(get_ds());
ret = vfs_read(file, data, size, offset);
set_fs(oldfs);
return ret;
}
static int file_write(struct file *file, unsigned long long *offset, unsigned char *data, unsigned int size)
{
mm_segment_t oldfs;
int ret;
oldfs = get_fs();
set_fs(get_ds());
ret = vfs_write(file, data, size, offset);
set_fs(oldfs);
return ret;
}
int file_sync(struct file *file)
{
vfs_fsync(file, 0);
return 0;
}
static int thread_function(void *data){
loff_t pos;
int len;
while(serial_thread_condition){
mutex_lock(&serial_mutex);
if (IS_ERR(serialfp)|| serial_thread_condition==0) {
printk(KERN_INFO "serial reading thread has been terminated.\r\n");
mutex_unlock(&serial_mutex);
serial_thread_condition=0;
return 0;
}
pos = serialfp->f_pos;
if((len=file_read(serialfp,&pos, rmg_drvstruct[0].RxSerial, 100))>0){
printk(KERN_INFO "Received data : %s\r\n", rmg_drvstruct[0].RxSerial);
serialfp->f_pos = pos;
file_write(serialfp,&pos,"I have received:",16);
file_write(serialfp,&pos, rmg_drvstruct[0].RxSerial,len);
serialfp->f_pos = pos;
}
file_sync(serialfp);
mutex_unlock(&serial_mutex);
mdelay(5);
}
}
所以我的设备打开功能是这样的。
static int device_open(struct inode *inode, struct file *file){
loff_t pos =0;
struct tty_struct *tty;
...
serialfp = file_open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NDELAY ,0);
if(serialfp == NULL)
printk(KERN_ALERT "ARIO RMG Serial openning error!!.\n");
else{
tty = (struct tty_struct *)serialfp->private_data;
tty_termios_encode_baud_rate(&tty->termios,B115200,B115200 );
printk(KERN_ALERT "Serial configured....\n");
pos = serialfp->f_pos;
file_write(serialfp,&pos,"\n\n\n\n\nThis is first test of sending serial data from kernel module\n\n\n\n\n",70);
serialfp->f_pos=pos;
file_sync(serialfp);
serial_thread_condition = 1;
mutex_init(&serial_mutex);
task1 = kthread_create(&thread_function, (void *)&pid1, "pradeep");
wake_up_process(task1);
}
...
}
和关闭模块的功能:
static int device_release(struct inode *inode, struct file *file){
...
if (!IS_ERR(serialfp)) {
mutex_lock(&serial_mutex);
printk(KERN_INFO " Trying to realease serail thread");
if(serial_thread_condition==1){
int i=0;
while(i++<256)serial_thread_condition =0;
}
printk(KERN_INFO " serial thread released.");
file_close(serialfp);
mutex_unlock(&serial_mutex);
}
....
}
感谢0andriy的帮助,感谢dmeister的回答。该环节.
EDIT:
所以我在内核中做了我想做的事,在内核空间中打开一个文件,而不考虑任何不这样做的建议。
但是我需要在内核模块中打开一个文件......
那么为什么每个人都说不要在内核中打开用户空间的文件呢?在这两篇文章中,有一些不使用内核文件的原因。这个环节 和 这个环节.
有一些原因,比如:1-内核模块随时可能失去CPU,而被内核打开的文件可能会关闭。
2- 我不太清楚,但他们说文件需要有一个进程才能打开,但内核模块本身不是一个进程(也许我错了!)。
3- 如果在处理文件时发生任何错误(openclosereadwrite),内核模块不能处理它并导致内核恐慌......
我经历过很多内核恐慌,只是在打开和关闭我想处理的文件时。这就是为什么你不应该在内核模块中使用文件的一些原因,所以就像每个人之前说的 "如果你需要在内核模块中使用文件,你可能在你的代码中做错了什么!"