内核中的串行端口访问 space

serialport access in kernel space

我想在内核 space 中使用串行端口,我发现了一些在用户 space 中的代码,我试图将这些代码转换为在内核 space 中工作。 ..

这是我的代码

#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()函数使内核崩溃并且计算机死机,所以我应该怎么做才能正确接收数据使用中断或线程?

所以经过一段时间的搜索和测试,我使用this code与串口通信,但我改变了一些。

使用此代码前请阅读我的编辑

我使用线程从串口读取,因为使用中断 (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 在 that link 中的回答。

编辑:

所以我在内核中做了我想做的,在内核中打开了一个文件space,不管任何建议不要这样做。

但是我需要在内核模块中打开一个文件...

那么为什么每个人都说不要在内核中打开用户 space 文件? 在这两篇文章中有一些不在内核中使用文件的原因,this link and this link.

有一些原因,例如: 1- 内核模块随时可能丢失CPU,内核打开的文件可能会关闭。

2- 我不太确定这一点,但他们说文件需要有一个进程才能保持打开状态,但内核模块本身不是一个进程(也许我错了!)。

3- 如果在处理文件时发生任何错误(open/close/read/write),内核模块无法处理它并导致内核崩溃...

只有在打开和关闭我想要使用的文件时,我才经历过很多内核恐慌。这些是你不应该在内核模块中使用文件的一些原因,正如每个人之前所说 "If you need to use files in kernel module you probably did something wrong in your code!"