diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index a3ff0514f9cd..a71ddaa810a0 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -71,8 +71,8 @@ static u32 s32ton(__s32 value, unsigned int n) if (!value || !n) return 0; - if (n > 32) - n = 32; + if (n >= 32) + return (u32) value; a = value >> (n - 1); if (a && a != -1) diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c index c99c3c0d442e..847b1ddefeec 100644 --- a/drivers/hid/hid-google-hammer.c +++ b/drivers/hid/hid-google-hammer.c @@ -268,7 +268,7 @@ static void cbas_ec_remove(struct platform_device *pdev) #ifdef CONFIG_ACPI static const struct acpi_device_id cbas_ec_acpi_ids[] = { - { "GOOG000B", 0 }, + { .id = "GOOG000B" }, { } }; MODULE_DEVICE_TABLE(acpi, cbas_ec_acpi_ids); diff --git a/drivers/hid/i2c-hid/i2c-hid-acpi.c b/drivers/hid/i2c-hid/i2c-hid-acpi.c index 13f977d6aab6..9371db200fc4 100644 --- a/drivers/hid/i2c-hid/i2c-hid-acpi.c +++ b/drivers/hid/i2c-hid/i2c-hid-acpi.c @@ -39,12 +39,12 @@ static const struct acpi_device_id i2c_hid_acpi_blacklist[] = { * The CHPN0001 ACPI device, which is used to describe the Chipone * ICN8505 controller, has a _CID of PNP0C50 but is not HID compatible. */ - { "CHPN0001" }, + { .id = "CHPN0001" }, /* * The IDEA5002 ACPI device causes high interrupt usage and spurious * wakeups from suspend. */ - { "IDEA5002" }, + { .id = "IDEA5002" }, { } }; @@ -93,8 +93,8 @@ static int i2c_hid_acpi_probe(struct i2c_client *client) } static const struct acpi_device_id i2c_hid_acpi_match[] = { - { "ACPI0C50" }, - { "PNP0C50" }, + { .id = "ACPI0C50" }, + { .id = "PNP0C50" }, { } }; MODULE_DEVICE_TABLE(acpi, i2c_hid_acpi_match); diff --git a/drivers/hid/surface-hid/surface_kbd.c b/drivers/hid/surface-hid/surface_kbd.c index 0be01b5e7425..036829ba47d4 100644 --- a/drivers/hid/surface-hid/surface_kbd.c +++ b/drivers/hid/surface-hid/surface_kbd.c @@ -277,8 +277,8 @@ static void surface_kbd_remove(struct platform_device *pdev) } static const struct acpi_device_id surface_kbd_match[] = { - { "MSHW0096" }, - { }, + { .id = "MSHW0096" }, + { } }; MODULE_DEVICE_TABLE(acpi, surface_kbd_match); diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 6378801b22c6..8430655c00fe 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -46,6 +46,12 @@ struct hiddev_list { struct mutex thread_lock; }; +static void hiddev_put(struct hiddev *hiddev) +{ + if (refcount_dec_and_test(&hiddev->refcount)) + kfree(hiddev); +} + /* * Find a report, given the report's type and ID. The ID can be specified * indirectly by REPORT_ID_FIRST (which returns the first report of the given @@ -216,26 +222,21 @@ static int hiddev_fasync(int fd, struct file *file, int on) static int hiddev_release(struct inode * inode, struct file * file) { struct hiddev_list *list = file->private_data; + struct hiddev *hiddev = list->hiddev; unsigned long flags; - spin_lock_irqsave(&list->hiddev->list_lock, flags); + spin_lock_irqsave(&hiddev->list_lock, flags); list_del(&list->node); - spin_unlock_irqrestore(&list->hiddev->list_lock, flags); + spin_unlock_irqrestore(&hiddev->list_lock, flags); - mutex_lock(&list->hiddev->existancelock); - if (!--list->hiddev->open) { - if (list->hiddev->exist) { - hid_hw_close(list->hiddev->hid); - hid_hw_power(list->hiddev->hid, PM_HINT_NORMAL); - } else { - mutex_unlock(&list->hiddev->existancelock); - kfree(list->hiddev); - vfree(list); - return 0; - } + mutex_lock(&hiddev->existancelock); + if (!--hiddev->open && hiddev->exist) { + hid_hw_close(hiddev->hid); + hid_hw_power(hiddev->hid, PM_HINT_NORMAL); } - mutex_unlock(&list->hiddev->existancelock); + mutex_unlock(&hiddev->existancelock); + hiddev_put(hiddev); vfree(list); return 0; @@ -270,6 +271,7 @@ static int __hiddev_open(struct hiddev *hiddev, struct file *file) spin_unlock_irq(&hiddev->list_lock); file->private_data = list; + refcount_inc(&hiddev->refcount); return 0; @@ -897,9 +899,12 @@ int hiddev_connect(struct hid_device *hid, unsigned int force) INIT_LIST_HEAD(&hiddev->list); spin_lock_init(&hiddev->list_lock); mutex_init(&hiddev->existancelock); + refcount_set(&hiddev->refcount, 1); hid->hiddev = hiddev; hiddev->hid = hid; hiddev->exist = 1; + /* Honor NO_INIT_REPORTS before the character device becomes visible. */ + hiddev->initialized = hid->quirks & HID_QUIRK_NO_INIT_REPORTS; retval = usb_register_dev(usbhid->intf, &hiddev_class); if (retval) { hid_err(hid, "Not able to get a minor for this device\n"); @@ -908,12 +913,6 @@ int hiddev_connect(struct hid_device *hid, unsigned int force) return retval; } - /* - * If HID_QUIRK_NO_INIT_REPORTS is set, make sure we don't initialize - * the reports. - */ - hiddev->initialized = hid->quirks & HID_QUIRK_NO_INIT_REPORTS; - hiddev->minor = usbhid->intf->minor; return 0; @@ -937,9 +936,7 @@ void hiddev_disconnect(struct hid_device *hid) if (hiddev->open) { hid_hw_close(hiddev->hid); wake_up_interruptible(&hiddev->wait); - mutex_unlock(&hiddev->existancelock); - } else { - mutex_unlock(&hiddev->existancelock); - kfree(hiddev); } + mutex_unlock(&hiddev->existancelock); + hiddev_put(hiddev); } diff --git a/include/linux/hiddev.h b/include/linux/hiddev.h index 2164c03d2c72..8e9f8a33e359 100644 --- a/include/linux/hiddev.h +++ b/include/linux/hiddev.h @@ -13,6 +13,7 @@ #ifndef _HIDDEV_H #define _HIDDEV_H +#include #include @@ -24,6 +25,7 @@ struct hiddev { int minor; int exist; int open; + refcount_t refcount; struct mutex existancelock; wait_queue_head_t wait; struct hid_device *hid;