From d65da6eae10cc77f93ead0188cde0b45f124d912 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 17 Aug 2005 17:33:11 -0700 Subject: [PATCH] Fix manual binding infinite loop Fix for manual binding of drivers to devices. Problem is if you pass in a valid device id, but the driver refuses to bind. Infinite loop as write() tries to resubmit the data it just sent. Thanks to Michal Ostrowski for pointing the problem out. Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index ab53832d57e5..6966aff74efe 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -156,7 +156,9 @@ static ssize_t driver_unbind(struct device_driver *drv, device_release_driver(dev); err = count; } - return err; + if (err) + return err; + return count; } static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); -- cgit v1.2.2 From 76d1ce00bdd76c2987fbfb763cd40447413a55b3 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 10 Jul 2005 01:21:24 -0500 Subject: [PATCH] Driver core: link device and all class devices derived from it. Driver core: link device and all class devices derived from it. To ease the task of locating class devices derived from a certain device create symlinks from parent device to its class devices. Change USB host class device name from usbX to usb_hostX to avoid conflict when creating aforementioned links. Tweaked by Greg to have the symlink be "class_name:class_device_name" in order to prevent duplicate links. Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 33 +++++++++++++++++++++++++++++++-- drivers/usb/core/hcd.c | 2 +- 2 files changed, 32 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/base/class.c b/drivers/base/class.c index 0154a1623b21..d207296b18dc 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -452,10 +452,29 @@ void class_device_initialize(struct class_device *class_dev) INIT_LIST_HEAD(&class_dev->node); } +static char *make_class_name(struct class_device *class_dev) +{ + char *name; + int size; + + size = strlen(class_dev->class->name) + + strlen(kobject_name(&class_dev->kobj)) + 2; + + name = kmalloc(size, GFP_KERNEL); + if (!name) + return ERR_PTR(-ENOMEM); + + strcpy(name, class_dev->class->name); + strcat(name, ":"); + strcat(name, kobject_name(&class_dev->kobj)); + return name; +} + int class_device_add(struct class_device *class_dev) { struct class * parent = NULL; struct class_interface * class_intf; + char *class_name = NULL; int error; class_dev = class_device_get(class_dev); @@ -500,9 +519,13 @@ int class_device_add(struct class_device *class_dev) } class_device_add_attrs(class_dev); - if (class_dev->dev) + if (class_dev->dev) { + class_name = make_class_name(class_dev); sysfs_create_link(&class_dev->kobj, &class_dev->dev->kobj, "device"); + sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, + class_name); + } /* notify any interfaces this device is now here */ if (parent) { @@ -519,6 +542,7 @@ int class_device_add(struct class_device *class_dev) if (error && parent) class_put(parent); class_device_put(class_dev); + kfree(class_name); return error; } @@ -584,6 +608,7 @@ void class_device_del(struct class_device *class_dev) { struct class * parent = class_dev->class; struct class_interface * class_intf; + char *class_name = NULL; if (parent) { down(&parent->sem); @@ -594,8 +619,11 @@ void class_device_del(struct class_device *class_dev) up(&parent->sem); } - if (class_dev->dev) + if (class_dev->dev) { + class_name = make_class_name(class_dev); sysfs_remove_link(&class_dev->kobj, "device"); + sysfs_remove_link(&class_dev->dev->kobj, class_name); + } if (class_dev->devt_attr) class_device_remove_file(class_dev, class_dev->devt_attr); class_device_remove_attrs(class_dev); @@ -605,6 +633,7 @@ void class_device_del(struct class_device *class_dev) if (parent) class_put(parent); + kfree(class_name); } void class_device_unregister(struct class_device *class_dev) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 79422a3b07bc..9f44e83c6a69 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -782,7 +782,7 @@ static int usb_register_bus(struct usb_bus *bus) return -E2BIG; } - bus->class_dev = class_device_create(usb_host_class, MKDEV(0,0), bus->controller, "usb%d", busnum); + bus->class_dev = class_device_create(usb_host_class, MKDEV(0,0), bus->controller, "usb_host%d", busnum); if (IS_ERR(bus->class_dev)) { clear_bit(busnum, busmap.busmap); up(&usb_bus_list_lock); -- cgit v1.2.2 From 94fd0db7bfb4a03da202fd426d4e8e7eab42ab86 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 15 Jul 2005 10:09:25 +0200 Subject: [PATCH] Floppy: Add cmos attribute to floppy driver Currently only a device 'fdX' shows up in sysfs; the other possible device for this drive (like fd0h1440 etc) must be guessed from there. This patch corrects the floppy driver to create a platform device for each floppy found; each platform device also has an attribute 'cmos' which represents the cmos type for this drive. From this attribute the other possible device types can be computed. From: Hannes Reinecke Signed-off-by: Greg Kroah-Hartman --- drivers/block/floppy.c | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index f0c1084b840f..21f58c4b3c79 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -493,6 +493,8 @@ static struct floppy_struct user_params[N_DRIVE]; static sector_t floppy_sizes[256]; +static char floppy_device_name[] = "floppy"; + /* * The driver is trying to determine the correct media format * while probing is set. rw_interrupt() clears it after a @@ -4191,18 +4193,25 @@ static int __init floppy_setup(char *str) static int have_no_fdc = -ENODEV; +static ssize_t floppy_cmos_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct platform_device *p = container_of(dev,struct platform_device,dev); + int drive = p->id; + ssize_t retval; + + retval = sprintf(buf,"%X\n", UDP->cmos); + + return retval; +} + +DEVICE_ATTR(cmos,S_IRUGO,floppy_cmos_show,NULL); + static void floppy_device_release(struct device *dev) { complete(&device_release); } -static struct platform_device floppy_device = { - .name = "floppy", - .id = 0, - .dev = { - .release = floppy_device_release, - } -}; +static struct platform_device floppy_device[N_DRIVE]; static struct kobject *floppy_find(dev_t dev, int *part, void *data) { @@ -4370,20 +4379,26 @@ static int __init floppy_init(void) goto out_flush_work; } - err = platform_device_register(&floppy_device); - if (err) - goto out_flush_work; - for (drive = 0; drive < N_DRIVE; drive++) { if (!(allowed_drive_mask & (1 << drive))) continue; if (fdc_state[FDC(drive)].version == FDC_NONE) continue; + + floppy_device[drive].name = floppy_device_name; + floppy_device[drive].id = drive; + floppy_device[drive].dev.release = floppy_device_release; + + err = platform_device_register(&floppy_device[drive]); + if (err) + goto out_flush_work; + + device_create_file(&floppy_device[drive].dev,&dev_attr_cmos); /* to be cleaned up... */ disks[drive]->private_data = (void *)(long)drive; disks[drive]->queue = floppy_queue; disks[drive]->flags |= GENHD_FL_REMOVABLE; - disks[drive]->driverfs_dev = &floppy_device.dev; + disks[drive]->driverfs_dev = &floppy_device[drive].dev; add_disk(disks[drive]); } @@ -4603,10 +4618,11 @@ void cleanup_module(void) fdc_state[FDC(drive)].version != FDC_NONE) { del_gendisk(disks[drive]); unregister_devfs_entries(drive); + device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos); + platform_device_unregister(&floppy_device[drive]); } put_disk(disks[drive]); } - platform_device_unregister(&floppy_device); devfs_remove("floppy"); del_timer_sync(&fd_timeout); -- cgit v1.2.2 From 9a8af6b3b64ee97a1aeecde017ffd02e6796913a Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 27 Jul 2005 17:37:34 -0700 Subject: [PATCH] Floppy: add cmos attribute to floppy driver tidy Fiddle with coding style a bit. Cc: Hannes Reinecke Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/block/floppy.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 21f58c4b3c79..888dad5eef34 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4193,17 +4193,16 @@ static int __init floppy_setup(char *str) static int have_no_fdc = -ENODEV; -static ssize_t floppy_cmos_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t floppy_cmos_show(struct device *dev, + struct device_attribute *attr, char *buf) { - struct platform_device *p = container_of(dev,struct platform_device,dev); - int drive = p->id; - ssize_t retval; - - retval = sprintf(buf,"%X\n", UDP->cmos); + struct platform_device *p; + int drive; - return retval; + p = container_of(dev, struct platform_device,dev); + drive = p->id; + return sprintf(buf, "%X\n", UDP->cmos); } - DEVICE_ATTR(cmos,S_IRUGO,floppy_cmos_show,NULL); static void floppy_device_release(struct device *dev) -- cgit v1.2.2 From ceaeade1f94c0a1c0163906ceeaede6493a9715e Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Thu, 11 Aug 2005 10:37:39 +0800 Subject: [PATCH] Driver core: hande sysdev suspend failure This patch adds the return value check for sysdev suspend and does restore in failure case. Send the patch to pm-list, but seems lost, so I resend it. Signed-off-by: Shaohua Li Signed-off-by: Greg Kroah-Hartman --- drivers/base/sys.c | 110 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 85 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 214b96435409..3431eb6004c3 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -288,6 +288,27 @@ void sysdev_shutdown(void) up(&sysdev_drivers_lock); } +static void __sysdev_resume(struct sys_device *dev) +{ + struct sysdev_class *cls = dev->cls; + struct sysdev_driver *drv; + + /* First, call the class-specific one */ + if (cls->resume) + cls->resume(dev); + + /* Call auxillary drivers next. */ + list_for_each_entry(drv, &cls->drivers, entry) { + if (drv->resume) + drv->resume(dev); + } + + /* Call global drivers. */ + list_for_each_entry(drv, &sysdev_drivers, entry) { + if (drv->resume) + drv->resume(dev); + } +} /** * sysdev_suspend - Suspend all system devices. @@ -305,38 +326,93 @@ void sysdev_shutdown(void) int sysdev_suspend(pm_message_t state) { struct sysdev_class * cls; + struct sys_device *sysdev, *err_dev; + struct sysdev_driver *drv, *err_drv; + int ret; pr_debug("Suspending System Devices\n"); list_for_each_entry_reverse(cls, &system_subsys.kset.list, kset.kobj.entry) { - struct sys_device * sysdev; pr_debug("Suspending type '%s':\n", kobject_name(&cls->kset.kobj)); list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { - struct sysdev_driver * drv; pr_debug(" %s\n", kobject_name(&sysdev->kobj)); /* Call global drivers first. */ list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->suspend) - drv->suspend(sysdev, state); + if (drv->suspend) { + ret = drv->suspend(sysdev, state); + if (ret) + goto gbl_driver; + } } /* Call auxillary drivers next. */ list_for_each_entry(drv, &cls->drivers, entry) { - if (drv->suspend) - drv->suspend(sysdev, state); + if (drv->suspend) { + ret = drv->suspend(sysdev, state); + if (ret) + goto aux_driver; + } } /* Now call the generic one */ - if (cls->suspend) - cls->suspend(sysdev, state); + if (cls->suspend) { + ret = cls->suspend(sysdev, state); + if (ret) + goto cls_driver; + } } } return 0; + /* resume current sysdev */ +cls_driver: + drv = NULL; + printk(KERN_ERR "Class suspend failed for %s\n", + kobject_name(&sysdev->kobj)); + +aux_driver: + if (drv) + printk(KERN_ERR "Class driver suspend failed for %s\n", + kobject_name(&sysdev->kobj)); + list_for_each_entry(err_drv, &cls->drivers, entry) { + if (err_drv == drv) + break; + if (err_drv->resume) + err_drv->resume(sysdev); + } + drv = NULL; + +gbl_driver: + if (drv) + printk(KERN_ERR "sysdev driver suspend failed for %s\n", + kobject_name(&sysdev->kobj)); + list_for_each_entry(err_drv, &sysdev_drivers, entry) { + if (err_drv == drv) + break; + if (err_drv->resume) + err_drv->resume(sysdev); + } + /* resume other sysdevs in current class */ + list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { + if (err_dev == sysdev) + break; + pr_debug(" %s\n", kobject_name(&err_dev->kobj)); + __sysdev_resume(err_dev); + } + + /* resume other classes */ + list_for_each_entry_continue(cls, &system_subsys.kset.list, + kset.kobj.entry) { + list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { + pr_debug(" %s\n", kobject_name(&err_dev->kobj)); + __sysdev_resume(err_dev); + } + } + return ret; } @@ -362,25 +438,9 @@ int sysdev_resume(void) kobject_name(&cls->kset.kobj)); list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { - struct sysdev_driver * drv; pr_debug(" %s\n", kobject_name(&sysdev->kobj)); - /* First, call the class-specific one */ - if (cls->resume) - cls->resume(sysdev); - - /* Call auxillary drivers next. */ - list_for_each_entry(drv, &cls->drivers, entry) { - if (drv->resume) - drv->resume(sysdev); - } - - /* Call global drivers. */ - list_for_each_entry(drv, &sysdev_drivers, entry) { - if (drv->resume) - drv->resume(sysdev); - } - + __sysdev_resume(sysdev); } } return 0; -- cgit v1.2.2 From fef6ec8dd96205fb22e3cfe2e4abd69d89413631 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Wed, 17 Aug 2005 22:06:34 +0200 Subject: [PATCH] Driver core: small cleanup; remove check for NULL before kfree() in driver core Remove needless checking of variable for NULL before calling kfree() on it. Applies to 2.6.13-rc6-git9 Signed-off-by: Jesper Juhl Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/base/class.c b/drivers/base/class.c index d207296b18dc..d164c32a97ad 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -299,10 +299,8 @@ static void class_dev_release(struct kobject * kobj) pr_debug("device class '%s': release.\n", cd->class_id); - if (cd->devt_attr) { - kfree(cd->devt_attr); - cd->devt_attr = NULL; - } + kfree(cd->devt_attr); + cd->devt_attr = NULL; if (cls->release) cls->release(cd); -- cgit v1.2.2 From d856f1e337782326c638c70c0b4df2b909350dec Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 19 Aug 2005 09:14:01 -0400 Subject: [PATCH] klist: fix klist to have the same klist_add semantics as list_head at the moment, the list_head semantics are list_add(node, head) whereas current klist semantics are klist_add(head, node) This is bound to cause confusion, and since klist is the newcomer, it should follow the list_head semantics. I also added missing include guards to klist.h Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/base/bus.c | 4 ++-- drivers/base/core.c | 2 +- drivers/base/dd.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 6966aff74efe..17e96698410e 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -360,7 +360,7 @@ int bus_add_device(struct device * dev) if (bus) { pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id); device_attach(dev); - klist_add_tail(&bus->klist_devices, &dev->knode_bus); + klist_add_tail(&dev->knode_bus, &bus->klist_devices); error = device_add_attrs(bus, dev); if (!error) { sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id); @@ -448,7 +448,7 @@ int bus_add_driver(struct device_driver * drv) } driver_attach(drv); - klist_add_tail(&bus->klist_drivers, &drv->knode_bus); + klist_add_tail(&drv->knode_bus, &bus->klist_drivers); module_add_driver(drv->owner, drv); driver_add_attrs(bus, drv); diff --git a/drivers/base/core.c b/drivers/base/core.c index efe03a024a5b..c8a33df00761 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -249,7 +249,7 @@ int device_add(struct device *dev) if ((error = bus_add_device(dev))) goto BusError; if (parent) - klist_add_tail(&parent->klist_children, &dev->knode_parent); + klist_add_tail(&dev->knode_parent, &parent->klist_children); /* notify platform of device entry */ if (platform_notify) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 16323f9cbff0..d5bbce38282f 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -42,7 +42,7 @@ void device_bind_driver(struct device * dev) { pr_debug("bound device '%s' to driver '%s'\n", dev->bus_id, dev->driver->name); - klist_add_tail(&dev->driver->klist_devices, &dev->knode_driver); + klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices); sysfs_create_link(&dev->driver->kobj, &dev->kobj, kobject_name(&dev->kobj)); sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver"); -- cgit v1.2.2