From d78112e1f1da2a8be1ac0d7b583dcc25aa4f079c Mon Sep 17 00:00:00 2001 From: Michael Hanselmann Date: Sat, 10 Feb 2007 00:47:44 -0500 Subject: ACPI: video: Fix null pointer in appledisplay driver commit "ACPI: video: Add dev argument for backlight_device_register" 519ab5f2be65b72cf12ae99c89752bbe79b44df6 broke the apple display driver. Signed-off-by: Michael Hanselmann Signed-off-by: Len Brown --- drivers/usb/misc/appledisplay.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/misc') diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index a7932a72d29..31ab83cc95d 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -281,7 +281,7 @@ static int appledisplay_probe(struct usb_interface *iface, /* Register backlight device */ snprintf(bl_name, sizeof(bl_name), "appledisplay%d", atomic_inc_return(&count_displays) - 1); - pdata->bd = backlight_device_register(bl_name, NULL, NULL, + pdata->bd = backlight_device_register(bl_name, NULL, pdata &appledisplay_bl_data); if (IS_ERR(pdata->bd)) { err("appledisplay: Backlight registration failed"); -- cgit v1.2.3-70-g09d2 From df23fa01acc77444453633e1dec59cd7a4ea8ec3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 13 Jan 2007 10:57:42 -0800 Subject: USB: Driver to charge USB blackberry devices A simple driver to turn on the charging capability of a USB BlackBerry device when it is plugged into the machine. It does not bind to the device, so all userspace programs can still sync properly with it. Note, if CONFIG_USB_SUSPEND is enabled, it can play havoc with this device as the power to the port will be shut down. This device id will have to be added to the global blacklist table when it is created. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/Makefile | 1 + drivers/usb/misc/Kconfig | 11 ++++ drivers/usb/misc/Makefile | 1 + drivers/usb/misc/berry_charge.c | 140 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 drivers/usb/misc/berry_charge.c (limited to 'drivers/usb/misc') diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 825bf884537..8b7ff467d26 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_USB_SERIAL) += serial/ obj-$(CONFIG_USB_ADUTUX) += misc/ obj-$(CONFIG_USB_APPLEDISPLAY) += misc/ obj-$(CONFIG_USB_AUERSWALD) += misc/ +obj-$(CONFIG_USB_BERRY_CHARGE) += misc/ obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/ obj-$(CONFIG_USB_CYTHERM) += misc/ obj-$(CONFIG_USB_EMI26) += misc/ diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index a74bf8617e7..4907e8b8007 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -88,6 +88,17 @@ config USB_LCD To compile this driver as a module, choose M here: the module will be called usblcd. +config USB_BERRY_CHARGE + tristate "USB BlackBerry recharge support" + depends on USB + help + Say Y here if you want to connect a BlackBerry device to your + computer's USB port and have it automatically switch to "recharge" + mode. + + To compile this driver as a module, choose M here: the + module will be called berry_charge. + config USB_LED tristate "USB LED driver support" depends on USB diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 2cba07d3197..dac2d5b7156 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_USB_ADUTUX) += adutux.o obj-$(CONFIG_USB_APPLEDISPLAY) += appledisplay.o obj-$(CONFIG_USB_AUERSWALD) += auerswald.o +obj-$(CONFIG_USB_BERRY_CHARGE) += berry_charge.o obj-$(CONFIG_USB_CYPRESS_CY7C63)+= cypress_cy7c63.o obj-$(CONFIG_USB_CYTHERM) += cytherm.o obj-$(CONFIG_USB_EMI26) += emi26.o diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c new file mode 100644 index 00000000000..60893c6c822 --- /dev/null +++ b/drivers/usb/misc/berry_charge.c @@ -0,0 +1,140 @@ +/* + * USB BlackBerry charging module + * + * Copyright (C) 2007 Greg Kroah-Hartman + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + * Information on how to switch configs was taken by the bcharge.cc file + * created by the barry.sf.net project. + * + * bcharge.cc has the following copyright: + * Copyright (C) 2006, Net Direct Inc. (http://www.netdirect.ca/) + * and is released under the GPLv2. + * + * + */ + +#include +#include +#include +#include +#include +#include + +#define RIM_VENDOR 0x0fca +#define BLACKBERRY 0x0001 + +static int debug; + +#ifdef dbg +#undef dbg +#endif +#define dbg(dev, format, arg...) \ + if (debug) \ + dev_printk(KERN_DEBUG , dev , format , ## arg) + +static struct usb_device_id id_table [] = { + { USB_DEVICE(RIM_VENDOR, BLACKBERRY) }, + { }, /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static int magic_charge(struct usb_device *udev) +{ + char *dummy_buffer = kzalloc(2, GFP_KERNEL); + int retval; + + if (!dummy_buffer) + return -ENOMEM; + + /* send two magic commands and then set the configuration. The device + * will then reset itself with the new power usage and should start + * charging. */ + + /* Note, with testing, it only seems that the first message is really + * needed (at least for the 8700c), but to be safe, we emulate what + * other operating systems seem to be sending to their device. We + * really need to get some specs for this device to be sure about what + * is going on here. + */ + dbg(&udev->dev, "Sending first magic command\n"); + retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0xa5, 0xc0, 0, 1, dummy_buffer, 2, 100); + if (retval != 2) { + dev_err(&udev->dev, "First magic command failed: %d.\n", + retval); + return retval; + } + + dbg(&udev->dev, "Sending first magic command\n"); + retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0xa2, 0x40, 0, 1, dummy_buffer, 0, 100); + if (retval != 0) { + dev_err(&udev->dev, "Second magic command failed: %d.\n", + retval); + return retval; + } + + dbg(&udev->dev, "Calling set_configuration\n"); + retval = usb_driver_set_configuration(udev, 1); + if (retval) + dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval); + + return retval; +} + +static int berry_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + + dbg(&udev->dev, "Power is set to %dmA\n", + udev->actconfig->desc.bMaxPower * 2); + + /* check the power usage so we don't try to enable something that is + * already enabled */ + if ((udev->actconfig->desc.bMaxPower * 2) == 500) { + dbg(&udev->dev, "device is already charging, power is " + "set to %dmA\n", udev->actconfig->desc.bMaxPower * 2); + return -ENODEV; + } + + /* turn the power on */ + magic_charge(udev); + + /* we don't really want to bind to the device, userspace programs can + * handle the syncing just fine, so get outta here. */ + return -ENODEV; +} + +static void berry_disconnect(struct usb_interface *intf) +{ +} + +static struct usb_driver berry_driver = { + .name = "berry_charge", + .probe = berry_probe, + .disconnect = berry_disconnect, + .id_table = id_table, +}; + +static int __init berry_init(void) +{ + return usb_register(&berry_driver); +} + +static void __exit berry_exit(void) +{ + usb_deregister(&berry_driver); +} + +module_init(berry_init); +module_exit(berry_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Greg Kroah-Hartman "); +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); -- cgit v1.2.3-70-g09d2 From dfcba200679dc3f62212154b65b40b835ce69ab7 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Thu, 8 Feb 2007 00:06:32 +0000 Subject: backlight: Remove unneeded owner field Remove uneeded owner field from backlight_properties structure. Nothing uses it and it is unlikely that it will ever be used. The backlight class uses other means to ensure that nothing references unloaded code. Based on a patch from Dmitry Torokhov Signed-off-by: Richard Purdie --- drivers/acpi/asus_acpi.c | 1 - drivers/acpi/ibm_acpi.c | 1 - drivers/acpi/toshiba_acpi.c | 1 - drivers/acpi/video.c | 1 - drivers/macintosh/via-pmu-backlight.c | 1 - drivers/misc/asus-laptop.c | 1 - drivers/misc/msi-laptop.c | 1 - drivers/misc/sony-laptop.c | 1 - drivers/usb/misc/appledisplay.c | 1 - drivers/video/aty/aty128fb.c | 1 - drivers/video/aty/atyfb_base.c | 1 - drivers/video/aty/radeon_backlight.c | 1 - drivers/video/backlight/corgi_bl.c | 1 - drivers/video/backlight/hp680_bl.c | 1 - drivers/video/backlight/locomolcd.c | 1 - drivers/video/backlight/progear_bl.c | 1 - drivers/video/nvidia/nv_backlight.c | 1 - drivers/video/riva/fbdev.c | 1 - include/linux/backlight.h | 3 --- include/linux/lcd.h | 2 -- 20 files changed, 23 deletions(-) (limited to 'drivers/usb/misc') diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index 772299fb5f9..906c54f9ba5 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -1353,7 +1353,6 @@ static int asus_hotk_remove(struct acpi_device *device, int type) } static struct backlight_properties asus_backlight_data = { - .owner = THIS_MODULE, .get_brightness = read_brightness, .update_status = set_brightness_status, .max_brightness = 15, diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c index 1a0ed3dc409..accf4f7da88 100644 --- a/drivers/acpi/ibm_acpi.c +++ b/drivers/acpi/ibm_acpi.c @@ -1705,7 +1705,6 @@ static int brightness_update_status(struct backlight_device *bd) } static struct backlight_properties ibm_backlight_data = { - .owner = THIS_MODULE, .get_brightness = brightness_get, .update_status = brightness_update_status, .max_brightness = 7, diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c index faf8a5232d8..efc3669a84e 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/acpi/toshiba_acpi.c @@ -534,7 +534,6 @@ static acpi_status __exit remove_device(void) } static struct backlight_properties toshiba_backlight_data = { - .owner = THIS_MODULE, .get_brightness = get_lcd, .update_status = set_lcd_status, .max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1, diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index bf525cca3b6..75e422bd926 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -621,7 +621,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) kfree(name); return; } - acpi_video_data->owner = THIS_MODULE; acpi_video_data->get_brightness = acpi_video_get_brightness; acpi_video_data->update_status = diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c index 801a974342f..db8bcc35bc0 100644 --- a/drivers/macintosh/via-pmu-backlight.c +++ b/drivers/macintosh/via-pmu-backlight.c @@ -111,7 +111,6 @@ static int pmu_backlight_get_brightness(struct backlight_device *bd) } static struct backlight_properties pmu_backlight_data = { - .owner = THIS_MODULE, .get_brightness = pmu_backlight_get_brightness, .update_status = pmu_backlight_update_status, .max_brightness = (FB_BACKLIGHT_LEVELS - 1), diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c index e4e2b707a35..d15ee5e3420 100644 --- a/drivers/misc/asus-laptop.c +++ b/drivers/misc/asus-laptop.c @@ -196,7 +196,6 @@ static struct backlight_device *asus_backlight_device; static int read_brightness(struct backlight_device *bd); static int update_bl_status(struct backlight_device *bd); static struct backlight_properties asusbl_data = { - .owner = THIS_MODULE, .get_brightness = read_brightness, .update_status = update_bl_status, .max_brightness = 15, diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c index 8e5e07e4c1c..dd4d92e031b 100644 --- a/drivers/misc/msi-laptop.c +++ b/drivers/misc/msi-laptop.c @@ -161,7 +161,6 @@ static int bl_update_status(struct backlight_device *b) } static struct backlight_properties msibl_props = { - .owner = THIS_MODULE, .get_brightness = bl_get_brightness, .update_status = bl_update_status, .max_brightness = MSI_LCD_LEVEL_MAX-1, diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index cabbed0015e..03d02bd9f12 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -399,7 +399,6 @@ static int sony_backlight_get_brightness(struct backlight_device *bd) static struct backlight_device *sony_backlight_device; static struct backlight_properties sony_backlight_properties = { - .owner = THIS_MODULE, .update_status = sony_backlight_update_status, .get_brightness = sony_backlight_get_brightness, .max_brightness = SONY_MAX_BRIGHTNESS - 1, diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index e573c8ba978..416cde5893a 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -178,7 +178,6 @@ static int appledisplay_bl_get_brightness(struct backlight_device *bd) } static struct backlight_properties appledisplay_bl_data = { - .owner = THIS_MODULE, .get_brightness = appledisplay_bl_get_brightness, .update_status = appledisplay_bl_update_status, .max_brightness = 0xFF diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 2e976ffcde0..1fa211c0d7b 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -1797,7 +1797,6 @@ static int aty128_bl_get_brightness(struct backlight_device *bd) } static struct backlight_properties aty128_bl_data = { - .owner = THIS_MODULE, .get_brightness = aty128_bl_get_brightness, .update_status = aty128_bl_update_status, .max_brightness = (FB_BACKLIGHT_LEVELS - 1), diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 301612cef35..5ea5a00e58a 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2178,7 +2178,6 @@ static int aty_bl_get_brightness(struct backlight_device *bd) } static struct backlight_properties aty_bl_data = { - .owner = THIS_MODULE, .get_brightness = aty_bl_get_brightness, .update_status = aty_bl_update_status, .max_brightness = (FB_BACKLIGHT_LEVELS - 1), diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c index 3abfd4a380c..8b66df6f199 100644 --- a/drivers/video/aty/radeon_backlight.c +++ b/drivers/video/aty/radeon_backlight.c @@ -134,7 +134,6 @@ static int radeon_bl_get_brightness(struct backlight_device *bd) } static struct backlight_properties radeon_bl_data = { - .owner = THIS_MODULE, .get_brightness = radeon_bl_get_brightness, .update_status = radeon_bl_update_status, .max_brightness = (FB_BACKLIGHT_LEVELS - 1), diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c index fde1d951812..4ca24e26157 100644 --- a/drivers/video/backlight/corgi_bl.c +++ b/drivers/video/backlight/corgi_bl.c @@ -106,7 +106,6 @@ EXPORT_SYMBOL(corgibl_limit_intensity); static struct backlight_properties corgibl_data = { - .owner = THIS_MODULE, .get_brightness = corgibl_get_intensity, .update_status = corgibl_set_intensity, }; diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index c07d8207fb5..074625a46e3 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -96,7 +96,6 @@ static int hp680bl_get_intensity(struct backlight_device *bd) } static struct backlight_properties hp680bl_data = { - .owner = THIS_MODULE, .max_brightness = HP680_MAX_INTENSITY, .get_brightness = hp680bl_get_intensity, .update_status = hp680bl_set_intensity, diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c index fc812d96c31..3c5abbf0d04 100644 --- a/drivers/video/backlight/locomolcd.c +++ b/drivers/video/backlight/locomolcd.c @@ -142,7 +142,6 @@ static int locomolcd_get_intensity(struct backlight_device *bd) } static struct backlight_properties locomobl_data = { - .owner = THIS_MODULE, .get_brightness = locomolcd_get_intensity, .update_status = locomolcd_set_intensity, .max_brightness = 4, diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c index 13d831da8d9..42d6acd96c1 100644 --- a/drivers/video/backlight/progear_bl.c +++ b/drivers/video/backlight/progear_bl.c @@ -56,7 +56,6 @@ static int progearbl_get_intensity(struct backlight_device *bd) } static struct backlight_properties progearbl_data = { - .owner = THIS_MODULE, .get_brightness = progearbl_get_intensity, .update_status = progearbl_set_intensity, }; diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c index df934bd2189..4254c090dc4 100644 --- a/drivers/video/nvidia/nv_backlight.c +++ b/drivers/video/nvidia/nv_backlight.c @@ -104,7 +104,6 @@ static int nvidia_bl_get_brightness(struct backlight_device *bd) } static struct backlight_properties nvidia_bl_data = { - .owner = THIS_MODULE, .get_brightness = nvidia_bl_get_brightness, .update_status = nvidia_bl_update_status, .max_brightness = (FB_BACKLIGHT_LEVELS - 1), diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index f2e9b742c92..fd825711bb6 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -347,7 +347,6 @@ static int riva_bl_get_brightness(struct backlight_device *bd) } static struct backlight_properties riva_bl_data = { - .owner = THIS_MODULE, .get_brightness = riva_bl_get_brightness, .update_status = riva_bl_update_status, .max_brightness = (FB_BACKLIGHT_LEVELS - 1), diff --git a/include/linux/backlight.h b/include/linux/backlight.h index a5cf1beacb4..287c62d956f 100644 --- a/include/linux/backlight.h +++ b/include/linux/backlight.h @@ -17,9 +17,6 @@ struct fb_info; /* This structure defines all the properties of a backlight (usually attached to a LCD). */ struct backlight_properties { - /* Owner module */ - struct module *owner; - /* Notify the backlight driver some property has changed */ int (*update_status)(struct backlight_device *); /* Return the current backlight brightness (accounting for power, diff --git a/include/linux/lcd.h b/include/linux/lcd.h index d739b2e7eac..8a468f168c4 100644 --- a/include/linux/lcd.h +++ b/include/linux/lcd.h @@ -16,8 +16,6 @@ struct fb_info; /* This structure defines all the properties of a LCD flat panel. */ struct lcd_properties { - /* Owner module */ - struct module *owner; /* Get the LCD panel power status (0: full on, 1..3: controller power on, flat panel power off, 4: full off), see FB_BLANK_XXX */ int (*get_power)(struct lcd_device *); -- cgit v1.2.3-70-g09d2 From 28ee086d5b36aab2931f6740e409bb0fb6c65e5f Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Thu, 8 Feb 2007 22:25:09 +0000 Subject: backlight: Fix external uses of backlight internal semaphore backlight_device->sem has a very specific use as documented in the header file. The external users of this are using it for a different reason, to serialise access to the update_status() method. backlight users were supposed to implement their own internal serialisation of update_status() if needed but everyone is doing things differently and incorrectly. Therefore add a global mutex to take care of serialisation for everyone, once and for all. Locking for get_brightness remains optional since most users don't need it. Also update the lcd class in a similar way. Signed-off-by: Richard Purdie --- arch/powerpc/kernel/traps.c | 4 +--- arch/powerpc/platforms/powermac/backlight.c | 19 +++++-------------- drivers/macintosh/via-pmu-backlight.c | 4 +--- drivers/misc/asus-laptop.c | 20 +++++--------------- drivers/usb/misc/appledisplay.c | 6 ------ drivers/video/aty/aty128fb.c | 6 +----- drivers/video/aty/atyfb_base.c | 6 +----- drivers/video/aty/radeon_backlight.c | 4 +--- drivers/video/backlight/backlight.c | 10 ++++------ drivers/video/backlight/lcd.c | 1 + drivers/video/chipsfb.c | 8 ++------ drivers/video/nvidia/nv_backlight.c | 6 +----- drivers/video/riva/fbdev.c | 6 +----- include/linux/backlight.h | 26 ++++++++++++++++++++++++++ include/linux/lcd.h | 26 ++++++++++++++++++++++++++ 15 files changed, 76 insertions(+), 76 deletions(-) (limited to 'drivers/usb/misc') diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index dcc6f159fd9..35ce07b6a5b 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -107,12 +107,10 @@ int die(const char *str, struct pt_regs *regs, long err) if (machine_is(powermac) && pmac_backlight) { struct backlight_properties *props; - down(&pmac_backlight->sem); props = pmac_backlight->props; props->brightness = props->max_brightness; props->power = FB_BLANK_UNBLANK; - props->update_status(pmac_backlight); - up(&pmac_backlight->sem); + backlight_update_status(pmac_backlight); } mutex_unlock(&pmac_backlight_mutex); #endif diff --git a/arch/powerpc/platforms/powermac/backlight.c b/arch/powerpc/platforms/powermac/backlight.c index c3a89414ddc..1be358c1448 100644 --- a/arch/powerpc/platforms/powermac/backlight.c +++ b/arch/powerpc/platforms/powermac/backlight.c @@ -37,7 +37,9 @@ static int pmac_backlight_set_legacy_queued; */ static atomic_t kernel_backlight_disabled = ATOMIC_INIT(0); -/* Protect the pmac_backlight variable */ +/* Protect the pmac_backlight variable below. + You should hold this lock when using the pmac_backlight pointer to + prevent its potential removal. */ DEFINE_MUTEX(pmac_backlight_mutex); /* Main backlight storage @@ -49,9 +51,6 @@ DEFINE_MUTEX(pmac_backlight_mutex); * internal display, it doesn't matter. Other backlight drivers can be used * independently. * - * Lock ordering: - * pmac_backlight_mutex (global, main backlight) - * pmac_backlight->sem (backlight class) */ struct backlight_device *pmac_backlight; @@ -104,7 +103,6 @@ static void pmac_backlight_key_worker(struct work_struct *work) struct backlight_properties *props; int brightness; - down(&pmac_backlight->sem); props = pmac_backlight->props; brightness = props->brightness + @@ -117,9 +115,7 @@ static void pmac_backlight_key_worker(struct work_struct *work) brightness = props->max_brightness; props->brightness = brightness; - props->update_status(pmac_backlight); - - up(&pmac_backlight->sem); + backlight_update_status(pmac_backlight); } mutex_unlock(&pmac_backlight_mutex); } @@ -145,7 +141,6 @@ static int __pmac_backlight_set_legacy_brightness(int brightness) if (pmac_backlight) { struct backlight_properties *props; - down(&pmac_backlight->sem); props = pmac_backlight->props; props->brightness = brightness * (props->max_brightness + 1) / @@ -156,8 +151,7 @@ static int __pmac_backlight_set_legacy_brightness(int brightness) else if (props->brightness < 0) props->brightness = 0; - props->update_status(pmac_backlight); - up(&pmac_backlight->sem); + backlight_update_status(pmac_backlight); error = 0; } @@ -196,14 +190,11 @@ int pmac_backlight_get_legacy_brightness() if (pmac_backlight) { struct backlight_properties *props; - down(&pmac_backlight->sem); props = pmac_backlight->props; result = props->brightness * (OLD_BACKLIGHT_MAX + 1) / (props->max_brightness + 1); - - up(&pmac_backlight->sem); } mutex_unlock(&pmac_backlight_mutex); diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c index db8bcc35bc0..7ba2042b2dd 100644 --- a/drivers/macintosh/via-pmu-backlight.c +++ b/drivers/macintosh/via-pmu-backlight.c @@ -166,11 +166,9 @@ void __init pmu_backlight_init() pmu_backlight_data.max_brightness / 15); } - down(&bd->sem); bd->props->brightness = level; bd->props->power = FB_BLANK_UNBLANK; - bd->props->update_status(bd); - up(&bd->sem); + backlight_update_status(bd); mutex_lock(&pmac_backlight_mutex); if (!pmac_backlight) diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c index d15ee5e3420..7ace5b9a3d2 100644 --- a/drivers/misc/asus-laptop.c +++ b/drivers/misc/asus-laptop.c @@ -348,13 +348,8 @@ static void lcd_blank(int blank) struct backlight_device *bd = asus_backlight_device; if (bd) { - down(&bd->sem); - if (likely(bd->props)) { - bd->props->power = blank; - if (likely(bd->props->update_status)) - bd->props->update_status(bd); - } - up(&bd->sem); + bd->props->power = blank; + backlight_update_status(bd); } } @@ -1028,14 +1023,9 @@ static int asus_backlight_init(struct device *dev) asus_backlight_device = bd; - down(&bd->sem); - if (likely(bd->props)) { - bd->props->brightness = read_brightness(NULL); - bd->props->power = FB_BLANK_UNBLANK; - if (likely(bd->props->update_status)) - bd->props->update_status(bd); - } - up(&bd->sem); + bd->props->brightness = read_brightness(NULL); + bd->props->power = FB_BLANK_UNBLANK; + backlight_update_status(bd); } return 0; } diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index 416cde5893a..cd2c5574cf9 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -189,11 +189,9 @@ static void appledisplay_work(struct work_struct *work) container_of(work, struct appledisplay, work.work); int retval; - up(&pdata->bd->sem); retval = appledisplay_bl_get_brightness(pdata->bd); if (retval >= 0) pdata->bd->props->brightness = retval; - down(&pdata->bd->sem); /* Poll again in about 125ms if there's still a button pressed */ if (pdata->button_pressed) @@ -288,9 +286,7 @@ static int appledisplay_probe(struct usb_interface *iface, } /* Try to get brightness */ - up(&pdata->bd->sem); brightness = appledisplay_bl_get_brightness(pdata->bd); - down(&pdata->bd->sem); if (brightness < 0) { retval = brightness; @@ -299,9 +295,7 @@ static int appledisplay_probe(struct usb_interface *iface, } /* Set brightness in backlight device */ - up(&pdata->bd->sem); pdata->bd->props->brightness = brightness; - down(&pdata->bd->sem); /* save our data pointer in the interface device */ usb_set_intfdata(iface, pdata); diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 1fa211c0d7b..5d8f73b2b66 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -1807,10 +1807,8 @@ static void aty128_bl_set_power(struct fb_info *info, int power) mutex_lock(&info->bl_mutex); if (info->bl_dev) { - down(&info->bl_dev->sem); info->bl_dev->props->power = power; __aty128_bl_update_status(info->bl_dev); - up(&info->bl_dev->sem); } mutex_unlock(&info->bl_mutex); @@ -1847,11 +1845,9 @@ static void aty128_bl_init(struct aty128fb_par *par) 219 * FB_BACKLIGHT_MAX / MAX_LEVEL); mutex_unlock(&info->bl_mutex); - down(&bd->sem); bd->props->brightness = aty128_bl_data.max_brightness; bd->props->power = FB_BLANK_UNBLANK; - bd->props->update_status(bd); - up(&bd->sem); + backlight_update_status(bd); #ifdef CONFIG_PMAC_BACKLIGHT mutex_lock(&pmac_backlight_mutex); diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 5ea5a00e58a..23deb356602 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2188,10 +2188,8 @@ static void aty_bl_set_power(struct fb_info *info, int power) mutex_lock(&info->bl_mutex); if (info->bl_dev) { - down(&info->bl_dev->sem); info->bl_dev->props->power = power; __aty_bl_update_status(info->bl_dev); - up(&info->bl_dev->sem); } mutex_unlock(&info->bl_mutex); @@ -2224,11 +2222,9 @@ static void aty_bl_init(struct atyfb_par *par) 0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL); mutex_unlock(&info->bl_mutex); - down(&bd->sem); bd->props->brightness = aty_bl_data.max_brightness; bd->props->power = FB_BLANK_UNBLANK; - bd->props->update_status(bd); - up(&bd->sem); + backlight_update_status(bd); #ifdef CONFIG_PMAC_BACKLIGHT mutex_lock(&pmac_backlight_mutex); diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c index 8b66df6f199..9cfcecac8b5 100644 --- a/drivers/video/aty/radeon_backlight.c +++ b/drivers/video/aty/radeon_backlight.c @@ -194,11 +194,9 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo) 217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL); mutex_unlock(&rinfo->info->bl_mutex); - down(&bd->sem); bd->props->brightness = radeon_bl_data.max_brightness; bd->props->power = FB_BLANK_UNBLANK; - bd->props->update_status(bd); - up(&bd->sem); + backlight_update_status(bd); #ifdef CONFIG_PMAC_BACKLIGHT mutex_lock(&pmac_backlight_mutex); diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 7a85be4d2b0..347081daf7a 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -37,8 +37,7 @@ static int fb_notifier_callback(struct notifier_block *self, if (!bd->props->check_fb || bd->props->check_fb(evdata->info)) { bd->props->fb_blank = *(int *)evdata->data; - if (bd->props && bd->props->update_status) - bd->props->update_status(bd); + backlight_update_status(bd); } up(&bd->sem); return 0; @@ -97,8 +96,7 @@ static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, if (bd->props) { pr_debug("backlight: set power to %d\n", power); bd->props->power = power; - if (bd->props->update_status) - bd->props->update_status(bd); + backlight_update_status(bd); rc = count; } up(&bd->sem); @@ -140,8 +138,7 @@ static ssize_t backlight_store_brightness(struct class_device *cdev, const char pr_debug("backlight: set brightness to %d\n", brightness); bd->props->brightness = brightness; - if (bd->props->update_status) - bd->props->update_status(bd); + backlight_update_status(bd); rc = count; } } @@ -230,6 +227,7 @@ struct backlight_device *backlight_device_register(const char *name, if (!new_bd) return ERR_PTR(-ENOMEM); + mutex_init(&new_bd->update_lock); init_MUTEX(&new_bd->sem); new_bd->props = bp; memset(&new_bd->class_dev, 0, sizeof(new_bd->class_dev)); diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index 959024812ab..1e1e61a4b5d 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -198,6 +198,7 @@ struct lcd_device *lcd_device_register(const char *name, void *devdata, return ERR_PTR(-ENOMEM); init_MUTEX(&new_ld->sem); + mutex_init(&new_ld->update_lock); new_ld->props = lp; memset(&new_ld->class_dev, 0, sizeof(new_ld->class_dev)); new_ld->class_dev.class = &lcd_class; diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index 73cb426bf2d..9a656bc6295 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c @@ -153,13 +153,11 @@ static int chipsfb_blank(int blank, struct fb_info *info) * useful at blank = 1 too (saves battery, extends backlight * life) */ - down(&pmac_backlight->sem); if (blank) pmac_backlight->props->power = FB_BLANK_POWERDOWN; else pmac_backlight->props->power = FB_BLANK_UNBLANK; - pmac_backlight->props->update_status(pmac_backlight); - up(&pmac_backlight->sem); + backlight_update_status(pmac_backlight); } mutex_unlock(&pmac_backlight_mutex); @@ -415,10 +413,8 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) /* turn on the backlight */ mutex_lock(&pmac_backlight_mutex); if (pmac_backlight) { - down(&pmac_backlight->sem); pmac_backlight->props->power = FB_BLANK_UNBLANK; - pmac_backlight->props->update_status(pmac_backlight); - up(&pmac_backlight->sem); + backlight_update_status(pmac_backlight); } mutex_unlock(&pmac_backlight_mutex); #endif /* CONFIG_PMAC_BACKLIGHT */ diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c index 4254c090dc4..f5e42d0bd0d 100644 --- a/drivers/video/nvidia/nv_backlight.c +++ b/drivers/video/nvidia/nv_backlight.c @@ -114,10 +114,8 @@ void nvidia_bl_set_power(struct fb_info *info, int power) mutex_lock(&info->bl_mutex); if (info->bl_dev) { - down(&info->bl_dev->sem); info->bl_dev->props->power = power; __nvidia_bl_update_status(info->bl_dev); - up(&info->bl_dev->sem); } mutex_unlock(&info->bl_mutex); @@ -154,11 +152,9 @@ void nvidia_bl_init(struct nvidia_par *par) 0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL); mutex_unlock(&info->bl_mutex); - down(&bd->sem); bd->props->brightness = nvidia_bl_data.max_brightness; bd->props->power = FB_BLANK_UNBLANK; - bd->props->update_status(bd); - up(&bd->sem); + backlight_update_status(bd); #ifdef CONFIG_PMAC_BACKLIGHT mutex_lock(&pmac_backlight_mutex); diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index fd825711bb6..b70d18f7fcd 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -357,10 +357,8 @@ static void riva_bl_set_power(struct fb_info *info, int power) mutex_lock(&info->bl_mutex); if (info->bl_dev) { - down(&info->bl_dev->sem); info->bl_dev->props->power = power; __riva_bl_update_status(info->bl_dev); - up(&info->bl_dev->sem); } mutex_unlock(&info->bl_mutex); @@ -397,11 +395,9 @@ static void riva_bl_init(struct riva_par *par) FB_BACKLIGHT_MAX); mutex_unlock(&info->bl_mutex); - down(&bd->sem); bd->props->brightness = riva_bl_data.max_brightness; bd->props->power = FB_BLANK_UNBLANK; - bd->props->update_status(bd); - up(&bd->sem); + backlight_update_status(bd); #ifdef CONFIG_PMAC_BACKLIGHT mutex_lock(&pmac_backlight_mutex); diff --git a/include/linux/backlight.h b/include/linux/backlight.h index 287c62d956f..d1426b852bd 100644 --- a/include/linux/backlight.h +++ b/include/linux/backlight.h @@ -9,8 +9,24 @@ #define _LINUX_BACKLIGHT_H #include +#include #include +/* Notes on locking: + * + * backlight_device->sem is an internal backlight lock protecting the props + * field and no code outside the core should need to touch it. + * + * Access to update_status() is serialised by the update_lock mutex since + * most drivers seem to need this and historically get it wrong. + * + * Most drivers don't need locking on their get_brightness() method. + * If yours does, you need to implement it in the driver. You can use the + * update_lock mutex if appropriate. + * + * Any other use of the locks below is probably wrong. + */ + struct backlight_device; struct fb_info; @@ -44,12 +60,22 @@ struct backlight_device { struct semaphore sem; /* If this is NULL, the backing module is unloaded */ struct backlight_properties *props; + /* Serialise access to update_status method */ + struct mutex update_lock; /* The framebuffer notifier block */ struct notifier_block fb_notif; /* The class device structure */ struct class_device class_dev; }; +static inline void backlight_update_status(struct backlight_device *bd) +{ + mutex_lock(&bd->update_lock); + if (bd->props && bd->props->update_status) + bd->props->update_status(bd); + mutex_unlock(&bd->update_lock); +} + extern struct backlight_device *backlight_device_register(const char *name, struct device *dev,void *devdata,struct backlight_properties *bp); extern void backlight_device_unregister(struct backlight_device *bd); diff --git a/include/linux/lcd.h b/include/linux/lcd.h index 8a468f168c4..bfbf6552eb5 100644 --- a/include/linux/lcd.h +++ b/include/linux/lcd.h @@ -9,8 +9,24 @@ #define _LINUX_LCD_H #include +#include #include +/* Notes on locking: + * + * lcd_device->sem is an internal backlight lock protecting the props + * field and no code outside the core should need to touch it. + * + * Access to set_power() is serialised by the update_lock mutex since + * most drivers seem to need this and historically get it wrong. + * + * Most drivers don't need locking on their get_power() method. + * If yours does, you need to implement it in the driver. You can use the + * update_lock mutex if appropriate. + * + * Any other use of the locks below is probably wrong. + */ + struct lcd_device; struct fb_info; @@ -39,12 +55,22 @@ struct lcd_device { struct semaphore sem; /* If this is NULL, the backing module is unloaded */ struct lcd_properties *props; + /* Serialise access to set_power method */ + struct mutex update_lock; /* The framebuffer notifier block */ struct notifier_block fb_notif; /* The class device structure */ struct class_device class_dev; }; +static inline void lcd_set_power(struct lcd_device *ld, int power) +{ + mutex_lock(&ld->update_lock); + if (ld->props && ld->props->set_power) + ld->props->set_power(ld, power); + mutex_unlock(&ld->update_lock); +} + extern struct lcd_device *lcd_device_register(const char *name, void *devdata, struct lcd_properties *lp); extern void lcd_device_unregister(struct lcd_device *ld); -- cgit v1.2.3-70-g09d2 From 599a52d12629394236d785615808845823875868 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Sat, 10 Feb 2007 23:07:48 +0000 Subject: backlight: Separate backlight properties from backlight ops pointers Per device data such as brightness belongs to the indivdual device and should therefore be separate from the the backlight operation function pointers. This patch splits the two types of data and allows simplifcation of some code. Signed-off-by: Richard Purdie --- arch/powerpc/kernel/traps.c | 2 +- arch/powerpc/platforms/powermac/backlight.c | 8 +-- drivers/acpi/asus_acpi.c | 6 +-- drivers/acpi/ibm_acpi.c | 7 +-- drivers/acpi/toshiba_acpi.c | 6 +-- drivers/acpi/video.c | 35 +++++-------- drivers/macintosh/via-pmu-backlight.c | 23 +++++---- drivers/misc/asus-laptop.c | 16 +++--- drivers/misc/msi-laptop.c | 9 ++-- drivers/usb/misc/appledisplay.c | 11 ++-- drivers/video/aty/aty128fb.c | 20 ++++---- drivers/video/aty/atyfb_base.c | 18 +++---- drivers/video/aty/radeon_backlight.c | 18 +++---- drivers/video/backlight/backlight.c | 79 +++++++++++------------------ drivers/video/backlight/corgi_bl.c | 16 +++--- drivers/video/backlight/hp680_bl.c | 14 ++--- drivers/video/backlight/lcd.c | 67 +++++++++++------------- drivers/video/backlight/locomolcd.c | 12 ++--- drivers/video/backlight/progear_bl.c | 16 +++--- drivers/video/chipsfb.c | 2 +- drivers/video/nvidia/nv_backlight.c | 18 +++---- drivers/video/riva/fbdev.c | 18 +++---- include/linux/backlight.h | 33 +++++++----- include/linux/lcd.h | 23 +++++---- 24 files changed, 223 insertions(+), 254 deletions(-) (limited to 'drivers/usb/misc') diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 35ce07b6a5b..17724fb2067 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -107,7 +107,7 @@ int die(const char *str, struct pt_regs *regs, long err) if (machine_is(powermac) && pmac_backlight) { struct backlight_properties *props; - props = pmac_backlight->props; + props = &pmac_backlight->props; props->brightness = props->max_brightness; props->power = FB_BLANK_UNBLANK; backlight_update_status(pmac_backlight); diff --git a/arch/powerpc/platforms/powermac/backlight.c b/arch/powerpc/platforms/powermac/backlight.c index 1be358c1448..de7440e62cc 100644 --- a/arch/powerpc/platforms/powermac/backlight.c +++ b/arch/powerpc/platforms/powermac/backlight.c @@ -44,7 +44,7 @@ DEFINE_MUTEX(pmac_backlight_mutex); /* Main backlight storage * - * Backlight drivers in this variable are required to have the "props" + * Backlight drivers in this variable are required to have the "ops" * attribute set and to have an update_status function. * * We can only store one backlight here, but since Apple laptops have only one @@ -103,7 +103,7 @@ static void pmac_backlight_key_worker(struct work_struct *work) struct backlight_properties *props; int brightness; - props = pmac_backlight->props; + props = &pmac_backlight->props; brightness = props->brightness + ((pmac_backlight_key_queued?-1:1) * @@ -141,7 +141,7 @@ static int __pmac_backlight_set_legacy_brightness(int brightness) if (pmac_backlight) { struct backlight_properties *props; - props = pmac_backlight->props; + props = &pmac_backlight->props; props->brightness = brightness * (props->max_brightness + 1) / (OLD_BACKLIGHT_MAX + 1); @@ -190,7 +190,7 @@ int pmac_backlight_get_legacy_brightness() if (pmac_backlight) { struct backlight_properties *props; - props = pmac_backlight->props; + props = &pmac_backlight->props; result = props->brightness * (OLD_BACKLIGHT_MAX + 1) / diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index 906c54f9ba5..b770deab968 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -848,7 +848,7 @@ out: static int set_brightness_status(struct backlight_device *bd) { - return set_brightness(bd->props->brightness); + return set_brightness(bd->props.brightness); } static int @@ -1352,10 +1352,9 @@ static int asus_hotk_remove(struct acpi_device *device, int type) return 0; } -static struct backlight_properties asus_backlight_data = { +static struct backlight_ops asus_backlight_data = { .get_brightness = read_brightness, .update_status = set_brightness_status, - .max_brightness = 15, }; static void __exit asus_acpi_exit(void) @@ -1409,6 +1408,7 @@ static int __init asus_acpi_init(void) asus_backlight_device = NULL; asus_acpi_exit(); } + asus_backlight_device->props.max_brightness = 15; return 0; } diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c index accf4f7da88..4cc534e36e8 100644 --- a/drivers/acpi/ibm_acpi.c +++ b/drivers/acpi/ibm_acpi.c @@ -1701,13 +1701,12 @@ static int brightness_write(char *buf) static int brightness_update_status(struct backlight_device *bd) { - return brightness_set(bd->props->brightness); + return brightness_set(bd->props.brightness); } -static struct backlight_properties ibm_backlight_data = { +static struct backlight_ops ibm_backlight_data = { .get_brightness = brightness_get, .update_status = brightness_update_status, - .max_brightness = 7, }; static int brightness_init(void) @@ -1719,6 +1718,8 @@ static int brightness_init(void) return PTR_ERR(ibm_backlight_device); } + ibm_backlight_device->props.max_brightness = 7; + return 0; } diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c index efc3669a84e..3906d47b978 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/acpi/toshiba_acpi.c @@ -315,7 +315,7 @@ static int set_lcd(int value) static int set_lcd_status(struct backlight_device *bd) { - return set_lcd(bd->props->brightness); + return set_lcd(bd->props.brightness); } static unsigned long write_lcd(const char *buffer, unsigned long count) @@ -533,10 +533,9 @@ static acpi_status __exit remove_device(void) return AE_OK; } -static struct backlight_properties toshiba_backlight_data = { +static struct backlight_ops toshiba_backlight_data = { .get_brightness = get_lcd, .update_status = set_lcd_status, - .max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1, }; static void __exit toshiba_acpi_exit(void) @@ -596,6 +595,7 @@ static int __init toshiba_acpi_init(void) toshiba_backlight_device = NULL; toshiba_acpi_exit(); } + toshiba_backlight_device->props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; return (ACPI_SUCCESS(status)) ? 0 : -ENODEV; } diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 75e422bd926..0771b434feb 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -169,7 +169,6 @@ struct acpi_video_device { struct acpi_device *dev; struct acpi_video_device_brightness *brightness; struct backlight_device *backlight; - struct backlight_properties *data; }; /* bus */ @@ -286,13 +285,18 @@ static int acpi_video_get_brightness(struct backlight_device *bd) static int acpi_video_set_brightness(struct backlight_device *bd) { - int request_level = bd->props->brightness; + int request_level = bd->props.brightness; struct acpi_video_device *vd = (struct acpi_video_device *)class_get_devdata(&bd->class_dev); acpi_video_device_lcd_set_level(vd, request_level); return 0; } +static struct backlight_ops acpi_backlight_ops = { + .get_brightness = acpi_video_get_brightness, + .update_status = acpi_video_set_brightness, +}; + /* -------------------------------------------------------------------------- Video Management -------------------------------------------------------------------------- */ @@ -608,30 +612,18 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) unsigned long tmp; static int count = 0; char *name; - struct backlight_properties *acpi_video_data; - name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); if (!name) return; - acpi_video_data = kzalloc( - sizeof(struct backlight_properties), - GFP_KERNEL); - if (!acpi_video_data){ - kfree(name); - return; - } - acpi_video_data->get_brightness = - acpi_video_get_brightness; - acpi_video_data->update_status = - acpi_video_set_brightness; sprintf(name, "acpi_video%d", count++); - device->data = acpi_video_data; - acpi_video_data->max_brightness = max_level; acpi_video_device_lcd_get_level_current(device, &tmp); - acpi_video_data->brightness = (int)tmp; device->backlight = backlight_device_register(name, - NULL, device, acpi_video_data); + NULL, device, &acpi_backlight_ops); + device->backlight->props.max_brightness = max_level; + device->backlight->props.brightness = (int)tmp; + backlight_update_status(device->backlight); + kfree(name); } return; @@ -1676,10 +1668,7 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device) status = acpi_remove_notify_handler(device->dev->handle, ACPI_DEVICE_NOTIFY, acpi_video_device_notify); - if (device->backlight){ - backlight_device_unregister(device->backlight); - kfree(device->data); - } + backlight_device_unregister(device->backlight); return 0; } diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c index 9f9d0312797..7e27071746e 100644 --- a/drivers/macintosh/via-pmu-backlight.c +++ b/drivers/macintosh/via-pmu-backlight.c @@ -15,7 +15,7 @@ #define MAX_PMU_LEVEL 0xFF -static struct backlight_properties pmu_backlight_data; +static struct backlight_ops pmu_backlight_data; static DEFINE_SPINLOCK(pmu_backlight_lock); static int sleeping; static u8 bl_curve[FB_BACKLIGHT_LEVELS]; @@ -72,7 +72,7 @@ static int pmu_backlight_update_status(struct backlight_device *bd) { struct adb_request req; unsigned long flags; - int level = bd->props->brightness; + int level = bd->props.brightness; spin_lock_irqsave(&pmu_backlight_lock, flags); @@ -80,8 +80,8 @@ static int pmu_backlight_update_status(struct backlight_device *bd) if (sleeping) goto out; - if (bd->props->power != FB_BLANK_UNBLANK || - bd->props->fb_blank != FB_BLANK_UNBLANK) + if (bd->props.power != FB_BLANK_UNBLANK || + bd->props.fb_blank != FB_BLANK_UNBLANK) level = 0; if (level > 0) { @@ -107,13 +107,13 @@ out: static int pmu_backlight_get_brightness(struct backlight_device *bd) { - return bd->props->brightness; + return bd->props.brightness; } -static struct backlight_properties pmu_backlight_data = { +static struct backlight_ops pmu_backlight_data = { .get_brightness = pmu_backlight_get_brightness, .update_status = pmu_backlight_update_status, - .max_brightness = (FB_BACKLIGHT_LEVELS - 1), + }; #ifdef CONFIG_PM @@ -151,9 +151,10 @@ void __init pmu_backlight_init() printk("pmubl: Backlight registration failed\n"); goto error; } + bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1; pmu_backlight_init_curve(0x7F, 0x46, 0x0E); - level = pmu_backlight_data.max_brightness; + level = bd->props.max_brightness; if (autosave) { /* read autosaved value if available */ @@ -163,11 +164,11 @@ void __init pmu_backlight_init() level = pmu_backlight_curve_lookup( (req.reply[0] >> 4) * - pmu_backlight_data.max_brightness / 15); + bd->props.max_brightness / 15); } - bd->props->brightness = level; - bd->props->power = FB_BLANK_UNBLANK; + bd->props.brightness = level; + bd->props.power = FB_BLANK_UNBLANK; backlight_update_status(bd); printk("pmubl: Backlight initialized (%s)\n", name); diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c index 7ace5b9a3d2..295e931c0df 100644 --- a/drivers/misc/asus-laptop.c +++ b/drivers/misc/asus-laptop.c @@ -195,10 +195,9 @@ static struct backlight_device *asus_backlight_device; */ static int read_brightness(struct backlight_device *bd); static int update_bl_status(struct backlight_device *bd); -static struct backlight_properties asusbl_data = { +static struct backlight_ops asusbl_ops = { .get_brightness = read_brightness, .update_status = update_bl_status, - .max_brightness = 15, }; /* These functions actually update the LED's, and are called from a @@ -348,7 +347,7 @@ static void lcd_blank(int blank) struct backlight_device *bd = asus_backlight_device; if (bd) { - bd->props->power = blank; + bd->props.power = blank; backlight_update_status(bd); } } @@ -381,13 +380,13 @@ static int set_brightness(struct backlight_device *bd, int value) static int update_bl_status(struct backlight_device *bd) { int rv; - int value = bd->props->brightness; + int value = bd->props.brightness; rv = set_brightness(bd, value); if (rv) return rv; - value = (bd->props->power == FB_BLANK_UNBLANK) ? 1 : 0; + value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0; return set_lcd_state(value); } @@ -1013,7 +1012,7 @@ static int asus_backlight_init(struct device *dev) if (brightness_set_handle && lcd_switch_handle) { bd = backlight_device_register(ASUS_HOTK_FILE, dev, - NULL, &asusbl_data); + NULL, &asusbl_ops); if (IS_ERR(bd)) { printk(ASUS_ERR "Could not register asus backlight device\n"); @@ -1023,8 +1022,9 @@ static int asus_backlight_init(struct device *dev) asus_backlight_device = bd; - bd->props->brightness = read_brightness(NULL); - bd->props->power = FB_BLANK_UNBLANK; + bd->props.max_brightness = 15; + bd->props.brightness = read_brightness(NULL); + bd->props.power = FB_BLANK_UNBLANK; backlight_update_status(bd); } return 0; diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c index dd4d92e031b..68c4b58525b 100644 --- a/drivers/misc/msi-laptop.c +++ b/drivers/misc/msi-laptop.c @@ -157,13 +157,12 @@ static int bl_get_brightness(struct backlight_device *b) static int bl_update_status(struct backlight_device *b) { - return set_lcd_level(b->props->brightness); + return set_lcd_level(b->props.brightness); } -static struct backlight_properties msibl_props = { +static struct backlight_ops msibl_ops = { .get_brightness = bl_get_brightness, .update_status = bl_update_status, - .max_brightness = MSI_LCD_LEVEL_MAX-1, }; static struct backlight_device *msibl_device; @@ -317,10 +316,12 @@ static int __init msi_init(void) /* Register backlight stuff */ msibl_device = backlight_device_register("msi-laptop-bl", NULL, NULL, - &msibl_props); + &msibl_ops); if (IS_ERR(msibl_device)) return PTR_ERR(msibl_device); + msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1, + ret = platform_driver_register(&msipf_driver); if (ret) goto fail_backlight; diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index cd2c5574cf9..cf70c16f0e3 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -141,7 +141,7 @@ static int appledisplay_bl_update_status(struct backlight_device *bd) int retval; pdata->msgdata[0] = 0x10; - pdata->msgdata[1] = bd->props->brightness; + pdata->msgdata[1] = bd->props.brightness; retval = usb_control_msg( pdata->udev, @@ -177,10 +177,9 @@ static int appledisplay_bl_get_brightness(struct backlight_device *bd) return pdata->msgdata[1]; } -static struct backlight_properties appledisplay_bl_data = { +static struct backlight_ops appledisplay_bl_data = { .get_brightness = appledisplay_bl_get_brightness, .update_status = appledisplay_bl_update_status, - .max_brightness = 0xFF }; static void appledisplay_work(struct work_struct *work) @@ -191,7 +190,7 @@ static void appledisplay_work(struct work_struct *work) retval = appledisplay_bl_get_brightness(pdata->bd); if (retval >= 0) - pdata->bd->props->brightness = retval; + pdata->bd->props.brightness = retval; /* Poll again in about 125ms if there's still a button pressed */ if (pdata->button_pressed) @@ -285,6 +284,8 @@ static int appledisplay_probe(struct usb_interface *iface, goto error; } + pdata->bd->props.max_brightness = 0xff; + /* Try to get brightness */ brightness = appledisplay_bl_get_brightness(pdata->bd); @@ -295,7 +296,7 @@ static int appledisplay_probe(struct usb_interface *iface, } /* Set brightness in backlight device */ - pdata->bd->props->brightness = brightness; + pdata->bd->props.brightness = brightness; /* save our data pointer in the interface device */ usb_set_intfdata(iface, pdata); diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 4de8d6252c3..8726c366971 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -1695,8 +1695,6 @@ static int __devinit aty128fb_setup(char *options) #ifdef CONFIG_FB_ATY128_BACKLIGHT #define MAX_LEVEL 0xFF -static struct backlight_properties aty128_bl_data; - static int aty128_bl_get_level_brightness(struct aty128fb_par *par, int level) { @@ -1730,12 +1728,12 @@ static int aty128_bl_update_status(struct backlight_device *bd) unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL); int level; - if (bd->props->power != FB_BLANK_UNBLANK || - bd->props->fb_blank != FB_BLANK_UNBLANK || + if (bd->props.power != FB_BLANK_UNBLANK || + bd->props.fb_blank != FB_BLANK_UNBLANK || !par->lcd_on) level = 0; else - level = bd->props->brightness; + level = bd->props.brightness; reg |= LVDS_BL_MOD_EN | LVDS_BLON; if (level > 0) { @@ -1779,19 +1777,18 @@ static int aty128_bl_update_status(struct backlight_device *bd) static int aty128_bl_get_brightness(struct backlight_device *bd) { - return bd->props->brightness; + return bd->props.brightness; } -static struct backlight_properties aty128_bl_data = { +static struct backlight_ops aty128_bl_data = { .get_brightness = aty128_bl_get_brightness, .update_status = aty128_bl_update_status, - .max_brightness = (FB_BACKLIGHT_LEVELS - 1), }; static void aty128_bl_set_power(struct fb_info *info, int power) { if (info->bl_dev) { - info->bl_dev->props->power = power; + info->bl_dev->props.power = power; backlight_update_status(info->bl_dev); } } @@ -1825,8 +1822,9 @@ static void aty128_bl_init(struct aty128fb_par *par) 63 * FB_BACKLIGHT_MAX / MAX_LEVEL, 219 * FB_BACKLIGHT_MAX / MAX_LEVEL); - bd->props->brightness = aty128_bl_data.max_brightness; - bd->props->power = FB_BLANK_UNBLANK; + bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1; + bd->props.brightness = bd->props.max_brightness; + bd->props.power = FB_BLANK_UNBLANK; backlight_update_status(bd); printk("aty128: Backlight initialized (%s)\n", name); diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 35ba2656759..a7e0062233f 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2114,8 +2114,6 @@ static int atyfb_pci_resume(struct pci_dev *pdev) #ifdef CONFIG_FB_ATY_BACKLIGHT #define MAX_LEVEL 0xFF -static struct backlight_properties aty_bl_data; - static int aty_bl_get_level_brightness(struct atyfb_par *par, int level) { struct fb_info *info = pci_get_drvdata(par->pdev); @@ -2139,11 +2137,11 @@ static int aty_bl_update_status(struct backlight_device *bd) unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par); int level; - if (bd->props->power != FB_BLANK_UNBLANK || - bd->props->fb_blank != FB_BLANK_UNBLANK) + if (bd->props.power != FB_BLANK_UNBLANK || + bd->props.fb_blank != FB_BLANK_UNBLANK) level = 0; else - level = bd->props->brightness; + level = bd->props.brightness; reg |= (BLMOD_EN | BIASMOD_EN); if (level > 0) { @@ -2160,13 +2158,12 @@ static int aty_bl_update_status(struct backlight_device *bd) static int aty_bl_get_brightness(struct backlight_device *bd) { - return bd->props->brightness; + return bd->props.brightness; } -static struct backlight_properties aty_bl_data = { +static struct backlight_ops aty_bl_data = { .get_brightness = aty_bl_get_brightness, .update_status = aty_bl_update_status, - .max_brightness = (FB_BACKLIGHT_LEVELS - 1), }; static void aty_bl_init(struct atyfb_par *par) @@ -2194,8 +2191,9 @@ static void aty_bl_init(struct atyfb_par *par) 0x3F * FB_BACKLIGHT_MAX / MAX_LEVEL, 0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL); - bd->props->brightness = aty_bl_data.max_brightness; - bd->props->power = FB_BLANK_UNBLANK; + bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1; + bd->props.brightness = bd->props.max_brightness; + bd->props.power = FB_BLANK_UNBLANK; backlight_update_status(bd); printk("aty: Backlight initialized (%s)\n", name); diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c index 8c775e6a7e0..0be25fa5540 100644 --- a/drivers/video/aty/radeon_backlight.c +++ b/drivers/video/aty/radeon_backlight.c @@ -19,8 +19,6 @@ #define MAX_RADEON_LEVEL 0xFF -static struct backlight_properties radeon_bl_data; - struct radeon_bl_privdata { struct radeonfb_info *rinfo; uint8_t negative; @@ -61,11 +59,11 @@ static int radeon_bl_update_status(struct backlight_device *bd) * backlight. This provides some greater power saving and the display * is useless without backlight anyway. */ - if (bd->props->power != FB_BLANK_UNBLANK || - bd->props->fb_blank != FB_BLANK_UNBLANK) + if (bd->props.power != FB_BLANK_UNBLANK || + bd->props.fb_blank != FB_BLANK_UNBLANK) level = 0; else - level = bd->props->brightness; + level = bd->props.brightness; del_timer_sync(&rinfo->lvds_timer); radeon_engine_idle(); @@ -126,13 +124,12 @@ static int radeon_bl_update_status(struct backlight_device *bd) static int radeon_bl_get_brightness(struct backlight_device *bd) { - return bd->props->brightness; + return bd->props.brightness; } -static struct backlight_properties radeon_bl_data = { +static struct backlight_ops radeon_bl_data = { .get_brightness = radeon_bl_get_brightness, .update_status = radeon_bl_update_status, - .max_brightness = (FB_BACKLIGHT_LEVELS - 1), }; void radeonfb_bl_init(struct radeonfb_info *rinfo) @@ -188,8 +185,9 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo) 63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL, 217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL); - bd->props->brightness = radeon_bl_data.max_brightness; - bd->props->power = FB_BLANK_UNBLANK; + bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1; + bd->props.brightness = bd->props.max_brightness; + bd->props.power = FB_BLANK_UNBLANK; backlight_update_status(bd); printk("radeonfb: Backlight initialized (%s)\n", name); diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 822a373d334..c65e81ff357 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -35,14 +35,14 @@ static int fb_notifier_callback(struct notifier_block *self, return 0; bd = container_of(self, struct backlight_device, fb_notif); - mutex_lock(&bd->props_lock); - if (bd->props) - if (!bd->props->check_fb || - bd->props->check_fb(evdata->info)) { - bd->props->fb_blank = *(int *)evdata->data; + mutex_lock(&bd->ops_lock); + if (bd->ops) + if (!bd->ops->check_fb || + bd->ops->check_fb(evdata->info)) { + bd->props.fb_blank = *(int *)evdata->data; backlight_update_status(bd); } - mutex_unlock(&bd->props_lock); + mutex_unlock(&bd->ops_lock); return 0; } @@ -71,15 +71,9 @@ static inline void backlight_unregister_fb(struct backlight_device *bd) static ssize_t backlight_show_power(struct class_device *cdev, char *buf) { - int rc = -ENXIO; struct backlight_device *bd = to_backlight_device(cdev); - mutex_lock(&bd->props_lock); - if (bd->props) - rc = sprintf(buf, "%d\n", bd->props->power); - mutex_unlock(&bd->props_lock); - - return rc; + return sprintf(buf, "%d\n", bd->props.power); } static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count) @@ -95,29 +89,23 @@ static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, if (size != count) return -EINVAL; - mutex_lock(&bd->props_lock); - if (bd->props) { + mutex_lock(&bd->ops_lock); + if (bd->ops) { pr_debug("backlight: set power to %d\n", power); - bd->props->power = power; + bd->props.power = power; backlight_update_status(bd); rc = count; } - mutex_unlock(&bd->props_lock); + mutex_unlock(&bd->ops_lock); return rc; } static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf) { - int rc = -ENXIO; struct backlight_device *bd = to_backlight_device(cdev); - mutex_lock(&bd->props_lock); - if (bd->props) - rc = sprintf(buf, "%d\n", bd->props->brightness); - mutex_unlock(&bd->props_lock); - - return rc; + return sprintf(buf, "%d\n", bd->props.brightness); } static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count) @@ -133,34 +121,28 @@ static ssize_t backlight_store_brightness(struct class_device *cdev, const char if (size != count) return -EINVAL; - mutex_lock(&bd->props_lock); - if (bd->props) { - if (brightness > bd->props->max_brightness) + mutex_lock(&bd->ops_lock); + if (bd->ops) { + if (brightness > bd->props.max_brightness) rc = -EINVAL; else { pr_debug("backlight: set brightness to %d\n", brightness); - bd->props->brightness = brightness; + bd->props.brightness = brightness; backlight_update_status(bd); rc = count; } } - mutex_unlock(&bd->props_lock); + mutex_unlock(&bd->ops_lock); return rc; } static ssize_t backlight_show_max_brightness(struct class_device *cdev, char *buf) { - int rc = -ENXIO; struct backlight_device *bd = to_backlight_device(cdev); - mutex_lock(&bd->props_lock); - if (bd->props) - rc = sprintf(buf, "%d\n", bd->props->max_brightness); - mutex_unlock(&bd->props_lock); - - return rc; + return sprintf(buf, "%d\n", bd->props.max_brightness); } static ssize_t backlight_show_actual_brightness(struct class_device *cdev, @@ -169,10 +151,10 @@ static ssize_t backlight_show_actual_brightness(struct class_device *cdev, int rc = -ENXIO; struct backlight_device *bd = to_backlight_device(cdev); - mutex_lock(&bd->props_lock); - if (bd->props && bd->props->get_brightness) - rc = sprintf(buf, "%d\n", bd->props->get_brightness(bd)); - mutex_unlock(&bd->props_lock); + mutex_lock(&bd->ops_lock); + if (bd->ops && bd->ops->get_brightness) + rc = sprintf(buf, "%d\n", bd->ops->get_brightness(bd)); + mutex_unlock(&bd->ops_lock); return rc; } @@ -211,7 +193,7 @@ static const struct class_device_attribute bl_class_device_attributes[] = { * respective framebuffer device). * @devdata: an optional pointer to be stored in the class_device. The * methods may retrieve it by using class_get_devdata(&bd->class_dev). - * @bp: the backlight properties structure. + * @ops: the backlight operations structure. * * Creates and registers new backlight class_device. Returns either an * ERR_PTR() or a pointer to the newly allocated device. @@ -219,21 +201,20 @@ static const struct class_device_attribute bl_class_device_attributes[] = { struct backlight_device *backlight_device_register(const char *name, struct device *dev, void *devdata, - struct backlight_properties *bp) + struct backlight_ops *ops) { int i, rc; struct backlight_device *new_bd; pr_debug("backlight_device_alloc: name=%s\n", name); - new_bd = kmalloc(sizeof(struct backlight_device), GFP_KERNEL); + new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL); if (!new_bd) return ERR_PTR(-ENOMEM); mutex_init(&new_bd->update_lock); - mutex_init(&new_bd->props_lock); - new_bd->props = bp; - memset(&new_bd->class_dev, 0, sizeof(new_bd->class_dev)); + mutex_init(&new_bd->ops_lock); + new_bd->ops = ops; new_bd->class_dev.class = &backlight_class; new_bd->class_dev.dev = dev; strlcpy(new_bd->class_dev.class_id, name, KOBJ_NAME_LEN); @@ -302,9 +283,9 @@ void backlight_device_unregister(struct backlight_device *bd) class_device_remove_file(&bd->class_dev, &bl_class_device_attributes[i]); - mutex_lock(&bd->props_lock); - bd->props = NULL; - mutex_unlock(&bd->props_lock); + mutex_lock(&bd->ops_lock); + bd->ops = NULL; + mutex_unlock(&bd->ops_lock); backlight_unregister_fb(bd); diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c index c1eba0e8a1b..05f36811ac9 100644 --- a/drivers/video/backlight/corgi_bl.c +++ b/drivers/video/backlight/corgi_bl.c @@ -34,11 +34,11 @@ static unsigned long corgibl_flags; static int corgibl_send_intensity(struct backlight_device *bd) { void (*corgi_kick_batt)(void); - int intensity = bd->props->brightness; + int intensity = bd->props.brightness; - if (bd->props->power != FB_BLANK_UNBLANK) + if (bd->props.power != FB_BLANK_UNBLANK) intensity = 0; - if (bd->props->fb_blank != FB_BLANK_UNBLANK) + if (bd->props.fb_blank != FB_BLANK_UNBLANK) intensity = 0; if (corgibl_flags & CORGIBL_SUSPENDED) intensity = 0; @@ -103,7 +103,7 @@ void corgibl_limit_intensity(int limit) EXPORT_SYMBOL(corgibl_limit_intensity); -static struct backlight_properties corgibl_data = { +static struct backlight_ops corgibl_ops = { .get_brightness = corgibl_get_intensity, .update_status = corgibl_send_intensity, }; @@ -113,19 +113,19 @@ static int corgibl_probe(struct platform_device *pdev) struct corgibl_machinfo *machinfo = pdev->dev.platform_data; bl_machinfo = machinfo; - corgibl_data.max_brightness = machinfo->max_intensity; if (!machinfo->limit_mask) machinfo->limit_mask = -1; corgi_backlight_device = backlight_device_register ("corgi-bl", - &pdev->dev, NULL, &corgibl_data); + &pdev->dev, NULL, &corgibl_ops); if (IS_ERR (corgi_backlight_device)) return PTR_ERR (corgi_backlight_device); platform_set_drvdata(pdev, corgi_backlight_device); - corgibl_data.power = FB_BLANK_UNBLANK; - corgibl_data.brightness = machinfo->default_intensity; + corgi_backlight_device->props.max_brightness = machinfo->max_intensity; + corgi_backlight_device->props.power = FB_BLANK_UNBLANK; + corgi_backlight_device->props.brightness = machinfo->default_intensity; corgibl_send_intensity(corgi_backlight_device); printk("Corgi Backlight Driver Initialized.\n"); diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index e7444c8f289..0899fccbd57 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -33,11 +33,11 @@ static void hp680bl_send_intensity(struct backlight_device *bd) { unsigned long flags; u16 v; - int intensity = bd->props->brightness; + int intensity = bd->props.brightness; - if (bd->props->power != FB_BLANK_UNBLANK) + if (bd->props.power != FB_BLANK_UNBLANK) intensity = 0; - if (bd->props->fb_blank != FB_BLANK_UNBLANK) + if (bd->props.fb_blank != FB_BLANK_UNBLANK) intensity = 0; if (hp680bl_suspended) intensity = 0; @@ -98,8 +98,7 @@ static int hp680bl_get_intensity(struct backlight_device *bd) return current_intensity; } -static struct backlight_properties hp680bl_data = { - .max_brightness = HP680_MAX_INTENSITY, +static struct backlight_ops hp680bl_ops = { .get_brightness = hp680bl_get_intensity, .update_status = hp680bl_set_intensity, }; @@ -109,13 +108,14 @@ static int __init hp680bl_probe(struct platform_device *pdev) struct backlight_device *bd; bd = backlight_device_register ("hp680-bl", &pdev->dev, NULL, - &hp680bl_data); + &hp680bl_ops); if (IS_ERR(bd)) return PTR_ERR(bd); platform_set_drvdata(pdev, bd); - bd->props->brightness = HP680_DEFAULT_INTENSITY; + bd->props.max_brightness = HP680_MAX_INTENSITY; + bd->props.brightness = HP680_DEFAULT_INTENSITY; hp680bl_send_intensity(bd); return 0; diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index 430ba018a89..6ef8f0a7a13 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -31,11 +31,11 @@ static int fb_notifier_callback(struct notifier_block *self, return 0; ld = container_of(self, struct lcd_device, fb_notif); - mutex_lock(&ld->props_lock); - if (ld->props) - if (!ld->props->check_fb || ld->props->check_fb(evdata->info)) - ld->props->set_power(ld, *(int *)evdata->data); - mutex_unlock(&ld->props_lock); + mutex_lock(&ld->ops_lock); + if (ld->ops) + if (!ld->ops->check_fb || ld->ops->check_fb(evdata->info)) + ld->ops->set_power(ld, *(int *)evdata->data); + mutex_unlock(&ld->ops_lock); return 0; } @@ -66,12 +66,12 @@ static ssize_t lcd_show_power(struct class_device *cdev, char *buf) int rc; struct lcd_device *ld = to_lcd_device(cdev); - mutex_lock(&ld->props_lock); - if (ld->props && ld->props->get_power) - rc = sprintf(buf, "%d\n", ld->props->get_power(ld)); + mutex_lock(&ld->ops_lock); + if (ld->ops && ld->ops->get_power) + rc = sprintf(buf, "%d\n", ld->ops->get_power(ld)); else rc = -ENXIO; - mutex_unlock(&ld->props_lock); + mutex_unlock(&ld->ops_lock); return rc; } @@ -89,13 +89,13 @@ static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_ if (size != count) return -EINVAL; - mutex_lock(&ld->props_lock); - if (ld->props && ld->props->set_power) { + mutex_lock(&ld->ops_lock); + if (ld->ops && ld->ops->set_power) { pr_debug("lcd: set power to %d\n", power); - ld->props->set_power(ld, power); + ld->ops->set_power(ld, power); rc = count; } - mutex_unlock(&ld->props_lock); + mutex_unlock(&ld->ops_lock); return rc; } @@ -105,10 +105,10 @@ static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf) int rc = -ENXIO; struct lcd_device *ld = to_lcd_device(cdev); - mutex_lock(&ld->props_lock); - if (ld->props && ld->props->get_contrast) - rc = sprintf(buf, "%d\n", ld->props->get_contrast(ld)); - mutex_unlock(&ld->props_lock); + mutex_lock(&ld->ops_lock); + if (ld->ops && ld->ops->get_contrast) + rc = sprintf(buf, "%d\n", ld->ops->get_contrast(ld)); + mutex_unlock(&ld->ops_lock); return rc; } @@ -126,28 +126,22 @@ static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, si if (size != count) return -EINVAL; - mutex_lock(&ld->props_lock); - if (ld->props && ld->props->set_contrast) { + mutex_lock(&ld->ops_lock); + if (ld->ops && ld->ops->set_contrast) { pr_debug("lcd: set contrast to %d\n", contrast); - ld->props->set_contrast(ld, contrast); + ld->ops->set_contrast(ld, contrast); rc = count; } - mutex_unlock(&ld->props_lock); + mutex_unlock(&ld->ops_lock); return rc; } static ssize_t lcd_show_max_contrast(struct class_device *cdev, char *buf) { - int rc = -ENXIO; struct lcd_device *ld = to_lcd_device(cdev); - mutex_lock(&ld->props_lock); - if (ld->props) - rc = sprintf(buf, "%d\n", ld->props->max_contrast); - mutex_unlock(&ld->props_lock); - - return rc; + return sprintf(buf, "%d\n", ld->props.max_contrast); } static void lcd_class_release(struct class_device *dev) @@ -180,27 +174,26 @@ static const struct class_device_attribute lcd_class_device_attributes[] = { * respective framebuffer device). * @devdata: an optional pointer to be stored in the class_device. The * methods may retrieve it by using class_get_devdata(ld->class_dev). - * @lp: the lcd properties structure. + * @ops: the lcd operations structure. * * Creates and registers a new lcd class_device. Returns either an ERR_PTR() * or a pointer to the newly allocated device. */ struct lcd_device *lcd_device_register(const char *name, void *devdata, - struct lcd_properties *lp) + struct lcd_ops *ops) { int i, rc; struct lcd_device *new_ld; pr_debug("lcd_device_register: name=%s\n", name); - new_ld = kmalloc(sizeof(struct lcd_device), GFP_KERNEL); + new_ld = kzalloc(sizeof(struct lcd_device), GFP_KERNEL); if (!new_ld) return ERR_PTR(-ENOMEM); - mutex_init(&new_ld->props_lock); + mutex_init(&new_ld->ops_lock); mutex_init(&new_ld->update_lock); - new_ld->props = lp; - memset(&new_ld->class_dev, 0, sizeof(new_ld->class_dev)); + new_ld->ops = ops; new_ld->class_dev.class = &lcd_class; strlcpy(new_ld->class_dev.class_id, name, KOBJ_NAME_LEN); class_set_devdata(&new_ld->class_dev, devdata); @@ -253,9 +246,9 @@ void lcd_device_unregister(struct lcd_device *ld) class_device_remove_file(&ld->class_dev, &lcd_class_device_attributes[i]); - mutex_lock(&ld->props_lock); - ld->props = NULL; - mutex_unlock(&ld->props_lock); + mutex_lock(&ld->ops_lock); + ld->ops = NULL; + mutex_unlock(&ld->ops_lock); lcd_unregister_fb(ld); class_device_unregister(&ld->class_dev); } diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c index 3c5abbf0d04..d1312477813 100644 --- a/drivers/video/backlight/locomolcd.c +++ b/drivers/video/backlight/locomolcd.c @@ -112,11 +112,11 @@ static int current_intensity; static int locomolcd_set_intensity(struct backlight_device *bd) { - int intensity = bd->props->brightness; + int intensity = bd->props.brightness; - if (bd->props->power != FB_BLANK_UNBLANK) + if (bd->props.power != FB_BLANK_UNBLANK) intensity = 0; - if (bd->props->fb_blank != FB_BLANK_UNBLANK) + if (bd->props.fb_blank != FB_BLANK_UNBLANK) intensity = 0; if (locomolcd_flags & LOCOMOLCD_SUSPENDED) intensity = 0; @@ -141,10 +141,9 @@ static int locomolcd_get_intensity(struct backlight_device *bd) return current_intensity; } -static struct backlight_properties locomobl_data = { +static struct backlight_ops locomobl_data = { .get_brightness = locomolcd_get_intensity, .update_status = locomolcd_set_intensity, - .max_brightness = 4, }; #ifdef CONFIG_PM @@ -189,7 +188,8 @@ static int locomolcd_probe(struct locomo_dev *ldev) return PTR_ERR (locomolcd_bl_device); /* Set up frontlight so that screen is readable */ - locomobl_data.brightness = 2; + locomolcd_bl_device->props.max_brightness = 4, + locomolcd_bl_device->props.brightness = 2; locomolcd_set_intensity(locomolcd_bl_device); return 0; diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c index 42d6acd96c1..70226935786 100644 --- a/drivers/video/backlight/progear_bl.c +++ b/drivers/video/backlight/progear_bl.c @@ -35,11 +35,11 @@ static struct pci_dev *sb_dev = NULL; static int progearbl_set_intensity(struct backlight_device *bd) { - int intensity = bd->props->brightness; + int intensity = bd->props.brightness; - if (bd->props->power != FB_BLANK_UNBLANK) + if (bd->props.power != FB_BLANK_UNBLANK) intensity = 0; - if (bd->props->fb_blank != FB_BLANK_UNBLANK) + if (bd->props.fb_blank != FB_BLANK_UNBLANK) intensity = 0; pci_write_config_byte(pmu_dev, PMU_LPCR, intensity + HW_LEVEL_MIN); @@ -55,7 +55,7 @@ static int progearbl_get_intensity(struct backlight_device *bd) return intensity - HW_LEVEL_MIN; } -static struct backlight_properties progearbl_data = { +static struct backlight_ops progearbl_ops = { .get_brightness = progearbl_get_intensity, .update_status = progearbl_set_intensity, }; @@ -84,15 +84,15 @@ static int progearbl_probe(struct platform_device *pdev) progear_backlight_device = backlight_device_register("progear-bl", &pdev->dev, NULL, - &progearbl_data); + &progearbl_ops); if (IS_ERR(progear_backlight_device)) return PTR_ERR(progear_backlight_device); platform_set_drvdata(pdev, progear_backlight_device); - progearbl_data.power = FB_BLANK_UNBLANK; - progearbl_data.brightness = HW_LEVEL_MAX - HW_LEVEL_MIN; - progearbl_data.max_brightness = HW_LEVEL_MAX - HW_LEVEL_MIN; + progear_backlight_device->props.power = FB_BLANK_UNBLANK; + progear_backlight_device->props.brightness = HW_LEVEL_MAX - HW_LEVEL_MIN; + progear_backlight_device->props.max_brightness = HW_LEVEL_MAX - HW_LEVEL_MIN; progearbl_set_intensity(progear_backlight_device); return 0; diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c index 2a17dfc232f..af313bf1a2d 100644 --- a/drivers/video/chipsfb.c +++ b/drivers/video/chipsfb.c @@ -395,7 +395,7 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent) /* turn on the backlight */ mutex_lock(&pmac_backlight_mutex); if (pmac_backlight) { - pmac_backlight->props->power = FB_BLANK_UNBLANK; + pmac_backlight->props.power = FB_BLANK_UNBLANK; backlight_update_status(pmac_backlight); } mutex_unlock(&pmac_backlight_mutex); diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c index 0e2bc519dca..b7016e9b9e1 100644 --- a/drivers/video/nvidia/nv_backlight.c +++ b/drivers/video/nvidia/nv_backlight.c @@ -54,11 +54,11 @@ static int nvidia_bl_update_status(struct backlight_device *bd) if (!par->FlatPanel) return 0; - if (bd->props->power != FB_BLANK_UNBLANK || - bd->props->fb_blank != FB_BLANK_UNBLANK) + if (bd->props.power != FB_BLANK_UNBLANK || + bd->props.fb_blank != FB_BLANK_UNBLANK) level = 0; else - level = bd->props->brightness; + level = bd->props.brightness; tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF; tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC; @@ -81,13 +81,12 @@ static int nvidia_bl_update_status(struct backlight_device *bd) static int nvidia_bl_get_brightness(struct backlight_device *bd) { - return bd->props->brightness; + return bd->props.brightness; } -static struct backlight_properties nvidia_bl_data = { +static struct backlight_ops nvidia_bl_ops = { .get_brightness = nvidia_bl_get_brightness, .update_status = nvidia_bl_update_status, - .max_brightness = (FB_BACKLIGHT_LEVELS - 1), }; void nvidia_bl_init(struct nvidia_par *par) @@ -107,7 +106,7 @@ void nvidia_bl_init(struct nvidia_par *par) snprintf(name, sizeof(name), "nvidiabl%d", info->node); - bd = backlight_device_register(name, info->dev, par, &nvidia_bl_data); + bd = backlight_device_register(name, info->dev, par, &nvidia_bl_ops); if (IS_ERR(bd)) { info->bl_dev = NULL; printk(KERN_WARNING "nvidia: Backlight registration failed\n"); @@ -119,8 +118,9 @@ void nvidia_bl_init(struct nvidia_par *par) 0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL, 0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL); - bd->props->brightness = nvidia_bl_data.max_brightness; - bd->props->power = FB_BLANK_UNBLANK; + bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1; + bd->props.brightness = nvidia_bl_data.max_brightness; + bd->props.power = FB_BLANK_UNBLANK; backlight_update_status(bd); printk("nvidia: Backlight initialized (%s)\n", name); diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 3a75def01b2..f8a3d608b20 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -308,11 +308,11 @@ static int riva_bl_update_status(struct backlight_device *bd) U032 tmp_pcrt, tmp_pmc; int level; - if (bd->props->power != FB_BLANK_UNBLANK || - bd->props->fb_blank != FB_BLANK_UNBLANK) + if (bd->props.power != FB_BLANK_UNBLANK || + bd->props.fb_blank != FB_BLANK_UNBLANK) level = 0; else - level = bd->props->brightness; + level = bd->props.brightness; tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF; tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC; @@ -329,13 +329,12 @@ static int riva_bl_update_status(struct backlight_device *bd) static int riva_bl_get_brightness(struct backlight_device *bd) { - return bd->props->brightness; + return bd->props.brightness; } -static struct backlight_properties riva_bl_data = { +static struct backlight_ops riva_bl_ops = { .get_brightness = riva_bl_get_brightness, .update_status = riva_bl_update_status, - .max_brightness = (FB_BACKLIGHT_LEVELS - 1), }; static void riva_bl_init(struct riva_par *par) @@ -355,7 +354,7 @@ static void riva_bl_init(struct riva_par *par) snprintf(name, sizeof(name), "rivabl%d", info->node); - bd = backlight_device_register(name, info->dev, par, &riva_bl_data); + bd = backlight_device_register(name, info->dev, par, &riva_bl_ops); if (IS_ERR(bd)) { info->bl_dev = NULL; printk(KERN_WARNING "riva: Backlight registration failed\n"); @@ -367,8 +366,9 @@ static void riva_bl_init(struct riva_par *par) MIN_LEVEL * FB_BACKLIGHT_MAX / MAX_LEVEL, FB_BACKLIGHT_MAX); - bd->props->brightness = riva_bl_data.max_brightness; - bd->props->power = FB_BLANK_UNBLANK; + bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1; + bd->props.brightness = riva_bl_data.max_brightness; + bd->props.power = FB_BLANK_UNBLANK; backlight_update_status(bd); printk("riva: Backlight initialized (%s)\n", name); diff --git a/include/linux/backlight.h b/include/linux/backlight.h index 43c6d55644b..1023ba0d6e5 100644 --- a/include/linux/backlight.h +++ b/include/linux/backlight.h @@ -14,8 +14,8 @@ /* Notes on locking: * - * backlight_device->props_lock is an internal backlight lock protecting the - * props field and no code outside the core should need to touch it. + * backlight_device->ops_lock is an internal backlight lock protecting the + * ops pointer and no code outside the core should need to touch it. * * Access to update_status() is serialised by the update_lock mutex since * most drivers seem to need this and historically get it wrong. @@ -30,9 +30,7 @@ struct backlight_device; struct fb_info; -/* This structure defines all the properties of a backlight - (usually attached to a LCD). */ -struct backlight_properties { +struct backlight_ops { /* Notify the backlight driver some property has changed */ int (*update_status)(struct backlight_device *); /* Return the current backlight brightness (accounting for power, @@ -41,7 +39,10 @@ struct backlight_properties { /* Check if given framebuffer device is the one bound to this backlight; return 0 if not, !=0 if it is. If NULL, backlight always matches the fb. */ int (*check_fb)(struct fb_info *); +}; +/* This structure defines all the properties of a backlight */ +struct backlight_properties { /* Current User requested brightness (0 - max_brightness) */ int brightness; /* Maximal value for brightness (read-only) */ @@ -54,14 +55,18 @@ struct backlight_properties { }; struct backlight_device { - /* This protects the 'props' field. If 'props' is NULL, the driver that - registered this device has been unloaded, and if class_get_devdata() - points to something in the body of that driver, it is also invalid. */ - struct mutex props_lock; - /* If this is NULL, the backing module is unloaded */ - struct backlight_properties *props; + /* Backlight properties */ + struct backlight_properties props; + /* Serialise access to update_status method */ struct mutex update_lock; + + /* This protects the 'ops' field. If 'ops' is NULL, the driver that + registered this device has been unloaded, and if class_get_devdata() + points to something in the body of that driver, it is also invalid. */ + struct mutex ops_lock; + struct backlight_ops *ops; + /* The framebuffer notifier block */ struct notifier_block fb_notif; /* The class device structure */ @@ -71,13 +76,13 @@ struct backlight_device { static inline void backlight_update_status(struct backlight_device *bd) { mutex_lock(&bd->update_lock); - if (bd->props && bd->props->update_status) - bd->props->update_status(bd); + if (bd->ops && bd->ops->update_status) + bd->ops->update_status(bd); mutex_unlock(&bd->update_lock); } extern struct backlight_device *backlight_device_register(const char *name, - struct device *dev,void *devdata,struct backlight_properties *bp); + struct device *dev, void *devdata, struct backlight_ops *ops); extern void backlight_device_unregister(struct backlight_device *bd); #define to_backlight_device(obj) container_of(obj, struct backlight_device, class_dev) diff --git a/include/linux/lcd.h b/include/linux/lcd.h index 46970af2ca8..598793c0745 100644 --- a/include/linux/lcd.h +++ b/include/linux/lcd.h @@ -14,7 +14,7 @@ /* Notes on locking: * - * lcd_device->props_lock is an internal backlight lock protecting the props + * lcd_device->ops_lock is an internal backlight lock protecting the ops * field and no code outside the core should need to touch it. * * Access to set_power() is serialised by the update_lock mutex since @@ -30,15 +30,17 @@ struct lcd_device; struct fb_info; -/* This structure defines all the properties of a LCD flat panel. */ struct lcd_properties { + /* The maximum value for contrast (read-only) */ + int max_contrast; +}; + +struct lcd_ops { /* Get the LCD panel power status (0: full on, 1..3: controller power on, flat panel power off, 4: full off), see FB_BLANK_XXX */ int (*get_power)(struct lcd_device *); /* Enable or disable power to the LCD (0: on; 4: off, see FB_BLANK_XXX) */ int (*set_power)(struct lcd_device *, int power); - /* The maximum value for contrast (read-only) */ - int max_contrast; /* Get the current contrast setting (0-max_contrast) */ int (*get_contrast)(struct lcd_device *); /* Set LCD panel contrast */ @@ -49,12 +51,13 @@ struct lcd_properties { }; struct lcd_device { - /* This protects the 'props' field. If 'props' is NULL, the driver that + struct lcd_properties props; + /* This protects the 'ops' field. If 'ops' is NULL, the driver that registered this device has been unloaded, and if class_get_devdata() points to something in the body of that driver, it is also invalid. */ - struct mutex props_lock; + struct mutex ops_lock; /* If this is NULL, the backing module is unloaded */ - struct lcd_properties *props; + struct lcd_ops *ops; /* Serialise access to set_power method */ struct mutex update_lock; /* The framebuffer notifier block */ @@ -66,13 +69,13 @@ struct lcd_device { static inline void lcd_set_power(struct lcd_device *ld, int power) { mutex_lock(&ld->update_lock); - if (ld->props && ld->props->set_power) - ld->props->set_power(ld, power); + if (ld->ops && ld->ops->set_power) + ld->ops->set_power(ld, power); mutex_unlock(&ld->update_lock); } extern struct lcd_device *lcd_device_register(const char *name, - void *devdata, struct lcd_properties *lp); + void *devdata, struct lcd_ops *ops); extern void lcd_device_unregister(struct lcd_device *ld); #define to_lcd_device(obj) container_of(obj, struct lcd_device, class_dev) -- cgit v1.2.3-70-g09d2 From 946b960d13c15f050a3b848987aaca79f6a459b7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 14 Feb 2007 13:40:14 -0800 Subject: USB: add driver for iowarrior devices. The ioctl is commented out for now, until we verify some userspace application issues. Cc: Christian Lucht Cc: Robert Marquardt Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/Kconfig | 14 + drivers/usb/misc/Makefile | 1 + drivers/usb/misc/iowarrior.c | 925 ++++++++++++++++++++++++++++++++++++++++++ include/linux/usb/iowarrior.h | 33 ++ 4 files changed, 973 insertions(+) create mode 100644 drivers/usb/misc/iowarrior.c create mode 100644 include/linux/usb/iowarrior.h (limited to 'drivers/usb/misc') diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 4907e8b8007..9c7eb6144d0 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -244,6 +244,20 @@ config USB_TRANCEVIBRATOR To compile this driver as a module, choose M here: the module will be called trancevibrator. +config USB_IOWARRIOR + tristate "IO Warrior driver support" + depends on USB + help + Say Y here if you want to support the IO Warrior devices from Code + Mercenaries. This includes support for the following devices: + IO Warrior 40 + IO Warrior 24 + IO Warrior 56 + IO Warrior 24 Power Vampire + + To compile this driver as a module, choose M here: the + module will be called iowarrior. + config USB_TEST tristate "USB testing driver (DEVELOPMENT)" depends on USB && USB_DEVICEFS && EXPERIMENTAL diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index dac2d5b7156..b68e6b774f1 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_EMI62) += emi62.o obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o obj-$(CONFIG_USB_IDMOUSE) += idmouse.o +obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o obj-$(CONFIG_USB_LCD) += usblcd.o obj-$(CONFIG_USB_LD) += ldusb.o obj-$(CONFIG_USB_LED) += usbled.o diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c new file mode 100644 index 00000000000..d69665c8de0 --- /dev/null +++ b/drivers/usb/misc/iowarrior.c @@ -0,0 +1,925 @@ +/* + * Native support for the I/O-Warrior USB devices + * + * Copyright (c) 2003-2005 Code Mercenaries GmbH + * written by Christian Lucht + * + * based on + + * usb-skeleton.c by Greg Kroah-Hartman + * brlvger.c by Stephane Dalton + * and St�hane Doyon + * + * Released under the GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Version Information */ +#define DRIVER_VERSION "v0.4.0" +#define DRIVER_AUTHOR "Christian Lucht " +#define DRIVER_DESC "USB IO-Warrior driver (Linux 2.6.x)" + +#define USB_VENDOR_ID_CODEMERCS 1984 +/* low speed iowarrior */ +#define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500 +#define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501 +#define USB_DEVICE_ID_CODEMERCS_IOWPV1 0x1511 +#define USB_DEVICE_ID_CODEMERCS_IOWPV2 0x1512 +/* full speed iowarrior */ +#define USB_DEVICE_ID_CODEMERCS_IOW56 0x1503 + +/* Get a minor range for your devices from the usb maintainer */ +#ifdef CONFIG_USB_DYNAMIC_MINORS +#define IOWARRIOR_MINOR_BASE 0 +#else +#define IOWARRIOR_MINOR_BASE 208 // SKELETON_MINOR_BASE 192 + 16, not offical yet +#endif + +/* interrupt input queue size */ +#define MAX_INTERRUPT_BUFFER 16 +/* + maximum number of urbs that are submitted for writes at the same time, + this applies to the IOWarrior56 only! + IOWarrior24 and IOWarrior40 use synchronous usb_control_msg calls. +*/ +#define MAX_WRITES_IN_FLIGHT 4 + +/* Use our own dbg macro */ +#undef dbg +#define dbg( format, arg... ) do { if( debug ) printk( KERN_DEBUG __FILE__ ": " format "\n" , ## arg ); } while ( 0 ) + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* Module parameters */ +static int debug = 0; +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "debug=1 enables debugging messages"); + +static struct usb_driver iowarrior_driver; + +/*--------------*/ +/* data */ +/*--------------*/ + +/* Structure to hold all of our device specific stuff */ +struct iowarrior { + struct mutex mutex; /* locks this structure */ + struct usb_device *udev; /* save off the usb device pointer */ + struct usb_interface *interface; /* the interface for this device */ + unsigned char minor; /* the starting minor number for this device */ + struct usb_endpoint_descriptor *int_out_endpoint; /* endpoint for reading (needed for IOW56 only) */ + struct usb_endpoint_descriptor *int_in_endpoint; /* endpoint for reading */ + struct urb *int_in_urb; /* the urb for reading data */ + unsigned char *int_in_buffer; /* buffer for data to be read */ + unsigned char serial_number; /* to detect lost packages */ + unsigned char *read_queue; /* size is MAX_INTERRUPT_BUFFER * packet size */ + wait_queue_head_t read_wait; + wait_queue_head_t write_wait; /* wait-queue for writing to the device */ + atomic_t write_busy; /* number of write-urbs submitted */ + atomic_t read_idx; + atomic_t intr_idx; + spinlock_t intr_idx_lock; /* protects intr_idx */ + atomic_t overflow_flag; /* signals an index 'rollover' */ + int present; /* this is 1 as long as the device is connected */ + int opened; /* this is 1 if the device is currently open */ + char chip_serial[9]; /* the serial number string of the chip connected */ + int report_size; /* number of bytes in a report */ + u16 product_id; +}; + +/*--------------*/ +/* globals */ +/*--------------*/ +/* prevent races between open() and disconnect() */ +static DECLARE_MUTEX(disconnect_sem); + +/* + * USB spec identifies 5 second timeouts. + */ +#define GET_TIMEOUT 5 +#define USB_REQ_GET_REPORT 0x01 +//#if 0 +static int usb_get_report(struct usb_device *dev, + struct usb_host_interface *inter, unsigned char type, + unsigned char id, void *buf, int size) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_REPORT, + USB_DIR_IN | USB_TYPE_CLASS | + USB_RECIP_INTERFACE, (type << 8) + id, + inter->desc.bInterfaceNumber, buf, size, + GET_TIMEOUT); +} +//#endif + +#define USB_REQ_SET_REPORT 0x09 + +static int usb_set_report(struct usb_interface *intf, unsigned char type, + unsigned char id, void *buf, int size) +{ + return usb_control_msg(interface_to_usbdev(intf), + usb_sndctrlpipe(interface_to_usbdev(intf), 0), + USB_REQ_SET_REPORT, + USB_TYPE_CLASS | USB_RECIP_INTERFACE, + (type << 8) + id, + intf->cur_altsetting->desc.bInterfaceNumber, buf, + size, 1); +} + +/*---------------------*/ +/* driver registration */ +/*---------------------*/ +/* table of devices that work with this driver */ +static struct usb_device_id iowarrior_ids[] = { + {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40)}, + {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24)}, + {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV1)}, + {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV2)}, + {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW56)}, + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, iowarrior_ids); + +/* + * USB callback handler for reading data + */ +static void iowarrior_callback(struct urb *urb) +{ + struct iowarrior *dev = (struct iowarrior *)urb->context; + int intr_idx; + int read_idx; + int aux_idx; + int offset; + int status; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + return; + default: + goto exit; + } + + spin_lock(&dev->intr_idx_lock); + intr_idx = atomic_read(&dev->intr_idx); + /* aux_idx become previous intr_idx */ + aux_idx = (intr_idx == 0) ? (MAX_INTERRUPT_BUFFER - 1) : (intr_idx - 1); + read_idx = atomic_read(&dev->read_idx); + + /* queue is not empty and it's interface 0 */ + if ((intr_idx != read_idx) + && (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0)) { + /* + 1 for serial number */ + offset = aux_idx * (dev->report_size + 1); + if (!memcmp + (dev->read_queue + offset, urb->transfer_buffer, + dev->report_size)) { + /* equal values on interface 0 will be ignored */ + spin_unlock(&dev->intr_idx_lock); + goto exit; + } + } + + /* aux_idx become next intr_idx */ + aux_idx = (intr_idx == (MAX_INTERRUPT_BUFFER - 1)) ? 0 : (intr_idx + 1); + if (read_idx == aux_idx) { + /* queue full, dropping oldest input */ + read_idx = (++read_idx == MAX_INTERRUPT_BUFFER) ? 0 : read_idx; + atomic_set(&dev->read_idx, read_idx); + atomic_set(&dev->overflow_flag, 1); + } + + /* +1 for serial number */ + offset = intr_idx * (dev->report_size + 1); + memcpy(dev->read_queue + offset, urb->transfer_buffer, + dev->report_size); + *(dev->read_queue + offset + (dev->report_size)) = dev->serial_number++; + + atomic_set(&dev->intr_idx, aux_idx); + spin_unlock(&dev->intr_idx_lock); + /* tell the blocking read about the new data */ + wake_up_interruptible(&dev->read_wait); + +exit: + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status) + dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d", + __FUNCTION__, status); + +} + +/* + * USB Callback handler for write-ops + */ +static void iowarrior_write_callback(struct urb *urb) +{ + struct iowarrior *dev; + dev = (struct iowarrior *)urb->context; + /* sync/async unlink faults aren't errors */ + if (urb->status && + !(urb->status == -ENOENT || + urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) { + dbg("%s - nonzero write bulk status received: %d", + __func__, urb->status); + } + /* free up our allocated buffer */ + usb_buffer_free(urb->dev, urb->transfer_buffer_length, + urb->transfer_buffer, urb->transfer_dma); + /* tell a waiting writer the interrupt-out-pipe is available again */ + atomic_dec(&dev->write_busy); + wake_up_interruptible(&dev->write_wait); +} + +/** + * iowarrior_delete + */ +static inline void iowarrior_delete(struct iowarrior *dev) +{ + dbg("%s - minor %d", __func__, dev->minor); + kfree(dev->int_in_buffer); + usb_free_urb(dev->int_in_urb); + kfree(dev->read_queue); + kfree(dev); +} + +/*---------------------*/ +/* fops implementation */ +/*---------------------*/ + +static int read_index(struct iowarrior *dev) +{ + int intr_idx, read_idx; + + read_idx = atomic_read(&dev->read_idx); + intr_idx = atomic_read(&dev->intr_idx); + + return (read_idx == intr_idx ? -1 : read_idx); +} + +/** + * iowarrior_read + */ +static ssize_t iowarrior_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct iowarrior *dev; + int read_idx; + int offset; + + dev = (struct iowarrior *)file->private_data; + + /* verify that the device wasn't unplugged */ + if (dev == NULL || !dev->present) + return -ENODEV; + + dbg("%s - minor %d, count = %zd", __func__, dev->minor, count); + + /* read count must be packet size (+ time stamp) */ + if ((count != dev->report_size) + && (count != (dev->report_size + 1))) + return -EINVAL; + + /* repeat until no buffer overrun in callback handler occur */ + do { + atomic_set(&dev->overflow_flag, 0); + if ((read_idx = read_index(dev)) == -1) { + /* queue emty */ + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + else { + //next line will return when there is either new data, or the device is unplugged + int r = wait_event_interruptible(dev->read_wait, + (!dev->present + || (read_idx = + read_index + (dev)) != + -1)); + if (r) { + //we were interrupted by a signal + return -ERESTART; + } + if (!dev->present) { + //The device was unplugged + return -ENODEV; + } + if (read_idx == -1) { + // Can this happen ??? + return 0; + } + } + } + + offset = read_idx * (dev->report_size + 1); + if (copy_to_user(buffer, dev->read_queue + offset, count)) { + return -EFAULT; + } + } while (atomic_read(&dev->overflow_flag)); + + read_idx = ++read_idx == MAX_INTERRUPT_BUFFER ? 0 : read_idx; + atomic_set(&dev->read_idx, read_idx); + return count; +} + +/* + * iowarrior_write + */ +static ssize_t iowarrior_write(struct file *file, + const char __user *user_buffer, + size_t count, loff_t *ppos) +{ + struct iowarrior *dev; + int retval = 0; + char *buf = NULL; /* for IOW24 and IOW56 we need a buffer */ + struct urb *int_out_urb = NULL; + + dev = (struct iowarrior *)file->private_data; + + mutex_lock(&dev->mutex); + /* verify that the device wasn't unplugged */ + if (dev == NULL || !dev->present) { + retval = -ENODEV; + goto exit; + } + dbg("%s - minor %d, count = %zd", __func__, dev->minor, count); + /* if count is 0 we're already done */ + if (count == 0) { + retval = 0; + goto exit; + } + /* We only accept full reports */ + if (count != dev->report_size) { + retval = -EINVAL; + goto exit; + } + switch (dev->product_id) { + case USB_DEVICE_ID_CODEMERCS_IOW24: + case USB_DEVICE_ID_CODEMERCS_IOWPV1: + case USB_DEVICE_ID_CODEMERCS_IOWPV2: + case USB_DEVICE_ID_CODEMERCS_IOW40: + /* IOW24 and IOW40 use a synchronous call */ + buf = kmalloc(8, GFP_KERNEL); /* 8 bytes are enough for both products */ + if (!buf) { + retval = -ENOMEM; + goto exit; + } + if (copy_from_user(buf, user_buffer, count)) { + retval = -EFAULT; + kfree(buf); + goto exit; + } + retval = usb_set_report(dev->interface, 2, 0, buf, count); + kfree(buf); + goto exit; + break; + case USB_DEVICE_ID_CODEMERCS_IOW56: + /* The IOW56 uses asynchronous IO and more urbs */ + if (atomic_read(&dev->write_busy) == MAX_WRITES_IN_FLIGHT) { + /* Wait until we are below the limit for submitted urbs */ + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto exit; + } else { + retval = wait_event_interruptible(dev->write_wait, + (!dev->present || (atomic_read (&dev-> write_busy) < MAX_WRITES_IN_FLIGHT))); + if (retval) { + /* we were interrupted by a signal */ + retval = -ERESTART; + goto exit; + } + if (!dev->present) { + /* The device was unplugged */ + retval = -ENODEV; + goto exit; + } + if (!dev->opened) { + /* We were closed while waiting for an URB */ + retval = -ENODEV; + goto exit; + } + } + } + atomic_inc(&dev->write_busy); + int_out_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!int_out_urb) { + retval = -ENOMEM; + dbg("%s Unable to allocate urb ", __func__); + goto error; + } + buf = usb_buffer_alloc(dev->udev, dev->report_size, + GFP_KERNEL, &int_out_urb->transfer_dma); + if (!buf) { + retval = -ENOMEM; + dbg("%s Unable to allocate buffer ", __func__); + goto error; + } + usb_fill_int_urb(int_out_urb, dev->udev, + usb_sndintpipe(dev->udev, + dev->int_out_endpoint->bEndpointAddress), + buf, dev->report_size, + iowarrior_write_callback, dev, + dev->int_out_endpoint->bInterval); + int_out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + if (copy_from_user(buf, user_buffer, count)) { + retval = -EFAULT; + goto error; + } + retval = usb_submit_urb(int_out_urb, GFP_KERNEL); + if (retval) { + dbg("%s submit error %d for urb nr.%d", __func__, + retval, atomic_read(&dev->write_busy)); + goto error; + } + /* submit was ok */ + retval = count; + usb_free_urb(int_out_urb); + goto exit; + break; + default: + /* what do we have here ? An unsupported Product-ID ? */ + dev_err(&dev->interface->dev, "%s - not supported for product=0x%x", + __FUNCTION__, dev->product_id); + retval = -EFAULT; + goto exit; + break; + } +error: + usb_buffer_free(dev->udev, dev->report_size, buf, + int_out_urb->transfer_dma); + usb_free_urb(int_out_urb); + atomic_dec(&dev->write_busy); + wake_up_interruptible(&dev->write_wait); +exit: + mutex_unlock(&dev->mutex); + return retval; +} + +/** + * iowarrior_ioctl + */ +static int iowarrior_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct iowarrior *dev = NULL; + __u8 *buffer; + __u8 __user *user_buffer; + int retval; + int io_res; /* checks for bytes read/written and copy_to/from_user results */ + + dev = (struct iowarrior *)file->private_data; + if (dev == NULL) { + return -ENODEV; + } + + buffer = kzalloc(dev->report_size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + /* lock this object */ + mutex_lock(&dev->mutex); + + /* verify that the device wasn't unplugged */ + if (!dev->present) { + mutex_unlock(&dev->mutex); + return -ENODEV; + } + + dbg("%s - minor %d, cmd 0x%.4x, arg %ld", __func__, dev->minor, cmd, + arg); + + retval = 0; + io_res = 0; + switch (cmd) { + case IOW_WRITE: + if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 || + dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV1 || + dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV2 || + dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW40) { + user_buffer = (__u8 __user *)arg; + io_res = copy_from_user(buffer, user_buffer, + dev->report_size); + if (io_res) { + retval = -EFAULT; + } else { + io_res = usb_set_report(dev->interface, 2, 0, + buffer, + dev->report_size); + if (io_res < 0) + retval = io_res; + } + } else { + retval = -EINVAL; + dev_err(&dev->interface->dev, + "ioctl 'IOW_WRITE' is not supported for product=0x%x.", + dev->product_id); + } + break; + case IOW_READ: + user_buffer = (__u8 __user *)arg; + io_res = usb_get_report(dev->udev, + dev->interface->cur_altsetting, 1, 0, + buffer, dev->report_size); + if (io_res < 0) + retval = io_res; + else { + io_res = copy_to_user(user_buffer, buffer, dev->report_size); + if (io_res < 0) + retval = -EFAULT; + } + break; + case IOW_GETINFO: + { + /* Report available information for the device */ + struct iowarrior_info info; + /* needed for power consumption */ + struct usb_config_descriptor *cfg_descriptor = &dev->udev->actconfig->desc; + + /* directly from the descriptor */ + info.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); + info.product = dev->product_id; + info.revision = le16_to_cpu(dev->udev->descriptor.bcdDevice); + + /* 0==UNKNOWN, 1==LOW(usb1.1) ,2=FULL(usb1.1), 3=HIGH(usb2.0) */ + info.speed = le16_to_cpu(dev->udev->speed); + info.if_num = dev->interface->cur_altsetting->desc.bInterfaceNumber; + info.report_size = dev->report_size; + + /* serial number string has been read earlier 8 chars or empty string */ + memcpy(info.serial, dev->chip_serial, + sizeof(dev->chip_serial)); + if (cfg_descriptor == NULL) { + info.power = -1; /* no information available */ + } else { + /* the MaxPower is stored in units of 2mA to make it fit into a byte-value */ + info.power = cfg_descriptor->bMaxPower * 2; + } + io_res = copy_to_user((struct iowarrior_info __user *)arg, &info, + sizeof(struct iowarrior_info)); + if (io_res < 0) + retval = -EFAULT; + break; + } + default: + /* return that we did not understand this ioctl call */ + retval = -ENOTTY; + break; + } + + /* unlock the device */ + mutex_unlock(&dev->mutex); + return retval; +} + +/** + * iowarrior_open + */ +static int iowarrior_open(struct inode *inode, struct file *file) +{ + struct iowarrior *dev = NULL; + struct usb_interface *interface; + int subminor; + int retval = 0; + + dbg("%s", __func__); + + subminor = iminor(inode); + + /* prevent disconnects */ + down(&disconnect_sem); + + interface = usb_find_interface(&iowarrior_driver, subminor); + if (!interface) { + err("%s - error, can't find device for minor %d", __FUNCTION__, + subminor); + retval = -ENODEV; + goto out; + } + + dev = usb_get_intfdata(interface); + if (!dev) { + retval = -ENODEV; + goto out; + } + + /* Only one process can open each device, no sharing. */ + if (dev->opened) { + retval = -EBUSY; + goto out; + } + + /* setup interrupt handler for receiving values */ + if ((retval = usb_submit_urb(dev->int_in_urb, GFP_KERNEL)) < 0) { + dev_err(&interface->dev, "Error %d while submitting URB\n", retval); + retval = -EFAULT; + goto out; + } + /* increment our usage count for the driver */ + ++dev->opened; + /* save our object in the file's private structure */ + file->private_data = dev; + retval = 0; + +out: + up(&disconnect_sem); + return retval; +} + +/** + * iowarrior_release + */ +static int iowarrior_release(struct inode *inode, struct file *file) +{ + struct iowarrior *dev; + int retval = 0; + + dev = (struct iowarrior *)file->private_data; + if (dev == NULL) { + return -ENODEV; + } + + dbg("%s - minor %d", __func__, dev->minor); + + /* lock our device */ + mutex_lock(&dev->mutex); + + if (dev->opened <= 0) { + retval = -ENODEV; /* close called more than once */ + mutex_unlock(&dev->mutex); + } else { + dev->opened = 0; /* we're closeing now */ + retval = 0; + if (dev->present) { + /* + The device is still connected so we only shutdown + pending read-/write-ops. + */ + usb_kill_urb(dev->int_in_urb); + wake_up_interruptible(&dev->read_wait); + wake_up_interruptible(&dev->write_wait); + mutex_unlock(&dev->mutex); + } else { + /* The device was unplugged, cleanup resources */ + mutex_unlock(&dev->mutex); + iowarrior_delete(dev); + } + } + return retval; +} + +static unsigned iowarrior_poll(struct file *file, poll_table * wait) +{ + struct iowarrior *dev = file->private_data; + unsigned int mask = 0; + + if (!dev->present) + return POLLERR | POLLHUP; + + poll_wait(file, &dev->read_wait, wait); + poll_wait(file, &dev->write_wait, wait); + + if (!dev->present) + return POLLERR | POLLHUP; + + if (read_index(dev) != -1) + mask |= POLLIN | POLLRDNORM; + + if (atomic_read(&dev->write_busy) < MAX_WRITES_IN_FLIGHT) + mask |= POLLOUT | POLLWRNORM; + return mask; +} + +/* + * File operations needed when we register this driver. + * This assumes that this driver NEEDS file operations, + * of course, which means that the driver is expected + * to have a node in the /dev directory. If the USB + * device were for a network interface then the driver + * would use "struct net_driver" instead, and a serial + * device would use "struct tty_driver". + */ +static struct file_operations iowarrior_fops = { + .owner = THIS_MODULE, + .write = iowarrior_write, + .read = iowarrior_read, + .ioctl = iowarrior_ioctl, + .open = iowarrior_open, + .release = iowarrior_release, + .poll = iowarrior_poll, +}; + +/* + * usb class driver info in order to get a minor number from the usb core, + * and to have the device registered with devfs and the driver core + */ +static struct usb_class_driver iowarrior_class = { + .name = "iowarrior%d", + .fops = &iowarrior_fops, + .minor_base = IOWARRIOR_MINOR_BASE, +}; + +/*---------------------------------*/ +/* probe and disconnect functions */ +/*---------------------------------*/ +/** + * iowarrior_probe + * + * Called by the usb core when a new device is connected that it thinks + * this driver might be interested in. + */ +static int iowarrior_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(interface); + struct iowarrior *dev = NULL; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + int i; + int retval = -ENOMEM; + int idele = 0; + + /* allocate memory for our device state and intialize it */ + dev = kzalloc(sizeof(struct iowarrior), GFP_KERNEL); + if (dev == NULL) { + dev_err(&interface->dev, "Out of memory"); + return retval; + } + + mutex_init(&dev->mutex); + + atomic_set(&dev->intr_idx, 0); + atomic_set(&dev->read_idx, 0); + spin_lock_init(&dev->intr_idx_lock); + atomic_set(&dev->overflow_flag, 0); + init_waitqueue_head(&dev->read_wait); + atomic_set(&dev->write_busy, 0); + init_waitqueue_head(&dev->write_wait); + + dev->udev = udev; + dev->interface = interface; + + iface_desc = interface->cur_altsetting; + dev->product_id = le16_to_cpu(udev->descriptor.idProduct); + + /* set up the endpoint information */ + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (usb_endpoint_is_int_in(endpoint)) + dev->int_in_endpoint = endpoint; + if (usb_endpoint_is_int_out(endpoint)) + /* this one will match for the IOWarrior56 only */ + dev->int_out_endpoint = endpoint; + } + /* we have to check the report_size often, so remember it in the endianess suitable for our machine */ + dev->report_size = le16_to_cpu(dev->int_in_endpoint->wMaxPacketSize); + if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) && + (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56)) + /* IOWarrior56 has wMaxPacketSize different from report size */ + dev->report_size = 7; + + /* create the urb and buffer for reading */ + dev->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->int_in_urb) { + dev_err(&interface->dev, "Couldn't allocate interrupt_in_urb\n"); + goto error; + } + dev->int_in_buffer = kmalloc(dev->report_size, GFP_KERNEL); + if (!dev->int_in_buffer) { + dev_err(&interface->dev, "Couldn't allocate int_in_buffer\n"); + goto error; + } + usb_fill_int_urb(dev->int_in_urb, dev->udev, + usb_rcvintpipe(dev->udev, + dev->int_in_endpoint->bEndpointAddress), + dev->int_in_buffer, dev->report_size, + iowarrior_callback, dev, + dev->int_in_endpoint->bInterval); + /* create an internal buffer for interrupt data from the device */ + dev->read_queue = + kmalloc(((dev->report_size + 1) * MAX_INTERRUPT_BUFFER), + GFP_KERNEL); + if (!dev->read_queue) { + dev_err(&interface->dev, "Couldn't allocate read_queue\n"); + goto error; + } + /* Get the serial-number of the chip */ + memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial)); + usb_string(udev, udev->descriptor.iSerialNumber, dev->chip_serial, + sizeof(dev->chip_serial)); + if (strlen(dev->chip_serial) != 8) + memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial)); + + /* Set the idle timeout to 0, if this is interface 0 */ + if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) { + idele = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x0A, + USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, + 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + dbg("idele = %d", idele); + } + /* allow device read and ioctl */ + dev->present = 1; + + /* we can register the device now, as it is ready */ + usb_set_intfdata(interface, dev); + + retval = usb_register_dev(interface, &iowarrior_class); + if (retval) { + /* something prevented us from registering this driver */ + dev_err(&interface->dev, "Not able to get a minor for this device.\n"); + usb_set_intfdata(interface, NULL); + goto error; + } + + dev->minor = interface->minor; + + /* let the user know what node this device is now attached to */ + dev_info(&interface->dev, "IOWarrior product=0x%x, serial=%s interface=%d " + "now attached to iowarrior%d\n", dev->product_id, dev->chip_serial, + iface_desc->desc.bInterfaceNumber, dev->minor - IOWARRIOR_MINOR_BASE); + return retval; + +error: + iowarrior_delete(dev); + return retval; +} + +/** + * iowarrior_disconnect + * + * Called by the usb core when the device is removed from the system. + */ +static void iowarrior_disconnect(struct usb_interface *interface) +{ + struct iowarrior *dev; + int minor; + + /* prevent races with open() */ + down(&disconnect_sem); + + dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + mutex_lock(&dev->mutex); + + minor = dev->minor; + + /* give back our minor */ + usb_deregister_dev(interface, &iowarrior_class); + + /* prevent device read, write and ioctl */ + dev->present = 0; + + mutex_unlock(&dev->mutex); + + if (dev->opened) { + /* There is a process that holds a filedescriptor to the device , + so we only shutdown read-/write-ops going on. + Deleting the device is postponed until close() was called. + */ + usb_kill_urb(dev->int_in_urb); + wake_up_interruptible(&dev->read_wait); + wake_up_interruptible(&dev->write_wait); + } else { + /* no process is using the device, cleanup now */ + iowarrior_delete(dev); + } + up(&disconnect_sem); + + dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n", + minor - IOWARRIOR_MINOR_BASE); +} + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver iowarrior_driver = { + .name = "iowarrior", + .probe = iowarrior_probe, + .disconnect = iowarrior_disconnect, + .id_table = iowarrior_ids, +}; + +static int __init iowarrior_init(void) +{ + return usb_register(&iowarrior_driver); +} + +static void __exit iowarrior_exit(void) +{ + usb_deregister(&iowarrior_driver); +} + +module_init(iowarrior_init); +module_exit(iowarrior_exit); diff --git a/include/linux/usb/iowarrior.h b/include/linux/usb/iowarrior.h new file mode 100644 index 00000000000..cbbe020a4f5 --- /dev/null +++ b/include/linux/usb/iowarrior.h @@ -0,0 +1,33 @@ +#ifndef _IOWARRIOR_H_ +#define _IOWARRIOR_H_ + +#define CODEMERCS_MAGIC_NUMBER 0xC0 /* like COde Mercenaries */ + +/* Define the ioctl commands for reading and writing data */ +#define IOW_WRITE _IOW(CODEMERCS_MAGIC_NUMBER, 1, __u8 *) +#define IOW_READ _IOW(CODEMERCS_MAGIC_NUMBER, 2, __u8 *) + +/* + A struct for available device info which is read + with the ioctl IOW_GETINFO. + To be compatible with 2.4 userspace which didn't have an easy way to get + this information. +*/ +struct iowarrior_info { + __u32 vendor; /* vendor id : supposed to be USB_VENDOR_ID_CODEMERCS in all cases */ + __u32 product; /* product id : depends on type of chip (USB_DEVICE_ID_CODEMERCS_XXXXX) */ + __u8 serial[9]; /* the serial number of our chip (if a serial-number is not available this is empty string) */ + __u32 revision; /* revision number of the chip */ + __u32 speed; /* USB-speed of the device (0=UNKNOWN, 1=LOW, 2=FULL 3=HIGH) */ + __u32 power; /* power consumption of the device in mA */ + __u32 if_num; /* the number of the endpoint */ + __u32 report_size; /* size of the data-packets on this interface */ +}; + +/* + Get some device-information (product-id , serial-number etc.) + in order to identify a chip. +*/ +#define IOW_GETINFO _IOR(CODEMERCS_MAGIC_NUMBER, 3, struct iowarrior_info) + +#endif /* _IOWARRIOR_H_ */ -- cgit v1.2.3-70-g09d2 From ee17b289732e04fdcdd8ce2ce19b18d3e8b08e20 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 6 Mar 2007 02:47:44 -0800 Subject: USB Elan FTDI: check for workqueue creation Avoid NULL pointer usage if workqueue creation failed. Signed-off-by: Cyrill Gorcunov Cc: Pete Zaitcev Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ftdi-elan.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers/usb/misc') diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 0c1d66ddb81..bc3327e3dd7 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -2905,17 +2905,31 @@ static int __init ftdi_elan_init(void) { int result; printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name, - __TIME__, __DATE__); + __TIME__, __DATE__); init_MUTEX(&ftdi_module_lock); INIT_LIST_HEAD(&ftdi_static_list); status_queue = create_singlethread_workqueue("ftdi-status-control"); + if (!status_queue) + goto err1; command_queue = create_singlethread_workqueue("ftdi-command-engine"); + if (!command_queue) + goto err2; respond_queue = create_singlethread_workqueue("ftdi-respond-engine"); + if (!respond_queue) + goto err3; result = usb_register(&ftdi_elan_driver); if (result) printk(KERN_ERR "usb_register failed. Error number %d\n", - result); + result); return result; + + err3: + destroy_workqueue(command_queue); + err2: + destroy_workqueue(status_queue); + err1: + printk(KERN_ERR "%s couldn't create workqueue\n", ftdi_elan_driver.name); + return -ENOMEM; } static void __exit ftdi_elan_exit(void) -- cgit v1.2.3-70-g09d2 From 774f78cf3b81c553c087ca0e8740e9cd779df578 Mon Sep 17 00:00:00 2001 From: Ken L Johnson Date: Fri, 16 Mar 2007 10:17:31 -0600 Subject: USB: berry_charge: correct dbg string for second magic command I was testing the berry_charge module with my Blackberry 8700c and had great success, thanks. Looking at the code for my own learning I noticed the following cut and paste error... just a nit. Signed-off-by: Ken L Johnson Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/berry_charge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/misc') diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c index 60893c6c822..b15f2fd8dab 100644 --- a/drivers/usb/misc/berry_charge.c +++ b/drivers/usb/misc/berry_charge.c @@ -69,7 +69,7 @@ static int magic_charge(struct usb_device *udev) return retval; } - dbg(&udev->dev, "Sending first magic command\n"); + dbg(&udev->dev, "Sending second magic command\n"); retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0xa2, 0x40, 0, 1, dummy_buffer, 0, 100); if (retval != 0) { -- cgit v1.2.3-70-g09d2 From 2e85c91e2e0f4e58fb54354bb7f6cc7dd3466dd9 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 5 Mar 2007 15:11:14 +0100 Subject: USB: kill BKL in usblcd this patch removes usage of BKL from usblcd, which got it from the old skeleton driver. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usblcd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/usb/misc') diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index ada2ebc464a..887ef953f3d 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -47,6 +47,7 @@ struct usb_lcd { #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref) static struct usb_driver lcd_driver; +static DEFINE_MUTEX(usb_lcd_open_mutex); static void lcd_delete(struct kref *kref) @@ -68,6 +69,7 @@ static int lcd_open(struct inode *inode, struct file *file) subminor = iminor(inode); + mutex_lock(&usb_lcd_open_mutex); interface = usb_find_interface(&lcd_driver, subminor); if (!interface) { err ("USBLCD: %s - error, can't find device for minor %d", @@ -89,6 +91,7 @@ static int lcd_open(struct inode *inode, struct file *file) file->private_data = dev; exit: + mutex_unlock(&usb_lcd_open_mutex); return retval; } @@ -347,7 +350,7 @@ static void lcd_disconnect(struct usb_interface *interface) int minor = interface->minor; /* prevent skel_open() from racing skel_disconnect() */ - lock_kernel(); + mutex_lock(&usb_lcd_open_mutex); dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); @@ -355,7 +358,7 @@ static void lcd_disconnect(struct usb_interface *interface) /* give back our minor */ usb_deregister_dev(interface, &lcd_class); - unlock_kernel(); + mutex_unlock(&usb_lcd_open_mutex); /* decrement our usage count */ kref_put(&dev->kref, lcd_delete); -- cgit v1.2.3-70-g09d2 From f81ee4d52880b08c213982df5041217212689960 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 19 Mar 2007 11:39:13 +0100 Subject: USB: iowarrior.c: fix NULL dereference Am Montag, 19. 2007 10:25 schrieb Adrian Bunk: > The Coverity checker spotted the following NULL dereference: And this fixes an oops upon allocation failures. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/iowarrior.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/usb/misc') diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index d69665c8de0..de97ed7b0b9 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -417,14 +417,14 @@ static ssize_t iowarrior_write(struct file *file, if (!int_out_urb) { retval = -ENOMEM; dbg("%s Unable to allocate urb ", __func__); - goto error; + goto error_no_urb; } buf = usb_buffer_alloc(dev->udev, dev->report_size, GFP_KERNEL, &int_out_urb->transfer_dma); if (!buf) { retval = -ENOMEM; dbg("%s Unable to allocate buffer ", __func__); - goto error; + goto error_no_buffer; } usb_fill_int_urb(int_out_urb, dev->udev, usb_sndintpipe(dev->udev, @@ -459,7 +459,9 @@ static ssize_t iowarrior_write(struct file *file, error: usb_buffer_free(dev->udev, dev->report_size, buf, int_out_urb->transfer_dma); +error_no_buffer: usb_free_urb(int_out_urb); +error_no_urb: atomic_dec(&dev->write_busy); wake_up_interruptible(&dev->write_wait); exit: -- cgit v1.2.3-70-g09d2 From 949ce47168a34618c3e24cb7dd4ab52233a4653c Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 30 Mar 2007 10:52:16 +0200 Subject: USB: cypress_cy7c63: race disconnect/sysfs read-write leading to following NULL pointer this driver sets intfdata to NULL while it still can be read and happily followed. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/cypress_cy7c63.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/usb/misc') diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c index b63b5f34b2a..d721380b242 100644 --- a/drivers/usb/misc/cypress_cy7c63.c +++ b/drivers/usb/misc/cypress_cy7c63.c @@ -246,11 +246,13 @@ static void cypress_disconnect(struct usb_interface *interface) struct cypress *dev; dev = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); /* remove device attribute files */ device_remove_file(&interface->dev, &dev_attr_port0); device_remove_file(&interface->dev, &dev_attr_port1); + /* the intfdata can be set to NULL only after the + * device files have been removed */ + usb_set_intfdata(interface, NULL); usb_put_dev(dev->udev); -- cgit v1.2.3-70-g09d2 From ebc3ac149bf3a20c235625f1c07e0f997b3e08ba Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 2 Apr 2007 15:16:36 +0200 Subject: USB: cleanup ofd adutux this driver does - ignore errors during open - submit a running urb - use down_interruptible not handling signals - GFP_KERNEL with a spinlock held Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/adutux.c | 48 +++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) (limited to 'drivers/usb/misc') diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index 75bfab95ab3..77145f9db04 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -285,23 +285,24 @@ static int adu_open(struct inode *inode, struct file *file) /* save device in the file's private structure */ file->private_data = dev; - /* initialize in direction */ - dev->read_buffer_length = 0; - - /* fixup first read by having urb waiting for it */ - usb_fill_int_urb(dev->interrupt_in_urb,dev->udev, - usb_rcvintpipe(dev->udev, - dev->interrupt_in_endpoint->bEndpointAddress), - dev->interrupt_in_buffer, - le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize), - adu_interrupt_in_callback, dev, - dev->interrupt_in_endpoint->bInterval); - /* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */ - dev->read_urb_finished = 0; - usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); - /* we ignore failure */ - /* end of fixup for first read */ + if (dev->open_count == 1) { + /* initialize in direction */ + dev->read_buffer_length = 0; + /* fixup first read by having urb waiting for it */ + usb_fill_int_urb(dev->interrupt_in_urb,dev->udev, + usb_rcvintpipe(dev->udev, + dev->interrupt_in_endpoint->bEndpointAddress), + dev->interrupt_in_buffer, + le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize), + adu_interrupt_in_callback, dev, + dev->interrupt_in_endpoint->bInterval); + /* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */ + dev->read_urb_finished = 0; + retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); + if (retval) + --dev->open_count; + } up(&dev->sem); exit_no_device: @@ -469,7 +470,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, adu_interrupt_in_callback, dev, dev->interrupt_in_endpoint->bInterval); - retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); + retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC); if (!retval) { spin_unlock_irqrestore(&dev->buflock, flags); dbg(2," %s : submitted OK", __FUNCTION__); @@ -539,7 +540,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, size_t bytes_written = 0; size_t bytes_to_write; size_t buffer_size; - int retval = 0; + int retval; int timeout = 0; dbg(2," %s : enter, count = %Zd", __FUNCTION__, count); @@ -547,7 +548,9 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, dev = file->private_data; /* lock this object */ - down_interruptible(&dev->sem); + retval = down_interruptible(&dev->sem); + if (retval) + goto exit_nolock; /* verify that the device wasn't unplugged */ if (dev->udev == NULL || dev->minor == 0) { @@ -575,7 +578,11 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, } up(&dev->sem); timeout = interruptible_sleep_on_timeout(&dev->write_wait, timeout); - down_interruptible(&dev->sem); + retval = down_interruptible(&dev->sem); + if (retval) { + retval = bytes_written ? bytes_written : retval; + goto exit_nolock; + } if (timeout > 0) { break; } @@ -637,6 +644,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, exit: /* unlock the device */ up(&dev->sem); +exit_nolock: dbg(2," %s : leave, return value %d", __FUNCTION__, retval); -- cgit v1.2.3-70-g09d2 From 893a342a686e6ce36ef24d322f3f52420a041313 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Thu, 26 Apr 2007 00:38:00 -0700 Subject: USB Elan FTDI: check for driver registration status Add checking of driver registration status and release allocated resources if it failed. Signed-off-by: Cyrill Gorcunov Cc: Pete Zaitcev Cc: "Luiz Fernando N. Capitulino" Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ftdi-elan.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers/usb/misc') diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index bc3327e3dd7..d9cbdb87fac 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -2910,24 +2910,28 @@ static int __init ftdi_elan_init(void) INIT_LIST_HEAD(&ftdi_static_list); status_queue = create_singlethread_workqueue("ftdi-status-control"); if (!status_queue) - goto err1; + goto err_status_queue; command_queue = create_singlethread_workqueue("ftdi-command-engine"); if (!command_queue) - goto err2; + goto err_command_queue; respond_queue = create_singlethread_workqueue("ftdi-respond-engine"); if (!respond_queue) - goto err3; + goto err_respond_queue; result = usb_register(&ftdi_elan_driver); - if (result) + if (result) { + destroy_workqueue(status_queue); + destroy_workqueue(command_queue); + destroy_workqueue(respond_queue); printk(KERN_ERR "usb_register failed. Error number %d\n", result); + } return result; - err3: + err_respond_queue: destroy_workqueue(command_queue); - err2: + err_command_queue: destroy_workqueue(status_queue); - err1: + err_status_queue: printk(KERN_ERR "%s couldn't create workqueue\n", ftdi_elan_driver.name); return -ENOMEM; } -- cgit v1.2.3-70-g09d2 From 5c975acb99168827a8ce5453be0e44ad2e4b70b2 Mon Sep 17 00:00:00 2001 From: "S.Caglar Onur" Date: Thu, 26 Apr 2007 00:38:03 -0700 Subject: USB: Remove duplicate define of OHCI_QUIRK_ZFMICRO Remove duplicate define of OHCI_QUIRK_ZFMICRO from ftdi-elan.c, its already defined in drivers/ush/host/ohci.c Signed-off-by: "S.Caglar Onur" Cc: Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ftdi-elan.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/usb/misc') diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index d9cbdb87fac..e2172e5cf15 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -2304,7 +2304,6 @@ static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi) #define OHCI_QUIRK_SUPERIO 0x02 #define OHCI_QUIRK_INITRESET 0x04 #define OHCI_BIG_ENDIAN 0x08 -#define OHCI_QUIRK_ZFMICRO 0x10 #define OHCI_CONTROL_INIT OHCI_CTRL_CBSR #define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ OHCI_INTR_WDH) -- cgit v1.2.3-70-g09d2 From 79dcdbf67d8885375711c4f2261168fa87389a31 Mon Sep 17 00:00:00 2001 From: Joey Goncalves Date: Fri, 20 Apr 2007 11:05:54 -0700 Subject: USB: add picdem device to ldusb Hi Greg: I have found that /drivers/usb/misc/ldusb.c works with the "PICDEM Full Speed USB" http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en021940 Signed-off-by: Joey S Goncalves Cc: Michael Hund Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ldusb.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/usb/misc') diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 788a11e6772..11555bde655 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -62,6 +62,8 @@ #define USB_DEVICE_ID_VERNIER_SKIP 0x0003 #define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004 +#define USB_VENDOR_ID_MICROCHIP 0x04d8 +#define USB_DEVICE_ID_PICDEM 0x000c #ifdef CONFIG_USB_DYNAMIC_MINORS #define USB_LD_MINOR_BASE 0 @@ -89,6 +91,7 @@ static struct usb_device_id ld_usb_table [] = { { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) }, { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) }, { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) }, + { USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICDEM) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, ld_usb_table); -- cgit v1.2.3-70-g09d2 From 147c5a17338fc72a89452f0a6c14ae6fcf853919 Mon Sep 17 00:00:00 2001 From: Eberhard Fahle Date: Thu, 5 Apr 2007 11:13:21 +0200 Subject: USB: iowarrior.c: timeouts too small in usb_control_msg calls The driver uses usb_control_msg() for exchanging data with the device. When the driver lived freeley _outside_ the kernel tree (pre 2.6.21) the timeouts for these calls where set to 5*HZ for reading, 1HZ for writing. (These timeouts seemed to work fine for all users of the driver, at least nobody complained in the last 2 years. The current code (2.6.21-rc5) removed the 'HZ' from the timeouts and left the driver with 5 jiffies for reading and 1 jiffy for writing. My new machine is fast, but not that fast. The patch also removes a useless debug statement, which was left over from testing a broken firmware version From: Eberhard Fahle Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/iowarrior.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers/usb/misc') diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index de97ed7b0b9..fc51207b71b 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -118,7 +118,7 @@ static int usb_get_report(struct usb_device *dev, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, (type << 8) + id, inter->desc.bInterfaceNumber, buf, size, - GET_TIMEOUT); + GET_TIMEOUT*HZ); } //#endif @@ -133,7 +133,7 @@ static int usb_set_report(struct usb_interface *intf, unsigned char type, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (type << 8) + id, intf->cur_altsetting->desc.bInterfaceNumber, buf, - size, 1); + size, HZ); } /*---------------------*/ @@ -750,7 +750,6 @@ static int iowarrior_probe(struct usb_interface *interface, struct usb_endpoint_descriptor *endpoint; int i; int retval = -ENOMEM; - int idele = 0; /* allocate memory for our device state and intialize it */ dev = kzalloc(sizeof(struct iowarrior), GFP_KERNEL); @@ -826,11 +825,10 @@ static int iowarrior_probe(struct usb_interface *interface, /* Set the idle timeout to 0, if this is interface 0 */ if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) { - idele = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x0A, - USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, - 0, NULL, 0, USB_CTRL_SET_TIMEOUT); - dbg("idele = %d", idele); + usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x0A, + USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, + 0, NULL, 0, USB_CTRL_SET_TIMEOUT); } /* allow device read and ioctl */ dev->present = 1; -- cgit v1.2.3-70-g09d2