字符设备驱动

来源:互联网 发布:单身约会软件app 编辑:程序博客网 时间:2024/06/06 09:13

使用原子锁实现设备只能被一个进程打开

[cpp] view plaincopyprint?
  1. #include <linux/module.h>  
  2. #include <linux/init.h>  
  3. #include <linux/cdev.h>  
  4. #include <linux/errno.h>  
  5. #include <linux/mm.h>  
  6. #include <linux/types.h>  
  7. #include <linux/sched.h>  
  8. #include <linux/fs.h>  
  9. #include <asm/io.h>  
  10. #include <linux/slab.h>  
  11. #include <asm/uaccess.h>  
  12.   
  13. #define GLOBAL_MAJOR 0  
  14. #define GLOBAL_MAXMEM 0x1000  
  15. #define DEV_NAME ("globalmem")  
  16.   
  17. int globalmem_major = GLOBAL_MAJOR;  
  18. static atomic_t my_available = ATOMIC_INIT(1);  
  19.   
  20. struct globalmem_dev{  
  21.     struct cdev cdev;  
  22.     unsigned char mem[GLOBAL_MAXMEM];  
  23. };  
  24.   
  25. struct globalmem_dev *globalmem_devp;  
  26.   
  27. static int globalmem_open(struct inode *inode, struct file *filp)  
  28. {  
  29.     if(!atomic_dec_and_test(&my_available))  
  30.     {  
  31.         atomic_inc(&my_available);  
  32.         return -EBUSY;  
  33.     }  
  34.     filp->private_data = globalmem_devp;  
  35.     return 0;  
  36. }  
  37.   
  38. static int globalmem_release(struct inode *inode, struct file *filp)  
  39. {  
  40.     atomic_inc(&my_available);  
  41.     return 0;  
  42. }  
  43.   
  44. static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)  
  45. {  
  46.     unsigned long p = *ppos;  
  47.     unsigned int count = size;  
  48.     int ret = 0;  
  49.       
  50.     struct globalmem_dev *dev = filp->private_data;  
  51.       
  52.     if(p >= GLOBAL_MAXMEM)  
  53.         return 0;  
  54.     if(count + p > GLOBAL_MAXMEM)  
  55.         count = GLOBAL_MAXMEM - p;  
  56.       
  57.     if(copy_to_user(buf, (void*)dev->mem, count))  
  58.     {  
  59.         return -EFAULT;  
  60.     }  
  61.     else  
  62.     {  
  63.         *ppos += count;  
  64.         ret = count;  
  65.     }  
  66.       
  67.     return ret;  
  68. }  
  69.   
  70. static ssize_t globalmem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)  
  71. {  
  72.     unsigned long p = *ppos;  
  73.     unsigned int count = size;  
  74.     int ret = 0;  
  75.       
  76.     struct globalmem_dev *dev = filp->private_data;  
  77.       
  78.     if(p > GLOBAL_MAXMEM)  
  79.         return 0;  
  80.     if(count + p > GLOBAL_MAXMEM)  
  81.         count = GLOBAL_MAXMEM - p;  
  82.           
  83.     if(copy_from_user(dev->mem, buf, count))  
  84.     {  
  85.         return -EFAULT;  
  86.     }  
  87.     else  
  88.     {  
  89.         *ppos += count;  
  90.         ret = count;  
  91.     }  
  92.     return ret;  
  93. }  
  94.   
  95. static const struct file_operations globalmem_ops = {  
  96.     .owner = THIS_MODULE,  
  97.     .open = globalmem_open,  
  98.     .read = globalmem_read,  
  99.     .write = globalmem_write,  
  100.     .release = globalmem_release,  
  101. };  
  102.   
  103. static void globalmem_setup(struct globalmem_dev *dev, int index)  
  104. {  
  105.     int err, devno = MKDEV(globalmem_major, index);  
  106.       
  107.     cdev_init(&dev->cdev, &globalmem_ops);  
  108.     dev->cdev.owner = THIS_MODULE;  
  109.     err = cdev_add(&dev->cdev, devno, 1);  
  110.     if(err)  
  111.         printk(KERN_ERR "### cdev_add fail \n");  
  112. }  
  113.   
  114. static int __init globalmem_init(void)  
  115. {  
  116.     int res;  
  117.     dev_t devno = MKDEV(globalmem_major, 0);  
  118.       
  119.     if(globalmem_major)  
  120.         res = register_chrdev_region(devno, 1, DEV_NAME);  
  121.     else  
  122.     {  
  123.         res = alloc_chrdev_region(&devno, 0, 1, DEV_NAME);  
  124.         globalmem_major = MAJOR(devno);  
  125.     }  
  126.     if(res < 0)  
  127.         return res;  
  128.           
  129.     globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);  
  130.     if(!globalmem_devp)  
  131.     {  
  132.         res = -ENOMEM;  
  133.         goto fail_malloc;  
  134.     }  
  135.       
  136.     memset(globalmem_devp, 0, sizeof(struct globalmem_dev));  
  137.       
  138.     globalmem_setup(globalmem_devp, 0);  
  139.     return 0;  
  140.       
  141. fail_malloc:  
  142.     unregister_chrdev_region(devno, 1);  
  143.     return res;  
  144. }  
  145.   
  146. static void __exit globalmem_exit(void)  
  147. {  
  148.     cdev_del(&globalmem_devp->cdev);  
  149.     kfree(globalmem_devp);  
  150.     unregister_chrdev_region(MKDEV(globalmem_major, 0), 1);  
  151. }  
  152.   
  153. MODULE_LICENSE("GPL");  
  154. module_init(globalmem_init);  
  155. module_exit(globalmem_exit);  

 

Makefile

[cpp] view plaincopyprint?
  1. obj-m := globalmem_dev.o  
  2. globalmem_dev-objs := dev_globalmem.o  
  3.   
  4. KID :=/lib/modules/`uname -r`/build  
  5. PWD := ${shell pwd}   
  6.   
  7. defalt:  
  8.     make -C $(KID) M=${PWD} modules  
  9.       
  10. clean:  
  11.     rm -rf *.o *.cmd *.ko *.mod.c *.tmp_versions *.order *.symvers .*.*.cmd  


 

测试程序:

[cpp] view plaincopyprint?
  1. #include <sys/types.h>  
  2. #include <sys/stat.h>  
  3. #include <stdlib.h>  
  4. #include <stdio.h>  
  5. #include <string.h>  
  6. #include <fcntl.h>  
  7.   
  8. #define NODE_NAME ("/dev/globalmem")  
  9. #define TO_WRITE "664"  
  10. #define BUF_LENGTH 128  
  11.   
  12. int main()  
  13. {  
  14.     int filp, filp2;  
  15.     int res = 0;  
  16.     char buf[BUF_LENGTH];  
  17.       
  18.     memset(buf, 0, BUF_LENGTH);   
  19.       
  20.     filp = open(NODE_NAME, O_RDWR);  
  21.   
  22.     if(filp > 0)  
  23.     {  
  24.               
  25.         if( (res = read(filp, buf, BUF_LENGTH) ) < 0)  
  26.             printf("read error \n");  
  27.         else  
  28.         {  
  29.             printf("first read is %s\n", buf);  
  30.         }  
  31.       
  32.         if((res = write(filp, TO_WRITE, strlen(TO_WRITE))) != strlen(TO_WRITE))  
  33.             printf("write error \n");  
  34.           
  35.         close(filp);  
  36.         filp = open(NODE_NAME, O_RDWR);  
  37.         memset(buf, 0, BUF_LENGTH);   
  38.       
  39.         if( (res = read(filp, buf, BUF_LENGTH) ) < 0)  
  40.             printf("read error \n");  
  41.         else  
  42.         {  
  43.             printf("second read is %s\n", buf);  
  44.         }  
  45.     }  
  46.     else  
  47.     {  
  48.         printf("open file fail \n");  
  49.     }  
  50.     while(1);  
  51.     close(filp);      
  52.     exit(0);  
  53. }  


4. 验证效果

1) make

2) insmod scull.ko

3) cat /proc/devices | grep scull    //获取字符设备scull的主设备号,我的是248

4) cd /dev/

5) mknod scull c 248 0

 


编译 测试程序

cc -o test test.c

运行

 

 

 

成功锁住。

0 0
原创粉丝点击