diff options
-rw-r--r-- | drivers/hid/hid-core.c | 112 | ||||
-rw-r--r-- | include/linux/hid.h | 14 |
2 files changed, 94 insertions, 32 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 4da66b4b977c..9ed4ff37dc2b 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
@@ -546,12 +546,11 @@ static void hid_free_report(struct hid_report *report) | |||
546 | } | 546 | } |
547 | 547 | ||
548 | /* | 548 | /* |
549 | * Free a device structure, all reports, and all fields. | 549 | * Close report. This function returns the device |
550 | * state to the point prior to hid_open_report(). | ||
550 | */ | 551 | */ |
551 | 552 | static void hid_close_report(struct hid_device *device) | |
552 | static void hid_device_release(struct device *dev) | ||
553 | { | 553 | { |
554 | struct hid_device *device = container_of(dev, struct hid_device, dev); | ||
555 | unsigned i, j; | 554 | unsigned i, j; |
556 | 555 | ||
557 | for (i = 0; i < HID_REPORT_TYPES; i++) { | 556 | for (i = 0; i < HID_REPORT_TYPES; i++) { |
@@ -562,11 +561,34 @@ static void hid_device_release(struct device *dev) | |||
562 | if (report) | 561 | if (report) |
563 | hid_free_report(report); | 562 | hid_free_report(report); |
564 | } | 563 | } |
564 | memset(report_enum, 0, sizeof(*report_enum)); | ||
565 | INIT_LIST_HEAD(&report_enum->report_list); | ||
565 | } | 566 | } |
566 | 567 | ||
567 | kfree(device->rdesc); | 568 | kfree(device->rdesc); |
569 | device->rdesc = NULL; | ||
570 | device->rsize = 0; | ||
571 | |||
568 | kfree(device->collection); | 572 | kfree(device->collection); |
569 | kfree(device); | 573 | device->collection = NULL; |
574 | device->collection_size = 0; | ||
575 | device->maxcollection = 0; | ||
576 | device->maxapplication = 0; | ||
577 | |||
578 | device->status &= ~HID_STAT_PARSED; | ||
579 | } | ||
580 | |||
581 | /* | ||
582 | * Free a device structure, all reports, and all fields. | ||
583 | */ | ||
584 | |||
585 | static void hid_device_release(struct device *dev) | ||
586 | { | ||
587 | struct hid_device *hid = container_of(dev, struct hid_device, dev); | ||
588 | |||
589 | hid_close_report(hid); | ||
590 | kfree(hid->dev_rdesc); | ||
591 | kfree(hid); | ||
570 | } | 592 | } |
571 | 593 | ||
572 | /* | 594 | /* |
@@ -643,15 +665,37 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) | |||
643 | * @start: report start | 665 | * @start: report start |
644 | * @size: report size | 666 | * @size: report size |
645 | * | 667 | * |
668 | * Allocate the device report as read by the bus driver. This function should | ||
669 | * only be called from parse() in ll drivers. | ||
670 | */ | ||
671 | int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size) | ||
672 | { | ||
673 | hid->dev_rdesc = kmemdup(start, size, GFP_KERNEL); | ||
674 | if (!hid->dev_rdesc) | ||
675 | return -ENOMEM; | ||
676 | hid->dev_rsize = size; | ||
677 | return 0; | ||
678 | } | ||
679 | EXPORT_SYMBOL_GPL(hid_parse_report); | ||
680 | |||
681 | /** | ||
682 | * hid_open_report - open a driver-specific device report | ||
683 | * | ||
684 | * @device: hid device | ||
685 | * | ||
646 | * Parse a report description into a hid_device structure. Reports are | 686 | * Parse a report description into a hid_device structure. Reports are |
647 | * enumerated, fields are attached to these reports. | 687 | * enumerated, fields are attached to these reports. |
648 | * 0 returned on success, otherwise nonzero error value. | 688 | * 0 returned on success, otherwise nonzero error value. |
689 | * | ||
690 | * This function (or the equivalent hid_parse() macro) should only be | ||
691 | * called from probe() in drivers, before starting the device. | ||
649 | */ | 692 | */ |
650 | int hid_parse_report(struct hid_device *device, __u8 *start, | 693 | int hid_open_report(struct hid_device *device) |
651 | unsigned size) | ||
652 | { | 694 | { |
653 | struct hid_parser *parser; | 695 | struct hid_parser *parser; |
654 | struct hid_item item; | 696 | struct hid_item item; |
697 | unsigned int size; | ||
698 | __u8 *start; | ||
655 | __u8 *end; | 699 | __u8 *end; |
656 | int ret; | 700 | int ret; |
657 | static int (*dispatch_type[])(struct hid_parser *parser, | 701 | static int (*dispatch_type[])(struct hid_parser *parser, |
@@ -662,6 +706,14 @@ int hid_parse_report(struct hid_device *device, __u8 *start, | |||
662 | hid_parser_reserved | 706 | hid_parser_reserved |
663 | }; | 707 | }; |
664 | 708 | ||
709 | if (WARN_ON(device->status & HID_STAT_PARSED)) | ||
710 | return -EBUSY; | ||
711 | |||
712 | start = device->dev_rdesc; | ||
713 | if (WARN_ON(!start)) | ||
714 | return -ENODEV; | ||
715 | size = device->dev_rsize; | ||
716 | |||
665 | if (device->driver->report_fixup) | 717 | if (device->driver->report_fixup) |
666 | start = device->driver->report_fixup(device, start, &size); | 718 | start = device->driver->report_fixup(device, start, &size); |
667 | 719 | ||
@@ -679,6 +731,15 @@ int hid_parse_report(struct hid_device *device, __u8 *start, | |||
679 | parser->device = device; | 731 | parser->device = device; |
680 | 732 | ||
681 | end = start + size; | 733 | end = start + size; |
734 | |||
735 | device->collection = kcalloc(HID_DEFAULT_NUM_COLLECTIONS, | ||
736 | sizeof(struct hid_collection), GFP_KERNEL); | ||
737 | if (!device->collection) { | ||
738 | ret = -ENOMEM; | ||
739 | goto err; | ||
740 | } | ||
741 | device->collection_size = HID_DEFAULT_NUM_COLLECTIONS; | ||
742 | |||
682 | ret = -EINVAL; | 743 | ret = -EINVAL; |
683 | while ((start = fetch_item(start, end, &item)) != NULL) { | 744 | while ((start = fetch_item(start, end, &item)) != NULL) { |
684 | 745 | ||
@@ -704,6 +765,7 @@ int hid_parse_report(struct hid_device *device, __u8 *start, | |||
704 | goto err; | 765 | goto err; |
705 | } | 766 | } |
706 | vfree(parser); | 767 | vfree(parser); |
768 | device->status |= HID_STAT_PARSED; | ||
707 | return 0; | 769 | return 0; |
708 | } | 770 | } |
709 | } | 771 | } |
@@ -711,9 +773,10 @@ int hid_parse_report(struct hid_device *device, __u8 *start, | |||
711 | hid_err(device, "item fetching failed at offset %d\n", (int)(end - start)); | 773 | hid_err(device, "item fetching failed at offset %d\n", (int)(end - start)); |
712 | err: | 774 | err: |
713 | vfree(parser); | 775 | vfree(parser); |
776 | hid_close_report(device); | ||
714 | return ret; | 777 | return ret; |
715 | } | 778 | } |
716 | EXPORT_SYMBOL_GPL(hid_parse_report); | 779 | EXPORT_SYMBOL_GPL(hid_open_report); |
717 | 780 | ||
718 | /* | 781 | /* |
719 | * Convert a signed n-bit integer to signed 32-bit integer. Common | 782 | * Convert a signed n-bit integer to signed 32-bit integer. Common |
@@ -1718,12 +1781,14 @@ static int hid_device_probe(struct device *dev) | |||
1718 | if (hdrv->probe) { | 1781 | if (hdrv->probe) { |
1719 | ret = hdrv->probe(hdev, id); | 1782 | ret = hdrv->probe(hdev, id); |
1720 | } else { /* default probe */ | 1783 | } else { /* default probe */ |
1721 | ret = hid_parse(hdev); | 1784 | ret = hid_open_report(hdev); |
1722 | if (!ret) | 1785 | if (!ret) |
1723 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | 1786 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); |
1724 | } | 1787 | } |
1725 | if (ret) | 1788 | if (ret) { |
1789 | hid_close_report(hdev); | ||
1726 | hdev->driver = NULL; | 1790 | hdev->driver = NULL; |
1791 | } | ||
1727 | } | 1792 | } |
1728 | unlock: | 1793 | unlock: |
1729 | up(&hdev->driver_lock); | 1794 | up(&hdev->driver_lock); |
@@ -1744,6 +1809,7 @@ static int hid_device_remove(struct device *dev) | |||
1744 | hdrv->remove(hdev); | 1809 | hdrv->remove(hdev); |
1745 | else /* default remove */ | 1810 | else /* default remove */ |
1746 | hid_hw_stop(hdev); | 1811 | hid_hw_stop(hdev); |
1812 | hid_close_report(hdev); | ||
1747 | hdev->driver = NULL; | 1813 | hdev->driver = NULL; |
1748 | } | 1814 | } |
1749 | 1815 | ||
@@ -2075,6 +2141,16 @@ int hid_add_device(struct hid_device *hdev) | |||
2075 | && (hid_ignore(hdev) || (hdev->quirks & HID_QUIRK_IGNORE))) | 2141 | && (hid_ignore(hdev) || (hdev->quirks & HID_QUIRK_IGNORE))) |
2076 | return -ENODEV; | 2142 | return -ENODEV; |
2077 | 2143 | ||
2144 | /* | ||
2145 | * Read the device report descriptor once and use as template | ||
2146 | * for the driver-specific modifications. | ||
2147 | */ | ||
2148 | ret = hdev->ll_driver->parse(hdev); | ||
2149 | if (ret) | ||
2150 | return ret; | ||
2151 | if (!hdev->dev_rdesc) | ||
2152 | return -ENODEV; | ||
2153 | |||
2078 | /* XXX hack, any other cleaner solution after the driver core | 2154 | /* XXX hack, any other cleaner solution after the driver core |
2079 | * is converted to allow more than 20 bytes as the device name? */ | 2155 | * is converted to allow more than 20 bytes as the device name? */ |
2080 | dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus, | 2156 | dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus, |
@@ -2103,7 +2179,6 @@ EXPORT_SYMBOL_GPL(hid_add_device); | |||
2103 | struct hid_device *hid_allocate_device(void) | 2179 | struct hid_device *hid_allocate_device(void) |
2104 | { | 2180 | { |
2105 | struct hid_device *hdev; | 2181 | struct hid_device *hdev; |
2106 | unsigned int i; | ||
2107 | int ret = -ENOMEM; | 2182 | int ret = -ENOMEM; |
2108 | 2183 | ||
2109 | hdev = kzalloc(sizeof(*hdev), GFP_KERNEL); | 2184 | hdev = kzalloc(sizeof(*hdev), GFP_KERNEL); |
@@ -2114,23 +2189,13 @@ struct hid_device *hid_allocate_device(void) | |||
2114 | hdev->dev.release = hid_device_release; | 2189 | hdev->dev.release = hid_device_release; |
2115 | hdev->dev.bus = &hid_bus_type; | 2190 | hdev->dev.bus = &hid_bus_type; |
2116 | 2191 | ||
2117 | hdev->collection = kcalloc(HID_DEFAULT_NUM_COLLECTIONS, | 2192 | hid_close_report(hdev); |
2118 | sizeof(struct hid_collection), GFP_KERNEL); | ||
2119 | if (hdev->collection == NULL) | ||
2120 | goto err; | ||
2121 | hdev->collection_size = HID_DEFAULT_NUM_COLLECTIONS; | ||
2122 | |||
2123 | for (i = 0; i < HID_REPORT_TYPES; i++) | ||
2124 | INIT_LIST_HEAD(&hdev->report_enum[i].report_list); | ||
2125 | 2193 | ||
2126 | init_waitqueue_head(&hdev->debug_wait); | 2194 | init_waitqueue_head(&hdev->debug_wait); |
2127 | INIT_LIST_HEAD(&hdev->debug_list); | 2195 | INIT_LIST_HEAD(&hdev->debug_list); |
2128 | sema_init(&hdev->driver_lock, 1); | 2196 | sema_init(&hdev->driver_lock, 1); |
2129 | 2197 | ||
2130 | return hdev; | 2198 | return hdev; |
2131 | err: | ||
2132 | put_device(&hdev->dev); | ||
2133 | return ERR_PTR(ret); | ||
2134 | } | 2199 | } |
2135 | EXPORT_SYMBOL_GPL(hid_allocate_device); | 2200 | EXPORT_SYMBOL_GPL(hid_allocate_device); |
2136 | 2201 | ||
@@ -2141,6 +2206,9 @@ static void hid_remove_device(struct hid_device *hdev) | |||
2141 | hid_debug_unregister(hdev); | 2206 | hid_debug_unregister(hdev); |
2142 | hdev->status &= ~HID_STAT_ADDED; | 2207 | hdev->status &= ~HID_STAT_ADDED; |
2143 | } | 2208 | } |
2209 | kfree(hdev->dev_rdesc); | ||
2210 | hdev->dev_rdesc = NULL; | ||
2211 | hdev->dev_rsize = 0; | ||
2144 | } | 2212 | } |
2145 | 2213 | ||
2146 | /** | 2214 | /** |
diff --git a/include/linux/hid.h b/include/linux/hid.h index 3a95da60fd3e..d8e7cc7f894f 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
@@ -467,6 +467,8 @@ struct hid_driver; | |||
467 | struct hid_ll_driver; | 467 | struct hid_ll_driver; |
468 | 468 | ||
469 | struct hid_device { /* device report descriptor */ | 469 | struct hid_device { /* device report descriptor */ |
470 | __u8 *dev_rdesc; | ||
471 | unsigned dev_rsize; | ||
470 | __u8 *rdesc; | 472 | __u8 *rdesc; |
471 | unsigned rsize; | 473 | unsigned rsize; |
472 | struct hid_collection *collection; /* List of HID collections */ | 474 | struct hid_collection *collection; /* List of HID collections */ |
@@ -735,6 +737,7 @@ void hid_output_report(struct hid_report *report, __u8 *data); | |||
735 | struct hid_device *hid_allocate_device(void); | 737 | struct hid_device *hid_allocate_device(void); |
736 | struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id); | 738 | struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id); |
737 | int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size); | 739 | int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size); |
740 | int hid_open_report(struct hid_device *device); | ||
738 | int hid_check_keys_pressed(struct hid_device *hid); | 741 | int hid_check_keys_pressed(struct hid_device *hid); |
739 | int hid_connect(struct hid_device *hid, unsigned int connect_mask); | 742 | int hid_connect(struct hid_device *hid, unsigned int connect_mask); |
740 | void hid_disconnect(struct hid_device *hid); | 743 | void hid_disconnect(struct hid_device *hid); |
@@ -805,16 +808,7 @@ static inline void hid_map_usage_clear(struct hid_input *hidinput, | |||
805 | */ | 808 | */ |
806 | static inline int __must_check hid_parse(struct hid_device *hdev) | 809 | static inline int __must_check hid_parse(struct hid_device *hdev) |
807 | { | 810 | { |
808 | int ret; | 811 | return hid_open_report(hdev); |
809 | |||
810 | if (hdev->status & HID_STAT_PARSED) | ||
811 | return 0; | ||
812 | |||
813 | ret = hdev->ll_driver->parse(hdev); | ||
814 | if (!ret) | ||
815 | hdev->status |= HID_STAT_PARSED; | ||
816 | |||
817 | return ret; | ||
818 | } | 812 | } |
819 | 813 | ||
820 | /** | 814 | /** |