xzy610030

一起探讨,一起进步,一起分享!

linux驱动入门

0
阅读(2773)

有足够的理由来说服自己来学习linux设备驱动!学习linux设备驱动,第一个就是helloworld驱动了,第二个应该是memdev这个驱动了。

今天通过学习国嵌的memdev这个设备驱动程序,简单的理解了下设备驱动程序运作过程,这个和前面的globalmem设备驱动是类似的。

我对源码有轻微的改动,如果学习的话,建议手动敲一遍代码,这样理解会深刻一些。

memdev.c

[html] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include<linux/module.h>
  2. #include<linux/types.h>
  3. #include<linux/fs.h>
  4. #include<linux/errno.h>
  5. #include<linux/mm.h>
  6. #include<linux/sched.h>
  7. #include<linux/init.h>
  8. #include<linux/cdev.h>
  9. #include<asm/io.h>
  10. #include<linux/slab.h>
  11. //#include<asm/system.h>
  12. #include<asm/uaccess.h>
  13. #define MEMDEV_MAJOR 250
  14. staticmem_major=MEMDEV_MAJOR;
  15. struct cdev cdev;
  16. struct mem_dev
  17. {
  18. char *data;
  19. unsigned long size;
  20. };
  21. struct mem_dev *mem_devp;
  22. // open function
  23. int mem_open(struct inode *inode,struct file *filp)
  24. {
  25. struct mem_dev *dev;
  26. intnum=MINOR(inode->i_rdev);
  27. if(num>=2)
  28. return -ENODEV;
  29. dev=&mem_devp[num];
  30. filp->private_data=dev;
  31. return 0;
  32. }
  33. //release function
  34. int mem_release(struct inode *inode,struct file *filp)
  35. {
  36. return 0;
  37. }
  38. //read function
  39. static ssize_t mem_read(struct file *filp,char __user *buf,size_t size,loff_t *ppos)
  40. {
  41. unsigned longp=*ppos;
  42. unsigned intcount=size;
  43. intret=0;
  44. struct mem_dev *dev=filp->private_data;
  45. if(p>=4096)
  46. return 0;
  47. if(count>4096-p)
  48. count=4096-p;
  49. if(copy_to_user(buf,(void *)(dev->data+p),count))
  50. {
  51. ret=-EFAULT;
  52. }
  53. else
  54. {
  55. *ppos+=count;
  56. ret=count;
  57. printk(KERN_INFO "read %d bytes from %d\n",count,p);
  58. }
  59. return ret;
  60. }
  61. // write function
  62. static ssize_t mem_write(struct file *filp,const char __user *buf,size_t size,loff_t *ppos)
  63. {
  64. unsigned longp=*ppos;
  65. unsigned intcount=size;
  66. intret=0;
  67. struct mem_dev *dev=filp->private_data;
  68. if(p>=4096)
  69. {
  70. return 0;
  71. }
  72. if(count>4096-p)
  73. count=4096-p;
  74. if(copy_from_user(dev->data+p,buf,count))
  75. ret=-EFAULT;
  76. else
  77. {
  78. *ppos+=count;
  79. ret=count;
  80. printk(KERN_INFO "written %d bytes from %d\n",count,p);
  81. }
  82. return ret;
  83. }
  84. //seek function
  85. static loff_t mem_llseek(struct file *filp,loff_t offset,int whence)
  86. {
  87. loff_t newpos;
  88. switch(whence)
  89. {
  90. case 0:newpos=offset; break;
  91. case 1:newpos=filp->f_pos+offset;break;
  92. case 2:newpos=4095+offset;break;
  93. default : return -EINVAL;
  94. }
  95. if((newpos<0)||(newpos>4096))
  96. return -EINVAL;
  97. filp->f_pos=newpos;
  98. return newpos;
  99. }
  100. //
  101. static const struct file_operationsmem_fops=
  102. {
  103. .owner=THIS_MODULE,
  104. .llseek=mem_llseek,
  105. .read=mem_read,
  106. .write=mem_write,
  107. .open=mem_open,
  108. .release=mem_release,
  109. };
  110. //init function
  111. static int memdev_init(void)
  112. {
  113. int result;
  114. dev_tdevno=MKDEV(mem_major,0);
  115. //get major
  116. if(mem_major)
  117. {
  118. result=register_chrdev_region(devno,2,"memdev");
  119. }
  120. else
  121. {
  122. result=alloc_chrdev_region(&devno,0,2,"memdev");
  123. mem_major=MAJOR(devno);
  124. }
  125. if(result<0)
  126. return result;
  127. //init cdev
  128. cdev_init(&cdev,&mem_fops);
  129. cdev.owner=THIS_MODULE;
  130. //register memdev
  131. cdev_add(&cdev,MKDEV(mem_major,0),2);
  132. mem_devp=kmalloc(2*sizeof(struct mem_dev),GFP_KERNEL);
  133. if(!mem_devp)
  134. {
  135. result= -ENOMEM;
  136. goto fail_malloc;
  137. }
  138. memset(mem_devp,0,2*sizeof(struct mem_dev));
  139. mem_devp[0].size=4096;
  140. mem_devp[0].data=kmalloc(4096,GFP_KERNEL);
  141. memset(mem_devp[0].data,0,4096);
  142. mem_devp[1].size=4096;
  143. mem_devp[1].data=kmalloc(4096,GFP_KERNEL);
  144. memset(mem_devp[1].data,0,4096);
  145. return 0;
  146. fail_malloc:unregister_chrdev_region(devno,1);
  147. return result;
  148. }
  149. //exit function
  150. static int memdev_exit(void)
  151. {
  152. cdev_del(&cdev);
  153. kfree(mem_devp);
  154. unregister_chrdev_region(MKDEV(mem_major,0),2);
  155. }
  156. module_init(memdev_init);
  157. module_exit(memdev_exit);
  158. MODULE_AUTHOR("by xzy 214");
  159. MODULE_LICENSE("GPL");

Makefile如下

[html] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. ifneq ($(KERNELRELEASE),)
  2. obj-m:=memdev.o
  3. else
  4. KERNELDIR:=/lib/modules/$(shell uname -r)/build
  5. PWD:=$(shell pwd)
  6. default:
  7. $(MAKE) -C $(KERNELDIR)M=$(PWD) modules
  8. clean:
  9. rm -rf *.o *.mod.c *.mod.o *.ko
  10. endif


测试该驱动的应用程序

app_mem.c,源码是用c库函数的文件操作来做的。我这里用系统调用来完成。

[html] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. #include<unistd.h>
  2. #include<fcntl.h>
  3. #include<stdio.h>
  4. #include<string.h>
  5. int main()
  6. {
  7. int fd;
  8. char buf[4096];
  9. strcpy(buf,"mem is char dev!!hello xzy");
  10. printf("buf:%s\n",buf);
  11. fd=open("/dev/memdev0",O_RDWR);
  12. printf("fd: %d\n",fd);
  13. if(fd<0)
  14. {
  15. printf("open memdev0 error!\n");
  16. return -1;
  17. }
  18. write(fd,buf,sizeof(buf));
  19. lseek(fd,0,SEEK_SET);
  20. strcpy(buf,"buf is null");
  21. printf("buf: %s\n",buf);
  22. read(fd,buf,sizeof(buf));
  23. printf("buf: %s\n",buf);
  24. close(fd);
  25. return 0;
  26. }

驱动运行的过程:自己理解。应用程序来打开设备节点文件,这个设备节点文件是通过主设备号和驱动程序联系在一起的。打开这个设备文件的同时,在内核空间会相应的有一个关联的struct file结构和关于该设备的inode结构体,所以你必须要了解一下这两个结构,在file结构中保存着文件读写的信息,还有一个file_operation,这个可以认为是一个转化表,对应着驱动程序的一些文件操作的函数,这样就对应起来了,inode包括了设备号,这个在文件打开的时候,可以判断是次设备号。

系统调用open的执行过程:用户空间open,会执行的sys_open,这个就为打开的文件分配一个file结构体和从inode的节点中找到对应的file_operations

具体可以见:http://blog.csdn.net/xzyiverson/article/details/12676911

系统调用read的执行过程:先调用vfs_read,file->fop->read,我们可以看内核源码,我截下了一张图

上述内核源码见于read_write.c


了解了大致的过程,看看上面的memdev驱动程序,从init看起:

1.申请设备号2.初始化并添加cdev结构

然后就是该设备的一些操作函数的编写了,分析起来应该是不难的。


注明:出错误的地方,解决办法如下:

http://blog.csdn.net/xzyiverson/article/details/17315931


运行结果:

insmod memdev.ko

mknod memdev0 c 250 0

mknod memdev1 c 250 1

Baidu
map