aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/hid/usbhid/hid-core.c58
-rw-r--r--drivers/hid/usbhid/usbhid.h2
-rw-r--r--include/linux/hid.h1
3 files changed, 44 insertions, 17 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 42bdd83444c1..3b1c489998c3 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -20,6 +20,7 @@
20#include <linux/kernel.h> 20#include <linux/kernel.h>
21#include <linux/list.h> 21#include <linux/list.h>
22#include <linux/mm.h> 22#include <linux/mm.h>
23#include <linux/mutex.h>
23#include <linux/smp_lock.h> 24#include <linux/smp_lock.h>
24#include <linux/spinlock.h> 25#include <linux/spinlock.h>
25#include <asm/unaligned.h> 26#include <asm/unaligned.h>
@@ -776,21 +777,10 @@ static int usbhid_start(struct hid_device *hid)
776 struct usb_interface *intf = to_usb_interface(hid->dev.parent); 777 struct usb_interface *intf = to_usb_interface(hid->dev.parent);
777 struct usb_host_interface *interface = intf->cur_altsetting; 778 struct usb_host_interface *interface = intf->cur_altsetting;
778 struct usb_device *dev = interface_to_usbdev(intf); 779 struct usb_device *dev = interface_to_usbdev(intf);
779 struct usbhid_device *usbhid; 780 struct usbhid_device *usbhid = hid->driver_data;
780 unsigned int n, insize = 0; 781 unsigned int n, insize = 0;
781 int ret; 782 int ret;
782 783
783 WARN_ON(hid->driver_data);
784
785 usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL);
786 if (usbhid == NULL) {
787 ret = -ENOMEM;
788 goto err;
789 }
790
791 hid->driver_data = usbhid;
792 usbhid->hid = hid;
793
794 usbhid->bufsize = HID_MIN_BUFFER_SIZE; 784 usbhid->bufsize = HID_MIN_BUFFER_SIZE;
795 hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize); 785 hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize);
796 hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize); 786 hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize);
@@ -804,6 +794,7 @@ static int usbhid_start(struct hid_device *hid)
804 if (insize > HID_MAX_BUFFER_SIZE) 794 if (insize > HID_MAX_BUFFER_SIZE)
805 insize = HID_MAX_BUFFER_SIZE; 795 insize = HID_MAX_BUFFER_SIZE;
806 796
797 mutex_lock(&usbhid->setup);
807 if (hid_alloc_buffers(dev, hid)) { 798 if (hid_alloc_buffers(dev, hid)) {
808 ret = -ENOMEM; 799 ret = -ENOMEM;
809 goto fail; 800 goto fail;
@@ -888,6 +879,9 @@ static int usbhid_start(struct hid_device *hid)
888 usbhid_init_reports(hid); 879 usbhid_init_reports(hid);
889 hid_dump_device(hid); 880 hid_dump_device(hid);
890 881
882 set_bit(HID_STARTED, &usbhid->iofl);
883 mutex_unlock(&usbhid->setup);
884
891 return 0; 885 return 0;
892 886
893fail: 887fail:
@@ -895,8 +889,7 @@ fail:
895 usb_free_urb(usbhid->urbout); 889 usb_free_urb(usbhid->urbout);
896 usb_free_urb(usbhid->urbctrl); 890 usb_free_urb(usbhid->urbctrl);
897 hid_free_buffers(dev, hid); 891 hid_free_buffers(dev, hid);
898 kfree(usbhid); 892 mutex_unlock(&usbhid->setup);
899err:
900 return ret; 893 return ret;
901} 894}
902 895
@@ -907,6 +900,8 @@ static void usbhid_stop(struct hid_device *hid)
907 if (WARN_ON(!usbhid)) 900 if (WARN_ON(!usbhid))
908 return; 901 return;
909 902
903 mutex_lock(&usbhid->setup);
904 clear_bit(HID_STARTED, &usbhid->iofl);
910 spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ 905 spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
911 set_bit(HID_DISCONNECTED, &usbhid->iofl); 906 set_bit(HID_DISCONNECTED, &usbhid->iofl);
912 spin_unlock_irq(&usbhid->inlock); 907 spin_unlock_irq(&usbhid->inlock);
@@ -931,8 +926,7 @@ static void usbhid_stop(struct hid_device *hid)
931 usb_free_urb(usbhid->urbout); 926 usb_free_urb(usbhid->urbout);
932 927
933 hid_free_buffers(hid_to_usb_dev(hid), hid); 928 hid_free_buffers(hid_to_usb_dev(hid), hid);
934 kfree(usbhid); 929 mutex_unlock(&usbhid->setup);
935 hid->driver_data = NULL;
936} 930}
937 931
938static struct hid_ll_driver usb_hid_driver = { 932static struct hid_ll_driver usb_hid_driver = {
@@ -947,6 +941,7 @@ static struct hid_ll_driver usb_hid_driver = {
947static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) 941static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
948{ 942{
949 struct usb_device *dev = interface_to_usbdev(intf); 943 struct usb_device *dev = interface_to_usbdev(intf);
944 struct usbhid_device *usbhid;
950 struct hid_device *hid; 945 struct hid_device *hid;
951 size_t len; 946 size_t len;
952 int ret; 947 int ret;
@@ -1000,14 +995,26 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
1000 if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0) 995 if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
1001 hid->uniq[0] = 0; 996 hid->uniq[0] = 0;
1002 997
998 usbhid = kzalloc(sizeof(*usbhid), GFP_KERNEL);
999 if (usbhid == NULL) {
1000 ret = -ENOMEM;
1001 goto err;
1002 }
1003
1004 hid->driver_data = usbhid;
1005 usbhid->hid = hid;
1006 mutex_init(&usbhid->setup); /* needed on suspend/resume */
1007
1003 ret = hid_add_device(hid); 1008 ret = hid_add_device(hid);
1004 if (ret) { 1009 if (ret) {
1005 if (ret != -ENODEV) 1010 if (ret != -ENODEV)
1006 dev_err(&intf->dev, "can't add hid device: %d\n", ret); 1011 dev_err(&intf->dev, "can't add hid device: %d\n", ret);
1007 goto err; 1012 goto err_free;
1008 } 1013 }
1009 1014
1010 return 0; 1015 return 0;
1016err_free:
1017 kfree(usbhid);
1011err: 1018err:
1012 hid_destroy_device(hid); 1019 hid_destroy_device(hid);
1013 return ret; 1020 return ret;
@@ -1016,11 +1023,14 @@ err:
1016static void hid_disconnect(struct usb_interface *intf) 1023static void hid_disconnect(struct usb_interface *intf)
1017{ 1024{
1018 struct hid_device *hid = usb_get_intfdata(intf); 1025 struct hid_device *hid = usb_get_intfdata(intf);
1026 struct usbhid_device *usbhid;
1019 1027
1020 if (WARN_ON(!hid)) 1028 if (WARN_ON(!hid))
1021 return; 1029 return;
1022 1030
1031 usbhid = hid->driver_data;
1023 hid_destroy_device(hid); 1032 hid_destroy_device(hid);
1033 kfree(usbhid);
1024} 1034}
1025 1035
1026static int hid_suspend(struct usb_interface *intf, pm_message_t message) 1036static int hid_suspend(struct usb_interface *intf, pm_message_t message)
@@ -1028,11 +1038,18 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
1028 struct hid_device *hid = usb_get_intfdata (intf); 1038 struct hid_device *hid = usb_get_intfdata (intf);
1029 struct usbhid_device *usbhid = hid->driver_data; 1039 struct usbhid_device *usbhid = hid->driver_data;
1030 1040
1041 mutex_lock(&usbhid->setup);
1042 if (!test_bit(HID_STARTED, &usbhid->iofl)) {
1043 mutex_unlock(&usbhid->setup);
1044 return 0;
1045 }
1046
1031 spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ 1047 spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
1032 set_bit(HID_SUSPENDED, &usbhid->iofl); 1048 set_bit(HID_SUSPENDED, &usbhid->iofl);
1033 spin_unlock_irq(&usbhid->inlock); 1049 spin_unlock_irq(&usbhid->inlock);
1034 del_timer(&usbhid->io_retry); 1050 del_timer(&usbhid->io_retry);
1035 usb_kill_urb(usbhid->urbin); 1051 usb_kill_urb(usbhid->urbin);
1052 mutex_unlock(&usbhid->setup);
1036 dev_dbg(&intf->dev, "suspend\n"); 1053 dev_dbg(&intf->dev, "suspend\n");
1037 return 0; 1054 return 0;
1038} 1055}
@@ -1043,9 +1060,16 @@ static int hid_resume(struct usb_interface *intf)
1043 struct usbhid_device *usbhid = hid->driver_data; 1060 struct usbhid_device *usbhid = hid->driver_data;
1044 int status; 1061 int status;
1045 1062
1063 mutex_lock(&usbhid->setup);
1064 if (!test_bit(HID_STARTED, &usbhid->iofl)) {
1065 mutex_unlock(&usbhid->setup);
1066 return 0;
1067 }
1068
1046 clear_bit(HID_SUSPENDED, &usbhid->iofl); 1069 clear_bit(HID_SUSPENDED, &usbhid->iofl);
1047 usbhid->retry_delay = 0; 1070 usbhid->retry_delay = 0;
1048 status = hid_start_in(hid); 1071 status = hid_start_in(hid);
1072 mutex_unlock(&usbhid->setup);
1049 dev_dbg(&intf->dev, "resume status %d\n", status); 1073 dev_dbg(&intf->dev, "resume status %d\n", status);
1050 return status; 1074 return status;
1051} 1075}
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index abedb13c623e..55973ff54008 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -27,6 +27,7 @@
27#include <linux/types.h> 27#include <linux/types.h>
28#include <linux/slab.h> 28#include <linux/slab.h>
29#include <linux/list.h> 29#include <linux/list.h>
30#include <linux/mutex.h>
30#include <linux/timer.h> 31#include <linux/timer.h>
31#include <linux/wait.h> 32#include <linux/wait.h>
32#include <linux/workqueue.h> 33#include <linux/workqueue.h>
@@ -73,6 +74,7 @@ struct usbhid_device {
73 dma_addr_t outbuf_dma; /* Output buffer dma */ 74 dma_addr_t outbuf_dma; /* Output buffer dma */
74 spinlock_t outlock; /* Output fifo spinlock */ 75 spinlock_t outlock; /* Output fifo spinlock */
75 76
77 struct mutex setup;
76 unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ 78 unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
77 struct timer_list io_retry; /* Retry timer */ 79 struct timer_list io_retry; /* Retry timer */
78 unsigned long stop_retry; /* Time to give up, in jiffies */ 80 unsigned long stop_retry; /* Time to give up, in jiffies */
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 5355ca4b939e..e5780f8c934a 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -410,6 +410,7 @@ struct hid_output_fifo {
410#define HID_SUSPENDED 5 410#define HID_SUSPENDED 5
411#define HID_CLEAR_HALT 6 411#define HID_CLEAR_HALT 6
412#define HID_DISCONNECTED 7 412#define HID_DISCONNECTED 7
413#define HID_STARTED 8
413 414
414struct hid_input { 415struct hid_input {
415 struct list_head list; 416 struct list_head list;