1
2
3
4
5
6
7
8
9
10
11
12#include <linux/config.h>
13#include <linux/fs.h>
14#include <linux/major.h>
15#include <linux/string.h>
16#include <linux/sched.h>
17#include <linux/stat.h>
18#include <linux/fcntl.h>
19#include <linux/errno.h>
20#ifdef CONFIG_KMOD
21#include <linux/kmod.h>
22
23#include <linux/tty.h>
24
25
26struct tty_driver *get_tty_driver(kdev_t device);
27#define isa_tty_dev(ma) (ma == TTY_MAJOR || ma == TTYAUX_MAJOR)
28#define need_serial(ma,mi) (get_tty_driver(MKDEV(ma,mi)) == NULL)
29#endif
30
31struct device_struct {
32 const char * name;
33 struct file_operations * fops;
34};
35
36static struct device_struct chrdevs[MAX_CHRDEV] = {
37 { NULL, NULL },
38};
39
40static struct device_struct blkdevs[MAX_BLKDEV] = {
41 { NULL, NULL },
42};
43
44int get_device_list(char * page)
45{
46 int i;
47 int len;
48
49 len = sprintf(page, "Character devices:\n");
50 for (i = 0; i < MAX_CHRDEV ; i++) {
51 if (chrdevs[i].fops) {
52 len += sprintf(page+len, "%3d %s\n", i, chrdevs[i].name);
53 }
54 }
55 len += sprintf(page+len, "\nBlock devices:\n");
56 for (i = 0; i < MAX_BLKDEV ; i++) {
57 if (blkdevs[i].fops) {
58 len += sprintf(page+len, "%3d %s\n", i, blkdevs[i].name);
59 }
60 }
61 return len;
62}
63
64
65
66
67
68static struct file_operations * get_fops(
69 unsigned int major,
70 unsigned int minor,
71 unsigned int maxdev,
72 const char *mangle,
73 struct device_struct tb[])
74{
75 struct file_operations *ret = NULL;
76
77 if (major < maxdev){
78#ifdef CONFIG_KMOD
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94 if ((isa_tty_dev(major) && need_serial(major,minor)) ||
95 (major != 0 && !tb[major].fops)) {
96 char name[20];
97 sprintf(name, mangle, major);
98 request_module(name);
99 }
100#endif
101 ret = tb[major].fops;
102 }
103 return ret;
104}
105
106
107
108
109
110
111struct file_operations * get_blkfops(unsigned int major)
112{
113 return get_fops (major,0,MAX_BLKDEV,"block-major-%d",blkdevs);
114}
115
116struct file_operations * get_chrfops(unsigned int major, unsigned int minor)
117{
118 return get_fops (major,minor,MAX_CHRDEV,"char-major-%d",chrdevs);
119}
120
121int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)
122{
123 if (major == 0) {
124 for (major = MAX_CHRDEV-1; major > 0; major--) {
125 if (chrdevs[major].fops == NULL) {
126 chrdevs[major].name = name;
127 chrdevs[major].fops = fops;
128 return major;
129 }
130 }
131 return -EBUSY;
132 }
133 if (major >= MAX_CHRDEV)
134 return -EINVAL;
135 if (chrdevs[major].fops && chrdevs[major].fops != fops)
136 return -EBUSY;
137 chrdevs[major].name = name;
138 chrdevs[major].fops = fops;
139 return 0;
140}
141
142int register_blkdev(unsigned int major, const char * name, struct file_operations *fops)
143{
144 if (major == 0) {
145 for (major = MAX_BLKDEV-1; major > 0; major--) {
146 if (blkdevs[major].fops == NULL) {
147 blkdevs[major].name = name;
148 blkdevs[major].fops = fops;
149 return major;
150 }
151 }
152 return -EBUSY;
153 }
154 if (major >= MAX_BLKDEV)
155 return -EINVAL;
156 if (blkdevs[major].fops && blkdevs[major].fops != fops)
157 return -EBUSY;
158 blkdevs[major].name = name;
159 blkdevs[major].fops = fops;
160 return 0;
161}
162
163int unregister_chrdev(unsigned int major, const char * name)
164{
165 if (major >= MAX_CHRDEV)
166 return -EINVAL;
167 if (!chrdevs[major].fops)
168 return -EINVAL;
169 if (strcmp(chrdevs[major].name, name))
170 return -EINVAL;
171 chrdevs[major].name = NULL;
172 chrdevs[major].fops = NULL;
173 return 0;
174}
175
176int unregister_blkdev(unsigned int major, const char * name)
177{
178 if (major >= MAX_BLKDEV)
179 return -EINVAL;
180 if (!blkdevs[major].fops)
181 return -EINVAL;
182 if (strcmp(blkdevs[major].name, name))
183 return -EINVAL;
184 blkdevs[major].name = NULL;
185 blkdevs[major].fops = NULL;
186 return 0;
187}
188
189
190
191
192
193
194
195
196
197
198int check_disk_change(kdev_t dev)
199{
200 int i;
201 struct file_operations * fops;
202 struct super_block * sb;
203
204 i = MAJOR(dev);
205 if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)
206 return 0;
207 if (fops->check_media_change == NULL)
208 return 0;
209 if (!fops->check_media_change(dev))
210 return 0;
211
212 printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
213 bdevname(dev));
214
215 sb = get_super(dev);
216 if (sb && invalidate_inodes(sb))
217 printk("VFS: busy inodes on changed media.\n");
218
219
220 destroy_buffers(dev);
221
222 if (fops->revalidate)
223 fops->revalidate(dev);
224 return 1;
225}
226
227
228
229
230int blkdev_open(struct inode * inode, struct file * filp)
231{
232 int ret = -ENODEV;
233 filp->f_op = get_blkfops(MAJOR(inode->i_rdev));
234 if (filp->f_op != NULL){
235 ret = 0;
236 if (filp->f_op->open != NULL)
237 ret = filp->f_op->open(inode,filp);
238 }
239 return ret;
240}
241
242int blkdev_release(struct inode * inode)
243{
244 struct file_operations *fops = get_blkfops(MAJOR(inode->i_rdev));
245 if (fops && fops->release)
246 return fops->release(inode,NULL);
247 return 0;
248}
249
250
251
252
253
254
255
256struct file_operations def_blk_fops = {
257 NULL,
258 NULL,
259 NULL,
260 NULL,
261 NULL,
262 NULL,
263 NULL,
264 blkdev_open,
265 NULL,
266 NULL,
267};
268
269struct inode_operations blkdev_inode_operations = {
270 &def_blk_fops,
271 NULL,
272 NULL,
273 NULL,
274 NULL,
275 NULL,
276 NULL,
277 NULL,
278 NULL,
279 NULL,
280 NULL,
281 NULL,
282 NULL,
283 NULL,
284 NULL,
285 NULL
286};
287
288
289
290
291int chrdev_open(struct inode * inode, struct file * filp)
292{
293 int ret = -ENODEV;
294
295 filp->f_op = get_chrfops(MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
296 if (filp->f_op != NULL){
297 ret = 0;
298 if (filp->f_op->open != NULL)
299 ret = filp->f_op->open(inode,filp);
300 }
301 return ret;
302}
303
304
305
306
307
308
309struct file_operations def_chr_fops = {
310 NULL,
311 NULL,
312 NULL,
313 NULL,
314 NULL,
315 NULL,
316 NULL,
317 chrdev_open,
318 NULL,
319 NULL,
320};
321
322struct inode_operations chrdev_inode_operations = {
323 &def_chr_fops,
324 NULL,
325 NULL,
326 NULL,
327 NULL,
328 NULL,
329 NULL,
330 NULL,
331 NULL,
332 NULL,
333 NULL,
334 NULL,
335 NULL,
336 NULL,
337 NULL,
338 NULL
339};
340
341
342
343
344
345char * kdevname(kdev_t dev)
346{
347 static char buffer[32];
348 sprintf(buffer, "%02x:%02x", MAJOR(dev), MINOR(dev));
349 return buffer;
350}
351
352char * bdevname(kdev_t dev)
353{
354 static char buffer[32];
355 const char * name = blkdevs[MAJOR(dev)].name;
356
357 if (!name)
358 name = "unknown-block";
359
360 sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
361 return buffer;
362}
363
364char * cdevname(kdev_t dev)
365{
366 static char buffer[32];
367 const char * name = chrdevs[MAJOR(dev)].name;
368
369 if (!name)
370 name = "unknown-char";
371 sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
372 return buffer;
373}
374