《linux字符驱动设备》由会员分享,可在线阅读,更多相关《linux字符驱动设备(11页珍藏版)》请在金锄头文库上搜索。
1、Linux 字符驱动设备的模板框架( 2.4 内核)/* leddrv.c - Create an input/output character device */#include #include #include #include /* for -EBUSY */#include /* for verify_area */#include /* for module_init */#include /* for get_user and put_user */#include #include drv.h#define BUF_LEN 4#define DEVICE_NAME char_d
2、ev/*驱动实现的功能函数*/static int device_open(struct inode *inode, struct file *file)static int device_release(struct inode *inode, struct file *file)static ssize_t device_read(struct file *file,char *buffer,size_t length, loff_t *offset) static ssize_t device_write(struct file *file,const char *buffer,size
3、_t length,loff_t *offset)int device_ioctl(struct inode *inode,struct file *file,unsigned int ioctl_num, unsigned long ioctl_param) /*驱动实现的功能函数*/*模块加载、卸载、声明*/struct file_operations Fops = .read = device_read, .write = device_write,.open = device_open,.release = device_release,.ioctl = device_ioctl;/*
4、这个文件结构体非常重要 ,联系内核和用户空间的桥梁*/* Initialize the module - Register the character device */static int _init led_module_init( void )ret_val = register_chrdev(MAJOR_NUM, DEVICE_NAME, /* Cleanup - unregister the appropriate file from /proc */static void _exit led_module_cleanup(void)ret = unregister_chrdev(M
5、AJOR_NUM, DEVICE_NAME);module_init(led_module_init);module_exit(led_module_cleanup);MODULE_LICENSE(GPL);MODULE_AUTHOR(Cvtech Co., Ltd );MODULE_DESCRIPTION(LED char driver);/*模块加载、卸载、声明*/重要函数的说明:1、 模块注册删除函数:模块注册register_chrdev(MAJOR_NUM, DEVICE_NAME, 功能:向内核注册一个字符驱动MAJOR_NUM 驱动主设备号。如果内核中已经相同的设备号,注册会失败
6、。DEVICE_NAME 设备名称模块删除unregister_chrdev( MAJOR_NUM, DEVICE_NAME ); 2、file_operationsstruct file_operations Fops = .read = device_read,/左边表示系统调用名称,右边表示编写的函数名.write = device_write,.open = device_open,.release = device_release,.ioctl = device_ioctl;file_operations 结构体中的成员函数是字符驱动设备程序设计中的主体内容,这些函数实际会在应用程序
7、进行 Linux 的 open(),write(),close()等系统调用时最终被调用。file_operations 的功能:file_operation 就是把系统调用和驱动程序关联起来的关键数据结构。这个结构的每一个成员都对应着一个系统调用。读取 file_operation 中相应的函数指针,接着把控制权转交给函数,从而完成了 Linux 设备驱动程序的工作。 在系统内部,I/O 设备的存取操作通过特定的入口点来进行,而这组特定的入口点恰恰是由设备驱动程序提供的。通常这组设备驱动程序接口是由结构file_operations 结构体向系统说明的,它定义在 include/linux/
8、fs.h 中。传统上, 一个 file_operation 结构或者其一个指针称为 fops( 或者它的一些变体).结构中的每个成员必须指向驱动中的函数, 这些函数实现一个特别的操作 , 或者对于不支持的操作留置为 NULL. 当指定为 NULL 指针时内核的确切的行为是每个函数不同的。file_operations 的理解:内核内部通过 file 结构识别设备,通过 file_operations 数据结构提供文件系统的入口点函数,也就是访问设备驱动的函数。这个结构的每一个成员的名字都对应着一个系统调用。在用户进程利用系统调用对设备文件进行诸如 read/write 操作时,系统调用通过设备
9、文件的主设备号找到相应的设备驱动程序,然后读取这个数据结构相应的函数指针,接着把控制权交给该函数,这是 Linux 设备驱动程序工作的基本原理。 从某种意义上说,写驱动程序的任务之一就是完成 file_operations 中的函数指针。File_operations 相关的函数说明:static int device_open(struct inode *inode, struct file *file)struct file 代表一个打开的文件,在执行 file_operation 中的 open 操作时被创建,这里需要注意的是与用户空间 inode 指针的区别,一个在内核,而 file
10、指针在用户空间,由 c 库来定义。struct inode 被内核用来代表一个文件,注意和 struct file 的区别,struct inode 一个是代表文件,struct file 一个是代表打开的文件static ssize_t device_read(struct file *file,char *buffer,size_t length, loff_t *offset)struct file*file 为文件结构体指针char*buffer 是读取文件的缓冲区size_t length 为读取信息的长度loff_t*offset 是读取文件当前的偏移位置,这个值通常是用来判断文件
11、是否越界注意:1、由于驱动工作在内核态,所以打印语句需要使用 printk()而不是 printf()2、 在驱动编写的 device_open 和 device_write 以及 device_ioctl 这几个个函数中会访问用户空间的内存,但是我们不能直接引用传递过来指针,这些传递过来的指针都是指向用户内存空间的,在驱动中需要使用 get_usr()函数和put_usr()函数来实现内核内存空间和用户内存空间之间的数据复制。get_usr(int a,int *buffer)从用户空间写入字符到内核空间设备文件:从缓冲区写入到变量 aput_usr(int a, int*buffer) 从
12、内核空间设备文件读入字符到用户空间实例:static ssize_t device_write(struct file *file, const char *buffer, size_t length, loff_t *offset)int value;int bytes_writes = 4;int* data = (int*)buffer;char str256;get_user(value, data);flags = value;sprintf(str, device_write %dn, flags);printk(str);/* Again, return the number o
13、f input characters used */return bytes_writes;驱动实例/* leddrv.c - Create an input/output character device */#include #include #include #include /* for -EBUSY */#include /* for verify_area */#include /* for module_init */#include /* for get_user and put_user */#include #include drv.h#define BUF_LEN 4#d
14、efine DEVICE_NAME char_devint device_ioctl(struct inode *,struct file *,unsigned int ,unsigned long ); /* This function is called whenever a process attempts * to open the device file */static int device_open(struct inode *inode, struct file *file)用户空间输入字符内核空间从用户空间复制字符 printk(Device Openn);/* We don
15、t want to talk to two processes at the * same time */if (Device_Open) return -EBUSY;Device_Open+; /标记打开的设备数MOD_INC_USE_COUNT;/* Initialize the message */Message_Ptr = Message; /消息队列return 0;/* This function is called when a process closes the * device file. It doesnt have a return value because * it cannot fail. Regardless of what else happens, you * should always be able to close a device (in 2.0, a 2.2* device file could be impossible to close).*/static int device_release(struct inode *inode, st