内核空间的串口访问

问题描述 投票:0回答:1

我想在内核空间使用串口,我发现了一些在用户空间的代码,我试着把这些代码转换为内核空间的代码... ...

这是我的代码

#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() 函数使内核恐慌,计算机冻结,那么我应该怎么做才能正确地用中断或线程接收数据?

linux linux-kernel serial-port kernel-module
1个回答
0
投票

所以经过一段时间的搜索和测试,我用了 此代码 与串口通信,但我已经改变了一点。

在使用这段代码之前,请阅读我的编辑

我使用了一个线程从串口读取数据,因为使用中断(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),内核模块不能处理它并导致内核恐慌......

我经历过很多内核恐慌,只是在打开和关闭我想处理的文件时。这就是为什么你不应该在内核模块中使用文件的一些原因,所以就像每个人之前说的 "如果你需要在内核模块中使用文件,你可能在你的代码中做错了什么!"

© www.soinside.com 2019 - 2024. All rights reserved.