[ZLG-ARM] Linux设备驱动程序学习(1)-字符设备驱动程序

[复制链接]
2330|1
 楼主| reeper 发表于 2009-4-6 17:22 | 显示全部楼层 |阅读模式
一、主设备号和此设备号<br />主设备号表示设备对应的驱动程序;次设备号由内核使用,用于正确确定设备文件所指的设备。<br />内核用dev_t类型()来保存设备编号,dev_t是一个32位的数,12位表示主设备号,20为表示次设备号。<br />在实际使用中,是通过中定义的宏来转换格式。<br />(dev_t)--&gt主设备号、次设备号&nbsp;&nbsp;MAJOR(dev_t&nbsp;dev)<br />MINOR(dev_t&nbsp;dev)<br /><br />主设备号、次设备号--&gt(dev_t)&nbsp;&nbsp;MKDEV(int&nbsp;major,int&nbsp;minor)&nbsp;&nbsp;<br /><br />建立一个字符设备之前,驱动程序首先要做的事情就是获得设备编号。其这主要函数在中声明:<br /><br />int&nbsp;register_chrdev_region(dev_t&nbsp;first,&nbsp;unsigned&nbsp;int&nbsp;count,<br />char&nbsp;*name);&nbsp;&nbsp;&nbsp;//指定设备编号<br /><br />int&nbsp;alloc_chrdev_region(dev_t&nbsp;*dev,&nbsp;unsigned&nbsp;int&nbsp;firstminor,<br />unsigned&nbsp;int&nbsp;count,&nbsp;char&nbsp;*name);&nbsp;&nbsp;&nbsp;//动态生成设备编号<br /><br />void&nbsp;unregister_chrdev_region(dev_t&nbsp;first,&nbsp;unsigned&nbsp;int&nbsp;count);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//释放设备编号<br /><br /><br /><br />分配之设备号的最佳方式是:默认采用动态分配,同时保留在加载甚至是编译时指定主设备号的余地。<br /><br />以下是在scull.c中用来获取主设备好的代码:<br /><br />if&nbsp;(scull_major)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;dev&nbsp;=&nbsp;MKDEV(scull_major,&nbsp;scull_minor);<br />&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;=&nbsp;register_chrdev_region(dev,&nbsp;scull_nr_devs,&nbsp;'scull');<br />}&nbsp;else&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;=&nbsp;alloc_chrdev_region(&dev,&nbsp;scull_minor,&nbsp;scull_nr_devs,'scull');<br />&nbsp;&nbsp;&nbsp;&nbsp;scull_major&nbsp;=&nbsp;MAJOR(dev);<br />}<br />if&nbsp;(result&nbsp;&lt&nbsp;0)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;printk(KERN_WARNING&nbsp;'scull:&nbsp;can't&nbsp;get&nbsp;major&nbsp;%d<br />',&nbsp;scull_major);<br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result;<br />}<br /><br /><br /><br /><br /><br />在这部分中,比较重要的是在用函数获取设备编号后,其中的参数name是和该编号范围关联的设备名称,它将出现在/proc/devices和sysfs中。<br /><br />看到这里,就可以理解为什么mdev和udev可以动态、自动地生成当前系统需要的设备文件。udev就是通过读取sysfs下的信息来识别硬件设备的.<br />(请看《理解和认识udev》<br />URL:http://blog.chinaunix.net/u/6541/showart_396425.html)<br /><br /><br /><br /><br />--------------------------------------------------------------------------------<br /><br /><br />二、一些重要的数据结构<br />大部分基本的驱动程序操作涉及及到三个重要的内核数据结构,分别是file_operations、file和inode,它们的定义都在。<br /><br /><br /><br /><br /><br />--------------------------------------------------------------------------------<br /><br /><br />三、字符设备的注册<br /><br />内核内部使用struct&nbsp;cdev结构来表示字符设备。在内核调用设备的操作之前,必须分配并注册一个或多个struct&nbsp;cdev。代码应包含,它定义了struct&nbsp;cdev以及与其相关的一些辅助函数。<br /><br />注册一个独立的cdev设备的基本过程如下:<br /><br />1、为struct&nbsp;cdev&nbsp;分配空间(如果已经将struct&nbsp;cdev&nbsp;嵌入到自己的设备的特定结构体中,并分配了空间,这步略过!)<br /><br />struct&nbsp;cdev&nbsp;*my_cdev&nbsp;=&nbsp;cdev_alloc();<br /><br />2、初始化struct&nbsp;cdev&nbsp;<br /><br />void&nbsp;cdev_init(struct&nbsp;cdev&nbsp;*cdev,&nbsp;const&nbsp;struct&nbsp;file_operations&nbsp;*fops)&nbsp;<br />3、初始化cdev.owner<br /><br />cdev.owner&nbsp;=&nbsp;THIS_MODULE;<br /><br />4、cdev设置完成,通知内核struct&nbsp;cdev的信息(在执行这步之前必须确定你对struct&nbsp;cdev的以上设置已经完成!)<br /><br />int&nbsp;cdev_add(struct&nbsp;cdev&nbsp;*p,&nbsp;dev_t&nbsp;dev,&nbsp;unsigned&nbsp;count)<br /><br />从系统中移除一个字符设备:void&nbsp;cdev_del(struct&nbsp;cdev&nbsp;*p)<br /><br />以下是scull中的初始化代码(之前已经为struct&nbsp;scull_dev&nbsp;分配了空间):<br /><br />/*<br />*&nbsp;Set&nbsp;up&nbsp;the&nbsp;char_dev&nbsp;structure&nbsp;for&nbsp;this&nbsp;device.<br />*/<br />static&nbsp;void&nbsp;scull_setup_cdev(struct&nbsp;scull_dev&nbsp;*dev,&nbsp;int&nbsp;index)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;err,&nbsp;devno&nbsp;=&nbsp;MKDEV(scull_major,&nbsp;scull_minor&nbsp;+&nbsp;index);<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;cdev_init(&dev-&gtcdev,&nbsp;&scull_fops);<br />&nbsp;&nbsp;&nbsp;&nbsp;dev-&gtcdev.owner&nbsp;=&nbsp;THIS_MODULE;<br />&nbsp;&nbsp;&nbsp;&nbsp;dev-&gtcdev.ops&nbsp;=&nbsp;&scull_fops;&nbsp;&nbsp;//这句可以省略,在cdev_init中已经做过<br />&nbsp;&nbsp;&nbsp;&nbsp;err&nbsp;=&nbsp;cdev_add&nbsp;(&dev-&gtcdev,&nbsp;devno,&nbsp;1);<br />&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Fail&nbsp;gracefully&nbsp;if&nbsp;need&nbsp;be&nbsp;这步值得注意*/<br />&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(err)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printk(KERN_NOTICE&nbsp;'Error&nbsp;%d&nbsp;adding&nbsp;scull%d',&nbsp;err,&nbsp;index);<br />}<br /><br /><br /><br /><br />--------------------------------------------------------------------------------<br />四、scull模型的内存使用&nbsp;<br /><br /><br /><br />以下是scull模型的结构体:<br /><br />/*<br />*&nbsp;Representation&nbsp;of&nbsp;scull&nbsp;quantum&nbsp;sets.<br />*/<br />struct&nbsp;scull_qset&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;**data;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;scull_qset&nbsp;*next;<br />};<br /><br />struct&nbsp;scull_dev&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;scull_qset&nbsp;*data;&nbsp;/*&nbsp;Pointer&nbsp;to&nbsp;first&nbsp;quantum&nbsp;set&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;quantum;&nbsp;/*&nbsp;the&nbsp;current&nbsp;quantum&nbsp;size&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;qset;&nbsp;/*&nbsp;the&nbsp;current&nbsp;array&nbsp;size&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;long&nbsp;size;&nbsp;/*&nbsp;amount&nbsp;of&nbsp;data&nbsp;stored&nbsp;here&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;int&nbsp;access_key;&nbsp;/*&nbsp;used&nbsp;by&nbsp;sculluid&nbsp;and&nbsp;scullpriv&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;semaphore&nbsp;sem;&nbsp;/*&nbsp;mutual&nbsp;exclusion&nbsp;semaphore&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;cdev&nbsp;cdev;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Char&nbsp;device&nbsp;structure&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/<br />};<br /><br /><br />scull驱动程序引入了两个Linux内核中用于内存管理的核心函数,它们的定义都在:&nbsp;void&nbsp;*kmalloc(size_t&nbsp;size,&nbsp;int&nbsp;flags);<br />void&nbsp;kfree(void&nbsp;*ptr);<br /><br /><br /><br />以下是scull模块中的一个释放整个数据区的函数(类似清零),将在scull以写方式打开和scull_cleanup_module中被调用:<br /><br />int&nbsp;scull_trim(struct&nbsp;scull_dev&nbsp;*dev)<br />{<br />&nbsp;&nbsp;struct&nbsp;scull_qset&nbsp;*next,&nbsp;*dptr;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;qset&nbsp;=&nbsp;dev-&gtqset;&nbsp;/*&nbsp;量子集中量子的个数*/<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;i;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(dptr&nbsp;=&nbsp;dev-&gtdata;&nbsp;dptr;&nbsp;dptr&nbsp;=&nbsp;next)&nbsp;{&nbsp;/*&nbsp;循环scull_set个数次,直到dptr为NULL为止。*/<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(dptr-&gtdata)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt&nbsp;qset;&nbsp;i++)/*&nbsp;循环一个量子集中量子的个数次*/<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kfree(dptr-&gtdata);/*&nbsp;释放其中一个量子的空间*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kfree(dptr-&gtdata);/*&nbsp;释放当前的scull_set的量子集的空间*/<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dptr-&gtdata&nbsp;=&nbsp;NULL;/*&nbsp;释放一个scull_set中的void&nbsp;**data指针*/<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next&nbsp;=&nbsp;dptr-&gtnext;&nbsp;/*&nbsp;准备下个scull_set的指针*/<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kfree(dptr);/*&nbsp;释放当前的scull_set*/<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;dev-&gtsize&nbsp;=&nbsp;0;&nbsp;/*&nbsp;当前的scull_device所存的数据为0字节*/<br />&nbsp;&nbsp;dev-&gtquantum&nbsp;=&nbsp;scull_quantum;/*&nbsp;初始化一个量子的大小*/<br />&nbsp;&nbsp;dev-&gtqset&nbsp;=&nbsp;scull_qset;/*&nbsp;初始化一个量子集中量子的个数*/<br />&nbsp;&nbsp;dev-&gtdata&nbsp;=&nbsp;NULL;/*&nbsp;释放当前的scull_device的struct&nbsp;scull_qset&nbsp;*data指针*/<br />&nbsp;&nbsp;return&nbsp;0;<br />}<br /><br /><br />以下是scull模块中的一个沿链表前行得到正确scull_set指针的函数,将在read和write方法中被调用:<br /><br />/*Follow&nbsp;the&nbsp;list*/<br />struct&nbsp;scull_qset&nbsp;*scull_follow(struct&nbsp;scull_dev&nbsp;*dev,&nbsp;int&nbsp;n)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;scull_qset&nbsp;*qs&nbsp;=&nbsp;dev-&gtdata;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Allocate&nbsp;first&nbsp;qset&nbsp;explicitly&nbsp;if&nbsp;need&nbsp;be&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!&nbsp;qs)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;qs&nbsp;=&nbsp;dev-&gtdata&nbsp;=&nbsp;kmalloc(sizeof(struct&nbsp;scull_qset),&nbsp;GFP_KERNEL);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(qs&nbsp;==&nbsp;NULL)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;NULL;&nbsp;/*&nbsp;Never&nbsp;mind&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memset(qs,&nbsp;0,&nbsp;sizeof(struct&nbsp;scull_qset));<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Then&nbsp;follow&nbsp;the&nbsp;list&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;while&nbsp;(n--)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!qs-&gtnext)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;qs-&gtnext&nbsp;=&nbsp;kmalloc(sizeof(struct&nbsp;scull_qset),&nbsp;GFP_KERNEL);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(qs-&gtnext&nbsp;==&nbsp;NULL)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;NULL;&nbsp;/*&nbsp;Never&nbsp;mind&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;memset(qs-&gtnext,&nbsp;0,&nbsp;sizeof(struct&nbsp;scull_qset));<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;qs&nbsp;=&nbsp;qs-&gtnext;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;qs;<br />}<br /><br /><br />其实这个函数的实质是:如果已经存在这个scull_set,就返回这个scull_set的指针。如果不存在这个scull_set,一边沿链表为scull_set分配空间一边沿链表前行,直到所需要的scull_set被分配到空间并初始化为止,就返回这个scull_set的指针。&nbsp;<br /><br /><br /><br />--------------------------------------------------------------------------------<br />五、open和release&nbsp;<br /><br />open方法提供给驱动程序以初始化的能力,为以后的操作作准备。应完成的工作如下:<br /><br />(1)检查设备特定的错误(如设备未就绪或硬件问题);<br /><br />(2)如果设备是首次打开,则对其进行初始化;<br /><br />(3)如有必要,更新f_op指针;<br /><br />(4)分配并填写置于filp-&gtprivate_data里的数据结构。<br /><br />而根据scull的实际情况,他的open函数只要完成第四步(将初始化过的struct&nbsp;scull_dev&nbsp;dev的指针传递到filp-&gtprivate_data里,以备后用)就好了,所以open函数很简单。但是其中用到了定义在中的container_of宏,源码如下:<br /><br />#define&nbsp;container_of(ptr,&nbsp;type,&nbsp;member)&nbsp;({&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;typeof(&nbsp;((type&nbsp;*)0)-&gtmember&nbsp;)&nbsp;*__mptr&nbsp;=&nbsp;(ptr);&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;(type&nbsp;*)(&nbsp;(char&nbsp;*)__mptr&nbsp;-&nbsp;offsetof(type,member)&nbsp;);})<br /><br /><br /><br />其实从源码可以看出,其作用就是:通过指针ptr,获得包含ptr所指向数据(是member结构体)的type结构体的指针。即是用指针得到另外一个指针。<br /><br />release方法提供释放内存,关闭设备的功能。应完成的工作如下:<br /><br />(1)释放由open分配的、保存在file-&gtprivate_data中的所有内容;<br /><br />(2)在最后一次关闭操作时关闭设备。<br /><br />由于前面定义了scull是一个全局且持久的内存区,所以他的release什么都不做。<br /><br /><br /><br />--------------------------------------------------------------------------------<br />六、read和write&nbsp;<br /><br />read和write方法的主要作用就是实现内核与用户空间之间的数据拷贝。因为Linux的内核空间和用户空间隔离的,所以要实现数据拷贝就必须使用在中定义的:<br /><br />unsigned&nbsp;long&nbsp;copy_to_user(void&nbsp;__user&nbsp;*to,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;void&nbsp;*from,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;long&nbsp;count);<br />unsigned&nbsp;long&nbsp;copy_from_user(void&nbsp;*to,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;void&nbsp;__user&nbsp;*from,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;long&nbsp;count);<br /><br /><br />而值得一提的是以上两个函数和<br /><br />#define&nbsp;__copy_from_user(to,from,n)&nbsp;&nbsp;&nbsp;&nbsp;(memcpy(to,&nbsp;(void&nbsp;__force&nbsp;*)from,&nbsp;n),&nbsp;0)<br />#define&nbsp;__copy_to_user(to,from,n)&nbsp;&nbsp;&nbsp;&nbsp;(memcpy((void&nbsp;__force&nbsp;*)to,&nbsp;from,&nbsp;n),&nbsp;0)<br /><br /><br />之间的关系:通过源码可知,前者调用后者,但前者在调用前对用户空间指针进行了检查。<br /><br />至于read和write&nbsp;的具体函数比较简单,就在实验中验证好了。<br /><br /><br /><br /><br />--------------------------------------------------------------------------------<br /><br /><br />七、模块实验<br /><br /><br /><br />这次模块实验的使用是友善之臂SBC2440V4,使用Linux2.6.22.2内核。<br /><br />模块程序链接:scull模块源程序<br />模块测试程序链接:模块测试程序<br /><br />测试结果:<br /><br /><br />量子大小为6:<br /><br />[Tekkaman2440@SBC2440V4]#cd&nbsp;/lib/modules/&nbsp;[Tekkaman2440@SBC2440V4]#insmod&nbsp;scull.ko&nbsp;scull_quantum=6<br /><br />[Tekkaman2440@SBC2440V4]#cat&nbsp;/proc/devices<br />Character&nbsp;devices:<br />&nbsp;&nbsp;1&nbsp;mem<br />&nbsp;&nbsp;2&nbsp;pty<br />&nbsp;&nbsp;3&nbsp;ttyp<br />&nbsp;&nbsp;4&nbsp;/dev/vc/0<br />&nbsp;&nbsp;4&nbsp;tty<br />&nbsp;&nbsp;4&nbsp;ttyS<br />&nbsp;&nbsp;5&nbsp;/dev/tty<br />&nbsp;&nbsp;5&nbsp;/dev/console<br />&nbsp;&nbsp;5&nbsp;/dev/ptmx<br />&nbsp;&nbsp;7&nbsp;vcs<br />10&nbsp;misc<br />13&nbsp;input<br />14&nbsp;sound<br />81&nbsp;video4linux<br />89&nbsp;i2c<br />90&nbsp;mtd<br />116&nbsp;alsa<br />128&nbsp;ptm<br />136&nbsp;pts<br />180&nbsp;usb<br />189&nbsp;usb_device<br />204&nbsp;s3c2410_serial<br />252&nbsp;scull<br />253&nbsp;usb_endpoint<br />254&nbsp;rtc<br /><br />Block&nbsp;devices:<br />&nbsp;&nbsp;1&nbsp;ramdisk<br />256&nbsp;rfd<br />&nbsp;&nbsp;7&nbsp;loop<br />31&nbsp;mtdblock<br />93&nbsp;nftl<br />96&nbsp;inftl<br />179&nbsp;mmc<br />[Tekkaman2440@SBC2440V4]#mknod&nbsp;-m&nbsp;666&nbsp;scull0&nbsp;c&nbsp;&nbsp;252&nbsp;0<br />[Tekkaman2440@SBC2440V4]#mknod&nbsp;-m&nbsp;666&nbsp;scull1&nbsp;c&nbsp;&nbsp;252&nbsp;1<br />[Tekkaman2440@SBC2440V4]#mknod&nbsp;-m&nbsp;666&nbsp;scull2&nbsp;c&nbsp;&nbsp;252&nbsp;2<br />[Tekkaman2440@SBC2440V4]#mknod&nbsp;-m&nbsp;666&nbsp;scull3&nbsp;c&nbsp;&nbsp;252&nbsp;3<br /><br /><br /><br /><br />--------------------------------------------------------------------------------<br /><br />启动测试程序<br /><br /><br />[Tekkaman2440@SBC2440V4]#./scull_test&nbsp;<br /><br /><br />write&nbsp;error!&nbsp;code=6&nbsp;<br /><br /><br />write&nbsp;error!&nbsp;code=6&nbsp;<br /><br /><br />write&nbsp;error!&nbsp;code=6&nbsp;<br /><br /><br />write&nbsp;ok!&nbsp;code=2&nbsp;<br /><br /><br />read&nbsp;error!&nbsp;code=6&nbsp;<br /><br /><br />read&nbsp;error!&nbsp;code=6&nbsp;<br /><br /><br />read&nbsp;error!&nbsp;code=6&nbsp;<br /><br /><br />read&nbsp;ok!&nbsp;code=2&nbsp;<br /><br /><br />[0]=0&nbsp;[1]=1&nbsp;[2]=2&nbsp;[3]=3&nbsp;[4]=4&nbsp;<br /><br /><br />[5]=5&nbsp;[6]=6&nbsp;[7]=7&nbsp;[8]=8&nbsp;[9]=9&nbsp;<br /><br /><br />[10]=10&nbsp;[11]=11&nbsp;[12]=12&nbsp;[13]=13&nbsp;[14]=14&nbsp;<br /><br /><br />[15]=15&nbsp;[16]=16&nbsp;[17]=17&nbsp;[18]=18&nbsp;[19]=19<br /><br /><br />--------------------------------------------------------------------------------<br />改变量子大小为默认值4000:<br />[Tekkaman2440@SBC2440V4]#cd&nbsp;/lib/modules/<br />[Tekkaman2440@SBC2440V4]#rmmod&nbsp;scull<br />[Tekkaman2440@SBC2440V4]#insmod&nbsp;scull.ko<br /><br /><br />--------------------------------------------------------------------------------<br />启动测试程序<br />[Tekkaman2440@SBC2440V4]#./scull_test<br />write&nbsp;ok!&nbsp;code=20<br />read&nbsp;ok!&nbsp;code=20<br />[0]=0&nbsp;[1]=1&nbsp;[2]=2&nbsp;[3]=3&nbsp;[4]=4<br />[5]=5&nbsp;[6]=6&nbsp;[7]=7&nbsp;[8]=8&nbsp;[9]=9<br />[10]=10&nbsp;[11]=11&nbsp;[12]=12&nbsp;[13]=13&nbsp;[14]=14<br />[15]=15&nbsp;[16]=16&nbsp;[17]=17&nbsp;[18]=18&nbsp;[19]=19<br /><br />[Tekkaman2440@SBC2440V4]#&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />--------------------------------------------------------------------------------<br />改变量子大小为6,量子集大小为2:<br />[Tekkaman2440@SBC2440V4]#cd&nbsp;/lib/modules/<br />[Tekkaman2440@SBC2440V4]#rmmod&nbsp;scull<br />[Tekkaman2440@SBC2440V4]#insmod&nbsp;scull.ko&nbsp;scull_quantum=6&nbsp;scull_qset=2<br /><br />--------------------------------------------------------------------------------<br />启动测试程序<br />[Tekkaman2440@SBC2440V4]#./scull_test<br />write&nbsp;error!&nbsp;code=6<br />write&nbsp;error!&nbsp;code=6<br />write&nbsp;error!&nbsp;code=6<br />write&nbsp;ok!&nbsp;code=2<br />read&nbsp;error!&nbsp;code=6<br />read&nbsp;error!&nbsp;code=6<br />read&nbsp;error!&nbsp;code=6<br />read&nbsp;ok!&nbsp;code=2<br />[0]=0&nbsp;[1]=1&nbsp;[2]=2&nbsp;[3]=3&nbsp;[4]=4<br />[5]=5&nbsp;[6]=6&nbsp;[7]=7&nbsp;[8]=8&nbsp;[9]=9<br />[10]=10&nbsp;[11]=11&nbsp;[12]=12&nbsp;[13]=13&nbsp;[14]=14<br />[15]=15&nbsp;[16]=16&nbsp;[17]=17&nbsp;[18]=18&nbsp;[19]=19<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><br /><br />实验不仅测试了模块的读写能力,还测试了量子读写是否有效。<br />&nbsp;<br /> &nbsp;&nbsp;<br />
initer 发表于 2009-4-7 15:02 | 显示全部楼层

听说字符设备驱动是比较简单的

  
您需要登录后才可以回帖 登录 | 注册

本版积分规则

139

主题

185

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部