字符设备驱动程序实例
1:memdev.h
1 #ifndef MEMDEV_H_
2 #define MEMDEV_H_
3 #ifndef MEMDEV_MAJOR
4 #define MEMDEV_MAJOR 179 /*预设的mem的主设备号*/
5 #endif
6
7 #ifndef MEMDEV_NR_DEVS
8 #define MEMDEV_NR_DEVS 2 /*设备数*/
9 #endif
10
11 #ifndef MEMDEV_SIZE
12 #define MEMDEV_SIZE 4096
13 #endif
14
15 /*mem设备描述结构体*/
16 struct mem_dev
17 {
18 char *data;
19 unsigned long size;
20 };
21 #endif
~
2:memdev.c
#include <linux/module.h>
2 #include <linux/module.h>
3 #include <linux/kernel.h>
4 #include <linux/init.h>
5 #include <linux/fs.h>
6 #include <linux/cdev.h>
7 #include <linux/device.h>
8 #include <asm/uaccess.h>
9 #include <linux/slab.h>
10 #include"memdev.h"
11 static int mem_major = MEMDEV_MAJOR;
12
13 module_param(mem_major, int, S_IRUGO);
14
15 struct mem_dev *mem_devp; /*设备结构体指针*/
16
17 struct cdev cdev;
18
19 /*文件打开函数*/
20 int mem_open(struct inode *inode, struct file *filp)
21 {
22 struct mem_dev *dev;
23
24 /*获取次设备号*/
25 int num = MINOR(inode->i_rdev);
26
27 if (num >= MEMDEV_NR_DEVS)
28 return -ENODEV;
29 dev = &mem_devp[num];
30
31 /*将设备描述结构指针赋值给文件私有数据指针*/
32 filp->private_data = dev;
33
34 return 0;
35 }
36
37 /*文件释放函数*/
38 int mem_release(struct inode *inode, struct file *filp)
39 {
40 return 0;
41 }
42
43 /*读函数*/
44 static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, lof f_t *ppos)
45 {
46 unsigned long p = *ppos; /*记录文件指针偏移位置*/
47 unsigned int count = size; /*记录需要读取的字节数*/
48 int ret = 0; /*返回值*/
49 struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/
50
51 /*判断读位置是否有效*/
52 if (p >= MEMDEV_SIZE) /*要读取的偏移大于设备的内存空间*/
53 return 0;
54 if (count > MEMDEV_SIZE - p) /*要读取的字节大于设备的内存空间*/
55 count = MEMDEV_SIZE - p;
57 /*读数据到用户空间:内核空间->用户空间交换数据*/
58 if (copy_to_user(buf, (void*)(dev->data + p), count))
59 {
60 ret = - EFAULT;
61 }
62 else
63 {
64 *ppos += count;
65 ret = count;
66
67 printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);
68 }
69
70 return ret;
71 }
72
73 /*写函数*/
74 static ssize_t mem_write(struct file *filp, const char __user *buf, size_t si ze, loff_t *ppos)
75 {
76 unsigned long p = *ppos;
77 unsigned int count = size;
78 int ret = 0;
79 struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/
80
81 /*分析和获取有效的写长度*/
82 if (p >= MEMDEV_SIZE)
83 return 0;
84 if (count > MEMDEV_SIZE - p) /*要写入的字节大于设备的内存空间*/
85 count = MEMDEV_SIZE - p;
86
87 /*从用户空间写入数据*/
88 if (copy_from_user(dev->data + p, buf, count))
89 ret = - EFAULT;
90 else
91 {
92 *ppos += count; /*增加偏移位置*/
93 ret = count; /*返回实际的写入字节数*/
94
95 printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
96 }
97
98 return ret;
99 }
100
101 /* seek文件定位函数 */
102 static loff_t mem_llseek(struct file *filp, loff_t offset, int whence)
103 {
loff_t newpos;
105
106 switch(whence) {
107 case 0: /* SEEK_SET */ /*相对文件开始位置偏移*/
108 newpos = offset; /*更新文件指针位置*/
109 break;
110
111 case 1: /* SEEK_CUR */
112 newpos = filp->f_pos + offset;
113 break;
114
115 case 2: /* SEEK_END */
116 newpos = MEMDEV_SIZE -1 + offset;
117 break;
118
119 default: /* can't happen */
120 return -EINVAL;
121 }
122 if ((newpos<0) || (newpos>MEMDEV_SIZE))
123 return -EINVAL;
124
125 filp->f_pos = newpos;
126 return newpos;
127
128 }
129
130 /*文件操作结构体*/
131 static const struct file_operations mem_fops =
132 {
133 .owner = THIS_MODULE,
134 .llseek = mem_llseek,
135 .read = mem_read,
136 .write = mem_write,
137 .open = mem_open,
138 .release = mem_release,
139 };
140
141 /*设备驱动模块加载函数*/
142 static int memdev_init(void)
143 {
144 int result;
145 int i;
146 dev_t devno = MKDEV(mem_major, 0);
148
149 /* 申请设备号,当xxx_major不为0时,表示静态指定;当为0时,表示动态申请*/
150 /* 静态申请设备号*/
151 if (mem_major)
152 result = register_chrdev_region(devno, 2, "memdev");
153 else /* 动态分配设备号 */
154 {
155 result = alloc_chrdev_region(&devno, 0, 2, "memdev");
156 mem_major = MAJOR(devno); /*获得申请的主设备号*/
157 }
158
159 if (result < 0)
160 return result;
161
162 /*初始化cdev结构,并传递file_operations结构指针*/
163 cdev_init(&cdev, &mem_fops);
164 cdev.owner = THIS_MODULE; /*指定所属模块*/
165 cdev.ops = &mem_fops;
166
167 /* 注册字符设备 */
168 cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS);
169
170 /* 为设备描述结构分配内存*/
171 mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);
172 if (!mem_devp) /*申请失败*/
173 {
174 result = - ENOMEM;
175 goto fail_malloc;
176 }
177 memset(mem_devp, 0, sizeof(struct mem_dev));
178
179 /*为设备分配内存*/
180 for (i=0; i < MEMDEV_NR_DEVS; i++)
181 {
182 mem_devp[i].size = MEMDEV_SIZE;
183 mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);
184 memset(mem_devp[i].data, 0, MEMDEV_SIZE);
185 }
186
187 return 0;
fail_malloc:
190 unregister_chrdev_region(devno, 1);
191
192 return result;
193 }
194
195 /*模块卸载函数*/
196 static void memdev_exit(void)
197 {
198 cdev_del(&cdev); /*注销设备*/
199 kfree(mem_devp); /*释放设备结构体内存*/
200 unregister_chrdev_region(MKDEV(mem_major, 0), 2); /*释放设备号*/
201 }
202
203 MODULE_AUTHOR("David Xie");
204 MODULE_LICENSE("GPL");
205
206 module_init(memdev_init);
207 module_exit(memdev_exit);
makefile 编写:
1 ifeq ($(KERNELRELEASE),)
2 #KERNEL_DIR:=/home/archermind/zhaoxi/bsw_ww02_2016/kernel/cht
3 KERNEL_DIR:=/usr/src/linux-headers-3.13.0-32-generic
4 PWD:=$(shell pwd)
5 modules:
6 $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
7 modules_install:
8 $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules_install
9 clean:
10 rm -rf .*.cmd *.ko *.o modules.order Module.symvers *mod.c
11 .PHONY: modules modules_install clean
12 else
13 modules-objs := memdev.o
14 obj-m := memdev.o
15 endif
~
3:加载驱动:make
sudo insmod memdev.ko(如果出现insmod: error inserting 'memdev.ko': -1 Device or resource busy)查看 cat /proc/devices设备号和自己注册的是不是存在冲突导致加载失败)
修改头文件宏#define MEMDEV_MAJOR 主节点号
在/sys/modules会出先设备文件->需要在/dev下创建节点号,mknod /dev/memdev0 c 主设备号 次设备号 (例如上述代码不休改,则是sudo mknod /dev/memdev0 c 179 0)
用户空间的操作test.c
1 #include <stdio.h>
2
3 int main()
4 {
5 FILE *fp0 = NULL;
6 char Buf[4096];
7
8 /*初始化Buf*/
9 strcpy(Buf,"Mem is char dev!");
10 printf("BUF: %s\n",Buf);
11
12 /*打开设备文件*/
13 fp0 = fopen("/dev/memdev0","r+");
14 if (fp0 == NULL)
15 {
16 printf("Open Memdev0 Error!\n");
17 return -1;
18 }
19
20 /*写入设备*/
21 fwrite(Buf, sizeof(Buf), 1, fp0);
22
23 /*重新定位文件位置(思考没有该指令,会有何后果)*/
24 fseek(fp0,0,SEEK_SET);
25
26 /*清除Buf*/
27 strcpy(Buf,"Buf is NULL!");
28 printf("BUF: %s\n",Buf);
29
30
31 /*读出设备*/
32 fread(Buf, sizeof(Buf), 1, fp0);
33
34 /*检测结果*/
35 printf("BUF: %s\n",Buf);
36
37 return 0;
38
39 }
~