给网站做排名优化学什么好,浙江虎霸建设机械有限公司网站,泉州模板网站建站,佛山网站建设 骏域网站一、字符设备概述
Linux 系统中#xff0c;设备被分为字符设备、块设备和网络设备等。字符设备以字节流的方式进行数据传输#xff0c;数据的访问是按顺序的#xff0c;一个字节一个字节地进行读取和写入操作#xff0c;没有缓冲区。例如#xff0c;终端#xff08;/dev…一、字符设备概述
Linux 系统中设备被分为字符设备、块设备和网络设备等。字符设备以字节流的方式进行数据传输数据的访问是按顺序的一个字节一个字节地进行读取和写入操作没有缓冲区。例如终端/dev/tty、鼠标、键盘等设备都是典型的字符设备。
字符设备通过特殊的设备文件来表示。这些设备文件通常位于/dev目录下。设备文件有主设备号major number和次设备号minor number。主设备号用于标识设备驱动程序内核通过主设备号来查找对应的驱动程序次设备号用于标识同一类型设备中的不同个体。例如系统中可能有多个串口设备它们的主设备号相同表示使用相同的驱动程序但次设备号不同用于区分不同的串口。
二、字符设备驱动开发
1、驱动文件
//添加头文件
#include linux/init.h
#include linux/module.h
#include linux/ide.hstatic char readbuf[100]; // 读缓冲区
static char writebuf[100]; // 写缓冲区
static char message[] {This message comes from kernel.};static int drive_major; //设备号
static struct class *KernelPrint_cls;//1.5.5 驱动程序的打开读取写入关闭。
static int KernelPrint_open(struct inode *inode, struct file *filp) //打开函数
{//本DEMO无需申请资源此处留白printk(-KernelPrint open-\n);return 0;
}
static ssize_t KernelPrint_read(struct file *filp, char __user *buf, size_t count, loff_t *fops) //用户读取内核发送信息
{int flag 0;memcpy(readbuf, message, sizeof(message)); //使用memcpy将内核中要发送的内容写入读缓冲区flag copy_to_user(buf, readbuf, count); //使用copy_to_user函数将读缓冲区的内容发送到用户态if (flag 0) //返回0成功否则失败{printk(Kernel send data success!\n);}else{printk(Kernel send data failed!\n);}printk(-KernelPrint read-\n);return 0;
}
static ssize_t KernelPrint_write(struct file *filp, const char __user *buf, size_t count, loff_t *fops) //用户发送内核读取信息并打印
{int flag 0;flag copy_from_user(writebuf, buf, count); //使用copy_from_user读取用户态发送过来的数据if (flag 0){printk(KERN_CRIT Kernel receive data: %s\n, writebuf);}else{printk(Kernel receive data failed!\n);}printk(-KernelPrint write-\n);return 0;
}
static int KernelPrint_release(struct inode *inode, struct file *filp) //释放设备
{//由于open函数并没有占用什么资源因此无需释放printk(-KernelPrint release-\n);return 0;
}//1.5.1 驱动文件描述集合
static struct file_operations drive_fops {.owner THIS_MODULE,.open KernelPrint_open,.read KernelPrint_read,.write KernelPrint_write,.release KernelPrint_release,
};//1.5.2 装载入口函数
static __init int KernelPrint_init(void)
{printk(-------^v^-------\n);printk(-KernelPrint init-\n);//1.5.3 设备的申请//申请主设备号//参数1----需要的主设备号0静态分配 0自动分配//参数2----设备的描述 信息体现在cat /proc/devices 一般自定义//参数3----文件描述集合//返回值小于0报错drive_major register_chrdev(0, KernelPrint, drive_fops);if (drive_major 0) //判断是否申请成功{printk(register chrdev faile!\n);return drive_major;}else{printk(register chrdev ok!\n);}//1.5.4 //自动创建设备节点//创建设备的类别//参数1----设备的拥有者当前模块直接填THIS_MODULE//参数2----设备类别的名字自定义//返回值类别结构体指针其实就是分配了一个结构体空间KernelPrint_cls class_create(THIS_MODULE, KernelPrint_class);printk(class create ok!\n);//创建设备//参数1----设备对应的类别//参数2----当前设备的父类直接填NULL//参数3----设备节点关联的设备号//参数4----私有数据直接填NULL//参数5----设备节点的名字device_create(KernelPrint_cls, NULL, MKDEV(drive_major, 0), NULL, KernelPrint_%d, 0);printk(device create ok!\n);return 0;
}//1.5.2 卸载入口函数
static __exit void KernelPrint_exit(void)
{//1.5.3 设备的注销device_destroy(KernelPrint_cls, MKDEV(drive_major, 0)); //删除设备class_destroy(KernelPrint_cls); //删除类unregister_chrdev(drive_major, KernelPrint); //注销主设备号printk(-------^v^-------\n);printk(-KernelPrint exit-\n);
}//申明装载入口函数和卸载入口函数
module_init(KernelPrint_init);
module_exit(KernelPrint_exit);//添加各类信息
MODULE_LICENSE(GPL);
MODULE_AUTHOR(Popeye);2、应用文件
#include stdio.h
#include unistd.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdlib.h
#include string.hint main(int argc, char *argv[])
{int fd, retvalue;char *filename;char readbuf[100], writebuf[100];filename argv[1];fd open(filename, O_RDWR); //打开设备if (fd 0){printf(Cant open file %s\n, filename);return -1;}switch (*argv[2]) //对操作数进行解析{case r:if (argc ! 3) //进行鲁棒性检查{printf(Unknow operation, use the formate: ./APPNAME /dev/DRIVENAME r to read date from kernel.\n);return -1;}retvalue read(fd, readbuf, 100);if (retvalue 0) //检查是否读取成功{printf(Read file %s failed!\n, filename);}else{printf(User receive data: %s\n, readbuf);}break;case w:if (argc ! 4) //进行鲁棒性检查{printf(Unknow operation, use the formate: ./APPNAME /dev/DRIVENAME w \USERDATE\ to write date to kernel.\n);return -2;}memcpy(writebuf, argv[3], strlen(argv[3])); //将内容拷贝到缓冲区retvalue write(fd, writebuf, 50); //写数据if (retvalue 0){printf(Write file %s failed!\n, filename);}else{printf(Write file success!\n);}break;default:printf(Unknow Operation: %d\n, *argv[2]);break;}retvalue close(fd); //关闭设备if (retvalue 0){printf(Cant close file %s\n, filename);return -1;}return 0;
}三、上板验证
安装驱动insmod kernel_print.ko查看驱动安装是否成功ls /dev/kernel_print内核打印测试./kernel_print_app /dev/KernelPrint_0 w Popeye