Linux字符设备驱动(温故globalmem)


今天又温故了一下宋宝华《Linux设备驱动开发详解》【下载见 或 】中字符设备驱动,感觉每次都能温故而知新。顺便把我修改后的代码贴出来,给大家做个参考。

  1. /************************************************* 
  2. * File name   : globalmem.c 
  3. * Description : 源程序取自宋宝华书籍 
  4. * Author      : sg131971@qq.com 
  5. * Version     : V1.0 
  6. * Date        :  
  7. * Compiler    : arm-linux-gcc-4.4.3 
  8. * Target      : mini2440(Linux-2.6.32) 
  9. * History     :  
  10. *   <author>  <time>   <version >   <desc> 
  11.     ShiGuang  20100826  增加自动创建设备节点 
  12.     ShiGuang  20100826  增加幻数控制 
  13. *************************************************/  
  14. #include <linux/module.h>   
  15. #include <linux/types.h>   
  16. #include <linux/fs.h>   
  17. #include <linux/errno.h>   
  18. #include <linux/mm.h>   
  19. #include <linux/sched.h>   
  20. #include <linux/init.h>   
  21. #include <linux/cdev.h>   
  22. #include <asm/io.h>   
  23. #include <asm/system.h>   
  24. #include <asm/uaccess.h>   
  25. #include <linux/device.h>       /* device_create() */     
  26.   
  27. /* 取自Ioctl.h (include\asm-generic) */  
  28. //#define _IOC(dir,type,nr,size)  (((dir)  << _IOC_DIRSHIFT) | \   
  29. //                               ((type) << _IOC_TYPESHIFT) | \   
  30. //                               ((nr)   << _IOC_NRSHIFT) | \   
  31. //                               ((size) << _IOC_SIZESHIFT))   
  32. //#define _IOC_TYPECHECK(t) (sizeof(t))   
  33. //#define _IO(type,nr)              _IOC(_IOC_NONE,(type),(nr),0)   
  34. //#define _IOR(type,nr,size)        _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))   
  35. //#define _IOW(type,nr,size)        _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))   
  36. //#define _IOWR(type,nr,size)       _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))   
  37. //#define _IOR_BAD(type,nr,size)    _IOC(_IOC_READ,(type),(nr),sizeof(size))   
  38. //#define _IOW_BAD(type,nr,size)    _IOC(_IOC_WRITE,(type),(nr),sizeof(size))   
  39. //#define _IOWR_BAD(type,nr,size)   _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))   
  40.   
  41. #define GOLBALMEM_MAGIC         'g'   
  42. #define GLOBALMEM_IOC_MAXNR     3   
  43. #define GLOBALMEM_CLEAR         _IO (GLOBALMEM_IOC_MAGIC, 0)     
  44. #define GLOBALMEM_IOCGETDATA    _IOR(GLOBALMEM_IOC_MAGIC, 1, int)     
  45. #define GLOBALMEM_IOCSETDATA    _IOW(GLOBALMEM_IOC_MAGIC, 2, int)    
  46.   
  47. #define GLOBALMEM_SIZE  0x1000  /*全局内存最大4K字节 */   
  48. #define GLOBALMEM_MAJOR 250     /*预设的globalmem的主设备号 */   
  49.   
  50. static struct class *globalmem_class;    
  51. static struct class_device *globalmem_class_dev;   
  52.    
  53.   
  54. static int globalmem_major = 0; /* 采取自动分配方式 */  
  55.   
  56. struct globalmem_dev  
  57. {  
  58.     struct cdev cdev;           /*cdev结构体 */  
  59.     unsigned char mem[GLOBALMEM_SIZE];  /*全局内存 */  
  60. };  
  61.   
  62. struct globalmem_dev *globalmem_devp;   /*设备结构体指针 */  
  63.   
  64. int globalmem_open(struct inode *inode, struct file *filp)  
  65. {  
  66.     /*将设备结构体指针赋值给文件私有数据指针 */  
  67.     filp->private_data = globalmem_devp;  
  68.     return 0;  
  69. }  
  70.   
  71. int globalmem_release(struct inode *inode, struct file *filp)  
  72. {  
  73.     return 0;  
  74. }  
  75.   
  76. static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned  
  77.                            int cmd, unsigned long arg)  
  78. {  
  79.     struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针 */  
  80.       
  81.     /* 检测命令的有效性 */    
  82.     if (_IOC_TYPE(cmd) != GLOBALMEM_IOC_MAGIC)    
  83.         return -EINVAL;    
  84.     if (_IOC_NR(cmd) > GLOBALMEM_IOC_MAXNR)    
  85.         return -EINVAL;    
  86.   
  87.     switch (cmd)  
  88.     {  
  89.       case MEM_CLEAR:  
  90.           memset(dev->mem, 0, GLOBALMEM_SIZE);  
  91.           printk(KERN_INFO "globalmem is set to zero\n");  
  92.           break;  
  93.   
  94.       default:  
  95.           return -EINVAL;  
  96.     }  
  97.   
  98.     return 0;  
  99. }  
  100.   
  101. static ssize_t globalmem_read(struct file *filp, char __user * buf, size_t size, loff_t * ppos)  
  102. {  
  103.     unsigned long p = *ppos;  
  104.     unsigned int count = size;  
  105.     int ret = 0;  
  106.     struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针 */  
  107.   
  108.     /*分析和获取有效的写长度 */  
  109.     if (p >= GLOBALMEM_SIZE)  
  110.         return 0;  
  111.     if (count > GLOBALMEM_SIZE - p)  
  112.         count = GLOBALMEM_SIZE - p;  
  113.   
  114.     /*内核空间->用户空间 */  
  115.     if (copy_to_user(buf, (void *)(dev->mem + p), count))  
  116.     {  
  117.         ret = -EFAULT;  
  118.     }  
  119.     else  
  120.     {  
  121.         *ppos += count;  
  122.         ret = count;  
  123.   
  124.         printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p);  
  125.     }  
  126.   
  127.     return ret;  
  128. }  
  129.   
  130. static ssize_t globalmem_write(struct file *filp, const char __user * buf,  
  131.                                size_t size, loff_t * ppos)  
  132. {  
  133.     unsigned long p = *ppos;  
  134.     unsigned int count = size;  
  135.     int ret = 0;  
  136.     struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针 */  
  137.   
  138.     /*分析和获取有效的写长度 */  
  139.     if (p >= GLOBALMEM_SIZE)  
  140.         return 0;  
  141.     if (count > GLOBALMEM_SIZE - p)  
  142.         count = GLOBALMEM_SIZE - p;  
  143.   
  144.     /*用户空间->内核空间 */  
  145.     if (copy_from_user(dev->mem + p, buf, count))  
  146.         ret = -EFAULT;  
  147.     else  
  148.     {  
  149.         *ppos += count;  
  150.         ret = count;  
  151.   
  152.         printk(KERN_INFO "written %u bytes(s) from %lu\n", count, p);  
  153.     }  
  154.   
  155.     return ret;  
  156. }  
  157.   
  158. static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)  
  159. {  
  160.     loff_t ret = 0;  
  161.     switch (orig)  
  162.     {  
  163.       case 0:                  /*相对文件开始位置偏移 */  
  164.           if (offset < 0)  
  165.           {  
  166.               ret = -EINVAL;  
  167.               break;  
  168.           }  
  169.           if ((unsigned int)offset > GLOBALMEM_SIZE)  
  170.           {  
  171.               ret = -EINVAL;  
  172.               break;  
  173.           }  
  174.           filp->f_pos = (unsigned int)offset;  
  175.           ret = filp->f_pos;  
  176.           break;  
  177.       case 1:                  /*相对文件当前位置偏移 */  
  178.           if ((filp->f_pos + offset) > GLOBALMEM_SIZE)  
  179.           {  
  180.               ret = -EINVAL;  
  181.               break;  
  182.           }  
  183.           if ((filp->f_pos + offset) < 0)  
  184.           {  
  185.               ret = -EINVAL;  
  186.               break;  
  187.           }  
  188.           filp->f_pos += offset;  
  189.           ret = filp->f_pos;  
  190.           break;  
  191.       default:  
  192.           ret = -EINVAL;  
  193.           break;  
  194.     }  
  195.     return ret;  
  196. }  
  197.   
  198. static const struct file_operations globalmem_fops = {  
  199.     .owner  = THIS_MODULE,  
  200.     .llseek = globalmem_llseek,  
  201.     .read   = globalmem_read,  
  202.     .write  = globalmem_write,  
  203.     .ioctl  = globalmem_ioctl,  
  204.     .open   = globalmem_open,  
  205.     .release = globalmem_release,  
  206. };  
  207.   
  208. int globalmem_init(void)  
  209. {  
  210.     int result;  
  211.     int err;  
  212.     dev_t devno = MKDEV(globalmem_major, 0);  
  213.   
  214.     /* 申请设备号 */  
  215.     if (globalmem_major)  
  216.         result = register_chrdev_region(devno, 1, "globalmem_proc_devices");  
  217.     else  
  218.     {                           /* 动态申请设备号 */  
  219.         result = alloc_chrdev_region(&devno, 0, 1, "globalmem_proc_devices");  
  220.         globalmem_major = MAJOR(devno);  
  221.     }  
  222.     if (result < 0)  
  223.         return result;  
  224.   
  225.     /* 为新设备分配内存和初始化 */  
  226.     globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);  
  227.     if (!globalmem_devp)  
  228.     {                           /*申请失败 */  
  229.         result = -ENOMEM;  
  230.         goto fail_malloc;  
  231.     }  
  232.     memset(globalmem_devp, 0, sizeof(struct globalmem_dev));  
  233.       
  234.     /* 字符设备的初始化和添加 */  
  235.     cdev_init(&globalmem_devp->cdev, &globalmem_fops);  
  236.     globalmem_devp->cdev.owner = THIS_MODULE;  
  237.     err = cdev_add(&globalmem_devp->cdev, devno, 1);  
  238.     if (err)  
  239.         printk(KERN_NOTICE "Error %d adding globalmem", err);  
  240.       
  241.     /* 自动创建设备节点 */  
  242.     globalmem_class = class_create(THIS_MODULE, "globalmem_sys_class");        
  243.     if (IS_ERR(globalmem_class))    
  244.         return PTR_ERR(globalmem_class);    
  245.       
  246.     globalmem_class_dev = device_create(globalmem_class, NULL, MKDEV(globalmem_major, 0), NULL, "globalmem_dev");       
  247.     if (unlikely(IS_ERR(globalmem_class_dev)))    
  248.         return PTR_ERR(globalmem_class_dev);    
  249.           
  250.     return 0;  
  251.   
  252.   fail_malloc:  
  253.     unregister_chrdev_region(devno, 1);  
  254.     return result;  
  255. }  
  256.   
  257. static void __exit  globalmem_exit(void)  
  258. {  
  259.     cdev_del(&globalmem_devp->cdev);    /*注销cdev */  
  260.     kfree(globalmem_devp);      /*释放设备结构体内存 */  
  261.     unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /*释放设备号 */  
  262.     device_unregister(globalmem_class_dev);    
  263.     class_destroy(globalmem_class);    
  264. }  
  265.   
  266.     
  267. module_init(globalmem_init);    
  268. module_exit(globalmem_exit);    
  269.     
  270. MODULE_AUTHOR("WHUT-ShiGuang");    
  271. MODULE_DESCRIPTION("Mini2440 Globalmem Driver");    
  272. MODULE_VERSION("1.0");    
  273. MODULE_LICENSE("GPL"); 

makefile文件:

  1. KERN_DIR = /home/youshan/linux-2.6.32.2  
  2.   
  3. all:  
  4.     make -C $(KERN_DIR) M=`pwd` modules   
  5.   
  6. clean:  
  7.     make -C $(KERN_DIR) M=`pwd` modules clean  
  8.     rm -rf modules.order  
  9.   
  10. obj-m   += globalmem.o  

相关内容