]>
Commit | Line | Data |
---|---|---|
97ffca7c | 1 | diff -Nru a/drivers/base/Makefile b/drivers/base/Makefile |
2 | --- a/drivers/base/Makefile Thu Jan 15 11:05:59 2004 | |
3 | +++ b/drivers/base/Makefile Thu Jan 15 11:05:59 2004 | |
4 | @@ -1,7 +1,7 @@ | |
5 | # Makefile for the Linux device tree | |
6 | ||
7 | obj-y := core.o sys.o interface.o bus.o \ | |
8 | - driver.o class.o platform.o \ | |
9 | + driver.o class.o class_simple.o platform.o \ | |
10 | cpu.o firmware.o init.o map.o | |
11 | obj-y += power/ | |
12 | obj-$(CONFIG_FW_LOADER) += firmware_class.o | |
13 | diff -Nru a/drivers/base/class.c b/drivers/base/class.c | |
14 | --- a/drivers/base/class.c Thu Jan 15 11:06:02 2004 | |
15 | +++ b/drivers/base/class.c Thu Jan 15 11:06:02 2004 | |
16 | @@ -46,6 +46,19 @@ | |
17 | return ret; | |
18 | } | |
19 | ||
20 | +static void class_release(struct kobject * kobj) | |
21 | +{ | |
22 | + struct class *class = to_class(kobj); | |
23 | + | |
24 | + pr_debug("class '%s': release.\n", class->name); | |
25 | + | |
26 | + if (class->class_release) | |
27 | + class->class_release(class); | |
28 | + else | |
29 | + pr_debug("class '%s' does not have a release() function, " | |
30 | + "be careful\n", class->name); | |
31 | +} | |
32 | + | |
33 | static struct sysfs_ops class_sysfs_ops = { | |
34 | .show = class_attr_show, | |
35 | .store = class_attr_store, | |
36 | @@ -53,6 +66,7 @@ | |
37 | ||
38 | static struct kobj_type ktype_class = { | |
39 | .sysfs_ops = &class_sysfs_ops, | |
40 | + .release = class_release, | |
41 | }; | |
42 | ||
43 | /* Hotplug events for classes go to the class_obj subsys */ | |
44 | diff -Nru a/drivers/base/class_simple.c b/drivers/base/class_simple.c | |
45 | --- /dev/null Wed Dec 31 16:00:00 1969 | |
46 | +++ b/drivers/base/class_simple.c Thu Jan 15 11:06:03 2004 | |
47 | @@ -0,0 +1,201 @@ | |
48 | +/* | |
49 | + * class_simple.c - a "simple" interface for classes for simple char devices. | |
50 | + * | |
51 | + * Copyright (c) 2003-2004 Greg Kroah-Hartman <greg@kroah.com> | |
52 | + * Copyright (c) 2003-2004 IBM Corp. | |
53 | + * | |
54 | + * This file is released under the GPLv2 | |
55 | + * | |
56 | + */ | |
57 | + | |
58 | +#define DEBUG 1 | |
59 | + | |
60 | +#include <linux/device.h> | |
61 | +#include <linux/kdev_t.h> | |
62 | +#include <linux/err.h> | |
63 | + | |
64 | +struct class_simple { | |
65 | + struct class_device_attribute attr; | |
66 | + struct class class; | |
67 | +}; | |
68 | +#define to_class_simple(d) container_of(d, struct class_simple, class) | |
69 | + | |
70 | +struct simple_dev { | |
71 | + struct list_head node; | |
72 | + dev_t dev; | |
73 | + struct class_device class_dev; | |
74 | +}; | |
75 | +#define to_simple_dev(d) container_of(d, struct simple_dev, class_dev) | |
76 | + | |
77 | +static LIST_HEAD(simple_dev_list); | |
78 | +static spinlock_t simple_dev_list_lock = SPIN_LOCK_UNLOCKED; | |
79 | + | |
80 | +static void release_simple_dev(struct class_device *class_dev) | |
81 | +{ | |
82 | + struct simple_dev *s_dev = to_simple_dev(class_dev); | |
83 | + kfree(s_dev); | |
84 | +} | |
85 | + | |
86 | +static ssize_t show_dev(struct class_device *class_dev, char *buf) | |
87 | +{ | |
88 | + struct simple_dev *s_dev = to_simple_dev(class_dev); | |
89 | + return print_dev_t(buf, s_dev->dev); | |
90 | +} | |
91 | + | |
92 | +static void class_simple_release(struct class *class) | |
93 | +{ | |
94 | + struct class_simple *cs = to_class_simple(class); | |
95 | + kfree(cs); | |
96 | +} | |
97 | + | |
98 | +/** | |
99 | + * class_simple_create - create a struct class_simple structure | |
100 | + * @owner: pointer to the module that is to "own" this struct class_simple | |
101 | + * @name: pointer to a string for the name of this class. | |
102 | + * | |
103 | + * This is used to create a struct class_simple pointer that can then be used | |
104 | + * in calls to class_simple_device_add(). This is used when you do not wish to | |
105 | + * create a full blown class support for a type of char devices. | |
106 | + * | |
107 | + * Note, the pointer created here is to be destroyed when finished by making a | |
108 | + * call to class_simple_destroy(). | |
109 | + */ | |
110 | +struct class_simple *class_simple_create(struct module *owner, char *name) | |
111 | +{ | |
112 | + struct class_simple *cs; | |
113 | + int retval; | |
114 | + | |
115 | + cs = kmalloc(sizeof(*cs), GFP_KERNEL); | |
116 | + if (!cs) { | |
117 | + retval = -ENOMEM; | |
118 | + goto error; | |
119 | + } | |
120 | + memset(cs, 0x00, sizeof(*cs)); | |
121 | + | |
122 | + cs->class.name = name; | |
123 | + cs->class.class_release = class_simple_release; | |
124 | + cs->class.release = release_simple_dev; | |
125 | + | |
126 | + cs->attr.attr.name = "dev"; | |
127 | + cs->attr.attr.mode = S_IRUGO; | |
128 | + cs->attr.attr.owner = owner; | |
129 | + cs->attr.show = show_dev; | |
130 | + cs->attr.store = NULL; | |
131 | + | |
132 | + retval = class_register(&cs->class); | |
133 | + if (retval) | |
134 | + goto error; | |
135 | + | |
136 | + return cs; | |
137 | + | |
138 | +error: | |
139 | + kfree(cs); | |
140 | + return ERR_PTR(retval); | |
141 | +} | |
142 | +EXPORT_SYMBOL(class_simple_create); | |
143 | + | |
144 | +/** | |
145 | + * class_simple_destroy - destroys a struct class_simple structure | |
146 | + * @cs: pointer to the struct class_simple that is to be destroyed | |
147 | + * | |
148 | + * Note, the pointer to be destroyed must have been created with a call to | |
149 | + * class_simple_create(). | |
150 | + */ | |
151 | +void class_simple_destroy(struct class_simple *cs) | |
152 | +{ | |
153 | + if ((cs == NULL) || (IS_ERR(cs))) | |
154 | + return; | |
155 | + | |
156 | + class_unregister(&cs->class); | |
157 | +} | |
158 | +EXPORT_SYMBOL(class_simple_destroy); | |
159 | + | |
160 | +/** | |
161 | + * class_simple_device_add - adds a class device to sysfs for a character driver | |
162 | + * @cs: pointer to the struct class_simple that this device should be registered to. | |
163 | + * @dev: the dev_t for the device to be added. | |
164 | + * @device: a pointer to a struct device that is assiociated with this class device. | |
165 | + * @fmt: string for the class device's name | |
166 | + * | |
167 | + * This function can be used by simple char device classes that do not | |
168 | + * implement their own class device registration. A struct class_device will | |
169 | + * be created in sysfs, registered to the specified class. A "dev" file will | |
170 | + * be created, showing the dev_t for the device. The pointer to the struct | |
171 | + * class_device will be returned from the call. Any further sysfs files that | |
172 | + * might be required can be created using this pointer. | |
173 | + * Note: the struct class_device passed to this function must have previously been | |
174 | + * created with a call to class_simple_create(). | |
175 | + */ | |
176 | +struct class_device *class_simple_device_add(struct class_simple *cs, dev_t dev, struct device *device, const char *fmt, ...) | |
177 | +{ | |
178 | + va_list args; | |
179 | + struct simple_dev *s_dev = NULL; | |
180 | + int retval; | |
181 | + | |
182 | + if ((cs == NULL) || (IS_ERR(cs))) { | |
183 | + retval = -ENODEV; | |
184 | + goto error; | |
185 | + } | |
186 | + | |
187 | + s_dev = kmalloc(sizeof(*s_dev), GFP_KERNEL); | |
188 | + if (!s_dev) { | |
189 | + retval = -ENOMEM; | |
190 | + goto error; | |
191 | + } | |
192 | + memset(s_dev, 0x00, sizeof(*s_dev)); | |
193 | + | |
194 | + s_dev->dev = dev; | |
195 | + s_dev->class_dev.dev = device; | |
196 | + s_dev->class_dev.class = &cs->class; | |
197 | + | |
198 | + va_start(args,fmt); | |
199 | + vsnprintf(s_dev->class_dev.class_id, BUS_ID_SIZE, fmt, args); | |
200 | + va_end(args); | |
201 | + retval = class_device_register(&s_dev->class_dev); | |
202 | + if (retval) | |
203 | + goto error; | |
204 | + | |
205 | + class_device_create_file(&s_dev->class_dev, &cs->attr); | |
206 | + | |
207 | + spin_lock(&simple_dev_list_lock); | |
208 | + list_add(&s_dev->node, &simple_dev_list); | |
209 | + spin_unlock(&simple_dev_list_lock); | |
210 | + | |
211 | + return &s_dev->class_dev; | |
212 | + | |
213 | +error: | |
214 | + kfree(s_dev); | |
215 | + return ERR_PTR(retval); | |
216 | +} | |
217 | +EXPORT_SYMBOL(class_simple_device_add); | |
218 | + | |
219 | +/** | |
220 | + * class_simple_device_remove - removes a class device that was created with class_simple_device_add() | |
221 | + * @dev: the dev_t of the device that was previously registered. | |
222 | + * | |
223 | + * This call unregisters and cleans up a class device that was created with a | |
224 | + * call to class_device_simple_add() | |
225 | + */ | |
226 | +void class_simple_device_remove(dev_t dev) | |
227 | +{ | |
228 | + struct simple_dev *s_dev = NULL; | |
229 | + struct list_head *tmp; | |
230 | + int found = 0; | |
231 | + | |
232 | + spin_lock(&simple_dev_list_lock); | |
233 | + list_for_each(tmp, &simple_dev_list) { | |
234 | + s_dev = list_entry(tmp, struct simple_dev, node); | |
235 | + if (s_dev->dev == dev) { | |
236 | + found = 1; | |
237 | + break; | |
238 | + } | |
239 | + } | |
240 | + if (found) { | |
241 | + list_del(&s_dev->node); | |
242 | + spin_unlock(&simple_dev_list_lock); | |
243 | + class_device_unregister(&s_dev->class_dev); | |
244 | + } else { | |
245 | + spin_unlock(&simple_dev_list_lock); | |
246 | + } | |
247 | +} | |
248 | +EXPORT_SYMBOL(class_simple_device_remove); | |
249 | diff -Nru a/include/linux/device.h b/include/linux/device.h | |
250 | --- a/include/linux/device.h Thu Jan 15 11:05:58 2004 | |
251 | +++ b/include/linux/device.h Thu Jan 15 11:05:58 2004 | |
252 | @@ -46,6 +46,7 @@ | |
253 | struct device_driver; | |
254 | struct class; | |
255 | struct class_device; | |
256 | +struct class_simple; | |
257 | ||
258 | struct bus_type { | |
259 | char * name; | |
260 | @@ -155,6 +156,7 @@ | |
261 | int num_envp, char *buffer, int buffer_size); | |
262 | ||
263 | void (*release)(struct class_device *dev); | |
264 | + void (*class_release)(struct class *class); | |
265 | }; | |
266 | ||
267 | extern int class_register(struct class *); | |
268 | @@ -246,6 +248,13 @@ | |
269 | extern int class_interface_register(struct class_interface *); | |
270 | extern void class_interface_unregister(struct class_interface *); | |
271 | ||
272 | +/* interface for class simple stuff */ | |
273 | +extern struct class_simple *class_simple_create(struct module *owner, char *name); | |
274 | +extern void class_simple_destroy(struct class_simple *cs); | |
275 | +extern struct class_device *class_simple_device_add(struct class_simple *cs, dev_t dev, struct device *device, const char *fmt, ...) | |
276 | + __attribute__((format(printf,4,5))); | |
277 | +extern void class_simple_device_remove(dev_t dev); | |
278 | + | |
279 | ||
280 | struct device { | |
281 | struct list_head node; /* node in sibling list */ | |
282 | diff -Nru a/include/sound/core.h b/include/sound/core.h | |
283 | --- a/include/sound/core.h Thu Jan 15 11:06:00 2004 | |
284 | +++ b/include/sound/core.h Thu Jan 15 11:06:00 2004 | |
285 | @@ -160,6 +160,7 @@ | |
286 | int shutdown; /* this card is going down */ | |
287 | wait_queue_head_t shutdown_sleep; | |
288 | struct work_struct free_workq; /* for free in workqueue */ | |
289 | + struct device *dev; | |
290 | ||
291 | #ifdef CONFIG_PM | |
292 | int (*set_power_state) (snd_card_t *card, unsigned int state); | |
293 | diff -Nru a/sound/core/sound.c b/sound/core/sound.c | |
294 | --- a/sound/core/sound.c Thu Jan 15 11:05:49 2004 | |
295 | +++ b/sound/core/sound.c Thu Jan 15 11:05:49 2004 | |
296 | @@ -38,9 +38,7 @@ | |
297 | static int major = CONFIG_SND_MAJOR; | |
298 | int snd_major; | |
299 | static int cards_limit = SNDRV_CARDS; | |
300 | -#ifdef CONFIG_DEVFS_FS | |
301 | static int device_mode = S_IFCHR | S_IRUGO | S_IWUGO; | |
302 | -#endif | |
303 | ||
304 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); | |
305 | MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards."); | |
306 | @@ -66,6 +64,7 @@ | |
307 | ||
308 | static DECLARE_MUTEX(sound_mutex); | |
309 | ||
310 | +extern struct class_simple *sound_class; | |
311 | #ifdef CONFIG_KMOD | |
312 | ||
313 | /** | |
314 | @@ -203,6 +202,7 @@ | |
315 | { | |
316 | int minor = snd_kernel_minor(type, card, dev); | |
317 | snd_minor_t *preg; | |
318 | + struct device *device = NULL; | |
319 | ||
320 | if (minor < 0) | |
321 | return minor; | |
322 | @@ -221,10 +221,14 @@ | |
323 | return -EBUSY; | |
324 | } | |
325 | list_add_tail(&preg->list, &snd_minors_hash[SNDRV_MINOR_CARD(minor)]); | |
326 | -#ifdef CONFIG_DEVFS_FS | |
327 | - if (strncmp(name, "controlC", 8)) /* created in sound.c */ | |
328 | + | |
329 | + if (strncmp(name, "controlC", 8)) { /* created in sound.c */ | |
330 | devfs_mk_cdev(MKDEV(major, minor), S_IFCHR | device_mode, "snd/%s", name); | |
331 | -#endif | |
332 | + if (card) | |
333 | + device = card->dev; | |
334 | + class_simple_device_add(sound_class, MKDEV(major, minor), device, name); | |
335 | + } | |
336 | + | |
337 | up(&sound_mutex); | |
338 | return 0; | |
339 | } | |
340 | @@ -252,10 +256,12 @@ | |
341 | up(&sound_mutex); | |
342 | return -EINVAL; | |
343 | } | |
344 | -#ifdef CONFIG_DEVFS_FS | |
345 | - if (strncmp(mptr->name, "controlC", 8)) /* created in sound.c */ | |
346 | + | |
347 | + if (strncmp(mptr->name, "controlC", 8)) { /* created in sound.c */ | |
348 | devfs_remove("snd/%s", mptr->name); | |
349 | -#endif | |
350 | + class_simple_device_remove(MKDEV(major, minor)); | |
351 | + } | |
352 | + | |
353 | list_del(&mptr->list); | |
354 | up(&sound_mutex); | |
355 | kfree(mptr); | |
356 | @@ -322,9 +328,7 @@ | |
357 | ||
358 | static int __init alsa_sound_init(void) | |
359 | { | |
360 | -#ifdef CONFIG_DEVFS_FS | |
361 | short controlnum; | |
362 | -#endif | |
363 | #ifdef CONFIG_SND_OSSEMUL | |
364 | int err; | |
365 | #endif | |
366 | @@ -358,10 +362,10 @@ | |
367 | #ifdef CONFIG_SND_OSSEMUL | |
368 | snd_info_minor_register(); | |
369 | #endif | |
370 | -#ifdef CONFIG_DEVFS_FS | |
371 | - for (controlnum = 0; controlnum < cards_limit; controlnum++) | |
372 | + for (controlnum = 0; controlnum < cards_limit; controlnum++) { | |
373 | devfs_mk_cdev(MKDEV(major, controlnum<<5), S_IFCHR | device_mode, "snd/controlC%d", controlnum); | |
374 | -#endif | |
375 | + class_simple_device_add(sound_class, MKDEV(major, controlnum<<5), NULL, "controlC%d", controlnum); | |
376 | + } | |
377 | #ifndef MODULE | |
378 | printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"); | |
379 | #endif | |
380 | @@ -372,8 +376,10 @@ | |
381 | { | |
382 | short controlnum; | |
383 | ||
384 | - for (controlnum = 0; controlnum < cards_limit; controlnum++) | |
385 | + for (controlnum = 0; controlnum < cards_limit; controlnum++) { | |
386 | devfs_remove("snd/controlC%d", controlnum); | |
387 | + class_simple_device_remove(MKDEV(major, controlnum<<5)); | |
388 | + } | |
389 | ||
390 | #ifdef CONFIG_SND_OSSEMUL | |
391 | snd_info_minor_unregister(); | |
392 | diff -Nru a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c | |
393 | --- a/sound/pci/intel8x0.c Thu Jan 15 11:05:58 2004 | |
394 | +++ b/sound/pci/intel8x0.c Thu Jan 15 11:05:58 2004 | |
395 | @@ -2591,6 +2591,7 @@ | |
396 | break; | |
397 | } | |
398 | } | |
399 | + card->dev = &pci->dev; | |
400 | ||
401 | if ((err = snd_intel8x0_create(card, pci, pci_id->driver_data, &chip)) < 0) { | |
402 | snd_card_free(card); | |
403 | diff -Nru a/drivers/char/lp.c b/drivers/char/lp.c | |
404 | --- a/drivers/char/lp.c Thu Jan 15 12:13:07 2004 | |
405 | +++ b/drivers/char/lp.c Thu Jan 15 12:13:07 2004 | |
406 | @@ -145,6 +145,7 @@ | |
407 | struct lp_struct lp_table[LP_NO]; | |
408 | ||
409 | static unsigned int lp_count = 0; | |
410 | +static struct class_simple *lp_class; | |
411 | ||
412 | #ifdef CONFIG_LP_CONSOLE | |
413 | static struct parport *console_registered; // initially NULL | |
414 | @@ -795,6 +796,8 @@ | |
415 | if (reset) | |
416 | lp_reset(nr); | |
417 | ||
418 | + class_simple_device_add(lp_class, MKDEV(LP_MAJOR, nr), NULL, | |
419 | + "lp%d", nr); | |
420 | devfs_mk_cdev(MKDEV(LP_MAJOR, nr), S_IFCHR | S_IRUGO | S_IWUGO, | |
421 | "printers/%d", nr); | |
422 | ||
423 | @@ -897,6 +900,7 @@ | |
424 | } | |
425 | ||
426 | devfs_mk_dir("printers"); | |
427 | + lp_class = class_simple_create(THIS_MODULE, "printer"); | |
428 | ||
429 | if (parport_register_driver (&lp_driver)) { | |
430 | printk (KERN_ERR "lp: unable to register with parport\n"); | |
431 | @@ -958,8 +962,10 @@ | |
432 | continue; | |
433 | parport_unregister_device(lp_table[offset].dev); | |
434 | devfs_remove("printers/%d", offset); | |
435 | + class_simple_device_remove(MKDEV(LP_MAJOR, offset)); | |
436 | } | |
437 | devfs_remove("printers"); | |
438 | + class_simple_destroy(lp_class); | |
439 | } | |
440 | ||
441 | __setup("lp=", lp_setup); | |
442 | diff -Nru a/drivers/char/misc.c b/drivers/char/misc.c | |
443 | --- a/drivers/char/misc.c Thu Jan 15 11:05:56 2004 | |
444 | +++ b/drivers/char/misc.c Thu Jan 15 11:05:56 2004 | |
445 | @@ -47,7 +47,7 @@ | |
446 | #include <linux/devfs_fs_kernel.h> | |
447 | #include <linux/stat.h> | |
448 | #include <linux/init.h> | |
449 | - | |
450 | +#include <linux/device.h> | |
451 | #include <linux/tty.h> | |
452 | #include <linux/kmod.h> | |
453 | ||
454 | @@ -180,6 +180,13 @@ | |
455 | return err; | |
456 | } | |
457 | ||
458 | +/* | |
459 | + * TODO for 2.7: | |
460 | + * - add a struct class_device to struct miscdevice and make all usages of | |
461 | + * them dynamic. | |
462 | + */ | |
463 | +static struct class_simple *misc_class; | |
464 | + | |
465 | static struct file_operations misc_fops = { | |
466 | .owner = THIS_MODULE, | |
467 | .open = misc_open, | |
468 | @@ -234,6 +241,8 @@ | |
469 | "misc/%s", misc->name); | |
470 | } | |
471 | ||
472 | + class_simple_device_add(misc_class, MKDEV(MISC_MAJOR, misc->minor), | |
473 | + misc->dev, misc->name); | |
474 | devfs_mk_cdev(MKDEV(MISC_MAJOR, misc->minor), | |
475 | S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP, misc->devfs_name); | |
476 | ||
477 | @@ -265,6 +274,7 @@ | |
478 | ||
479 | down(&misc_sem); | |
480 | list_del(&misc->list); | |
481 | + class_simple_device_remove(MKDEV(MISC_MAJOR, misc->minor)); | |
482 | devfs_remove(misc->devfs_name); | |
483 | if (i < DYNAMIC_MINORS && i>0) { | |
484 | misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); | |
485 | @@ -285,6 +295,9 @@ | |
486 | if (ent) | |
487 | ent->proc_fops = &misc_proc_fops; | |
488 | #endif | |
489 | + misc_class = class_simple_create(THIS_MODULE, "misc"); | |
490 | + if (IS_ERR(misc_class)) | |
491 | + return PTR_ERR(misc_class); | |
492 | #ifdef CONFIG_MVME16x | |
493 | rtc_MK48T08_init(); | |
494 | #endif | |
495 | @@ -319,4 +332,4 @@ | |
496 | } | |
497 | return 0; | |
498 | } | |
499 | -module_init(misc_init); | |
500 | +subsys_initcall(misc_init); | |
501 | diff -Nru a/include/linux/miscdevice.h b/include/linux/miscdevice.h | |
502 | --- a/include/linux/miscdevice.h Thu Jan 15 11:05:53 2004 | |
503 | +++ b/include/linux/miscdevice.h Thu Jan 15 11:05:53 2004 | |
504 | @@ -36,12 +36,15 @@ | |
505 | ||
506 | #define TUN_MINOR 200 | |
507 | ||
508 | +struct device; | |
509 | + | |
510 | struct miscdevice | |
511 | { | |
512 | int minor; | |
513 | const char *name; | |
514 | struct file_operations *fops; | |
515 | struct list_head list; | |
516 | + struct device *dev; | |
517 | char devfs_name[64]; | |
518 | }; | |
519 | ||
520 | This adds class/raw/ support for all raw devices. It also provides a | |
521 | symlink to the block device that the raw device is mapped to. For | |
522 | example: | |
523 | ||
524 | $ tree /sys/class/raw/ | |
525 | /sys/class/raw/ | |
526 | |-- raw1 | |
527 | | |-- dev | |
528 | | `-- device -> ../../../block/sda | |
529 | |-- raw2 | |
530 | | |-- dev | |
531 | | `-- device -> ../../../block/sda/sda2 | |
532 | `-- rawctl | |
533 | `-- dev | |
534 | ||
535 | ||
536 | Note, in order to get that symlink, I had to export get_gendisk() so that | |
537 | modules can use it. I hope this is ok with everyone. | |
538 | ||
539 | This is based on a patch originally written by | |
540 | Leann Ogasawara <ogasawara@osdl.org> | |
541 | ||
542 | ||
543 | ||
544 | diff -Nru a/drivers/block/genhd.c b/drivers/block/genhd.c | |
545 | --- a/drivers/block/genhd.c Thu Jan 15 11:05:57 2004 | |
546 | +++ b/drivers/block/genhd.c Thu Jan 15 11:05:57 2004 | |
547 | @@ -224,6 +224,8 @@ | |
548 | return kobj ? to_disk(kobj) : NULL; | |
549 | } | |
550 | ||
551 | +EXPORT_SYMBOL(get_gendisk); | |
552 | + | |
553 | #ifdef CONFIG_PROC_FS | |
554 | /* iterator */ | |
555 | static void *part_start(struct seq_file *part, loff_t *pos) | |
556 | diff -Nru a/drivers/char/raw.c b/drivers/char/raw.c | |
557 | --- a/drivers/char/raw.c Thu Jan 15 11:05:47 2004 | |
558 | +++ b/drivers/char/raw.c Thu Jan 15 11:05:47 2004 | |
559 | @@ -17,6 +17,8 @@ | |
560 | #include <linux/raw.h> | |
561 | #include <linux/capability.h> | |
562 | #include <linux/uio.h> | |
563 | +#include <linux/device.h> | |
564 | +#include <linux/genhd.h> | |
565 | ||
566 | #include <asm/uaccess.h> | |
567 | ||
568 | @@ -25,6 +27,7 @@ | |
569 | int inuse; | |
570 | }; | |
571 | ||
572 | +static struct class_simple *raw_class; | |
573 | static struct raw_device_data raw_devices[MAX_RAW_MINORS]; | |
574 | static DECLARE_MUTEX(raw_mutex); | |
575 | static struct file_operations raw_ctl_fops; /* forward declaration */ | |
576 | @@ -119,6 +122,29 @@ | |
577 | return ioctl_by_bdev(bdev, command, arg); | |
578 | } | |
579 | ||
580 | +static void bind_device(struct raw_config_request rq) | |
581 | +{ | |
582 | + int part; | |
583 | + struct gendisk *gen; | |
584 | + struct class_device *dev; | |
585 | + struct kobject *target = NULL; | |
586 | + | |
587 | + gen = get_gendisk(MKDEV(rq.block_major, rq.block_minor), &part); | |
588 | + if (gen) { | |
589 | + if (part && gen->part[part]) | |
590 | + target = &gen->part[part]->kobj; | |
591 | + else | |
592 | + target = &gen->kobj; | |
593 | + } | |
594 | + | |
595 | + class_simple_device_remove(MKDEV(RAW_MAJOR, rq.raw_minor)); | |
596 | + dev = class_simple_device_add(raw_class, MKDEV(RAW_MAJOR, rq.raw_minor), | |
597 | + NULL, "raw%d", rq.raw_minor); | |
598 | + if (dev && target) { | |
599 | + sysfs_create_link(&dev->kobj, target, "device"); | |
600 | + } | |
601 | +} | |
602 | + | |
603 | /* | |
604 | * Deal with ioctls against the raw-device control interface, to bind | |
605 | * and unbind other raw devices. | |
606 | @@ -187,12 +213,15 @@ | |
607 | if (rq.block_major == 0 && rq.block_minor == 0) { | |
608 | /* unbind */ | |
609 | rawdev->binding = NULL; | |
610 | + class_simple_device_remove(MKDEV(RAW_MAJOR, rq.raw_minor)); | |
611 | } else { | |
612 | rawdev->binding = bdget(dev); | |
613 | if (rawdev->binding == NULL) | |
614 | err = -ENOMEM; | |
615 | - else | |
616 | + else { | |
617 | __module_get(THIS_MODULE); | |
618 | + bind_device(rq); | |
619 | + } | |
620 | } | |
621 | up(&raw_mutex); | |
622 | } else { | |
623 | @@ -262,6 +291,14 @@ | |
624 | int i; | |
625 | ||
626 | register_chrdev(RAW_MAJOR, "raw", &raw_fops); | |
627 | + | |
628 | + raw_class = class_simple_create(THIS_MODULE, "raw"); | |
629 | + if (IS_ERR(raw_class)) { | |
630 | + printk (KERN_ERR "Error creating raw class.\n"); | |
631 | + return PTR_ERR(raw_class); | |
632 | + } | |
633 | + class_simple_device_add(raw_class, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); | |
634 | + | |
635 | devfs_mk_cdev(MKDEV(RAW_MAJOR, 0), | |
636 | S_IFCHR | S_IRUGO | S_IWUGO, | |
637 | "raw/rawctl"); | |
638 | @@ -280,6 +317,8 @@ | |
639 | devfs_remove("raw/raw%d", i); | |
640 | devfs_remove("raw/rawctl"); | |
641 | devfs_remove("raw"); | |
642 | + class_simple_device_remove(MKDEV(RAW_MAJOR, 0)); | |
643 | + class_simple_destroy(raw_class); | |
644 | unregister_chrdev(RAW_MAJOR, "raw"); | |
645 | } | |
646 | ||
647 | diff -Nru a/sound/oss/soundcard.c b/sound/oss/soundcard.c | |
648 | --- a/sound/oss/soundcard.c Thu Jan 15 11:06:01 2004 | |
649 | +++ b/sound/oss/soundcard.c Thu Jan 15 11:06:01 2004 | |
650 | @@ -73,6 +73,7 @@ | |
651 | ||
652 | ||
653 | unsigned long seq_time = 0; /* Time for /dev/sequencer */ | |
654 | +extern struct class_simple *sound_class; | |
655 | ||
656 | /* | |
657 | * Table for configurable mixer volume handling | |
658 | @@ -569,6 +570,9 @@ | |
659 | devfs_mk_cdev(MKDEV(SOUND_MAJOR, dev_list[i].minor), | |
660 | S_IFCHR | dev_list[i].mode, | |
661 | "sound/%s", dev_list[i].name); | |
662 | + class_simple_device_add(sound_class, | |
663 | + MKDEV(SOUND_MAJOR, dev_list[i].minor), | |
664 | + NULL, "%s", dev_list[i].name); | |
665 | ||
666 | if (!dev_list[i].num) | |
667 | continue; | |
668 | @@ -578,6 +582,10 @@ | |
669 | dev_list[i].minor + (j*0x10)), | |
670 | S_IFCHR | dev_list[i].mode, | |
671 | "sound/%s%d", dev_list[i].name, j); | |
672 | + class_simple_device_add(sound_class, | |
673 | + MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10)), | |
674 | + NULL, | |
675 | + "%s%d", dev_list[i].name, j); | |
676 | } | |
677 | } | |
678 | ||
679 | @@ -593,10 +601,13 @@ | |
680 | ||
681 | for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++) { | |
682 | devfs_remove("sound/%s", dev_list[i].name); | |
683 | + class_simple_device_remove(MKDEV(SOUND_MAJOR, dev_list[i].minor)); | |
684 | if (!dev_list[i].num) | |
685 | continue; | |
686 | - for (j = 1; j < *dev_list[i].num; j++) | |
687 | + for (j = 1; j < *dev_list[i].num; j++) { | |
688 | devfs_remove("sound/%s%d", dev_list[i].name, j); | |
689 | + class_simple_device_remove(MKDEV(SOUND_MAJOR, dev_list[i].minor + (j*0x10))); | |
690 | + } | |
691 | } | |
692 | ||
693 | unregister_sound_special(1); | |
694 | diff -Nru a/sound/sound_core.c b/sound/sound_core.c | |
695 | --- a/sound/sound_core.c Thu Jan 15 11:05:56 2004 | |
696 | +++ b/sound/sound_core.c Thu Jan 15 11:05:56 2004 | |
697 | @@ -65,6 +65,9 @@ | |
698 | extern int msnd_pinnacle_init(void); | |
699 | #endif | |
700 | ||
701 | +struct class_simple *sound_class; | |
702 | +EXPORT_SYMBOL(sound_class); | |
703 | + | |
704 | /* | |
705 | * Low level list operator. Scan the ordered list, find a hole and | |
706 | * join into it. Called with the lock asserted | |
707 | @@ -171,6 +174,8 @@ | |
708 | ||
709 | devfs_mk_cdev(MKDEV(SOUND_MAJOR, s->unit_minor), | |
710 | S_IFCHR | mode, s->name); | |
711 | + class_simple_device_add(sound_class, MKDEV(SOUND_MAJOR, s->unit_minor), | |
712 | + NULL, s->name+6); | |
713 | return r; | |
714 | ||
715 | fail: | |
716 | @@ -193,6 +198,7 @@ | |
717 | spin_unlock(&sound_loader_lock); | |
718 | if (p) { | |
719 | devfs_remove(p->name); | |
720 | + class_simple_device_remove(MKDEV(SOUND_MAJOR, p->unit_minor)); | |
721 | kfree(p); | |
722 | } | |
723 | } | |
724 | @@ -556,6 +562,7 @@ | |
725 | empty */ | |
726 | unregister_chrdev(SOUND_MAJOR, "sound"); | |
727 | devfs_remove("sound"); | |
728 | + class_simple_destroy(sound_class); | |
729 | } | |
730 | ||
731 | static int __init init_soundcore(void) | |
732 | @@ -565,6 +572,9 @@ | |
733 | return -EBUSY; | |
734 | } | |
735 | devfs_mk_dir ("sound"); | |
736 | + sound_class = class_simple_create(THIS_MODULE, "sound"); | |
737 | + if (IS_ERR(sound_class)) | |
738 | + return PTR_ERR(sound_class); | |
739 | ||
740 | return 0; | |
741 | } | |
742 | diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c | |
743 | --- a/drivers/char/tty_io.c Thu Jan 15 11:05:50 2004 | |
744 | +++ b/drivers/char/tty_io.c Thu Jan 15 11:05:50 2004 | |
745 | @@ -2069,79 +2069,7 @@ | |
746 | tty->driver->write(tty, 0, &ch, 1); | |
747 | } | |
748 | ||
749 | -struct tty_dev { | |
750 | - struct list_head node; | |
751 | - dev_t dev; | |
752 | - struct class_device class_dev; | |
753 | -}; | |
754 | -#define to_tty_dev(d) container_of(d, struct tty_dev, class_dev) | |
755 | - | |
756 | -static void release_tty_dev(struct class_device *class_dev) | |
757 | -{ | |
758 | - struct tty_dev *tty_dev = to_tty_dev(class_dev); | |
759 | - kfree(tty_dev); | |
760 | -} | |
761 | - | |
762 | -static struct class tty_class = { | |
763 | - .name = "tty", | |
764 | - .release = &release_tty_dev, | |
765 | -}; | |
766 | - | |
767 | -static LIST_HEAD(tty_dev_list); | |
768 | -static spinlock_t tty_dev_list_lock = SPIN_LOCK_UNLOCKED; | |
769 | - | |
770 | -static ssize_t show_dev(struct class_device *class_dev, char *buf) | |
771 | -{ | |
772 | - struct tty_dev *tty_dev = to_tty_dev(class_dev); | |
773 | - return print_dev_t(buf, tty_dev->dev); | |
774 | -} | |
775 | -static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); | |
776 | - | |
777 | -static void tty_add_class_device(char *name, dev_t dev, struct device *device) | |
778 | -{ | |
779 | - struct tty_dev *tty_dev = NULL; | |
780 | - int retval; | |
781 | - | |
782 | - tty_dev = kmalloc(sizeof(*tty_dev), GFP_KERNEL); | |
783 | - if (!tty_dev) | |
784 | - return; | |
785 | - memset(tty_dev, 0x00, sizeof(*tty_dev)); | |
786 | - | |
787 | - tty_dev->class_dev.dev = device; | |
788 | - tty_dev->class_dev.class = &tty_class; | |
789 | - snprintf(tty_dev->class_dev.class_id, BUS_ID_SIZE, "%s", name); | |
790 | - retval = class_device_register(&tty_dev->class_dev); | |
791 | - if (retval) | |
792 | - goto error; | |
793 | - class_device_create_file (&tty_dev->class_dev, &class_device_attr_dev); | |
794 | - tty_dev->dev = dev; | |
795 | - spin_lock(&tty_dev_list_lock); | |
796 | - list_add(&tty_dev->node, &tty_dev_list); | |
797 | - spin_unlock(&tty_dev_list_lock); | |
798 | - return; | |
799 | -error: | |
800 | - kfree(tty_dev); | |
801 | -} | |
802 | - | |
803 | -static void tty_remove_class_device(dev_t dev) | |
804 | -{ | |
805 | - struct tty_dev *tty_dev = NULL; | |
806 | - struct list_head *tmp; | |
807 | - int found = 0; | |
808 | - | |
809 | - spin_lock(&tty_dev_list_lock); | |
810 | - list_for_each (tmp, &tty_dev_list) { | |
811 | - tty_dev = list_entry(tmp, struct tty_dev, node); | |
812 | - if (tty_dev->dev == dev) { | |
813 | - list_del(&tty_dev->node); | |
814 | - found = 1; | |
815 | - break; | |
816 | - } | |
817 | - } | |
818 | - spin_unlock(&tty_dev_list_lock); | |
819 | - if (found) | |
820 | - class_device_unregister(&tty_dev->class_dev); | |
821 | -} | |
822 | +static struct class_simple *tty_class; | |
823 | ||
824 | /** | |
825 | * tty_register_device - register a tty device | |
826 | @@ -2174,7 +2102,7 @@ | |
827 | if (driver->type != TTY_DRIVER_TYPE_PTY) { | |
828 | char name[64]; | |
829 | tty_line_name(driver, index, name); | |
830 | - tty_add_class_device(name, dev, device); | |
831 | + class_simple_device_add(tty_class, dev, device, name); | |
832 | } | |
833 | } | |
834 | ||
835 | @@ -2189,7 +2117,7 @@ | |
836 | void tty_unregister_device(struct tty_driver *driver, unsigned index) | |
837 | { | |
838 | devfs_remove("%s%d", driver->devfs_name, index + driver->name_base); | |
839 | - tty_remove_class_device(MKDEV(driver->major, driver->minor_start) + index); | |
840 | + class_simple_device_remove(MKDEV(driver->major, driver->minor_start) + index); | |
841 | } | |
842 | ||
843 | EXPORT_SYMBOL(tty_register_device); | |
844 | @@ -2406,7 +2334,10 @@ | |
845 | ||
846 | static int __init tty_class_init(void) | |
847 | { | |
848 | - return class_register(&tty_class); | |
849 | + tty_class = class_simple_create(THIS_MODULE, "tty"); | |
850 | + if (IS_ERR(tty_class)) | |
851 | + return PTR_ERR(tty_class); | |
852 | + return 0; | |
853 | } | |
854 | ||
855 | postcore_initcall(tty_class_init); | |
856 | @@ -2431,7 +2362,7 @@ | |
857 | register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) | |
858 | panic("Couldn't register /dev/tty driver\n"); | |
859 | devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty"); | |
860 | - tty_add_class_device ("tty", MKDEV(TTYAUX_MAJOR, 0), NULL); | |
861 | + class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); | |
862 | ||
863 | strcpy(console_cdev.kobj.name, "dev.console"); | |
864 | cdev_init(&console_cdev, &console_fops); | |
865 | @@ -2439,7 +2370,7 @@ | |
866 | register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) | |
867 | panic("Couldn't register /dev/console driver\n"); | |
868 | devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console"); | |
869 | - tty_add_class_device ("console", MKDEV(TTYAUX_MAJOR, 1), NULL); | |
870 | + class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); | |
871 | ||
872 | tty_kobj.kset = tty_cdev.kobj.kset; | |
873 | kobject_register(&tty_kobj); | |
874 | @@ -2451,7 +2382,7 @@ | |
875 | register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) | |
876 | panic("Couldn't register /dev/ptmx driver\n"); | |
877 | devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx"); | |
878 | - tty_add_class_device ("ptmx", MKDEV(TTYAUX_MAJOR, 2), NULL); | |
879 | + class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); | |
880 | #endif | |
881 | ||
882 | #ifdef CONFIG_VT | |
883 | @@ -2461,7 +2392,7 @@ | |
884 | register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) | |
885 | panic("Couldn't register /dev/tty0 driver\n"); | |
886 | devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0"); | |
887 | - tty_add_class_device ("tty0", MKDEV(TTY_MAJOR, 0), NULL); | |
888 | + class_simple_device_add(tty_class, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); | |
889 | ||
890 | vty_init(); | |
891 | #endif | |
892 | diff -Nru a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c | |
893 | --- a/drivers/char/vc_screen.c Thu Jan 15 11:05:48 2004 | |
894 | +++ b/drivers/char/vc_screen.c Thu Jan 15 11:05:48 2004 | |
895 | @@ -36,6 +36,7 @@ | |
896 | #include <linux/kbd_kern.h> | |
897 | #include <linux/console.h> | |
898 | #include <linux/smp_lock.h> | |
899 | +#include <linux/device.h> | |
900 | #include <asm/uaccess.h> | |
901 | #include <asm/byteorder.h> | |
902 | #include <asm/unaligned.h> | |
903 | @@ -469,6 +470,8 @@ | |
904 | .open = vcs_open, | |
905 | }; | |
906 | ||
907 | +static struct class_simple *vc_class; | |
908 | + | |
909 | void vcs_make_devfs(struct tty_struct *tty) | |
910 | { | |
911 | devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 1), | |
912 | @@ -477,19 +480,26 @@ | |
913 | devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 129), | |
914 | S_IFCHR|S_IRUSR|S_IWUSR, | |
915 | "vcc/a%u", tty->index + 1); | |
916 | + class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, tty->index + 1), NULL, "vcs%u", tty->index + 1); | |
917 | + class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, tty->index + 129), NULL, "vcsa%u", tty->index + 1); | |
918 | } | |
919 | void vcs_remove_devfs(struct tty_struct *tty) | |
920 | { | |
921 | devfs_remove("vcc/%u", tty->index + 1); | |
922 | devfs_remove("vcc/a%u", tty->index + 1); | |
923 | + class_simple_device_remove(MKDEV(VCS_MAJOR, tty->index + 1)); | |
924 | + class_simple_device_remove(MKDEV(VCS_MAJOR, tty->index + 129)); | |
925 | } | |
926 | ||
927 | int __init vcs_init(void) | |
928 | { | |
929 | if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops)) | |
930 | panic("unable to get major %d for vcs device", VCS_MAJOR); | |
931 | + vc_class = class_simple_create(THIS_MODULE, "vc"); | |
932 | ||
933 | devfs_mk_cdev(MKDEV(VCS_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/0"); | |
934 | devfs_mk_cdev(MKDEV(VCS_MAJOR, 128), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a0"); | |
935 | + class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); | |
936 | + class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); | |
937 | return 0; | |
938 | } | |
939 | diff -Nru a/drivers/char/vt.c b/drivers/char/vt.c | |
940 | --- a/drivers/char/vt.c Thu Jan 15 11:05:50 2004 | |
941 | +++ b/drivers/char/vt.c Thu Jan 15 11:05:50 2004 | |
942 | @@ -2539,6 +2539,8 @@ | |
943 | ||
944 | int __init vty_init(void) | |
945 | { | |
946 | + vcs_init(); | |
947 | + | |
948 | console_driver = alloc_tty_driver(MAX_NR_CONSOLES); | |
949 | if (!console_driver) | |
950 | panic("Couldn't allocate console driver\n"); | |
951 | @@ -2566,7 +2568,6 @@ | |
952 | #ifdef CONFIG_FRAMEBUFFER_CONSOLE | |
953 | fb_console_init(); | |
954 | #endif | |
955 | - vcs_init(); | |
956 | return 0; | |
957 | } | |
958 |