中程在线信息产业培训网字符设备驱动程序中程在线信息产业培训网确定主设备号和次设备号。确定设备名称。创建设备文件。实现字符驱动程序实现file_operations结构体。实现初始化函数,注册字符设备。实现销毁函数,取消字符设备。实现步骤中程在线信息产业培训网什么是主设备/次设备号主设备号是内核识别一个设备的标识。是一个整数,范围从0到(4096-1),但是一般使用1到255。次设备号是驱动程序自己用来区别多个设备。是一个整数,范围从0到(1048576-1),但是一般使用0到255。预定义的设备号:详见Documentation/devices.txt查看设备号:$ls–l/dev设备编号的内部表示获得一个dev_t的主或者次编号:MAJOR(dev_tdev);MINOR(dev_tdev);主次编号转换为一个dev_t:MKDEV(intmajor,intminor);分配主设备号/次设备号手工分配主设备号:找一个内核没有使用的主设备号来使用。intregister_chrdev_region(dev_tfirst,unsignedintcount,char*name);动态分配主设备号intalloc_chrdev_region(dev_t*dev,unsignedintfirstminor,unsignedintcount,char*name);释放设备编号voidunregister_chrdev_region(dev_tfirst,unsignedintcount);确定设备号中程在线信息产业培训网获取主编号的代码if(scull_major){dev=MKDEV(scull_major,scull_minor);result=register_chrdev_region(dev,scull_nr_devs,scull);}else{result=alloc_chrdev_region(&dev,scull_minor,scull_nr_devs,scull);scull_major=MAJOR(dev);}if(result0){printk(KERN_WARNINGscull:can'tgetmajor%d\n,scull_major);returnresult;}中程在线信息产业培训网确定设备名称:设备名称是一个合法的文件名称即可。创建设备文件mknod设备文件名设备类型主设备号次设备号○设备文件名:一般是设备名称,或者是设备名称+数字。比如设备名称为chartest,设备文件名可以为chartest0,chartest1。○设备类型主要有c(字符设备类型)和b(块设备类型)。示例:○mknod/dev/chartest0c2540○mknod/dev/chartest1c2541确定设备名称中程在线信息产业培训网字符设备驱动架构图中程在线信息产业培训网scull_dev结构structscull_dev{structscull_qset*data;/*Pointertofirstquantumset*/intquantum;/*thecurrentquantumsize*/intqset;/*thecurrentarraysize*/unsignedlongsize;/*amountofdatastoredhere*/unsignedintaccess_key;/*usedbysculluidandscullpriv*/structsemaphoresem;/*mutualexclusionsemaphore*/structcdevcdev;/*Chardevicestructure*/};中程在线信息产业培训网设备注册staticvoidscull_setup_cdev(structscull_dev*dev,intindex){interr,devno=MKDEV(scull_major,scull_minor+index);cdev_init(&dev-cdev,&scull_fops);dev-cdev.owner=THIS_MODULE;dev-cdev.ops=&scull_fops;err=cdev_add(&dev-cdev,devno,1);/*Failgracefullyifneedbe*/if(err)printk(KERN_NOTICEError%daddingscull%d,err,index);}中程在线信息产业培训网向内核注册字符设备,在模块或者驱动初始化的时候调用。intregister_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops);注销设备驱动程序,在模块或者驱动销毁的时候调用。当从系统中卸载一个模块时,应该释放主设备号intunregister_chrdev(unsignedintmajor,constchar*name);注册和删除设备(旧方法)中程在线信息产业培训网字符驱动和内核的接口:file_operations结构体。结构体多是一些函数指针,我们要实现其中的主要函数。在(include/linux/fs.h)定义。字符驱动只要实现一个file_operations结构体,并注册到内核中,内核就有了操作此设备的能力。file_operations的主要域:○structmodule*owner:指向模块自身。○open:打开设备。○release:关闭设备。○read:从设备上读数据。○write::向设备上写数据。○ioctl:操作设备函数。○llseek:定位读写指针。○mmap:映射设备空间到进程的地址空间。file_operations结构体(1)中程在线信息产业培训网声明file_operations结构变量,使用了标记化的结构初始化语法。示例:structfile_operationsscull_fops={.owner=THIS_MODULE,.llseek=scull_llseek,.read=scull_read,.write=scull_write,.ioctl=scull_ioctl,.open=scull_open,.release=scull_release,};file_operations结构体(2)中程在线信息产业培训网file结构:和file_operations结构相关的一个结构体。描述一个正在打开的设备文件,相当于一个设备的实例。○loff_tf_pos:当前读/写位置。○unsignedintf_flags:标识文件打开时,是否可读或可写,如O_RDONLY、O_NONBLOCK和O_SYNC。○structfile_operations*f_op:与文件相关的操作,指向所实现的structfile_operations结构体。○void*private_data:私有数据指针。驱动程序可以将这个成员用于任何目的或者忽略这个成员。file结构中程在线信息产业培训网inode结构dev_ti_rdev;对于代表设备文件的节点,这个成员包含实际的设备编号.structcdev*i_cdev;内核的内部结构,代表字符设备;中程在线信息产业培训网file结构和file_operations结构体中程在线信息产业培训网打开open(structinode*inode,structfile*filp)模块使用计数加1。识别次设备号,如有必要更新f_op指针。分配并填写置于filp-private_data里的数据结构。硬件操作:○检查设备相关错误(诸如设备未就绪或类似的硬件问题)。○如果设备是首次打开,则对其初始化。○如果有中断操作,申请中断处理程序。打开和关闭(1)中程在线信息产业培训网scull_open代码intscull_open(structinode*inode,structfile*filp){structscull_dev*dev;/*deviceinformation*/dev=container_of(inode-i_cdev,structscull_dev,cdev);filp-private_data=dev;/*forothermethods*//*nowtrimto0thelengthofthedeviceifopenwaswrite-only*/if((filp-f_flags&O_ACCMODE)==O_WRONLY){scull_trim(dev);/*ignoreerrors*/}return0;/*success*/}中程在线信息产业培训网关闭release(structinode*inode,structfile*filp)模块使用计数减1释放放由open分配的,保存在filp-private_data中的所有内容硬件操作○如果申请了中断,则释放中断处理程序。○在最后一次关闭操作时关闭设备打开和关闭(2)中程在线信息产业培训网读写:read/writessize_tread(structfile*filp,char*buff,size_tcount,loff_t*offp);ssize_twrite(structfile*filp,constchar*buff,size_tcount,loff_t*offp);参数说明:参数filp是文件指针,参数buff是指向用户空间的缓冲区,这个缓冲区或者保存将写入的数据,或者是一个存放新读入数据的空缓冲区。参数count是请求传输的数据长度。最后的offp是一个指向“longoffsettype(长偏移量类型)”对象的指针,这个对象指明用户在文件中存取操作的位置。read/write(1)中程在线信息产业培训网用户空间和内核空间之间进行数据拷贝的函数。unsignedlongcopy_to_user(void*to,constvoid*from,unsignedlongcount);unsignedlongcopy_from_user(void*to,constvoid*from,unsignedlongcount);read/write(3)中程在线信息产业培训网read的参数说明read/write(4)中程在线信息产业培训网ioctl函数,为设备驱动程序执行“命令”提供了一个特有的入口点,用来设置或者读取设备的属性信息。int(*ioctl)(structinode*inode,structfile*filp,unsignedintcmd,unsignedlongarg);在用户空间对应的ioctl系统调用为:intioctl(intd,intcmd,...);在用户空间对字符设备调用ioctl系统调用,会最终调用字符设备的ioctl函数。ioctl函数中程在线信息产业培训网mmap函数mmap函数,将设备地址空间映射到进程地址空间。int(*mmap)(structfile*filp,structvm_area_struct*vma);在用户空间对应的mmap系统调用为:intmmap(caddr_taddr,size_tlen,intprot,intflags,intfd,off_toffset);