diff options
author | Michal Malý <madcatxster@devoid-pointer.net> | 2015-02-18 11:59:21 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2015-02-18 15:14:54 -0500 |
commit | b96d23ec698fdc1fdf904e5547d9abb6354eef5c (patch) | |
tree | 042da86c415119ce04290685012627d32a79f937 | |
parent | e7c234496d01c90a4b042d899a65e10f1f63ebc1 (diff) |
HID: hid-lg4ff: Export the real wheel model and supported alternate modes
Display the real wheel model and supported alternate modes through sysfs. This
applies only to multimode wheels.
Signed-off-by: Michal Malý <madcatxster@devoid-pointer.net>
Tested-by: Simon Wood <simon@mungewell.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r-- | Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff | 20 | ||||
-rw-r--r-- | drivers/hid/hid-lg4ff.c | 205 |
2 files changed, 218 insertions, 7 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff index 167d9032b970..60f24a1d8119 100644 --- a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff +++ b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff | |||
@@ -5,3 +5,23 @@ Contact: Michal Malý <madcatxster@gmail.com> | |||
5 | Description: Display minimum, maximum and current range of the steering | 5 | Description: Display minimum, maximum and current range of the steering |
6 | wheel. Writing a value within min and max boundaries sets the | 6 | wheel. Writing a value within min and max boundaries sets the |
7 | range of the wheel. | 7 | range of the wheel. |
8 | |||
9 | What: /sys/bus/hid/drivers/logitech/<dev>/alternate_modes | ||
10 | Date: Feb 2015 | ||
11 | KernelVersion: 4.1 | ||
12 | Contact: Michal Malý <madcatxster@gmail.com> | ||
13 | Description: Displays a set of alternate modes supported by a wheel. Each | ||
14 | mode is listed as follows: | ||
15 | Tag: Mode Name | ||
16 | Currently active mode is marked with an asterisk. List also | ||
17 | contains an abstract item "native" which always denotes the | ||
18 | native mode of the wheel. | ||
19 | |||
20 | What: /sys/bus/hid/drivers/logitech/<dev>/real_id | ||
21 | Date: Feb 2015 | ||
22 | KernelVersion: 4.1 | ||
23 | Contact: Michal Malý <madcatxster@gmail.com> | ||
24 | Description: Displays the real model of the wheel regardless of any | ||
25 | alternate mode the wheel might be switched to. | ||
26 | It is a read-only value. | ||
27 | This entry is not created for devices that have only one mode. | ||
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 190c5e3f46ce..a64a35ed291f 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c | |||
@@ -34,10 +34,36 @@ | |||
34 | 34 | ||
35 | #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev) | 35 | #define to_hid_device(pdev) container_of(pdev, struct hid_device, dev) |
36 | 36 | ||
37 | #define LG4FF_MMODE_DONE 0 | 37 | #define LG4FF_MMODE_IS_MULTIMODE 0 |
38 | #define LG4FF_MMODE_SWITCHED 1 | 38 | #define LG4FF_MMODE_SWITCHED 1 |
39 | #define LG4FF_MMODE_NOT_MULTIMODE 2 | 39 | #define LG4FF_MMODE_NOT_MULTIMODE 2 |
40 | 40 | ||
41 | #define LG4FF_MODE_NATIVE_IDX 0 | ||
42 | #define LG4FF_MODE_DFEX_IDX 1 | ||
43 | #define LG4FF_MODE_DFP_IDX 2 | ||
44 | #define LG4FF_MODE_G25_IDX 3 | ||
45 | #define LG4FF_MODE_DFGT_IDX 4 | ||
46 | #define LG4FF_MODE_G27_IDX 5 | ||
47 | #define LG4FF_MODE_MAX_IDX 6 | ||
48 | |||
49 | #define LG4FF_MODE_NATIVE BIT(LG4FF_MODE_NATIVE_IDX) | ||
50 | #define LG4FF_MODE_DFEX BIT(LG4FF_MODE_DFEX_IDX) | ||
51 | #define LG4FF_MODE_DFP BIT(LG4FF_MODE_DFP_IDX) | ||
52 | #define LG4FF_MODE_G25 BIT(LG4FF_MODE_G25_IDX) | ||
53 | #define LG4FF_MODE_DFGT BIT(LG4FF_MODE_DFGT_IDX) | ||
54 | #define LG4FF_MODE_G27 BIT(LG4FF_MODE_G27_IDX) | ||
55 | |||
56 | #define LG4FF_DFEX_TAG "DF-EX" | ||
57 | #define LG4FF_DFEX_NAME "Driving Force / Formula EX" | ||
58 | #define LG4FF_DFP_TAG "DFP" | ||
59 | #define LG4FF_DFP_NAME "Driving Force Pro" | ||
60 | #define LG4FF_G25_TAG "G25" | ||
61 | #define LG4FF_G25_NAME "G25 Racing Wheel" | ||
62 | #define LG4FF_G27_TAG "G27" | ||
63 | #define LG4FF_G27_NAME "G27 Racing Wheel" | ||
64 | #define LG4FF_DFGT_TAG "DFGT" | ||
65 | #define LG4FF_DFGT_NAME "Driving Force GT" | ||
66 | |||
41 | #define LG4FF_FFEX_REV_MAJ 0x21 | 67 | #define LG4FF_FFEX_REV_MAJ 0x21 |
42 | #define LG4FF_FFEX_REV_MIN 0x00 | 68 | #define LG4FF_FFEX_REV_MIN 0x00 |
43 | 69 | ||
@@ -53,6 +79,10 @@ struct lg4ff_device_entry { | |||
53 | __u8 led_state; | 79 | __u8 led_state; |
54 | struct led_classdev *led[5]; | 80 | struct led_classdev *led[5]; |
55 | #endif | 81 | #endif |
82 | u32 alternate_modes; | ||
83 | const char *real_tag; | ||
84 | const char *real_name; | ||
85 | u16 real_product_id; | ||
56 | struct list_head list; | 86 | struct list_head list; |
57 | void (*set_range)(struct hid_device *hid, u16 range); | 87 | void (*set_range)(struct hid_device *hid, u16 range); |
58 | }; | 88 | }; |
@@ -87,6 +117,19 @@ struct lg4ff_wheel_ident_checklist { | |||
87 | const struct lg4ff_wheel_ident_info *models[]; | 117 | const struct lg4ff_wheel_ident_info *models[]; |
88 | }; | 118 | }; |
89 | 119 | ||
120 | struct lg4ff_multimode_wheel { | ||
121 | const u16 product_id; | ||
122 | const u32 alternate_modes; | ||
123 | const char *real_tag; | ||
124 | const char *real_name; | ||
125 | }; | ||
126 | |||
127 | struct lg4ff_alternate_mode { | ||
128 | const u16 product_id; | ||
129 | const char *tag; | ||
130 | const char *name; | ||
131 | }; | ||
132 | |||
90 | static const struct lg4ff_wheel lg4ff_devices[] = { | 133 | static const struct lg4ff_wheel lg4ff_devices[] = { |
91 | {USB_DEVICE_ID_LOGITECH_WHEEL, lg4ff_wheel_effects, 40, 270, NULL}, | 134 | {USB_DEVICE_ID_LOGITECH_WHEEL, lg4ff_wheel_effects, 40, 270, NULL}, |
92 | {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL, lg4ff_wheel_effects, 40, 270, NULL}, | 135 | {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL, lg4ff_wheel_effects, 40, 270, NULL}, |
@@ -98,6 +141,30 @@ static const struct lg4ff_wheel lg4ff_devices[] = { | |||
98 | {USB_DEVICE_ID_LOGITECH_WII_WHEEL, lg4ff_wheel_effects, 40, 270, NULL} | 141 | {USB_DEVICE_ID_LOGITECH_WII_WHEEL, lg4ff_wheel_effects, 40, 270, NULL} |
99 | }; | 142 | }; |
100 | 143 | ||
144 | static const struct lg4ff_multimode_wheel lg4ff_multimode_wheels[] = { | ||
145 | {USB_DEVICE_ID_LOGITECH_DFP_WHEEL, | ||
146 | LG4FF_MODE_NATIVE | LG4FF_MODE_DFP | LG4FF_MODE_DFEX, | ||
147 | LG4FF_DFP_TAG, LG4FF_DFP_NAME}, | ||
148 | {USB_DEVICE_ID_LOGITECH_G25_WHEEL, | ||
149 | LG4FF_MODE_NATIVE | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX, | ||
150 | LG4FF_G25_TAG, LG4FF_G25_NAME}, | ||
151 | {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, | ||
152 | LG4FF_MODE_NATIVE | LG4FF_MODE_DFGT | LG4FF_MODE_DFP | LG4FF_MODE_DFEX, | ||
153 | LG4FF_DFGT_TAG, LG4FF_DFGT_NAME}, | ||
154 | {USB_DEVICE_ID_LOGITECH_G27_WHEEL, | ||
155 | LG4FF_MODE_NATIVE | LG4FF_MODE_G27 | LG4FF_MODE_G25 | LG4FF_MODE_DFP | LG4FF_MODE_DFEX, | ||
156 | LG4FF_G27_TAG, LG4FF_G27_NAME}, | ||
157 | }; | ||
158 | |||
159 | static const struct lg4ff_alternate_mode lg4ff_alternate_modes[] = { | ||
160 | [LG4FF_MODE_NATIVE_IDX] = {0, "native", ""}, | ||
161 | [LG4FF_MODE_DFEX_IDX] = {USB_DEVICE_ID_LOGITECH_WHEEL, LG4FF_DFEX_TAG, LG4FF_DFEX_NAME}, | ||
162 | [LG4FF_MODE_DFP_IDX] = {USB_DEVICE_ID_LOGITECH_DFP_WHEEL, LG4FF_DFP_TAG, LG4FF_DFP_NAME}, | ||
163 | [LG4FF_MODE_G25_IDX] = {USB_DEVICE_ID_LOGITECH_G25_WHEEL, LG4FF_G25_TAG, LG4FF_G25_NAME}, | ||
164 | [LG4FF_MODE_DFGT_IDX] = {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, LG4FF_DFGT_TAG, LG4FF_DFGT_NAME}, | ||
165 | [LG4FF_MODE_G27_IDX] = {USB_DEVICE_ID_LOGITECH_G27_WHEEL, LG4FF_G27_TAG, LG4FF_G27_NAME} | ||
166 | }; | ||
167 | |||
101 | /* Multimode wheel identificators */ | 168 | /* Multimode wheel identificators */ |
102 | static const struct lg4ff_wheel_ident_info lg4ff_dfp_ident_info = { | 169 | static const struct lg4ff_wheel_ident_info lg4ff_dfp_ident_info = { |
103 | 0xf000, | 170 | 0xf000, |
@@ -439,6 +506,61 @@ static int lg4ff_switch_compatibility_mode(struct hid_device *hid, const struct | |||
439 | return 0; | 506 | return 0; |
440 | } | 507 | } |
441 | 508 | ||
509 | static ssize_t lg4ff_alternate_modes_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
510 | { | ||
511 | struct hid_device *hid = to_hid_device(dev); | ||
512 | struct lg4ff_device_entry *entry; | ||
513 | struct lg_drv_data *drv_data; | ||
514 | ssize_t count = 0; | ||
515 | int i; | ||
516 | |||
517 | drv_data = hid_get_drvdata(hid); | ||
518 | if (!drv_data) { | ||
519 | hid_err(hid, "Private driver data not found!\n"); | ||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | entry = drv_data->device_props; | ||
524 | if (!entry) { | ||
525 | hid_err(hid, "Device properties not found!\n"); | ||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | if (!entry->real_name) { | ||
530 | hid_err(hid, "NULL pointer to string\n"); | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | for (i = 0; i < LG4FF_MODE_MAX_IDX; i++) { | ||
535 | if (entry->alternate_modes & BIT(i)) { | ||
536 | /* Print tag and full name */ | ||
537 | count += scnprintf(buf + count, PAGE_SIZE - count, "%s: %s", | ||
538 | lg4ff_alternate_modes[i].tag, | ||
539 | !lg4ff_alternate_modes[i].product_id ? entry->real_name : lg4ff_alternate_modes[i].name); | ||
540 | if (count >= PAGE_SIZE - 1) | ||
541 | return count; | ||
542 | |||
543 | /* Mark the currently active mode with an asterisk */ | ||
544 | if (lg4ff_alternate_modes[i].product_id == entry->product_id || | ||
545 | (lg4ff_alternate_modes[i].product_id == 0 && entry->product_id == entry->real_product_id)) | ||
546 | count += scnprintf(buf + count, PAGE_SIZE - count, " *\n"); | ||
547 | else | ||
548 | count += scnprintf(buf + count, PAGE_SIZE - count, "\n"); | ||
549 | |||
550 | if (count >= PAGE_SIZE - 1) | ||
551 | return count; | ||
552 | } | ||
553 | } | ||
554 | |||
555 | return count; | ||
556 | } | ||
557 | |||
558 | static ssize_t lg4ff_alternate_modes_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
559 | { | ||
560 | return -ENOSYS; | ||
561 | } | ||
562 | static DEVICE_ATTR(alternate_modes, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, lg4ff_alternate_modes_show, lg4ff_alternate_modes_store); | ||
563 | |||
442 | /* Read current range and display it in terminal */ | 564 | /* Read current range and display it in terminal */ |
443 | static ssize_t range_show(struct device *dev, struct device_attribute *attr, | 565 | static ssize_t range_show(struct device *dev, struct device_attribute *attr, |
444 | char *buf) | 566 | char *buf) |
@@ -500,6 +622,41 @@ static ssize_t range_store(struct device *dev, struct device_attribute *attr, | |||
500 | } | 622 | } |
501 | static DEVICE_ATTR_RW(range); | 623 | static DEVICE_ATTR_RW(range); |
502 | 624 | ||
625 | static ssize_t lg4ff_real_id_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
626 | { | ||
627 | struct hid_device *hid = to_hid_device(dev); | ||
628 | struct lg4ff_device_entry *entry; | ||
629 | struct lg_drv_data *drv_data; | ||
630 | size_t count; | ||
631 | |||
632 | drv_data = hid_get_drvdata(hid); | ||
633 | if (!drv_data) { | ||
634 | hid_err(hid, "Private driver data not found!\n"); | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | entry = drv_data->device_props; | ||
639 | if (!entry) { | ||
640 | hid_err(hid, "Device properties not found!\n"); | ||
641 | return 0; | ||
642 | } | ||
643 | |||
644 | if (!entry->real_tag || !entry->real_name) { | ||
645 | hid_err(hid, "NULL pointer to string\n"); | ||
646 | return 0; | ||
647 | } | ||
648 | |||
649 | count = scnprintf(buf, PAGE_SIZE, "%s: %s\n", entry->real_tag, entry->real_name); | ||
650 | return count; | ||
651 | } | ||
652 | |||
653 | static ssize_t lg4ff_real_id_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
654 | { | ||
655 | /* Real ID is a read-only value */ | ||
656 | return -EPERM; | ||
657 | } | ||
658 | static DEVICE_ATTR(real_id, S_IRUGO, lg4ff_real_id_show, lg4ff_real_id_store); | ||
659 | |||
503 | #ifdef CONFIG_LEDS_CLASS | 660 | #ifdef CONFIG_LEDS_CLASS |
504 | static void lg4ff_set_leds(struct hid_device *hid, __u8 leds) | 661 | static void lg4ff_set_leds(struct hid_device *hid, __u8 leds) |
505 | { | 662 | { |
@@ -664,7 +821,7 @@ static int lg4ff_handle_multimode_wheel(struct hid_device *hid, u16 *real_produc | |||
664 | break; | 821 | break; |
665 | default: | 822 | default: |
666 | hid_err(hid, "Invalid product id %X\n", *real_product_id); | 823 | hid_err(hid, "Invalid product id %X\n", *real_product_id); |
667 | return LG4FF_MMODE_DONE; | 824 | return LG4FF_MMODE_NOT_MULTIMODE; |
668 | } | 825 | } |
669 | 826 | ||
670 | ret = lg4ff_switch_compatibility_mode(hid, s); | 827 | ret = lg4ff_switch_compatibility_mode(hid, s); |
@@ -672,12 +829,12 @@ static int lg4ff_handle_multimode_wheel(struct hid_device *hid, u16 *real_produc | |||
672 | /* Wheel could not have been switched to native mode, | 829 | /* Wheel could not have been switched to native mode, |
673 | * leave it in "Driving Force" mode and continue */ | 830 | * leave it in "Driving Force" mode and continue */ |
674 | hid_err(hid, "Unable to switch wheel mode, errno %d\n", ret); | 831 | hid_err(hid, "Unable to switch wheel mode, errno %d\n", ret); |
675 | return LG4FF_MMODE_DONE; | 832 | return LG4FF_MMODE_IS_MULTIMODE; |
676 | } | 833 | } |
677 | return LG4FF_MMODE_SWITCHED; | 834 | return LG4FF_MMODE_SWITCHED; |
678 | } | 835 | } |
679 | 836 | ||
680 | return LG4FF_MMODE_DONE; | 837 | return LG4FF_MMODE_IS_MULTIMODE; |
681 | } | 838 | } |
682 | 839 | ||
683 | 840 | ||
@@ -689,7 +846,8 @@ int lg4ff_init(struct hid_device *hid) | |||
689 | const u16 bcdDevice = le16_to_cpu(udesc->bcdDevice); | 846 | const u16 bcdDevice = le16_to_cpu(udesc->bcdDevice); |
690 | struct lg4ff_device_entry *entry; | 847 | struct lg4ff_device_entry *entry; |
691 | struct lg_drv_data *drv_data; | 848 | struct lg_drv_data *drv_data; |
692 | int error, i, j, ret; | 849 | int error, i, j; |
850 | int mmode_ret, mmode_idx = -1; | ||
693 | u16 real_product_id; | 851 | u16 real_product_id; |
694 | 852 | ||
695 | /* Check that the report looks ok */ | 853 | /* Check that the report looks ok */ |
@@ -698,12 +856,12 @@ int lg4ff_init(struct hid_device *hid) | |||
698 | 856 | ||
699 | /* Check if a multimode wheel has been connected and | 857 | /* Check if a multimode wheel has been connected and |
700 | * handle it appropriately */ | 858 | * handle it appropriately */ |
701 | ret = lg4ff_handle_multimode_wheel(hid, &real_product_id, bcdDevice); | 859 | mmode_ret = lg4ff_handle_multimode_wheel(hid, &real_product_id, bcdDevice); |
702 | 860 | ||
703 | /* Wheel has been told to switch to native mode. There is no point in going on | 861 | /* Wheel has been told to switch to native mode. There is no point in going on |
704 | * with the initialization as the wheel will do a USB reset when it switches mode | 862 | * with the initialization as the wheel will do a USB reset when it switches mode |
705 | */ | 863 | */ |
706 | if (ret == LG4FF_MMODE_SWITCHED) | 864 | if (mmode_ret == LG4FF_MMODE_SWITCHED) |
707 | return 0; | 865 | return 0; |
708 | 866 | ||
709 | /* Check what wheel has been connected */ | 867 | /* Check what wheel has been connected */ |
@@ -720,6 +878,18 @@ int lg4ff_init(struct hid_device *hid) | |||
720 | return -1; | 878 | return -1; |
721 | } | 879 | } |
722 | 880 | ||
881 | if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) { | ||
882 | for (mmode_idx = 0; mmode_idx < ARRAY_SIZE(lg4ff_multimode_wheels); mmode_idx++) { | ||
883 | if (real_product_id == lg4ff_multimode_wheels[mmode_idx].product_id) | ||
884 | break; | ||
885 | } | ||
886 | |||
887 | if (mmode_idx == ARRAY_SIZE(lg4ff_multimode_wheels)) { | ||
888 | hid_err(hid, "Device product ID %X is not listed as a multimode wheel", real_product_id); | ||
889 | return -1; | ||
890 | } | ||
891 | } | ||
892 | |||
723 | /* Set supported force feedback capabilities */ | 893 | /* Set supported force feedback capabilities */ |
724 | for (j = 0; lg4ff_devices[i].ff_effects[j] >= 0; j++) | 894 | for (j = 0; lg4ff_devices[i].ff_effects[j] >= 0; j++) |
725 | set_bit(lg4ff_devices[i].ff_effects[j], dev->ffbit); | 895 | set_bit(lg4ff_devices[i].ff_effects[j], dev->ffbit); |
@@ -745,9 +915,16 @@ int lg4ff_init(struct hid_device *hid) | |||
745 | drv_data->device_props = entry; | 915 | drv_data->device_props = entry; |
746 | 916 | ||
747 | entry->product_id = lg4ff_devices[i].product_id; | 917 | entry->product_id = lg4ff_devices[i].product_id; |
918 | entry->real_product_id = real_product_id; | ||
748 | entry->min_range = lg4ff_devices[i].min_range; | 919 | entry->min_range = lg4ff_devices[i].min_range; |
749 | entry->max_range = lg4ff_devices[i].max_range; | 920 | entry->max_range = lg4ff_devices[i].max_range; |
750 | entry->set_range = lg4ff_devices[i].set_range; | 921 | entry->set_range = lg4ff_devices[i].set_range; |
922 | if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) { | ||
923 | BUG_ON(mmode_idx == -1); | ||
924 | entry->alternate_modes = lg4ff_multimode_wheels[mmode_idx].alternate_modes; | ||
925 | entry->real_tag = lg4ff_multimode_wheels[mmode_idx].real_tag; | ||
926 | entry->real_name = lg4ff_multimode_wheels[mmode_idx].real_name; | ||
927 | } | ||
751 | 928 | ||
752 | /* Check if autocentering is available and | 929 | /* Check if autocentering is available and |
753 | * set the centering force to zero by default */ | 930 | * set the centering force to zero by default */ |
@@ -766,6 +943,14 @@ int lg4ff_init(struct hid_device *hid) | |||
766 | error = device_create_file(&hid->dev, &dev_attr_range); | 943 | error = device_create_file(&hid->dev, &dev_attr_range); |
767 | if (error) | 944 | if (error) |
768 | return error; | 945 | return error; |
946 | if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) { | ||
947 | error = device_create_file(&hid->dev, &dev_attr_real_id); | ||
948 | if (error) | ||
949 | return error; | ||
950 | error = device_create_file(&hid->dev, &dev_attr_alternate_modes); | ||
951 | if (error) | ||
952 | return error; | ||
953 | } | ||
769 | dbg_hid("sysfs interface created\n"); | 954 | dbg_hid("sysfs interface created\n"); |
770 | 955 | ||
771 | /* Set the maximum range to start with */ | 956 | /* Set the maximum range to start with */ |
@@ -844,6 +1029,12 @@ int lg4ff_deinit(struct hid_device *hid) | |||
844 | 1029 | ||
845 | device_remove_file(&hid->dev, &dev_attr_range); | 1030 | device_remove_file(&hid->dev, &dev_attr_range); |
846 | 1031 | ||
1032 | /* Multimode devices will have at least the "MODE_NATIVE" bit set */ | ||
1033 | if (entry->alternate_modes) { | ||
1034 | device_remove_file(&hid->dev, &dev_attr_real_id); | ||
1035 | device_remove_file(&hid->dev, &dev_attr_alternate_modes); | ||
1036 | } | ||
1037 | |||
847 | #ifdef CONFIG_LEDS_CLASS | 1038 | #ifdef CONFIG_LEDS_CLASS |
848 | { | 1039 | { |
849 | int j; | 1040 | int j; |