首页 > 代码库 > 08 Linux字符驱动---信号量

08 Linux字符驱动---信号量

1. mycdev.c

  1 #include <linux/init.h>
  2 #include <linux/module.h>
  3 #include <linux/cdev.h>
  4 #include <linux/fs.h>
  5 #include <linux/device.h>
  6 #include <linux/err.h>
  7 #include <linux/uaccess.h>
  8 #include <asm-generic/ioctl.h>
  9 #include <linux/semaphore.h>
 10 #include "cmd.h"
 11 
 12 #define MAX 1024
 13 
 14 struct mycdev
 15 {
 16     int len;
 17     char kbuf[MAX];
 18     struct cdev cdev;
 19     struct semaphore sem;
 20 };
 21 
 22 struct mycdev mycdev;
 23 struct class *cls;
 24 
 25 int mycdev_open(struct inode *inode, struct file *file)
 26 {
 27     printk("Call mycdev_open()\n");
 28     return 0;
 29 }
 30 
 31 ssize_t mycdev_read(struct file *file,char __user *ubuf,size_t size,loff_t *offset)
 32 {
 33     int len;
 34 
 35     printk("Call mycdev_read()\n");
 36 
 37     if(down_interruptible(&mycdev.sem))
 38     {
 39         return -ERESTARTSYS;
 40     }
 41 
 42     if(size >= mycdev.len)
 43         len = mycdev.len; 
 44     else 
 45         len = size;
 46 
 47     if(copy_to_user(ubuf,mycdev.kbuf,len) != 0)
 48     {
 49         printk("copy_to_user() error\n");
 50         return -EFAULT;
 51     }
 52 
 53     up(&mycdev.sem);
 54 
 55     return len;
 56 }
 57 
 58 ssize_t mycdev_write(struct file *file,const char __user *ubuf,size_t size,loff_t *offset)
 59 {
 60     printk("call mycdev_write()\n");
 61 
 62     if(down_interruptible(&mycdev.sem))
 63     {
 64         return -ERESTARTSYS;
 65     }
 66 
 67     if(size >= MAX)
 68         return -1;  
 69 
 70     if(copy_from_user(mycdev.kbuf,ubuf,size) != 0)
 71     {
 72         printk("Fail to copy_from_user()");
 73         return -EFAULT;
 74     }
 75 
 76     mycdev.len = size;
 77     mycdev.kbuf[size] = \0;
 78     printk("write : %s\n",mycdev.kbuf);
 79  
 80     up(&mycdev.sem);
 81 
 82     return  size;
 83 }
 84 
 85 long mycdev_unlocked_ioctl(struct file *file,unsigned int cmd, unsigned long arg)
 86 {
 87     int ret = 0;
 88 
 89     switch(cmd)
 90     {
 91         case CMD_CDEV_CLEAN:
 92             memset(mycdev.kbuf,0,MAX);
 93             printk("CMD_CLEN\n");
 94             break;
 95 
 96         case CMD_SET_CDEV_LEN:
 97             mycdev.len = arg;
 98             printk("CMD_SET\n");
 99             break;
100 
101         case CMD_GET_CDEV_LEN:
102             put_user(mycdev.len,(unsigned long *)arg);
103             printk("CMD_GET\n");
104             break;
105 
106         default:
107             printk("INvalid\n");
108             ret = -EINVAL;
109             break;
110     }
111 
112     return ret;
113 }
114 
115 struct file_operations fops = {
116     .owner = THIS_MODULE,
117     .open = mycdev_open,
118     .read = mycdev_read,
119     .write = mycdev_write,
120     .unlocked_ioctl = mycdev_unlocked_ioctl,
121 };
122 
123 int mycdev_init(void)
124 {
125     int ret = 0;
126     dev_t dev;
127     struct device *device;
128 
129     ret = alloc_chrdev_region(&dev, 0, 1, "mycdev");
130     if (ret != 0)
131     {
132         printk("alloc_chrdev_region() error\n");
133         goto err_alloc_chrdev_region;
134     }
135 
136     cdev_init(&(mycdev.cdev), &fops);
137 
138     ret = cdev_add(&(mycdev.cdev), dev, 1);
139     if (ret != 0)
140     {
141         printk("cdev_add() error\n");
142         goto err_cdev_add;
143     }
144 
145     cls = class_create(THIS_MODULE, "mycdev");
146     if (IS_ERR(cls))
147     {
148         ret = PTR_ERR(cls);
149         printk("class_create() error\n");
150         goto err_class_create;
151     }
152 
153     device = device_create(cls, NULL, dev, NULL, "mycdev");
154     if (IS_ERR(device))
155     {
156         ret = PTR_ERR(device);
157         printk("device_create() error\n");
158         goto err_device_create;
159     }
160 
161     sema_init(&mycdev.sem, 1);
162 
163     printk("mycdev_init()\n");
164     return 0;
165 
166 err_device_create:
167     class_destroy(cls);
168 
169 err_class_create:
170     cdev_del(&(mycdev.cdev));
171 
172 err_cdev_add:
173     unregister_chrdev_region(dev, 1);
174 
175 err_alloc_chrdev_region:
176     return ret;
177 }
178 
179 void mycdev_exit(void)
180 {
181     dev_t dev = mycdev.cdev.dev;
182 
183     device_destroy(cls, dev);
184     class_destroy(cls);
185     cdev_del(&(mycdev.cdev));
186     cdev_del(&(mycdev.cdev));
187     unregister_chrdev_region(dev, 1);
188     
189     printk("mycdev_exit()\n");
190     return;
191 }
192 
193 module_init(mycdev_init);
194 module_exit(mycdev_exit);
195 
196 MODULE_LICENSE("GPL");
197 MODULE_AUTHOR("GNB");

2. cmd.h

1 #ifndef _CMD_H_
2 #define _CMD_H_
3 
4 #define CMD_TYPE            ‘k‘
5 #define CMD_CDEV_CLEAN      _IO(CMD_TYPE,0x10)
6 #define CMD_SET_CDEV_LEN    _IOW(CMD_TYPE,0x11,int)
7 #define CMD_GET_CDEV_LEN    _IOR(CMD_TYPE,0x12,int)
8 
9 #endif

3. Makefile

 1 KERNEL_DIR = /lib/modules/$(shell uname -r)/build
 2 PWD = $(shell pwd)
 3 
 4 ifneq ($(KERNELRELEASE),)
 5 
 6 obj-m := mycdev.o
 7 
 8 else
 9 
10 .PHONY:default clean
11 
12 default:
13     $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
14 
15 clean:
16     $(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean
17 
18 endif

 

08 Linux字符驱动---信号量