Chinaunix首页 | 论坛 | 博客

分类: C/C++

2012-10-25 10:35:58


点击(此处)折叠或打开

  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 <asm/system.h>
  11. #include <asm/uaccess.h>

  12. #include "memdev.h"

  13. static mem_major = MEMDEV_MAJOR;

  14. module_param(mem_major, int, S_IRUGO);

  15. struct mem_dev *mem_devp; /*设备结构体指针*/

  16. struct cdev cdev;

  17. /*文件打开函数*/
  18. int mem_open(struct inode *inode, struct file *filp)
  19. {
  20.     struct mem_dev *dev;
  21.     
  22.     /*获取次设备号*/
  23.     int num = MINOR(inode->i_rdev);

  24.     if (num >= MEMDEV_NR_DEVS)
  25.             return -ENODEV;
  26.     dev = &mem_devp[num];
  27.     
  28.     /*将设备描述结构指针赋值给文件私有数据指针*/
  29.     filp->private_data = dev;
  30.     
  31.     return 0;
  32. }

  33. /*文件释放函数*/
  34. int mem_release(struct inode *inode, struct file *filp)
  35. {
  36.   return 0;
  37. }

  38. /*读函数*/
  39. //read的参数当中没有inode,所以无法得到设备号,即无法得到次设备号,即无法知道到底现在是在操作哪个设备,所以要用file->private_data
  40. static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
  41. {
  42.   unsigned long p = *ppos;
  43.   unsigned int count = size;
  44.   int ret = 0;
  45.   struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/

  46.   /*判断读位置是否有效*/
  47.   //p为现在要读的位置,
  48.   if (p >= MEMDEV_SIZE)//读的位置超出文件的最大的位置
  49.     return 0;
  50.   if (count > MEMDEV_SIZE - p)//MEMDEV-p为现在最多可读的字节
  51.     count = MEMDEV_SIZE - p;

  52.   /*读数据到用户空间*/
  53.   if (copy_to_user(buf, (void*)(dev->data + p), count))
  54.   {
  55.     ret = - EFAULT;
  56.   }
  57.   else
  58.   {
  59.     *ppos += count;
  60.     ret = count;
  61.     
  62.     printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);
  63.   }

  64.   return ret;
  65. }

  66. /*写函数*/
  67. static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
  68. {
  69.   unsigned long p = *ppos;
  70.   unsigned int count = size;
  71.   int ret = 0;
  72.   struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/
  73.   
  74.   /*分析和获取有效的写长度*/
  75.   if (p >= MEMDEV_SIZE)
  76.     return 0;
  77.   if (count > MEMDEV_SIZE - p)
  78.     count = MEMDEV_SIZE - p;
  79.       /*从用户空间写入数据*/
  80.   if (copy_from_user(dev->data + p, buf, count))
  81.     ret = - EFAULT;
  82.   else
  83.   {
  84.     *ppos += count;
  85.     ret = count;
  86.     
  87.     printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
  88.   }

  89.   return ret;
  90. }

  91. /* seek文件定位函数 */
  92. static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)
  93. {
  94.     loff_t newpos;

  95.     switch(whence) {
  96.       case 0: /* SEEK_SET */
  97.         newpos = offset;
  98.         break;

  99.       case 1: /* SEEK_CUR */
  100.         newpos = filp->f_pos + offset;
  101.         break;

  102.       case 2: /* SEEK_END */
  103.         newpos = MEMDEV_SIZE -1 + offset;
  104.         break;

  105.       default: /* can't happen */
  106.         return -EINVAL;
  107.     }
  108.     if ((newpos<0) || (newpos>MEMDEV_SIZE))
  109.         return -EINVAL;
  110.         
  111.     filp->f_pos = newpos;
  112.     return newpos;

  113. }

  114. /*文件操作结构体*/
  115. static const struct file_operations mem_fops =
  116. {
  117.   .owner = THIS_MODULE,
  118.   .llseek = mem_llseek,
  119.   .read = mem_read,
  120.   .write = mem_write,
  121.   .open = mem_open,
  122.   .release = mem_release,
  123. };

  124. /*设备驱动模块加载函数*/
  125. static int memdev_init(void)
  126. {
  127.   int result;
  128.   int i;
  129.     //将主设备号和次设备号构造一个设备号
  130.   dev_t devno = MKDEV(mem_major, 0);

  131.   /* 静态申请设备号*/
  132.   if (mem_major)//如果为0则使用动态分配
  133.     result = register_chrdev_region(devno, 2, "memdev");
  134.   else /* 动态分配设备号 */
  135.   {
  136.     result = alloc_chrdev_region(&devno, 0, 2, "memdev");
  137.     mem_major = MAJOR(devno);
  138.   }
  139.   
  140.   if (result < 0)
  141.     return result;

  142.   /*初始化cdev结构*/
  143.   cdev_init(&cdev, &mem_fops);//将cdev与mem_fops绑定起来
  144.   cdev.owner = THIS_MODULE;//这个驱动属于这个模块,计算模块引用计数
  145.   cdev.ops = &mem_fops;
  146.   
  147.   /* 注册字符设备 */
  148.   cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS);
  149. /*********************分配的内存与设备的关联在open函数中*******************/
  150. /**这个程序其实是在操作内存,即读和写这段内存,所以要分配一段内存模拟设备*****/
  151.   /* 为设备描述结构分配内存*/
  152.   //mem_dev结构定义在memdev.h当中,因为是自己定义的结构体,所以要分配内存
  153.   mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);
  154.   if (!mem_devp) /*申请失败*/
  155.   {
  156.     result = - ENOMEM;
  157.     goto fail_malloc;
  158.   }
  159.   memset(mem_devp, 0, sizeof(struct mem_dev));
  160.   
  161.   /*为设备分配内存*/
  162.   //这个结构体里面有一个data的指针用来存放设备
  163.   for (i=0; i < MEMDEV_NR_DEVS; i++)
  164.   {
  165.         mem_devp[i].size = MEMDEV_SIZE;
  166.         mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);
  167.         memset(mem_devp[i].data, 0, MEMDEV_SIZE);
  168.   }
  169. /**************************************************************************/
  170.   return 0;

  171.   fail_malloc:
  172.   unregister_chrdev_region(devno, 1);
  173.   
  174.   return result;
  175. }

  176. /*模块卸载函数*/
  177. static void memdev_exit(void)
  178. {
  179.   cdev_del(&cdev); /*注销设备*/
  180.   kfree(mem_devp); /*释放设备结构体内存*/
  181.   unregister_chrdev_region(MKDEV(mem_major, 0), 2); /*释放设备号*/
  182. }

  183. MODULE_AUTHOR("daiban");
  184. MODULE_LICENSE("GPL");

  185. module_init(memdev_init);
  186. module_exit(memdev_exit);

阅读(1443) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~