国嵌内核驱动进阶班-7-3(阻塞型字符设备驱动)

  • 为什么阻塞?

在阻塞方式下,写没有足够的空间或读时候没有数据。

※ 阻塞方式是文件读写的默认方式。没有空间或者读时没有数据返回错误。


 

※残留问题:

驱动程序中全局变量 在不同进程间是共享的吗?

 


 

  • 阻塞型设备驱动程序

 


 驱动代码: 

 1 #ifndef _MEMDEV_H_
 2 #define _MEMDEV_H_
 3 
 4 #ifndef MEMDEV_MAJOR
 5 #define MEMDEV_MAJOR 0   /*预设的mem的主设备号*/
 6 #endif
 7 
 8 #ifndef MEMDEV_NR_DEVS
 9 #define MEMDEV_NR_DEVS 2    /*设备数*/
10 #endif
11 
12 #ifndef MEMDEV_SIZE
13 #define MEMDEV_SIZE 4096
14 #endif
15 
16 /*mem设备描述结构体*/
17 struct mem_dev                                     
18 {                                                        
19   char *data;                      
20   unsigned long size; 
21   wait_queue_head_t inq;      
22 };
23 
24 #endif /* _MEMDEV_H_ */

 

  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 <linux/slab.h>
 11 #include <asm/uaccess.h>
 12 
 13 #include "memdev.h"
 14 
 15 static int mem_major = MEMDEV_MAJOR;
 16 bool have_data = false; /*表明设备有足够数据可供读*/
 17 
 18 module_param(mem_major, int, S_IRUGO);
 19 
 20 struct mem_dev *mem_devp; /*设备结构体指针*/
 21 
 22 struct cdev cdev; 
 23 
 24 /*文件打开函数*/
 25 int mem_open(struct inode *inode, struct file *filp)
 26 {
 27     struct mem_dev *dev;
 28     
 29     /*获取次设备号*/
 30     int num = MINOR(inode->i_rdev);
 31 
 32     if (num >= MEMDEV_NR_DEVS) 
 33             return -ENODEV;
 34     dev = &mem_devp[num];
 35     
 36     /*将设备描述结构指针赋值给文件私有数据指针*/
 37     filp->private_data = dev;
 38     
 39     return 0; 
 40 }
 41 
 42 /*文件释放函数*/
 43 int mem_release(struct inode *inode, struct file *filp)
 44 {
 45   return 0;
 46 }
 47 
 48 /*读函数*/
 49 static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
 50 {
 51   unsigned long p =  *ppos;
 52   unsigned int count = size;
 53   int ret = 0;
 54   struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/
 55 
 56   /*判断读位置是否有效*/
 57   if (p >= MEMDEV_SIZE)
 58     return 0;
 59   if (count > MEMDEV_SIZE - p)
 60     count = MEMDEV_SIZE - p;
 61     
 62 while (!have_data) /* 没有数据可读,考虑为什么不用if,而用while,中断信号唤醒 */
 63 {
 64         if (filp->f_flags & O_NONBLOCK)
 65             return -EAGAIN;
 66     
 67     wait_event_interruptible(dev->inq,have_data);
 68 }
 69 
 70 
 71   /*读数据到用户空间*/
 72   if (copy_to_user(buf, (void*)(dev->data + p), count))
 73   {
 74     ret =  - EFAULT;
 75   }
 76   else
 77   {
 78     *ppos += count;
 79     ret = count;
 80    
 81     printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);
 82   }
 83   
 84   have_data = false; /* 表明不再有数据可读 */
 85   return ret;
 86 }
 87 
 88 /*写函数*/
 89 static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
 90 {
 91   unsigned long p =  *ppos;
 92   unsigned int count = size;
 93   int ret = 0;
 94   struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/
 95   
 96   /*分析和获取有效的写长度*/
 97   if (p >= MEMDEV_SIZE)
 98     return 0;
 99   if (count > MEMDEV_SIZE - p)
100     count = MEMDEV_SIZE - p;
101     
102   /*从用户空间写入数据*/
103   if (copy_from_user(dev->data + p, buf, count))
104     ret =  - EFAULT;
105   else
106   {
107     *ppos += count;
108     ret = count;
109     
110     printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
111   }
112   
113   have_data = true; /* 有新的数据可读 */
114     
115     /* 唤醒读进程 */
116     wake_up(&(dev->inq));
117 
118   return ret;
119 }
120 
121 /* seek文件定位函数 */
122 static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)
123 { 
124     loff_t newpos;
125 
126     switch(whence) {
127       case 0: /* SEEK_SET */
128         newpos = offset;
129         break;
130 
131       case 1: /* SEEK_CUR */
132         newpos = filp->f_pos + offset;
133         break;
134 
135       case 2: /* SEEK_END */
136         newpos = MEMDEV_SIZE -1 + offset;
137         break;
138 
139       default: /* can't happen */
140         return -EINVAL;
141     }
142     if ((newpos<0) || (newpos>MEMDEV_SIZE))
143         return -EINVAL;
144         
145     filp->f_pos = newpos;
146     return newpos;
147 
148 }
149 
150 /*文件操作结构体*/
151 static const struct file_operations mem_fops =
152 {
153   .owner = THIS_MODULE,
154   .llseek = mem_llseek,
155   .read = mem_read,
156   .write = mem_write,
157   .open = mem_open,
158   .release = mem_release,
159 };
160 
161 /*设备驱动模块加载函数*/
162 static int memdev_init(void)
163 {
164   int result;
165   int i;
166 
167   dev_t devno = MKDEV(mem_major, 0);
168 
169   /* 静态申请设备号*/
170   if (mem_major)
171     result = register_chrdev_region(devno, 2, "memdev");
172   else  /* 动态分配设备号 */
173   {
174     result = alloc_chrdev_region(&devno, 0, 2, "memdev");
175     mem_major = MAJOR(devno);
176   }  
177   
178   if (result < 0)
179     return result;
180 
181   /*初始化cdev结构*/
182   cdev_init(&cdev, &mem_fops);
183   cdev.owner = THIS_MODULE;
184   cdev.ops = &mem_fops;
185   
186   /* 注册字符设备 */
187   cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS);
188    
189   /* 为设备描述结构分配内存*/
190   mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);
191   if (!mem_devp)    /*申请失败*/
192   {
193     result =  - ENOMEM;
194     goto fail_malloc;
195   }
196   memset(mem_devp, 0, sizeof(struct mem_dev));
197   
198   /*为设备分配内存*/
199   for (i=0; i < MEMDEV_NR_DEVS; i++) 
200   {
201         mem_devp[i].size = MEMDEV_SIZE;
202         mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);
203         memset(mem_devp[i].data, 0, MEMDEV_SIZE);
204   
205       /*初始化等待队列*/
206      init_waitqueue_head(&(mem_devp[i].inq));
207   }
208    
209   return 0;
210 
211   fail_malloc: 
212   unregister_chrdev_region(devno, 1);
213   
214   return result;
215 }
216 
217 /*模块卸载函数*/
218 static void memdev_exit(void)
219 {
220   cdev_del(&cdev);   /*注销设备*/
221   kfree(mem_devp);     /*释放设备结构体内存*/
222   unregister_chrdev_region(MKDEV(mem_major, 0), 2); /*释放设备号*/
223 }
224 
225 MODULE_AUTHOR("David Xie");
226 MODULE_LICENSE("GPL");
227 
228 module_init(memdev_init);
229 module_exit(memdev_exit);
ifneq ($(KERNELRELEASE),)

obj-m := memdev.o

else
    
KDIR := /home/rpi/RpiLinux
all:
    make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=/home/rpi/RpiTools/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-

clean:
    rm -f *.ko *.o *.mod.o *.mod.c *.symvers  modul*

endif

 

测试程序:

 1 #include <stdio.h>
 2 
 3 int main()
 4 {
 5     FILE *fp = NULL;
 6     char Buf[128];
 7     
 8     
 9     /*打开设备文件*/
10     fp = fopen("/dev/memdev0","r+");
11     if (fp == NULL)
12     {
13         printf("Open Dev memdev0 Error!\n");
14         return -1;
15     }
16     
17     /*写入设备*/
18     strcpy(Buf,"memdev is char dev!");
19     printf("Write BUF: %s\n",Buf);
20     fwrite(Buf, sizeof(Buf), 1, fp);
21     
22     sleep(5);
23     fclose(fp);
24     
25     return 0;    
26 
27 }
 1 #include <stdio.h>
 2 
 3 int main()
 4 {
 5     FILE *fp = NULL;
 6     char Buf[128];
 7     
 8     /*初始化Buf*/
 9     strcpy(Buf,"memdev is char dev!");
10     printf("BUF: %s\n",Buf);
11     
12     /*打开设备文件*/
13     fp = fopen("/dev/memdev0","r+");
14     if (fp == NULL)
15     {
16         printf("Open memdev0 Error!\n");
17         return -1;
18     }
19     
20     /*清除Buf*/
21     strcpy(Buf,"Buf is NULL!");
22     printf("Read BUF1: %s\n",Buf);
23     
24     /*读出数据*/
25     fread(Buf, sizeof(Buf), 1, fp);
26     
27     /*检测结果*/
28     printf("Read BUF2: %s\n",Buf);
29     
30     fclose(fp);
31     
32     return 0;    
33 
34 }

 

测试结果:

 

posted @ 2015-06-03 23:53  renhl  阅读(222)  评论(0编辑  收藏  举报