доступ через последовательный порт в пространстве ядра - PullRequest
0 голосов
/ 26 апреля 2020

Я хочу использовать последовательный порт в пространстве ядра, я нашел некоторый код, который был в пространстве пользователя, я попытался преобразовать коды для работы в пространстве ядра ...

Это мой код

#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() заставляет ядро ​​pani c и компьютер зависает, так что я должен сделать, чтобы правильно получать данные с прерыванием или потоком?

1 Ответ

0 голосов
/ 02 мая 2020

Таким образом, через некоторое время поиска и тестирования я использовал этот код для связи с последовательным портом, но я немного его изменил.

Пожалуйста, прочитайте мое редактирование перед использованием этот код

Я использовал поток для чтения из последовательного порта, потому что использование прерываний (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 - модуль ядра может потеря ЦП в любой момент, и файл, который открывается ядром, может закрыться.

2- Я не совсем уверен в этом, но они сказали, что файлы должны иметь процесс, чтобы оставаться открытым, но сам модуль ядра не процесс (возможно, я ошибаюсь!).

3- Если во время работы с файлами возникает какая-либо ошибка (открытие / закрытие / чтение / запись), модуль ядра не может ее обработать и вызывает pani ядра c. ..

Я испытал много паники ядра только при открытии и закрытии файла, с которым я хотел работать. Это некоторые из причин, по которым вам не следует использовать файлы в модулях ядра, поэтому, как уже говорилось в каждом тексте: «Если вам нужно использовать файлы в модуле ядра, вы, вероятно, сделали что-то не так в своем коде!»

...