Chinaunix首页 | 论坛 | 博客
  • 博客访问: 929874
  • 博文数量: 376
  • 博客积分: 154
  • 博客等级: 入伍新兵
  • 技术积分: 1558
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-13 08:42
文章分类

全部博文(376)

文章存档

2014年(11)

2013年(88)

2012年(260)

2011年(17)

分类:

2012-06-12 18:17:14

  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8. #include   
  9. #include   
  10. #include   
  11. #include   
  12. #define GLOBALMEM_SIZE 0x1000  
  13. #define MEM_CLEAR 0x1  
  14. #define GLOBALMEM_MAJOR 254  
  15. static int globalmem_major = GLOBALMEM_MAJOR;  
  16.   
  17. struct globalmem_dev  
  18. {  
  19.   struct cdev cdev;  
  20. /*************************************** 
  21.   struct cdev 
  22.    { 
  23.       struct kobject koj; //内嵌的kobiject对象 
  24.       struct module *owner;//所属模块 
  25.      struct file_operations *ops;//文件操作结构体 
  26.       struct list_head list; 
  27.       dev_t dev;//设备号 
  28.       unsigned int count; 
  29.     }; 
  30. ******************************************/  
  31.   unsigned char mem[GLOBALMEM_SIZE];    
  32. };  
  33. struct globalmem_dev *globalmem_devp;  
  34. int globalmem_open(struct inode *inode,struct file *filep)  
  35. {  
  36.   filep->private_data=globalmem_devp;  
  37.   return 0;  
  38. }  
  39. int globalmem_release(struct inode *inode,struct file *filep)  
  40. {  
  41.   return 0;  
  42. }  
  43. static int globalmem_ioctl(struct inode *inodep,struct file *filep,unsigned int cmd,unsigned long arg)  
  44. {  
  45.  struct globalmem_dev *dev=filep->private_data;  
  46.  switch(cmd)  
  47.  {  
  48.   case MEM_CLEAR:  
  49.     memset(dev->mem,0,GLOBALMEM_SIZE);  
  50.     printk(KERN_INFO "globalmem is set to zero");  
  51.     break;  
  52.   default:  
  53.     return -EINVAL;  
  54.  }  
  55.  return 0;  
  56. }  
  57. static ssize_t globalmem_read(struct file *filep,char __user *buf,size_t size,loff_t *ppos)  
  58. {  
  59.   unsigned long p=*ppos;  
  60.   unsigned int count=size;  
  61.   int ret=0;  
  62.   struct globalmem_dev *dev=filep->private_data;  
  63.   if(p>=GLOBALMEM_SIZE)        //要读的偏移位置越界  
  64.     return count ? - ENXIO:0;  
  65.   if(count>GLOBALMEM_SIZE-p)   //要读的字节数太大  
  66.     count= GLOBALMEM_SIZE-p;  
  67.     /*内核空间—>用户空间:将内核空间中首地址为dev->mem+p的count个字节拷贝到用户空间的首地址为buf的字符串里面去*/  
  68.   if(copy_to_user(buf,(void *)(dev->mem+p),count))  
  69.     ret = -EFAULT;  
  70.   else  
  71.   {  
  72.     *ppos+=count;  
  73.     ret=count;  
  74.     printk(KERN_INFO "read %d bytes(s) from %d\n",(int)count,(int)p);  
  75.   }  
  76.   return ret;  
  77. }  
  78. static ssize_t globalmem_write(struct file *filep,const char __user *buf,size_t size,loff_t *ppos)  
  79. {  
  80.   unsigned long p=*ppos;  
  81.   unsigned int count =size;  
  82.   int ret =0;  
  83.   struct globalmem_dev *dev=filep->private_data;  
  84.   if(p>=GLOBALMEM_SIZE)       //要写的偏移位置越界  
  85.    return count ? -ENXIO:0;  
  86.   if(count>GLOBALMEM_SIZE-p)   //要写的字节数太大  
  87.    count=GLOBALMEM_SIZE-p;  
  88.    /*用户空间->内核空间:将用户空间中首地址为buf的count个字节拷贝到内核空间首地址为dev-mem+p的存储空间去*/  
  89.   if(copy_from_user(dev->mem+p,buf,count))  
  90.    ret=-EFAULT;  
  91.   else  
  92.    {  
  93.     *ppos+=count;  
  94.     ret=count;  
  95.     printk(KERN_INFO "written %d bytes from %d\n",(int)count,(int)p);  
  96.    }  
  97.   return ret;  
  98. }  
  99. static loff_t globalmem_llseek(struct file *filep,loff_t offset,int orig)  
  100. {  
  101.   loff_t ret=0;  
  102.   switch(orig)  
  103.   {  
  104.    case 0:             /*从文件开头开始偏移*/  
  105.      if(offset<0)         
  106.      {  
  107.        ret = -EINVAL;  
  108.        break;  
  109.      }  
  110.      if((unsigned int)offset>GLOBALMEM_SIZE)   //偏移越界  
  111.      {  
  112.       ret = -EINVAL;  
  113.       break;  
  114.      }  
  115.      filep->f_pos=(unsigned int)offset;  
  116.      ret =filep->f_pos;  
  117.      break;  
  118.    case 1:               /*从当前位置开始偏移*/  
  119.      if(((filep->f_pos+offset)>GLOBALMEM_SIZE)||((filep->f_pos+offset)<0))  //偏移越界  
  120.      {  
  121.        ret=-EINVAL;  
  122.        break;  
  123.      }  
  124.      filep->f_pos+=offset;  
  125.      ret=filep->f_pos;  
  126.      break;  
  127.    default:  
  128.      ret=-EINVAL;  
  129.      break;  
  130.    }  
  131.    return ret;  
  132. }  
  133. /* 
  134.  
  135. 通过file_operations方法将设备类型的差异屏蔽了, 
  136. 这就是linux能够将所有设备都理解为文件的原因。 
  137. */  
  138. static const struct file_operations globalmem_fops=  
  139. {  
  140.   /*指向拥有该结构的模块的指针,避免正在操作时被卸载,一般为初始化为THIS_MODULES*/  
  141.   .owner=THIS_MODULE,  
  142.    /*llseek用来修改文件当前的读写位置,返回新位置*/  
  143.   .llseek=globalmem_llseek,  
  144.    /*从设备中同步读取数据。读取成功返回读取的字节数。设置为NULL,调用时返回-EINVAL*/  
  145.   .read=globalmem_read,  
  146.    /*向设备发送数据*/  
  147.   .write=globalmem_write,  
  148.    /*提供一种执行设备特殊命令的方法*/  
  149.   .ioctl=globalmem_ioctl,  
  150.    /*由VFS调用,当VFS打开一个文件,即建立了一个新的"struct file",之后调用open方法分配文件结构。*/  
  151.   .open=globalmem_open,  
  152.    /*file结构释放时,将调用此指针函数,release与open相同可设置为NULL*/  
  153.   .release=globalmem_release,  
  154. };  
  155. static void globalmem_setup_cdev(struct globalmem_dev *dev,int index)  
  156. {  
  157.   int err,devno=MKDEV(globalmem_major,index);  
  158.   
  159.   /*初始化cdev,并建立cdev和file_operations之间的连接*/  
  160.   cdev_init(&dev->cdev,&globalmem_fops);  
  161.   dev->cdev.owner=THIS_MODULE;  
  162.   dev->cdev.ops=&globalmem_fops;  
  163.   /*注册设备,通常发生在驱动模块的加载函数中*/  
  164.   err=cdev_add(&dev->cdev,devno,1);  
  165.   if(err)  
  166.   printk(KERN_NOTICE "Error %d adding LED%d",err,index);  
  167. }  
  168. /*globalmem 设备驱动模块加载函数*/  
  169. int globalmem_init(void)  
  170. int result;  
  171.   dev_t devno=MKDEV(globalmem_major,0);  
  172.   /*主设备号是globalmem_major, 
  173.     从设备号是0, 
  174.     通过#define MKDEV(ma,mi) (((ma)< 
  175.    */  
  176.   if(globalmem_major)  
  177.     result = register_chrdev_region(devno,1,"globalmem");  
  178.     /**/  
  179.   else  
  180.   {  
  181.       result = alloc_chrdev_region(&devno,0,1,"globalmem");  
  182.     /**/  
  183.       globalmem_major = MAJOR(devno);  
  184.   }  
  185.   if(result<0)  
  186.     return result;  
  187.   globalmem_devp=kmalloc(sizeof(struct globalmem_dev),GFP_KERNEL);  
  188.     /* 
  189.        kmalloc的特殊之处在于分配的内存在物理地址上是连续的 
  190.      */  
  191.   if(!globalmem_devp)  
  192.   {  
  193.     result = -ENOMEM;  
  194.     goto fail_malloc;  
  195.   }  
  196.   memset(globalmem_devp,0,sizeof(struct globalmem_dev));  
  197.   /**/  
  198.   globalmem_setup_cdev(globalmem_devp,0);  
  199.   /*初始化并添加cdev结构体*/  
  200.   return 0;  
  201.   fail_malloc:unregister_chrdev_region(devno,1);  
  202.   return result;  
  203. }  
  204. /*globalmem设备驱动模块卸载函数*/  
  205. void globalmem_exit(void)  
  206. {   
  207.   /*注销设备,通常发生在驱动模块的卸载函数中*/  
  208.   cdev_del(&globalmem_devp->cdev);  
  209.   kfree(globalmem_devp);  
  210.   unregister_chrdev_region(MKDEV(globalmem_major,0),1);  
  211. }  
  212. MODULE_AUTHOR("Song Baohua");  
  213. /**/  
  214. MODULE_LICENSE("Dual BSD/GPL");  
  215. module_param(globalmem_major,int,S_IRUGO);  
  216. module_init(globalmem_init);  
  217. module_exit(globalmem_exit); 
阅读(417) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~