内核中的串行端口访问 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!"
我想在内核 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!"