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 #endif
23
24 struct device_struct {
25 const char * name;
26 struct file_operations * fops;
27 };
28
29 static struct device_struct chrdevs[MAX_CHRDEV] = {
30 { NULL, NULL },
31 };
32
33 static struct device_struct blkdevs[MAX_BLKDEV] = {
34 { NULL, NULL },
35 };
36
37 int get_device_list(char * page)
38 {
39 int i;
40 int len;
41
42 len = sprintf(page, "Character devices:\n");
43 for (i = 0; i < MAX_CHRDEV ; i++) {
44 if (chrdevs[i].fops) {
45 len += sprintf(page+len, "%2d %s\n", i, chrdevs[i].name);
46 }
47 }
48 len += sprintf(page+len, "\nBlock devices:\n");
49 for (i = 0; i < MAX_BLKDEV ; i++) {
50 if (blkdevs[i].fops) {
51 len += sprintf(page+len, "%2d %s\n", i, blkdevs[i].name);
52 }
53 }
54 return len;
55 }
56
57
58
59
60 static struct file_operations * get_fops(
61 unsigned int major,
62 unsigned int maxdev,
63 const char *mangle,
64 struct device_struct tb[])
65 {
66 struct file_operations *ret = NULL;
67 if (major < maxdev){
68 #ifdef CONFIG_KERNELD
69
70
71
72
73
74
75
76
77
78
79 if (!tb[major].fops && major != 0) {
80 char name[20];
81 sprintf(name, mangle, major);
82 request_module(name);
83 }
84 #endif
85 ret = tb[major].fops;
86 }
87 return ret;
88 }
89
90
91
92
93
94
95 struct file_operations * get_blkfops(unsigned int major)
96 {
97 return get_fops (major,MAX_BLKDEV,"block-major-%d",blkdevs);
98 }
99
100 struct file_operations * get_chrfops(unsigned int major)
101 {
102 return get_fops (major,MAX_CHRDEV,"char-major-%d",chrdevs);
103 }
104
105 int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)
106 {
107 if (major == 0) {
108 for (major = MAX_CHRDEV-1; major > 0; major--) {
109 if (chrdevs[major].fops == NULL) {
110 chrdevs[major].name = name;
111 chrdevs[major].fops = fops;
112 return major;
113 }
114 }
115 return -EBUSY;
116 }
117 if (major >= MAX_CHRDEV)
118 return -EINVAL;
119 if (chrdevs[major].fops && chrdevs[major].fops != fops)
120 return -EBUSY;
121 chrdevs[major].name = name;
122 chrdevs[major].fops = fops;
123 return 0;
124 }
125
126 int register_blkdev(unsigned int major, const char * name, struct file_operations *fops)
127 {
128 if (major == 0) {
129 for (major = MAX_BLKDEV-1; major > 0; major--) {
130 if (blkdevs[major].fops == NULL) {
131 blkdevs[major].name = name;
132 blkdevs[major].fops = fops;
133 return major;
134 }
135 }
136 return -EBUSY;
137 }
138 if (major >= MAX_BLKDEV)
139 return -EINVAL;
140 if (blkdevs[major].fops && blkdevs[major].fops != fops)
141 return -EBUSY;
142 blkdevs[major].name = name;
143 blkdevs[major].fops = fops;
144 return 0;
145 }
146
147 int unregister_chrdev(unsigned int major, const char * name)
148 {
149 if (major >= MAX_CHRDEV)
150 return -EINVAL;
151 if (!chrdevs[major].fops)
152 return -EINVAL;
153 if (strcmp(chrdevs[major].name, name))
154 return -EINVAL;
155 chrdevs[major].name = NULL;
156 chrdevs[major].fops = NULL;
157 return 0;
158 }
159
160 int unregister_blkdev(unsigned int major, const char * name)
161 {
162 if (major >= MAX_BLKDEV)
163 return -EINVAL;
164 if (!blkdevs[major].fops)
165 return -EINVAL;
166 if (strcmp(blkdevs[major].name, name))
167 return -EINVAL;
168 blkdevs[major].name = NULL;
169 blkdevs[major].fops = NULL;
170 return 0;
171 }
172
173
174
175
176
177
178
179
180
181
182 int check_disk_change(kdev_t dev)
183 {
184 int i;
185 struct file_operations * fops;
186
187 i = MAJOR(dev);
188 if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)
189 return 0;
190 if (fops->check_media_change == NULL)
191 return 0;
192 if (!fops->check_media_change(dev))
193 return 0;
194
195 printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
196 kdevname(dev));
197 for (i=0 ; i<NR_SUPER ; i++)
198 if (super_blocks[i].s_dev == dev)
199 put_super(super_blocks[i].s_dev);
200 invalidate_inodes(dev);
201 invalidate_buffers(dev);
202
203 if (fops->revalidate)
204 fops->revalidate(dev);
205 return 1;
206 }
207
208
209
210
211 int blkdev_open(struct inode * inode, struct file * filp)
212 {
213 int ret = -ENODEV;
214 filp->f_op = get_blkfops(MAJOR(inode->i_rdev));
215 if (filp->f_op != NULL){
216 ret = 0;
217 if (filp->f_op->open != NULL)
218 ret = filp->f_op->open(inode,filp);
219 }
220 return ret;
221 }
222
223 void blkdev_release(struct inode * inode)
224 {
225 struct file_operations *fops = get_blkfops(MAJOR(inode->i_rdev));
226 if (fops && fops->release)
227 fops->release(inode,NULL);
228 }
229
230
231
232
233
234
235
236 struct file_operations def_blk_fops = {
237 NULL,
238 NULL,
239 NULL,
240 NULL,
241 NULL,
242 NULL,
243 NULL,
244 blkdev_open,
245 NULL,
246 };
247
248 struct inode_operations blkdev_inode_operations = {
249 &def_blk_fops,
250 NULL,
251 NULL,
252 NULL,
253 NULL,
254 NULL,
255 NULL,
256 NULL,
257 NULL,
258 NULL,
259 NULL,
260 NULL,
261 NULL,
262 NULL,
263 NULL,
264 NULL,
265 NULL
266 };
267
268
269
270
271 int chrdev_open(struct inode * inode, struct file * filp)
272 {
273 int ret = -ENODEV;
274 filp->f_op = get_chrfops(MAJOR(inode->i_rdev));
275 if (filp->f_op != NULL){
276 ret = 0;
277 if (filp->f_op->open != NULL)
278 ret = filp->f_op->open(inode,filp);
279 }
280 return ret;
281 }
282
283
284
285
286
287
288 struct file_operations def_chr_fops = {
289 NULL,
290 NULL,
291 NULL,
292 NULL,
293 NULL,
294 NULL,
295 NULL,
296 chrdev_open,
297 NULL,
298 };
299
300 struct inode_operations chrdev_inode_operations = {
301 &def_chr_fops,
302 NULL,
303 NULL,
304 NULL,
305 NULL,
306 NULL,
307 NULL,
308 NULL,
309 NULL,
310 NULL,
311 NULL,
312 NULL,
313 NULL,
314 NULL,
315 NULL,
316 NULL,
317 NULL
318 };
319
320
321
322
323
324
325 char * kdevname(kdev_t dev)
326 {
327 static char buffer[32];
328 sprintf(buffer, "%02x:%02x", MAJOR(dev), MINOR(dev));
329 return buffer;
330 }