4.2 字符设备驱动之 字符设备的注册(第二种注册字符设备的方法) ----编写访问内核缓存的设备驱动

demo.c

  1 /* head file */
  2 #include <linux/init.h>
  3 #include <linux/module.h>
  4 #include <linux/fs.h>
  5 #include <linux/cdev.h>
  6 #include <linux/uaccess.h>
  7 #include <linux/slab.h>
  8 
  9 #define DEVNAME "scull"//设备名:内存设备scull
 10 #define CNT 200//创建次设备的数目
 11 
 12 #define SZ 512
 13 
 14 static unsigned int major = 0;
 15 static unsigned int minor = 0;
 16 static dev_t devnum;//定义字符设备名变量!是字符设备号吧!!!
 17 
 18 struct scull_t { //定义对应字符设备的结构体
 19     char *kbuf;  /*指向用户要访问的内核空间的一块内存的地址*/
 20     size_t sz; //内核层数据大小
 21     struct cdev cdev;
 22 }*sculls;   //struct scull_t *sculls;
 23     
 24 static int mill_open (struct inode *inodp, struct file *filp)
 25 {
 26     //求该字符设备的结构体的地址,用于一套驱动多个设备
 27     filp->private_data = container_of(inodp->i_cdev, struct scull_t, cdev);    
 28     
 29     return 0;
 30 }
 31 
 32 static ssize_t 
 33 mill_read (struct file *filp, char __user *buf, size_t cnt, loff_t *fpos)
 34 {
 35     struct scull_t *ptr = filp->private_data;//定义指向该结构体的一个指针
 36     
 37     if (cnt == 0) { //用户层传下来数据字节数为0
 38         return cnt;    //错误返回
 39     }    
 40 
 41     if (!ptr->sz) { //内核没有读到自己内存空间数据立即返回错误负值(无阻塞)
 42         return -EINVAL;
 43     }    
 44 
 45     cnt = min(cnt, ptr->sz);//得出用户层需要读取的数据字节数(比如512个字节)和内核实际字节数的最小值
 46     //读操作:将内核空间ptr->kbuf上的数据传递cnt(从用户层传下来的)个到用户层buf
 47     if (copy_to_user(buf, ptr->kbuf, cnt)) {
 48         return -EINVAL;
 49     }
 50     
 51     //后面挪到前面去读
 52     memmove(ptr->kbuf, ptr->kbuf + cnt, ptr->sz - cnt);
 53     ptr->sz -= cnt;//更新内核指定空间区域的数据字节数/每读一次减一次cnt个字节(比如512个字节)
 54 
 55     return cnt;//返回从内核读取的数据字节数
 56 }
 57 
 58 static ssize_t 
 59 mill_write (struct file *filp, const char __user *buf, size_t cnt, loff_t *fpos)
 60 {
 61     struct scull_t *ptr = filp->private_data;
 62 
 63     if (cnt == 0) { //从内核层传下来要写的数据字节数为0/不对了。。。
 64         return cnt;    //返回0个/错误返回
 65     }    
 66 
 67     if (ptr->sz == SZ) { //若内核层内存空间数据等于SZ,则满了,不能写了。。
 68         return -EINVAL;
 69     }    
 70 
 71     cnt = min(cnt, SZ- ptr->sz);//得出用户层需要写的数据字节数(比如512个字节)和内核实际字节数的最小值
 72 
 73     //写操作:从用户层传递数据到内核指定空间
 74     if  (copy_from_user(ptr->kbuf+ptr->sz, buf, cnt)) {
 75         return -EINVAL;
 76     }
 77 
 78     ptr->sz += cnt;//更新内核层内存空间数据字节数
 79     //ptr->sz = ptr->sz + cnt;
 80 
 81     return cnt;
 82 }
 83 
 84 static int mill_release (struct inode *inodp, struct file *filp)
 85 {
 86 
 87     return 0;
 88 }
 89 
 90 static struct file_operations fops = { //驱动函数集
 91     .owner         = THIS_MODULE,    
 92     .open          = mill_open,
 93     .read          = mill_read,
 94     .write        = mill_write,
 95     .release    = mill_release,
 96 };
 97 
 98 
 99 /* driver module entry */
100 static int __init demo_init(void)
101 {
102     int ret;
103     int i;
104 
105     /*首先*/
106     if (!major) {
107         //第二种申请设备号方法:内核自动(动态)申请设备号
108         ret = alloc_chrdev_region(&devnum, minor, CNT, DEVNAME);
109         major = MAJOR(devnum);
110     }else {
111         devnum = MKDEV(major, minor);
112         //注册字符设备驱动
113         ret = register_chrdev_region(devnum, CNT, DEVNAME);
114     }
115 
116     if (ret < 0) {
117         return -EINVAL;
118     }
119 
120     //给struct scull_t 申请空间
121     sculls = kzalloc(CNT*sizeof(*sculls), GFP_KERNEL);
122     if (NULL == sculls) {
123         ret = -ENOMEM; //申请失败返回-ENOMEM
124         goto error0;//跳到去执行移除字符设备驱动
125     }
126 
127     /*其次*/
128     //给每个次设备申请地址空间
129     for (i = 0; i < CNT; ++i) {
130         sculls[i].kbuf = kzalloc(SZ, GFP_KERNEL);
131         if (NULL == sculls[i].kbuf) {
132             ret = -ENOMEM;//申请失败返回-ENOMEM
133             goto error1;//
134         }
135 
136         cdev_init(&sculls[i].cdev, &fops);//字符设备次设备初始化
137         ret = cdev_add(&sculls[i].cdev, devnum+i, CNT);//增加200个次设备/
138         if (ret < 0) {
139             kfree(sculls[i].kbuf);//最后释放一次第200个次设备的空间
140             goto error1;
141         }
142     }    
143 
144     return 0;
145 
146 error1:
147     //释放所有199个次设备之前的空间
148     while (i--) {
149         kfree(sculls[i].kbuf);
150         cdev_del(&sculls[i].cdev);//删除所有200个次设备
151     }
152     //释放大的struct scull_t 结构体之前的空间
153     kfree(sculls);
154 
155 error0: 
156     //移除之前注册的字符设备驱动
157     unregister_chrdev_region(devnum, CNT);
158     
159     return ret;
160 }
161 
162 module_init(demo_init);
163 
164 /* driver module exit */
165 static void __exit demo_exit(void)
166 {
167     int i;
168     //移除驱动模块时:释放所有次设备之前的空间
169     for (i = 0; i < CNT; ++i) {
170         kfree(sculls[i].kbuf);
171         cdev_del(&sculls[i].cdev);
172     }
173     //释放大的struct scull_t 结构体之前的空间
174     kfree(sculls);
175     //移除之前注册的字符设备驱动
176     unregister_chrdev_region(devnum, CNT);
177 }
178 module_exit(demo_exit);
179 
180 /* driver module description */
181 MODULE_LICENSE("GPL");
182 
183 MODULE_AUTHOR("millet9527");
184 MODULE_VERSION("millet plus 18");
185 MODULE_DESCRIPTION("example for driver module arch");

makefile

1 obj-m    := demo.o
2 
3 KERNEL    := /linux-3.5
4 
5 all:
6     make -C $(KERNEL) M=`pwd`
7 clean:
8     make -C $(KERNEL) M=`pwd` clean
9     

====================================================================

write.c

 1 #include <fcntl.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <unistd.h>
 5 #include <sys/stat.h>
 6 #include <assert.h>
 7 
 8 #define LEN 512
 9 
10 int main(int argc, char **argv)
11 {
12     int ret;
13 
14     if (argc !=  3) {
15         fprintf(stderr, "Usage: %s devfile file\n", argv[0]);
16         exit(1);
17     }
18 
19     int fd_dev = open(argv[1], O_WRONLY | O_NDELAY);
20     assert(fd_dev > 0);
21 
22     int fd_file = open(argv[2], O_RDONLY | O_NDELAY);
23     assert(fd_file > 0);
24 
25     char buf[LEN];
26     ret = read(fd_file, buf, LEN);//
27     assert(ret > 0);
28 
29     ret = write(fd_dev, buf, ret);//
30     assert(ret >= 0);
31 
32     return 0;
33 }

read.c

 1 #include <fcntl.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <unistd.h>
 5 #include <sys/stat.h>
 6 #include <assert.h>
 7 
 8 #define LEN 512
 9 
10 int main(int argc, char **argv)
11 {
12     int ret;
13 
14     if (argc !=  2) {
15         fprintf(stderr, "Usage: %s devfile\n", argv[0]);
16         exit(1);
17     }
18 
19     int fd = open(argv[1], O_RDONLY | O_NDELAY);//非阻塞型读取方式
20     assert(fd > 0);
21 
22     char buf[LEN];
23 
24     ret = read(fd, buf, LEN);//只读512个字节
25     assert(fd > 0);
26 
27     buf[ret] = '\0';//读完了,读到的字节数据末尾加'\0'
28     printf("%s\n", buf);
29 
30     return 0;
31 }

makefile

 1 CC=arm-linux-gcc 

 

 

posted @ 2017-03-15 22:50  bkycrmn  阅读(199)  评论(0)    收藏  举报