1 /* globalmem字符设备驱动
2 * 作者:liwei.cai
3 * 日期:2012-08-03
4 * globalmem.c
5 */
6 #include <linux/module.h>
7 #include <linux/types.h>
8 #include <linux/fs.h>
9 #include <linux/errno.h>
10 #include <linux/mm.h>
11 #include <linux/sched.h>
12 #include <linux/init.h>
13 #include <linux/cdev.h>
14 #include <asm/io.h>
15 #include <asm/system.h>
16 #include <asm/uaccess.h>
17
18 #define GLOBALMEM_SIZE 0x1000 /* 全局内存大小:4KB */
19 #define MEM_CLEAR 0x01 /* 清零全局内存 */
20 #define GLOBALMEM_MAJOR 250 /* 预设的globalmem 的主设备号 */
21
22 static int globalmem_major = GLOBALMEM_MAJOR;
23
24 /* globalmem设备结构体 */
25 struct globalmem_dev
26 {
27 struct cdev cdev; /* cdev结构体 */
28 unsigned char mem[GLOBALMEM_SIZE]; /* 全局变量 */
29 };
30
31 //struct globalmem_dev dev; /* 设备结构体实例 */
32 struct globalmem_dev *globalmem_devp; /* 设备结构体指针 */
33
34 /* 文件打开函数 */
35 int globalmem_open(struct inode *inode, struct file *filp)
36 {
37 /* 将设备结构体指针赋值给文件私有数据指针 */
38 filp->private_data = globalmem_devp;
39 return 0;
40 }
41
42 /* 文件释放函数 */
43 int globalmem_release(struct inode *inode, struct file *filp)
44 {
45 return 0;
46 }
47
48 /* globalmem 设备驱动的读函数 */
49 static ssize_t globalmem_read(struct file *filp,
50 char __user *buf, size_t size, loff_t *ppos)
51 {
52 unsigned long p = *ppos;
53 unsigned int count = size;
54 int ret = 0;
55 struct globalmem_dev *dev = filp->private_data;//获得设备结构体指针
56
57 /* 分析和获取有效的读长度 */
58 if(p >= GLOBALMEM_SIZE) //要读的偏移位置越界
59 {
60 return count ? -ENXIO : 0;
61 }
62 if (count > GLOBALMEM_SIZE - p) //要读的字节太大
63 {
64 count = GLOBALMEM_SIZE - p;
65 }
66
67 /* 内核控件-->用户空间 */
68 if (copy_to_user(buf, (void*)(dev->mem + p), count))
69 {
70 ret = -EFAULT;
71 }
72 else
73 {
74 *ppos += count;
75 ret = count;
76
77 printk(KERN_INFO "read %d bytes(s) from %ld \n", count, p);
78 }
79
80 return ret;
81 }
82
83 /* globalmem 设备驱动的写函数 */
84 static ssize_t globalmem_write(struct file *filp,
85 const char __user *buf, size_t size, loff_t *ppos)
86 {
87 unsigned long p = *ppos;
88 unsigned int count = size;
89 int ret = 0;
90 <span style="white-space: pre; "> </span>struct globalmem_dev *dev = filp->private_data;//获取设备结构体指针
91
92 /* 分析和获取有效的写长度 */
93 if (p >= GLOBALMEM_SIZE) // 要写的偏移位置越界
94 {
95 return count ? -ENXIO : 0;
96 }
97 if (count > GLOBALMEM_SIZE - p) // 要写的字节数太多
98 {
99 count = GLOBALMEM_SIZE - p;
100 }
101
102 /* 用户空间 --> 内核空间 */
103 if (copy_from_user(dev->mem + p, buf, count))
104 {
105 ret = -EFAULT;
106 }
107 else
108 {
109 *ppos += count;
110 ret = count;
111
112 printk(KERN_INFO "written %d bytes(s) from %ld \n", count, p);
113 }
114 return ret;
115 }
116
117 /* seek()函数对文件定位的起始位置可以是文件开头(SEEK_SET, 0)、
118 * 当前位置(SEEK_CUR,1)和文件尾(SEEK_END,2)
119 */
120 static loff_t globalmem_llseek(struct file *filp,
121 loff_t offset, int orig)
122 {
123 loff_t ret;
124 switch(orig)
125 {
126 case 0: //从文件开头开始偏移
127 if (offset < 0)
128 {
129 ret = -EINVAL;
130 break;
131 }
132 if ((unsigned int)offset > GLOBALMEM_SIZE)// 偏移越界
133 {
134 ret = -EINVAL;
135 break;
136 }
137 filp->f_pos = (unsigned int)offset;
138 ret = filp->f_pos;
139 break;
140 case 1: //从当前位置开始偏移
141 if((filp->f_pos + offset) > GLOBALMEM_SIZE) //偏移越界
142 {
143 ret = -EINVAL;
144 break;
145 }
146 if ((filp->f_pos + offset) < 0)
147 {
148 ret = -EINVAL;
149 break;
150 }
151 filp->f_pos += offset;
152 ret = filp->f_pos;
153 break;
154 default:
155 ret = -EINVAL;
156 }
157 return ret;
158 }
159
160 /* ioctl()函数接受MEM_CLEAR命令,这个命令会将全局内存的有效数据长度清零
161 * 对于设备不支持的命令,返回-EINCVAL
162 */
163 static int globalmem_ioctl(struct inode *inodep, struct file *filp,
164 unsigned int cmd, unsigned long arg)
165 {
166 struct globalmem_dev *dev = filp->private_data; /* 获得设备结构体指针 */
167 switch(cmd)
168 {
169 case MEM_CLEAR://清除全局内存
170 memset(dev->mem, 0, GLOBALMEM_SIZE);
171 printk(KERN_INFO "globalmem is set to zero\n");
172 break;
173
174 default:
175 return -EINVAL;
176 }
177 return 0;
178 }
179
180 /* 与globalmem的cdev关联的file_operations结构体 */
181 static const struct file_operations globalmem_fops =
182 {
183 .owner = THIS_MODULE,
184 .llseek = globalmem_llseek,
185 .read = globalmem_read,
186 .write = globalmem_write,
187 .ioctl = globalmem_ioctl,
188 .open =globalmem_open,
189 .release = globalmem_release,
190 };
191
192 /* 初始化并添加cdev结构体 */
193 static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
194 {
195 int err, devno = MKDEV(globalmem_major, index);
196
197 cdev_init(&dev->cdev, &globalmem_fops);
198 dev->cdev.owner = THIS_MODULE;
199 dev->cdev.ops = &globalmem_fops;
200 err = cdev_add(&dev->cdev, devno, 1);
201 if(err)
202 {
203 printk(KERN_NOTICE "ERROR %d adding LED%d", err, index);
204 }
205 }
206
207 /* globalmem设备驱动模块加载函数 */
208 int globalmem_init(void)
209 {
210 int result;
211 dev_t devno = MKDEV(globalmem_major, 0);
212
213 /* 申请字符设备驱动区域 */
214 if (globalmem_major)
215 {
216 result = register_chrdev_region(devno, 1, "globalmem");
217 }
218 else
219 {
220 /* 动态加载主设备号 */
221 result = alloc_chrdev_region(&devno, 0, 1, "globalmem");
222 globalmem_major = MAJOR(devno);
223 }
224 if (result < 0)
225 {
226 return result;
227 }
228
229 /* 动态申请设备结构体的内存 */
230 globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
231 if (!globalmem_devp) //申请失败
232 {
233 result = -ENOMEM;
234 goto fail_malloc;
235 }
236 memset(globalmem_devp, 0, sizeof(struct globalmem_dev));
237
238 globalmem_setup_cdev(globalmem_devp, 0);
239 return 0;
240
241 fail_malloc:unregister_chrdev_region(devno, 1);
242 return result;
243 }
244
245 /* globalmem设备驱动卸载函数 */
246 void globalmem_exit(void)
247 {
248 cdev_del(&globalmem_devp->cdev); //注销cdev
249 // cdev_del(&dev.cdev); /* 删除cdev结构 */
250 kfree(globalmem_devp); //释放设备结构体内存
251
252 unregister_chrdev_region(MKDEV(globalmem_major,0), 1); /*注销设备区域 */
253 }
254
255 MODULE_AUTHOR("Liwei.Cai");
256 MODULE_LICENSE("Dual BSD/GPL");
257
258 module_param(globalmem_major, int, S_IRUGO);
259
260 module_init(globalmem_init);
261 module_exit(globalmem_exit);