当前位置: 首页 > news >正文

北京南站最新消息wordpress 安装字体

北京南站最新消息,wordpress 安装字体,这么做介绍网站的ppt,苏州做网站设计的公司有哪些linux设备驱动归纳总结(三)#xff1a;3.设备驱动面向对象思想和lseek的实现一、结构体structfile和struct inode在之前写的函数#xff0c;全部是定义了一些零散的全局变量。有没有办法整合成到一个结构体当中#xff1f;这样的话#xff0c;看起来和用起来都比较方便。接…linux设备驱动归纳总结(三)3.设备驱动面向对象思想和lseek的实现一、结构体structfile和struct inode在之前写的函数全部是定义了一些零散的全局变量。有没有办法整合成到一个结构体当中这样的话看起来和用起来都比较方便。接下来就要说这方面的问题。不过先要介绍一下除了fops以外的两个比较重要的结构体1)structfile在内核中file结构体是用来维护打开的文件的。每打开一次文件内核空间里就会多增加一个file来维护当文件关闭是释放。所以在内核中可以存在同一个文件的多个file因为该文件被应用程序打开被打开。在structfile中有几个重要的成员1)loff_tf_pos;这是用来记录文件的偏移量。在应用程序中打开文件时偏移量为0每次的读写操作都会使偏移量增加。从这个原因可以看出为什么每打开一次文件就新建一个file结构体了。不然的话每个打开文件的读写操作都修改同一个偏移量那读写岂不是乱套了吗2)void*private_data;这是空类型的指针可以用于存放任何数据我会用这个指针来存放待会要定义的结构体指针。回想一下文件操作结构体fops中所有的函数成员里面都有一个参数是file结构体所以每个函数都可以在file-private_data中拿到我自己定义的结构体了。3)struct file_operations *fops;打开文件后内核会把fops存放在这里以后的操作就在这里在这里找函数了。2)structinode这个结构体是用来保存一个文件的基本信息的结构体即使打开多个相同的文件也只会有一个对应的inode。它也有两个常用的成员1)dev_t i_rdev;这里存放着这个文件的设备号。2)struct cdev *i_cdev;这个结构体很熟悉吧这就是注册设备时用的cdev就存在这。这个结构体的用处现在我还不好说待会看程序就知道了。二、面向对象的思想接下来就封装一下之前程序的数据类型吧18 struct _test_t{19 charkbuf[DEV_SIZE];//这里存放数据20 unsigned intmajor;//这里存放主设备号21 unsigned intminor;//这里存放次设备号22 unsigned intcur_size;//这里存放当前的kbuf的大小23 dev_t devno;//这里存放设备号24 struct cdevtest_cdev;//这里存放cdev结构体25 };定义了这样的一个结构体后在操作函数中怎么拿到这个结构体的指针呢先来个函数#define container_of(ptr, type,member) ({\const typeof( ((type *)0)-member) *__mptr (ptr);\(type *)( (char *)__mptr -offsetof(type,member) );})使用已知一个结构体里面一个成员的指针ptr同时这个成员也是另外一个结构体类型中的一个成员这个结构体的类型是type而这个成员以member这个名字命名。就可以通过这个函数找到指向类型是type的结构体的指针。返回值返回值就是指向type结构体类型的数据的指针。如现在定义这样的两个结构体struct A {int *xiaobai_a;};struct B {int xiaobai_b;};struct A a;在遥远的另一处有这样的定义structB b;并且a.xiaobai_a b.xiaobai_b;这样在不知道b只知道a的情况下也可以找到b的位置struct B *bb container_of(a.xiaobai_a, struct B, xiaobai_b);估计被上面的解释说晕了吧。我还是举个例比较方便虽然一个函数不值得说这么久但是我觉得这种思想很不错内核中很多时候都用到这个函数如在内核链表中。来个邪恶的例子名字——老板与小秘老板他请了个年轻的小秘他就跟客户说“我电话号码经常换你记着我小秘的电话想找我嘛找我小秘就可以了”于是客户想找老板了就打通小秘的电话说“我知道你是秘书小红我想找你老板小黑麻烦给他的电话号码我。”这样客户就拿到了老板最新的电话号码了。想象老板和客户是个结构体秘书和他的电话号码是个各自成员电话号码想象成指针老板的电话 container_of(秘书的电话 老板小秘)说了半天还没进入正题这个函数用在哪里呢谁当小秘呢就是那个说了半天都不知道能做什么还经常出现的structcdev而我把cdev添加到了我自己建的结构体struct_test_t中所哟struct_test_t就是老板而structinode就是客户了因为它的成员里面有小秘的电话号码structcdev *i_cdev;所以如果想得到_test_t只要调用这个函数就行了。下面看一下改良后的open函数27 int test_open(struct inode *node,struct file *filp)28 {29 struct _test_t *dev;30 dev container_of(node-i_cdev, struct _test_t, test_cdev);31 filp-private_data dev;32 return 0;33 }上面还有一句将获得的结构体指针存放到filp的private_data中。这是因为structfile_operations中的每个函数的第一个参数就是structfile,只要有file每个函数都可以从private_data中得到数据了。相反structinode这个参数并不是file_operations中所有的函数都有。下面贴上部分代码1st/test.c18 struct _test_t{19 char kbuf[DEV_SIZE];20 unsigned int major;21 unsigned int minor;22 unsigned int cur_size;23 dev_t devno;24 struct cdev test_cdev;25 };2627 int test_open(struct inode *node,struct file *filp)28{/*open操作需要给把拿到的结构体指针赋值给private_data*/29 struct _test_t *dev;30 dev container_of(node-i_cdev, struct _test_t, test_cdev);31 filp-private_data dev;32 return 0;33 }3435 int test_close(struct inode*node, struct file *filp)36 {37 return 0;38 }3940 ssize_t test_read(struct file*filp, char __user *buf, size_t count, loff_t *offset)41 {42 int ret;43 struct _test_t *dev filp-private_data;4445 if(!dev-cur_size){46 return 0;47 }4849 if (copy_to_user(buf,dev-kbuf, count)){50 ret - EFAULT;51}else{/*read函数成功读取后要修改cur_size*/52 ret count;53 dev-cur_size -count;54 }55 P_DEBUG(cur_size:[%d]\n,dev-cur_size);5657 return ret;58 }5960 ssize_t test_write(struct file*filp, const char __user *buf, size_t count, loff_t *offset)61 {62 int ret;63 struct _test_t *dev filp-private_data;6465 if(copy_from_user(dev-kbuf,buf, count)){66 ret - EFAULT;67}else{/*write函数成功写入后也要修改cur_size*/68 ret count;69 dev-cur_size count;70 P_DEBUG(kbuf is[%s]\n, dev-kbuf);71P_DEBUG(cur_size:[%d]\n, dev-cur_size);72 }7374 return ret;//返回实际写入的字节数或错误号75 }上面的程序其实就多了比上一个程序多了三步1)封装了一个结构体。2)open函数要获得结构体并存放到private_data中。3)read和write函数成功后要更新cur_size这个值。这样一个像样点的程序出来了写个应用程序验证一下1 #include2 #include3 #include4 #include56 int main(void)7 {8 char buf[20];9 int fd;10 fd open(/dev/test,O_RDWR);11 if(fd 0)12 {13 perror(open);14 return -1;15 }1617 read(fd, buf, 10);18 printf(bufis [%s]\n, buf);1920 write(fd, xiao bai,10);2122 read(fd, buf, 10);23 printf(bufis [%s]\n, buf);2425 close(fd);26 return 0;27 }运行一下[root: 1st]# insmod test.komajor[253] minor[0]hello kernel[root: 1st]# mknod /dev/test c 253 0[root: 1st]# ./appbuf is[]//第一次读取时cur_size0没数据就会返回[test_write]kbuf is[xiao bai]//成功写入[test_write]cur_size:[10]//更新cur_size[test_read]cur_size:[0]//read读取成功跟新cur_sizebuf is [xiaobai]//应用程序返回读到的内容[root: 1st]#三、read、write的改进上面的函数还是不完善的想象一下平时的read、write函数会增加偏移量但上面的函数是不会的。这是因为还有一个参数我没用上就是loff_toffset。loff_toffset这个参数是内核在调用函数时从structfile的成员f_ops拿到指针并当作参数传入。这样的做法让用户不用再从structfile提取成员直接拿参数用就行了通过这个参数我们就可以改进并且实现三个函数1test_read当应用程序调用read时内核会调用test_read。读取数据的同时偏移量会增加。2test_write当应用程序调用write时内核会调用test_write。写入数据的同时偏移量也会增加。3test_llseek这是跟应用程序的lseek对应的用来修改偏移量的位置。有了上面的三个函数的功能这样才算是个像样的函数先改进一下read、write函数40 ssize_t test_read(struct file*filp, char __user *buf, size_t count, loff_t *offset)41 {42 int ret;43 struct _test_t *dev filp-private_data;4445 if(*offset DEV_SIZE){//如果偏移量已经超过了数组的容量46 return count ? - ENXIO :0; //count为0则返回0表示读取0个数据成功47 }//count不为0则分会错误号地址越界48 if(*offset count DEV_SIZE){ //如果读取字节数超过了最大偏移量49 count DEV_SIZE -*offset; //则减少读取字节数。50 }51 /*copy_to_user的参数也要改一下*/52 if (copy_to_user(buf,dev-kbuf *offset, count)){53 ret - EFAULT;54 }else{55 ret count;56 dev-cur_size -count; //读取后数组的字节数减少57 *offset count; //偏移量增加58 P_DEBUG(read %dbytes, cur_size:[%d]\n, count,dev-cur_size);59 }6061 return ret;//返回实际写入的字节数或错误号62 }6364 ssize_t test_write(struct file*filp, const char __user *buf, size_t count, loff_t *offset)65 {66 int ret;67 struct _test_t *dev filp-private_data;68 /*copy_from_user的参数也要改一下*/69 if(*offset DEV_SIZE){//如果偏移量已经超过了数组的容量70 return count ? - ENXIO :0; //count为0则返回0表示读取0个数据成功71 }//count不为0则分会错误号地址越界72 if(*offset count DEV_SIZE){ //如果读取字节数超过了最大偏移量73 count DEV_SIZE -*offset; //则减少读取字节数。74 }7576 if(copy_from_user(dev-kbuf,buf, count)){77 ret - EFAULT;78 }else{79 ret count;80 dev-cur_size count; //写入后数组的字节数增加81 *offset count; //偏移量增加82 P_DEBUG(write %dbytes, cur_size:[%d]\n, count, dev-cur_size);83 P_DEBUG(kbuf is[%s]\n, dev-kbuf);84 }8586 return ret;//返回实际写入的字节数或错误号87 }话说得好越是需要检测出错代码就会几何级增加如果不想看这么多代码把这两个函数前面的两个if(45-50、69-74)都删掉反正写应用程序的时候小心翼翼一点就好了。这个程序只是为了验证offset的作用。再来个小心翼翼的应用程序1 #include2 #include3 #include4 #include56 int main(void)7 {8 char buf[20];9 int fd;10 fd open(/dev/test,O_RDWR);11 if(fd 0)12 {13 perror(open);14 return -1;15 }1617 write(fd, xiao bai,10);1819 read(fd, buf, 10);20 printf(bufis [%s]\n, buf);2122 close(fd);23 return 0;24 }验证一下[root: 2nd]# insmod test.komajor[253] minor[0]hello kernel[root: 2nd]# mknod /dev/test c 253 0[root: 2nd]# ./app[test_write]write 10bytes, cur_size:[10]//写入[test_write]kbuf is[xiao bai][test_read]read 10bytes, cur_size:[0]//但读不出因为偏移量增加buf is []上面的read函数根本读不出数据这是因为偏移量增加了。这个时候需要一个函数来把偏移量移到开头lseek函数就用上场了。下面就讲一下。四、lseek函数的实现应用层的函数lseek函数对应驱动的函数是llseek(为什么多了一个l我也想不懂)。内核驱动loff_t (*llseek)(struct file * filp, loff_t offset, int whence);对应应用层off_t lseek(intfd, off_t offset, int whence);使用一看参数就知道这两个函数的第二和第三个参数就是对应的当应用层调用函数时对应的参数就会让内核传给驱动的函数llseek。参数offset一看这个参数不是指针就知道和read、write的参数不一样。这是应用层传来的参数并不是structfile的偏移量f_ops。whence这个也跟应用层的参数一样指定从哪个位置开始偏移。从开头位置#defineSEEK_SET0从当前位置#defineSEEK_CUR1从文件末端#defineSEEK_END2返回值成功返回当前的更新的偏移量失败返回错误号而应用层会返回-1。下面来个程序/3rd_char/3rd_char_3/3rd/test.c/*test_llseek*/89 loff_t test_llseek (struct file*filp, loff_t offset, int whence)90 {91 loff_t new_pos;//新偏移量92 loff_t old_pos filp-f_pos;//旧偏移量9394 switch(whence){95 case SEEK_SET:96 new_pos offset;97 break;98 case SEEK_CUR:99 new_pos old_pos offset;100 break;101 case SEEK_END:102 new_pos DEV_SIZE offset;103 break;104 default:105 P_DEBUG(unknowwhence\n);106 return - EINVAL;107 }108109 if(new_pos 0 || new_pos DEV_SIZE){ //如果偏移量越界返回错误号110 P_DEBUG(f_posfailed\n);111 return - EINVAL;112 }113114 filp-f_pos new_pos;115 returnnew_pos;//正确返回新的偏移量116 }再来个应用程序/3rd_char/3rd_char_3/3rd/app.c1 #include2 #include3 #include4 #include56 int main(void)7 {8 char buf[20];9 int fd;10 int ret;1112 fd open(/dev/test,O_RDWR);13 if(fd 0)14 {15 perror(open);16 return -1;17 }1819 write(fd, xiao bai,10);20 /*让偏移量移至开头这样才能读取数据*/21 ret lseek(fd, 0, SEEK_SET);2223 read(fd, buf, 10);24 printf(bufis [%s]\n, buf);2526 close(fd);27 return 0;28 }验证一下[root: 2nd]# ./app[test_write]write 10bytes, cur_size:[10][test_write]kbuf is[xiao bai][test_read]read 10bytes, cur_size:[0]//读到数据了buf is [xiaobai]//读到数据了五、总结拉风的时序图我就不画了。上面讲的东西不多1)container_of的使用2)怎么使用偏移量filp-f_ops。3)llseek的编写。
http://www.zqtcl.cn/news/690920/

相关文章:

  • 安徽网站开发培训价格百度seo排名公司
  • 青海网站建设费用oa系统和erp系统区别
  • 个人做网站的注意事项网站开发工程师6
  • 镇江百度网站建设北京网站开发价格
  • 大岭山镇仿做网站推广计划表格
  • 网站备案地址不是我的地址怎么办建设银行网站查询业务收费吗
  • 电商网站设计内容网站编辑及seo招聘
  • 用什么网站开发浙江省住房和建设厅网站
  • 站长工具seo优化建议微信小程序线上商城怎么申请
  • 建筑网站开发设计做网站的公司msgg
  • 设计师个人网站模板网站的尾页要怎么做
  • 营销型网站建设风格设定包括哪些方面wordpress企业魔板
  • 怎样做淘客网站做绿色产品的网站
  • 关于网站建设的通知wordpress点注册后一直不出来
  • 科技公司网站设计方案开发公司绩效考核
  • 深圳网站建设推进旗县政务网站建设工作方案
  • 南宁 网站建设网站集约建设
  • 做网站编辑好吗吉林省四平市
  • 石家庄网站制作最新军事新闻最新消息视频
  • 高端品牌网站设计企业网站建设wordpress文章前阅读
  • 广州做网站星珀各电商网站的特点
  • 西安模板做网站广州微信网站建设平台
  • 网站开发硬件工程师待遇微信商城有哪些第三方平台
  • 基于响应式设计的网站建设软件开发项目甘特图
  • 绍兴兴住房和城乡建设局网站网站更换名称需要重新备案吗
  • 跨境电商网站开发文档网站建设费可摊几年
  • 怎样建设一个游戏网站随便玩玩在线制作网站
  • 免费的成品网站用织梦模板做网站
  • 彩票网站开发 极云有的域名怎样做网站
  • 网店运营推广网站买个天猫店多少钱一个