This source file includes following definitions.
- get_device_list
- get_fops
- get_blkfops
- get_chrfops
- register_chrdev
- register_blkdev
- unregister_chrdev
- unregister_blkdev
- check_disk_change
- blkdev_open
- blkdev_release
- chrdev_open
- kdevname
1
2
3
4
5
6
7
8
9
10
11 #include <linux/config.h>
12 #include <linux/fs.h>
13 #include <linux/major.h>
14 #include <linux/string.h>
15 #include <linux/sched.h>
16 #include <linux/ext_fs.h>
17 #include <linux/stat.h>
18 #include <linux/fcntl.h>
19 #include <linux/errno.h>
20 #ifdef CONFIG_KERNELD
21 #include <linux/kerneld.h>
22
23 #include <linux/tty.h>
24
25
26 struct 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(to_kdev_t(MKDEV(ma,mi))) == NULL)
29 #endif
30
31 struct device_struct {
32 const char * name;
33 struct file_operations * fops;
34 };
35
36 static struct device_struct chrdevs[MAX_CHRDEV] = {
37 { NULL, NULL },
38 };
39
40 static struct device_struct blkdevs[MAX_BLKDEV] = {
41 { NULL, NULL },
42 };
43
44 int 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, "%2d %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, "%2d %s\n", i, blkdevs[i].name);
59 }
60 }
61 return len;
62 }
63
64
65
66
67
68 static 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_KERNELD
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
111 struct file_operations * get_blkfops(unsigned int major)
112 {
113 return get_fops (major,0,MAX_BLKDEV,"block-major-%d",blkdevs);
114 }
115
116 struct 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
121 int 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
142 int 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
163 int 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
176 int 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
198 int check_disk_change(kdev_t dev)
199 {
200 int i;
201 struct file_operations * fops;
202
203 i = MAJOR(dev);
204 if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)
205 return 0;
206 if (fops->check_media_change == NULL)
207 return 0;
208 if (!fops->check_media_change(dev))
209 return 0;
210
211 printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
212 kdevname(dev));
213 for (i=0 ; i<NR_SUPER ; i++)
214 if (super_blocks[i].s_dev == dev)
215 put_super(super_blocks[i].s_dev);
216 invalidate_inodes(dev);
217 invalidate_buffers(dev);
218
219 if (fops->revalidate)
220 fops->revalidate(dev);
221 return 1;
222 }
223
224
225
226
227 int blkdev_open(struct inode * inode, struct file * filp)
228 {
229 int ret = -ENODEV;
230 filp->f_op = get_blkfops(MAJOR(inode->i_rdev));
231 if (filp->f_op != NULL){
232 ret = 0;
233 if (filp->f_op->open != NULL)
234 ret = filp->f_op->open(inode,filp);
235 }
236 return ret;
237 }
238
239 void blkdev_release(struct inode * inode)
240 {
241 struct file_operations *fops = get_blkfops(MAJOR(inode->i_rdev));
242 if (fops && fops->release)
243 fops->release(inode,NULL);
244 }
245
246
247
248
249
250
251
252 struct file_operations def_blk_fops = {
253 NULL,
254 NULL,
255 NULL,
256 NULL,
257 NULL,
258 NULL,
259 NULL,
260 blkdev_open,
261 NULL,
262 };
263
264 struct inode_operations blkdev_inode_operations = {
265 &def_blk_fops,
266 NULL,
267 NULL,
268 NULL,
269 NULL,
270 NULL,
271 NULL,
272 NULL,
273 NULL,
274 NULL,
275 NULL,
276 NULL,
277 NULL,
278 NULL,
279 NULL,
280 NULL,
281 NULL
282 };
283
284
285
286
287 int chrdev_open(struct inode * inode, struct file * filp)
288 {
289 int ret = -ENODEV;
290
291 filp->f_op = get_chrfops(MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
292 if (filp->f_op != NULL){
293 ret = 0;
294 if (filp->f_op->open != NULL)
295 ret = filp->f_op->open(inode,filp);
296 }
297 return ret;
298 }
299
300
301
302
303
304
305 struct file_operations def_chr_fops = {
306 NULL,
307 NULL,
308 NULL,
309 NULL,
310 NULL,
311 NULL,
312 NULL,
313 chrdev_open,
314 NULL,
315 };
316
317 struct inode_operations chrdev_inode_operations = {
318 &def_chr_fops,
319 NULL,
320 NULL,
321 NULL,
322 NULL,
323 NULL,
324 NULL,
325 NULL,
326 NULL,
327 NULL,
328 NULL,
329 NULL,
330 NULL,
331 NULL,
332 NULL,
333 NULL,
334 NULL
335 };
336
337
338
339
340
341
342 char * kdevname(kdev_t dev)
343 {
344 static char buffer[32];
345 sprintf(buffer, "%02x:%02x", MAJOR(dev), MINOR(dev));
346 return buffer;
347 }