aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-07-28 17:30:16 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-07-28 17:30:16 -0400
commit884316deb4c9fdf9becfa31831a9e40717e3026c (patch)
tree9c0af0dd0ab659acd24c00f69c89b04058fe8f47
parent69c4289449b954f87ce33904bbb1b27dc075dcfa (diff)
parent8c2f421c1f0fa7768767ecaad497aa676fc9015a (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID updates from Jiri Kosina: - new hid-alps driver for ALPS Touchpad-Stick device, from Masaki Ota - much improved and generalized HID led handling, and merge of specialized hid-thingm driver into this generic hid-led one, from Heiner Kallweit - i2c-hid power management improvements from Fu Zhonghui and Guohua Zhong - uhid initialization race fix from Roderick Colenbrander * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (21 commits) HID: add usb device id for Apple Magic Keyboard HID: hid-led: fix Delcom support on big endian systems HID: hid-led: add support for Greynut Luxafor HID: hid-led: add support for Delcom Visual Signal Indicator G2 HID: hid-led: remove report id from struct hidled_config HID: alps: a few cleanups HID: remove ThingM blink(1) driver HID: hid-led: add support for ThingM blink(1) HID: hid-led: add support for reading from LED devices HID: hid-led: add support for devices with multiple independent LEDs HID: i2c-hid: set power sleep before shutdown HID: alps: match alps devices in core HID: thingm: simplify debug output code HID: alps: pass correct sizes to hid_hw_raw_request() HID: alps: struct u1_dev *priv is internal to the driver HID: add Alps I2C HID Touchpad-Stick support HID: led: fix config usb: misc: remove outdated USB LED driver HID: migrate USB LED driver from usb misc to hid HID: i2c_hid: enable i2c-hid devices to suspend/resume asynchronously ...
-rw-r--r--Documentation/hid/hid-alps.txt139
-rw-r--r--MAINTAINERS5
-rw-r--r--drivers/hid/Kconfig31
-rw-r--r--drivers/hid/Makefile3
-rw-r--r--drivers/hid/hid-alps.c506
-rw-r--r--drivers/hid/hid-apple.c2
-rw-r--r--drivers/hid/hid-core.c10
-rw-r--r--drivers/hid/hid-ids.h10
-rw-r--r--drivers/hid/hid-led.c523
-rw-r--r--drivers/hid/hid-thingm.c263
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c11
-rw-r--r--drivers/hid/uhid.c33
-rw-r--r--drivers/usb/misc/Kconfig9
-rw-r--r--drivers/usb/misc/Makefile1
-rw-r--r--drivers/usb/misc/usbled.c273
15 files changed, 1250 insertions, 569 deletions
diff --git a/Documentation/hid/hid-alps.txt b/Documentation/hid/hid-alps.txt
new file mode 100644
index 000000000000..6b02a2447c77
--- /dev/null
+++ b/Documentation/hid/hid-alps.txt
@@ -0,0 +1,139 @@
1ALPS HID Touchpad Protocol
2----------------------
3
4Introduction
5------------
6Currently ALPS HID driver supports U1 Touchpad device.
7
8U1 devuce basic information.
9Vender ID 0x044E
10Product ID 0x120B
11Version ID 0x0121
12
13
14HID Descriptor
15------------
16Byte Field Value Notes
170 wHIDDescLength 001E Length of HID Descriptor : 30 bytes
182 bcdVersion 0100 Compliant with Version 1.00
194 wReportDescLength 00B2 Report Descriptor is 178 Bytes (0x00B2)
206 wReportDescRegister 0002 Identifier to read Report Descriptor
218 wInputRegister 0003 Identifier to read Input Report
2210 wMaxInputLength 0053 Input Report is 80 Bytes + 2
2312 wOutputRegister 0000 Identifier to read Output Report
2414 wMaxOutputLength 0000 No Output Reports
2516 wCommandRegister 0005 Identifier for Command Register
2618 wDataRegister 0006 Identifier for Data Register
2720 wVendorID 044E Vendor ID 0x044E
2822 wProductID 120B Product ID 0x120B
2924 wVersionID 0121 Version 01.21
3026 RESERVED 0000 RESERVED
31
32
33Report ID
34------------
35ReportID-1 (Input Reports) (HIDUsage-Mouse) for TP&SP
36ReportID-2 (Input Reports) (HIDUsage-keyboard) for TP
37ReportID-3 (Input Reports) (Vendor Usage: Max 10 finger data) for TP
38ReportID-4 (Input Reports) (Vendor Usage: ON bit data) for GP
39ReportID-5 (Feature Reports) Feature Reports
40ReportID-6 (Input Reports) (Vendor Usage: StickPointer data) for SP
41ReportID-7 (Feature Reports) Flash update (Bootloader)
42
43
44Data pattern
45------------
46Case1 ReportID_1 TP/SP Relative/Relative
47Case2 ReportID_3 TP Absolute
48 ReportID_6 SP Absolute
49
50
51Command Read/Write
52------------------
53To read/write to RAM, need to send a commands to the device.
54The command format is as below.
55
56DataByte(SET_REPORT)
57Byte1 Command Byte
58Byte2 Address - Byte 0 (LSB)
59Byte3 Address - Byte 1
60Byte4 Address - Byte 2
61Byte5 Address - Byte 3 (MSB)
62Byte6 Value Byte
63Byte7 Checksum
64
65Command Byte is read=0xD1/write=0xD2 .
66Address is read/write RAM address.
67Value Byte is writing data when you send the write commands.
68When you read RAM, there is no meaning.
69
70DataByte(GET_REPORT)
71Byte1 Response Byte
72Byte2 Address - Byte 0 (LSB)
73Byte3 Address - Byte 1
74Byte4 Address - Byte 2
75Byte5 Address - Byte 3 (MSB)
76Byte6 Value Byte
77Byte7 Checksum
78
79Read value is stored in Value Byte.
80
81
82Packet Format
83Touchpad data byte
84------------------
85 b7 b6 b5 b4 b3 b2 b1 b0
861 0 0 SW6 SW5 SW4 SW3 SW2 SW1
872 0 0 0 Fcv Fn3 Fn2 Fn1 Fn0
883 Xa0_7 Xa0_6 Xa0_5 Xa0_4 Xa0_3 Xa0_2 Xa0_1 Xa0_0
894 Xa0_15 Xa0_14 Xa0_13 Xa0_12 Xa0_11 Xa0_10 Xa0_9 Xa0_8
905 Ya0_7 Ya0_6 Ya0_5 Ya0_4 Ya0_3 Ya0_2 Ya0_1 Ya0_0
916 Ya0_15 Ya0_14 Ya0_13 Ya0_12 Ya0_11 Ya0_10 Ya0_9 Ya0_8
927 LFB0 Zs0_6 Zs0_5 Zs0_4 Zs0_3 Zs0_2 Zs0_1 Zs0_0
93
948 Xa1_7 Xa1_6 Xa1_5 Xa1_4 Xa1_3 Xa1_2 Xa1_1 Xa1_0
959 Xa1_15 Xa1_14 Xa1_13 Xa1_12 Xa1_11 Xa1_10 Xa1_9 Xa1_8
9610 Ya1_7 Ya1_6 Ya1_5 Ya1_4 Ya1_3 Ya1_2 Ya1_1 Ya1_0
9711 Ya1_15 Ya1_14 Ya1_13 Ya1_12 Ya1_11 Ya1_10 Ya1_9 Ya1_8
9812 LFB1 Zs1_6 Zs1_5 Zs1_4 Zs1_3 Zs1_2 Zs1_1 Zs1_0
99
10013 Xa2_7 Xa2_6 Xa2_5 Xa2_4 Xa2_3 Xa2_2 Xa2_1 Xa2_0
10114 Xa2_15 Xa2_14 Xa2_13 Xa2_12 Xa2_11 Xa2_10 Xa2_9 Xa2_8
10215 Ya2_7 Ya2_6 Ya2_5 Ya2_4 Ya2_3 Ya2_2 Ya2_1 Ya2_0
10316 Ya2_15 Ya2_14 Ya2_13 Ya2_12 Ya2_11 Ya2_10 Ya2_9 Ya2_8
10417 LFB2 Zs2_6 Zs2_5 Zs2_4 Zs2_3 Zs2_2 Zs2_1 Zs2_0
105
10618 Xa3_7 Xa3_6 Xa3_5 Xa3_4 Xa3_3 Xa3_2 Xa3_1 Xa3_0
10719 Xa3_15 Xa3_14 Xa3_13 Xa3_12 Xa3_11 Xa3_10 Xa3_9 Xa3_8
10820 Ya3_7 Ya3_6 Ya3_5 Ya3_4 Ya3_3 Ya3_2 Ya3_1 Ya3_0
10921 Ya3_15 Ya3_14 Ya3_13 Ya3_12 Ya3_11 Ya3_10 Ya3_9 Ya3_8
11022 LFB3 Zs3_6 Zs3_5 Zs3_4 Zs3_3 Zs3_2 Zs3_1 Zs3_0
111
11223 Xa4_7 Xa4_6 Xa4_5 Xa4_4 Xa4_3 Xa4_2 Xa4_1 Xa4_0
11324 Xa4_15 Xa4_14 Xa4_13 Xa4_12 Xa4_11 Xa4_10 Xa4_9 Xa4_8
11425 Ya4_7 Ya4_6 Ya4_5 Ya4_4 Ya4_3 Ya4_2 Ya4_1 Ya4_0
11526 Ya4_15 Ya4_14 Ya4_13 Ya4_12 Ya4_11 Ya4_10 Ya4_9 Ya4_8
11627 LFB4 Zs4_6 Zs4_5 Zs4_4 Zs4_3 Zs4_2 Zs4_1 Zs4_0
117
118
119SW1-SW6: SW ON/OFF status
120Xan_15-0(16bit):X Absolute data of the "n"th finger
121Yan_15-0(16bit):Y Absolute data of the "n"th finger
122Zsn_6-0(7bit): Operation area of the "n"th finger
123
124
125StickPointer data byte
126------------------
127 b7 b6 b5 b4 b3 b2 b1 b0
128Byte1 1 1 1 0 1 SW3 SW2 SW1
129Byte2 X7 X6 X5 X4 X3 X2 X1 X0
130Byte3 X15 X14 X13 X12 X11 X10 X9 X8
131Byte4 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0
132Byte5 Y15 Y14 Y13 Y12 Y11 Y10 Y9 Y8
133Byte6 Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0
134Byte7 T&P Z14 Z13 Z12 Z11 Z10 Z9 Z8
135
136SW1-SW3: SW ON/OFF status
137Xn_15-0(16bit):X Absolute data
138Yn_15-0(16bit):Y Absolute data
139Zn_14-0(15bit):Z
diff --git a/MAINTAINERS b/MAINTAINERS
index c1739eba622d..6cbef714a975 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11440,11 +11440,6 @@ F: Documentation/thermal/cpu-cooling-api.txt
11440F: drivers/thermal/cpu_cooling.c 11440F: drivers/thermal/cpu_cooling.c
11441F: include/linux/cpu_cooling.h 11441F: include/linux/cpu_cooling.h
11442 11442
11443THINGM BLINK(1) USB RGB LED DRIVER
11444M: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
11445S: Maintained
11446F: drivers/hid/hid-thingm.c
11447
11448THINKPAD ACPI EXTRAS DRIVER 11443THINKPAD ACPI EXTRAS DRIVER
11449M: Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br> 11444M: Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br>
11450L: ibm-acpi-devel@lists.sourceforge.net 11445L: ibm-acpi-devel@lists.sourceforge.net
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 5646ca4b95de..78ac4811bd3c 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -388,6 +388,21 @@ config HID_LCPOWER
388 ---help--- 388 ---help---
389 Support for LC-Power RC1000MCE RF remote control. 389 Support for LC-Power RC1000MCE RF remote control.
390 390
391config HID_LED
392 tristate "Simple RGB LED support"
393 depends on HID
394 depends on LEDS_CLASS
395 ---help---
396 Support for simple RGB LED devices. Currently supported are:
397 - Riso Kagaku Webmail Notifier
398 - Dream Cheeky Webmail Notifier and Friends Alert
399 - ThingM blink(1)
400 - Delcom Visual Signal Indicator Generation 2
401 - Greynut Luxafor
402
403 To compile this driver as a module, choose M here: the
404 module will be called hid-led.
405
391config HID_LENOVO 406config HID_LENOVO
392 tristate "Lenovo / Thinkpad devices" 407 tristate "Lenovo / Thinkpad devices"
393 depends on HID 408 depends on HID
@@ -819,11 +834,11 @@ config HID_THINGM
819 tristate "ThingM blink(1) USB RGB LED" 834 tristate "ThingM blink(1) USB RGB LED"
820 depends on HID 835 depends on HID
821 depends on LEDS_CLASS 836 depends on LEDS_CLASS
837 select HID_LED
822 ---help--- 838 ---help---
823 Support for the ThingM blink(1) USB RGB LED. This driver registers a 839 Support for the ThingM blink(1) USB RGB LED. This driver has been
824 Linux LED class instance, plus additional sysfs attributes to control 840 merged into the generic hid led driver. Config symbol HID_THINGM
825 RGB colors, fade time and playing. The device is exposed through hidraw 841 just selects HID_LED and will be removed soon.
826 to access other functions.
827 842
828config HID_THRUSTMASTER 843config HID_THRUSTMASTER
829 tristate "ThrustMaster devices support" 844 tristate "ThrustMaster devices support"
@@ -936,6 +951,14 @@ config HID_SENSOR_CUSTOM_SENSOR
936 standard sensors. 951 standard sensors.
937 Select this config option for custom/generic sensor support. 952 Select this config option for custom/generic sensor support.
938 953
954config HID_ALPS
955 tristate "Alps HID device support"
956 depends on HID
957 ---help---
958 Support for Alps I2C HID touchpads and StickPointer.
959 Say Y here if you have a Alps touchpads over i2c-hid or usbhid
960 and want support for its special functionalities.
961
939endmenu 962endmenu
940 963
941endif # HID 964endif # HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index a2fb562de748..fc4b2aa47f2e 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -21,6 +21,7 @@ hid-wiimote-y := hid-wiimote-core.o hid-wiimote-modules.o
21hid-wiimote-$(CONFIG_DEBUG_FS) += hid-wiimote-debug.o 21hid-wiimote-$(CONFIG_DEBUG_FS) += hid-wiimote-debug.o
22 22
23obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o 23obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
24obj-$(CONFIG_HID_ALPS) += hid-alps.o
24obj-$(CONFIG_HID_ACRUX) += hid-axff.o 25obj-$(CONFIG_HID_ACRUX) += hid-axff.o
25obj-$(CONFIG_HID_APPLE) += hid-apple.o 26obj-$(CONFIG_HID_APPLE) += hid-apple.o
26obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o 27obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o
@@ -90,12 +91,12 @@ obj-$(CONFIG_HID_SPEEDLINK) += hid-speedlink.o
90obj-$(CONFIG_HID_STEELSERIES) += hid-steelseries.o 91obj-$(CONFIG_HID_STEELSERIES) += hid-steelseries.o
91obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o 92obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o
92obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o 93obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o
93obj-$(CONFIG_HID_THINGM) += hid-thingm.o
94obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o 94obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
95obj-$(CONFIG_HID_TIVO) += hid-tivo.o 95obj-$(CONFIG_HID_TIVO) += hid-tivo.o
96obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o 96obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
97obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o 97obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o
98obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o 98obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o
99obj-$(CONFIG_HID_LED) += hid-led.o
99obj-$(CONFIG_HID_XINMO) += hid-xinmo.o 100obj-$(CONFIG_HID_XINMO) += hid-xinmo.o
100obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o 101obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o
101obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o 102obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o
diff --git a/drivers/hid/hid-alps.c b/drivers/hid/hid-alps.c
new file mode 100644
index 000000000000..048befde295a
--- /dev/null
+++ b/drivers/hid/hid-alps.c
@@ -0,0 +1,506 @@
1/*
2 * Copyright (c) 2016 Masaki Ota <masaki.ota@jp.alps.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
7 * any later version.
8 */
9
10#include <linux/kernel.h>
11#include <linux/hid.h>
12#include <linux/input.h>
13#include <linux/input/mt.h>
14#include <linux/module.h>
15#include <asm/unaligned.h>
16#include "hid-ids.h"
17
18/* ALPS Device Product ID */
19#define HID_PRODUCT_ID_T3_BTNLESS 0xD0C0
20#define HID_PRODUCT_ID_COSMO 0x1202
21#define HID_PRODUCT_ID_U1_PTP_1 0x1207
22#define HID_PRODUCT_ID_U1 0x1209
23#define HID_PRODUCT_ID_U1_PTP_2 0x120A
24#define HID_PRODUCT_ID_U1_DUAL 0x120B
25#define HID_PRODUCT_ID_T4_BTNLESS 0x120C
26
27#define DEV_SINGLEPOINT 0x01
28#define DEV_DUALPOINT 0x02
29
30#define U1_MOUSE_REPORT_ID 0x01 /* Mouse data ReportID */
31#define U1_ABSOLUTE_REPORT_ID 0x03 /* Absolute data ReportID */
32#define U1_FEATURE_REPORT_ID 0x05 /* Feature ReportID */
33#define U1_SP_ABSOLUTE_REPORT_ID 0x06 /* Feature ReportID */
34
35#define U1_FEATURE_REPORT_LEN 0x08 /* Feature Report Length */
36#define U1_FEATURE_REPORT_LEN_ALL 0x0A
37#define U1_CMD_REGISTER_READ 0xD1
38#define U1_CMD_REGISTER_WRITE 0xD2
39
40#define U1_DEVTYPE_SP_SUPPORT 0x10 /* SP Support */
41#define U1_DISABLE_DEV 0x01
42#define U1_TP_ABS_MODE 0x02
43#define U1_SP_ABS_MODE 0x80
44
45#define ADDRESS_U1_DEV_CTRL_1 0x00800040
46#define ADDRESS_U1_DEVICE_TYP 0x00800043
47#define ADDRESS_U1_NUM_SENS_X 0x00800047
48#define ADDRESS_U1_NUM_SENS_Y 0x00800048
49#define ADDRESS_U1_PITCH_SENS_X 0x00800049
50#define ADDRESS_U1_PITCH_SENS_Y 0x0080004A
51#define ADDRESS_U1_RESO_DWN_ABS 0x0080004E
52#define ADDRESS_U1_PAD_BTN 0x00800052
53#define ADDRESS_U1_SP_BTN 0x0080009F
54
55#define MAX_TOUCHES 5
56
57/**
58 * struct u1_data
59 *
60 * @input: pointer to the kernel input device
61 * @input2: pointer to the kernel input2 device
62 * @hdev: pointer to the struct hid_device
63 *
64 * @dev_ctrl: device control parameter
65 * @dev_type: device type
66 * @sen_line_num_x: number of sensor line of X
67 * @sen_line_num_y: number of sensor line of Y
68 * @pitch_x: sensor pitch of X
69 * @pitch_y: sensor pitch of Y
70 * @resolution: resolution
71 * @btn_info: button information
72 * @x_active_len_mm: active area length of X (mm)
73 * @y_active_len_mm: active area length of Y (mm)
74 * @x_max: maximum x coordinate value
75 * @y_max: maximum y coordinate value
76 * @btn_cnt: number of buttons
77 * @sp_btn_cnt: number of stick buttons
78 */
79struct u1_dev {
80 struct input_dev *input;
81 struct input_dev *input2;
82 struct hid_device *hdev;
83
84 u8 dev_ctrl;
85 u8 dev_type;
86 u8 sen_line_num_x;
87 u8 sen_line_num_y;
88 u8 pitch_x;
89 u8 pitch_y;
90 u8 resolution;
91 u8 btn_info;
92 u8 sp_btn_info;
93 u32 x_active_len_mm;
94 u32 y_active_len_mm;
95 u32 x_max;
96 u32 y_max;
97 u32 btn_cnt;
98 u32 sp_btn_cnt;
99};
100
101static int u1_read_write_register(struct hid_device *hdev, u32 address,
102 u8 *read_val, u8 write_val, bool read_flag)
103{
104 int ret, i;
105 u8 check_sum;
106 u8 *input;
107 u8 *readbuf;
108
109 input = kzalloc(U1_FEATURE_REPORT_LEN, GFP_KERNEL);
110 if (!input)
111 return -ENOMEM;
112
113 input[0] = U1_FEATURE_REPORT_ID;
114 if (read_flag) {
115 input[1] = U1_CMD_REGISTER_READ;
116 input[6] = 0x00;
117 } else {
118 input[1] = U1_CMD_REGISTER_WRITE;
119 input[6] = write_val;
120 }
121
122 put_unaligned_le32(address, input + 2);
123
124 /* Calculate the checksum */
125 check_sum = U1_FEATURE_REPORT_LEN_ALL;
126 for (i = 0; i < U1_FEATURE_REPORT_LEN - 1; i++)
127 check_sum += input[i];
128
129 input[7] = check_sum;
130 ret = hid_hw_raw_request(hdev, U1_FEATURE_REPORT_ID, input,
131 U1_FEATURE_REPORT_LEN,
132 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
133
134 if (ret < 0) {
135 dev_err(&hdev->dev, "failed to read command (%d)\n", ret);
136 goto exit;
137 }
138
139 if (read_flag) {
140 readbuf = kzalloc(U1_FEATURE_REPORT_LEN, GFP_KERNEL);
141 if (!readbuf) {
142 kfree(input);
143 return -ENOMEM;
144 }
145
146 ret = hid_hw_raw_request(hdev, U1_FEATURE_REPORT_ID, readbuf,
147 U1_FEATURE_REPORT_LEN,
148 HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
149
150 if (ret < 0) {
151 dev_err(&hdev->dev, "failed read register (%d)\n", ret);
152 goto exit;
153 }
154
155 *read_val = readbuf[6];
156
157 kfree(readbuf);
158 }
159
160 ret = 0;
161
162exit:
163 kfree(input);
164 return ret;
165}
166
167static int alps_raw_event(struct hid_device *hdev,
168 struct hid_report *report, u8 *data, int size)
169{
170 unsigned int x, y, z;
171 int i;
172 short sp_x, sp_y;
173 struct u1_dev *hdata = hid_get_drvdata(hdev);
174
175 switch (data[0]) {
176 case U1_MOUSE_REPORT_ID:
177 break;
178 case U1_FEATURE_REPORT_ID:
179 break;
180 case U1_ABSOLUTE_REPORT_ID:
181 for (i = 0; i < MAX_TOUCHES; i++) {
182 u8 *contact = &data[i * 5];
183
184 x = get_unaligned_le16(contact + 3);
185 y = get_unaligned_le16(contact + 5);
186 z = contact[7] & 0x7F;
187
188 input_mt_slot(hdata->input, i);
189
190 if (z != 0) {
191 input_mt_report_slot_state(hdata->input,
192 MT_TOOL_FINGER, 1);
193 } else {
194 input_mt_report_slot_state(hdata->input,
195 MT_TOOL_FINGER, 0);
196 break;
197 }
198
199 input_report_abs(hdata->input, ABS_MT_POSITION_X, x);
200 input_report_abs(hdata->input, ABS_MT_POSITION_Y, y);
201 input_report_abs(hdata->input, ABS_MT_PRESSURE, z);
202
203 }
204
205 input_mt_sync_frame(hdata->input);
206
207 input_report_key(hdata->input, BTN_LEFT,
208 data[1] & 0x1);
209 input_report_key(hdata->input, BTN_RIGHT,
210 (data[1] & 0x2));
211 input_report_key(hdata->input, BTN_MIDDLE,
212 (data[1] & 0x4));
213
214 input_sync(hdata->input);
215
216 return 1;
217
218 case U1_SP_ABSOLUTE_REPORT_ID:
219 sp_x = get_unaligned_le16(data+2);
220 sp_y = get_unaligned_le16(data+4);
221
222 sp_x = sp_x / 8;
223 sp_y = sp_y / 8;
224
225 input_report_rel(hdata->input2, REL_X, sp_x);
226 input_report_rel(hdata->input2, REL_Y, sp_y);
227
228 input_report_key(hdata->input2, BTN_LEFT,
229 data[1] & 0x1);
230 input_report_key(hdata->input2, BTN_RIGHT,
231 (data[1] & 0x2));
232 input_report_key(hdata->input2, BTN_MIDDLE,
233 (data[1] & 0x4));
234
235 input_sync(hdata->input2);
236
237 return 1;
238 }
239
240 return 0;
241}
242
243#ifdef CONFIG_PM
244static int alps_post_reset(struct hid_device *hdev)
245{
246 return u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
247 NULL, U1_TP_ABS_MODE, false);
248}
249
250static int alps_post_resume(struct hid_device *hdev)
251{
252 return u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
253 NULL, U1_TP_ABS_MODE, false);
254}
255#endif /* CONFIG_PM */
256
257static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi)
258{
259 struct u1_dev *data = hid_get_drvdata(hdev);
260 struct input_dev *input = hi->input, *input2;
261 struct u1_dev devInfo;
262 int ret;
263 int res_x, res_y, i;
264
265 data->input = input;
266
267 hid_dbg(hdev, "Opening low level driver\n");
268 ret = hid_hw_open(hdev);
269 if (ret)
270 return ret;
271
272 /* Allow incoming hid reports */
273 hid_device_io_start(hdev);
274
275 /* Device initialization */
276 ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
277 &devInfo.dev_ctrl, 0, true);
278 if (ret < 0) {
279 dev_err(&hdev->dev, "failed U1_DEV_CTRL_1 (%d)\n", ret);
280 goto exit;
281 }
282
283 devInfo.dev_ctrl &= ~U1_DISABLE_DEV;
284 devInfo.dev_ctrl |= U1_TP_ABS_MODE;
285 ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
286 NULL, devInfo.dev_ctrl, false);
287 if (ret < 0) {
288 dev_err(&hdev->dev, "failed to change TP mode (%d)\n", ret);
289 goto exit;
290 }
291
292 ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_X,
293 &devInfo.sen_line_num_x, 0, true);
294 if (ret < 0) {
295 dev_err(&hdev->dev, "failed U1_NUM_SENS_X (%d)\n", ret);
296 goto exit;
297 }
298
299 ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_Y,
300 &devInfo.sen_line_num_y, 0, true);
301 if (ret < 0) {
302 dev_err(&hdev->dev, "failed U1_NUM_SENS_Y (%d)\n", ret);
303 goto exit;
304 }
305
306 ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_X,
307 &devInfo.pitch_x, 0, true);
308 if (ret < 0) {
309 dev_err(&hdev->dev, "failed U1_PITCH_SENS_X (%d)\n", ret);
310 goto exit;
311 }
312
313 ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_Y,
314 &devInfo.pitch_y, 0, true);
315 if (ret < 0) {
316 dev_err(&hdev->dev, "failed U1_PITCH_SENS_Y (%d)\n", ret);
317 goto exit;
318 }
319
320 ret = u1_read_write_register(hdev, ADDRESS_U1_RESO_DWN_ABS,
321 &devInfo.resolution, 0, true);
322 if (ret < 0) {
323 dev_err(&hdev->dev, "failed U1_RESO_DWN_ABS (%d)\n", ret);
324 goto exit;
325 }
326
327 ret = u1_read_write_register(hdev, ADDRESS_U1_PAD_BTN,
328 &devInfo.btn_info, 0, true);
329 if (ret < 0) {
330 dev_err(&hdev->dev, "failed U1_PAD_BTN (%d)\n", ret);
331 goto exit;
332 }
333
334 /* Check StickPointer device */
335 ret = u1_read_write_register(hdev, ADDRESS_U1_DEVICE_TYP,
336 &devInfo.dev_type, 0, true);
337 if (ret < 0) {
338 dev_err(&hdev->dev, "failed U1_DEVICE_TYP (%d)\n", ret);
339 goto exit;
340 }
341
342 devInfo.x_active_len_mm =
343 (devInfo.pitch_x * (devInfo.sen_line_num_x - 1)) / 10;
344 devInfo.y_active_len_mm =
345 (devInfo.pitch_y * (devInfo.sen_line_num_y - 1)) / 10;
346
347 devInfo.x_max =
348 (devInfo.resolution << 2) * (devInfo.sen_line_num_x - 1);
349 devInfo.y_max =
350 (devInfo.resolution << 2) * (devInfo.sen_line_num_y - 1);
351
352 __set_bit(EV_ABS, input->evbit);
353 input_set_abs_params(input, ABS_MT_POSITION_X, 1, devInfo.x_max, 0, 0);
354 input_set_abs_params(input, ABS_MT_POSITION_Y, 1, devInfo.y_max, 0, 0);
355
356 if (devInfo.x_active_len_mm && devInfo.y_active_len_mm) {
357 res_x = (devInfo.x_max - 1) / devInfo.x_active_len_mm;
358 res_y = (devInfo.y_max - 1) / devInfo.y_active_len_mm;
359
360 input_abs_set_res(input, ABS_MT_POSITION_X, res_x);
361 input_abs_set_res(input, ABS_MT_POSITION_Y, res_y);
362 }
363
364 input_set_abs_params(input, ABS_MT_PRESSURE, 0, 64, 0, 0);
365
366 input_mt_init_slots(input, MAX_TOUCHES, INPUT_MT_POINTER);
367
368 __set_bit(EV_KEY, input->evbit);
369 if ((devInfo.btn_info & 0x0F) == (devInfo.btn_info & 0xF0) >> 4) {
370 devInfo.btn_cnt = (devInfo.btn_info & 0x0F);
371 } else {
372 /* Button pad */
373 devInfo.btn_cnt = 1;
374 __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
375 }
376
377 for (i = 0; i < devInfo.btn_cnt; i++)
378 __set_bit(BTN_LEFT + i, input->keybit);
379
380
381 /* Stick device initialization */
382 if (devInfo.dev_type & U1_DEVTYPE_SP_SUPPORT) {
383
384 input2 = input_allocate_device();
385 if (!input2) {
386 input_free_device(input2);
387 goto exit;
388 }
389
390 data->input2 = input2;
391
392 devInfo.dev_ctrl |= U1_SP_ABS_MODE;
393 ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
394 NULL, devInfo.dev_ctrl, false);
395 if (ret < 0) {
396 dev_err(&hdev->dev, "failed SP mode (%d)\n", ret);
397 input_free_device(input2);
398 goto exit;
399 }
400
401 ret = u1_read_write_register(hdev, ADDRESS_U1_SP_BTN,
402 &devInfo.sp_btn_info, 0, true);
403 if (ret < 0) {
404 dev_err(&hdev->dev, "failed U1_SP_BTN (%d)\n", ret);
405 input_free_device(input2);
406 goto exit;
407 }
408
409 input2->phys = input->phys;
410 input2->name = "DualPoint Stick";
411 input2->id.bustype = BUS_I2C;
412 input2->id.vendor = input->id.vendor;
413 input2->id.product = input->id.product;
414 input2->id.version = input->id.version;
415 input2->dev.parent = input->dev.parent;
416
417 __set_bit(EV_KEY, input2->evbit);
418 devInfo.sp_btn_cnt = (devInfo.sp_btn_info & 0x0F);
419 for (i = 0; i < devInfo.sp_btn_cnt; i++)
420 __set_bit(BTN_LEFT + i, input2->keybit);
421
422 __set_bit(EV_REL, input2->evbit);
423 __set_bit(REL_X, input2->relbit);
424 __set_bit(REL_Y, input2->relbit);
425 __set_bit(INPUT_PROP_POINTER, input2->propbit);
426 __set_bit(INPUT_PROP_POINTING_STICK, input2->propbit);
427
428 if (input_register_device(data->input2)) {
429 input_free_device(input2);
430 goto exit;
431 }
432 }
433
434exit:
435 hid_device_io_stop(hdev);
436 hid_hw_close(hdev);
437 return ret;
438}
439
440static int alps_input_mapping(struct hid_device *hdev,
441 struct hid_input *hi, struct hid_field *field,
442 struct hid_usage *usage, unsigned long **bit, int *max)
443{
444 return -1;
445}
446
447static int alps_probe(struct hid_device *hdev, const struct hid_device_id *id)
448{
449 struct u1_dev *data = NULL;
450 int ret;
451
452 data = devm_kzalloc(&hdev->dev, sizeof(struct u1_dev), GFP_KERNEL);
453 if (!data)
454 return -ENOMEM;
455
456 data->hdev = hdev;
457 hid_set_drvdata(hdev, data);
458
459 hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
460
461 ret = hid_parse(hdev);
462 if (ret) {
463 hid_err(hdev, "parse failed\n");
464 return ret;
465 }
466
467 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
468 if (ret) {
469 hid_err(hdev, "hw start failed\n");
470 return ret;
471 }
472
473 return 0;
474}
475
476static void alps_remove(struct hid_device *hdev)
477{
478 hid_hw_stop(hdev);
479}
480
481static const struct hid_device_id alps_id[] = {
482 { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY,
483 USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) },
484 { }
485};
486MODULE_DEVICE_TABLE(hid, alps_id);
487
488static struct hid_driver alps_driver = {
489 .name = "hid-alps",
490 .id_table = alps_id,
491 .probe = alps_probe,
492 .remove = alps_remove,
493 .raw_event = alps_raw_event,
494 .input_mapping = alps_input_mapping,
495 .input_configured = alps_input_configured,
496#ifdef CONFIG_PM
497 .resume = alps_post_resume,
498 .reset_resume = alps_post_reset,
499#endif
500};
501
502module_hid_driver(alps_driver);
503
504MODULE_AUTHOR("Masaki Ota <masaki.ota@jp.alps.com>");
505MODULE_DESCRIPTION("ALPS HID driver");
506MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 884d82f9190e..2e046082210f 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -474,6 +474,8 @@ static const struct hid_device_id apple_devices[] = {
474 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, 474 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
475 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS), 475 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),
476 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, 476 .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
477 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI),
478 .driver_data = APPLE_HAS_FN },
477 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI), 479 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
478 .driver_data = APPLE_HAS_FN }, 480 .driver_data = APPLE_HAS_FN },
479 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO), 481 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO),
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 8ea3a26360e9..08f53c7fd513 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1772,6 +1772,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
1772 { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) }, 1772 { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
1773 { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) }, 1773 { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
1774 { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0xf705) }, 1774 { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0xf705) },
1775 { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) },
1775 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, 1776 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
1776 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) }, 1777 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
1777 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) }, 1778 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) },
@@ -1851,6 +1852,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
1851 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI) }, 1852 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI) },
1852 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) }, 1853 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },
1853 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS) }, 1854 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS) },
1855 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI) },
1854 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, 1856 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
1855 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, 1857 { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
1856 { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD) }, 1858 { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD) },
@@ -1877,8 +1879,11 @@ static const struct hid_device_id hid_have_special_driver[] = {
1877 { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) }, 1879 { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
1878 { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_4) }, 1880 { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_4) },
1879 { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, 1881 { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
1882 { HID_USB_DEVICE(USB_VENDOR_ID_DELCOM, USB_DEVICE_ID_DELCOM_VISUAL_IND) },
1880 { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, 1883 { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
1881 { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) }, 1884 { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
1885 { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_WN) },
1886 { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_FA) },
1882 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, 1887 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
1883 { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) }, 1888 { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) },
1884 { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0030) }, 1889 { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0030) },
@@ -1962,6 +1967,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
1962 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) }, 1967 { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) },
1963 { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) }, 1968 { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
1964 { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) }, 1969 { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
1970 { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_LUXAFOR) },
1965 { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) }, 1971 { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) },
1966 { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD) }, 1972 { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD) },
1967 { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) }, 1973 { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
@@ -2008,6 +2014,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
2008 { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, 2014 { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
2009 { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, HID_ANY_ID) }, 2015 { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, HID_ANY_ID) },
2010 { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) }, 2016 { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
2017 { HID_USB_DEVICE(USB_VENDOR_ID_RISO_KAGAKU, USB_DEVICE_ID_RI_KA_WEBMAIL) },
2011#if IS_ENABLED(CONFIG_HID_ROCCAT) 2018#if IS_ENABLED(CONFIG_HID_ROCCAT)
2012 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) }, 2019 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
2013 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) }, 2020 { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
@@ -2348,8 +2355,6 @@ static const struct hid_device_id hid_ignore_list[] = {
2348 { HID_USB_DEVICE(USB_VENDOR_ID_DEALEXTREAME, USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701) }, 2355 { HID_USB_DEVICE(USB_VENDOR_ID_DEALEXTREAME, USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701) },
2349 { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) }, 2356 { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
2350 { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) }, 2357 { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
2351 { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x0004) },
2352 { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x000a) },
2353 { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) }, 2358 { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) },
2354 { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0401) }, 2359 { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0401) },
2355 { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) }, 2360 { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
@@ -2486,7 +2491,6 @@ static const struct hid_device_id hid_ignore_list[] = {
2486 { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DPAD) }, 2491 { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DPAD) },
2487#endif 2492#endif
2488 { HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) }, 2493 { HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) },
2489 { HID_USB_DEVICE(USB_VENDOR_ID_RISO_KAGAKU, USB_DEVICE_ID_RI_KA_WEBMAIL) },
2490 { } 2494 { }
2491}; 2495};
2492 2496
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 3eec09a134cb..4ed9a4fdfea7 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -70,6 +70,9 @@
70#define USB_VENDOR_ID_ALPS 0x0433 70#define USB_VENDOR_ID_ALPS 0x0433
71#define USB_DEVICE_ID_IBM_GAMEPAD 0x1101 71#define USB_DEVICE_ID_IBM_GAMEPAD 0x1101
72 72
73#define USB_VENDOR_ID_ALPS_JP 0x044E
74#define HID_DEVICE_ID_ALPS_U1_DUAL 0x120B
75
73#define USB_VENDOR_ID_ANTON 0x1130 76#define USB_VENDOR_ID_ANTON 0x1130
74#define USB_DEVICE_ID_ANTON_TOUCH_PAD 0x3101 77#define USB_DEVICE_ID_ANTON_TOUCH_PAD 0x3101
75 78
@@ -142,6 +145,7 @@
142#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI 0x0255 145#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI 0x0255
143#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256 146#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256
144#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS 0x0257 147#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS 0x0257
148#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI 0x0267
145#define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0290 149#define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0290
146#define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0291 150#define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0291
147#define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0292 151#define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0292
@@ -296,6 +300,9 @@
296#define USB_VENDOR_ID_DEALEXTREAME 0x10c5 300#define USB_VENDOR_ID_DEALEXTREAME 0x10c5
297#define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701 0x819a 301#define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701 0x819a
298 302
303#define USB_VENDOR_ID_DELCOM 0x0fc5
304#define USB_DEVICE_ID_DELCOM_VISUAL_IND 0xb080
305
299#define USB_VENDOR_ID_DELORME 0x1163 306#define USB_VENDOR_ID_DELORME 0x1163
300#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100 307#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
301#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200 308#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200
@@ -334,6 +341,8 @@
334#define USB_DEVICE_ID_ELECOM_BM084 0x0061 341#define USB_DEVICE_ID_ELECOM_BM084 0x0061
335 342
336#define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34 343#define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34
344#define USB_DEVICE_ID_DREAM_CHEEKY_WN 0x0004
345#define USB_DEVICE_ID_DREAM_CHEEKY_FA 0x000a
337 346
338#define USB_VENDOR_ID_ELITEGROUP 0x03fc 347#define USB_VENDOR_ID_ELITEGROUP 0x03fc
339#define USB_DEVICE_ID_ELITEGROUP_05D8 0x05d8 348#define USB_DEVICE_ID_ELITEGROUP_05D8 0x05d8
@@ -680,6 +689,7 @@
680#define USB_DEVICE_ID_PICOLCD_BOOTLOADER 0xf002 689#define USB_DEVICE_ID_PICOLCD_BOOTLOADER 0xf002
681#define USB_DEVICE_ID_PICK16F1454 0x0042 690#define USB_DEVICE_ID_PICK16F1454 0x0042
682#define USB_DEVICE_ID_PICK16F1454_V2 0xf2f7 691#define USB_DEVICE_ID_PICK16F1454_V2 0xf2f7
692#define USB_DEVICE_ID_LUXAFOR 0xf372
683 693
684#define USB_VENDOR_ID_MICROSOFT 0x045e 694#define USB_VENDOR_ID_MICROSOFT 0x045e
685#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b 695#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
diff --git a/drivers/hid/hid-led.c b/drivers/hid/hid-led.c
new file mode 100644
index 000000000000..d8d55f37b4f5
--- /dev/null
+++ b/drivers/hid/hid-led.c
@@ -0,0 +1,523 @@
1/*
2 * Simple USB RGB LED driver
3 *
4 * Copyright 2016 Heiner Kallweit <hkallweit1@gmail.com>
5 * Based on drivers/hid/hid-thingm.c and
6 * drivers/usb/misc/usbled.c
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation, version 2.
11 */
12
13#include <linux/hid.h>
14#include <linux/hidraw.h>
15#include <linux/leds.h>
16#include <linux/module.h>
17#include <linux/mutex.h>
18
19#include "hid-ids.h"
20
21enum hidled_report_type {
22 RAW_REQUEST,
23 OUTPUT_REPORT
24};
25
26enum hidled_type {
27 RISO_KAGAKU,
28 DREAM_CHEEKY,
29 THINGM,
30 DELCOM,
31 LUXAFOR,
32};
33
34static unsigned const char riso_kagaku_tbl[] = {
35/* R+2G+4B -> riso kagaku color index */
36 [0] = 0, /* black */
37 [1] = 2, /* red */
38 [2] = 1, /* green */
39 [3] = 5, /* yellow */
40 [4] = 3, /* blue */
41 [5] = 6, /* magenta */
42 [6] = 4, /* cyan */
43 [7] = 7 /* white */
44};
45
46#define RISO_KAGAKU_IX(r, g, b) riso_kagaku_tbl[((r)?1:0)+((g)?2:0)+((b)?4:0)]
47
48union delcom_packet {
49 __u8 data[8];
50 struct {
51 __u8 major_cmd;
52 __u8 minor_cmd;
53 __u8 data_lsb;
54 __u8 data_msb;
55 } tx;
56 struct {
57 __u8 cmd;
58 } rx;
59 struct {
60 __le16 family_code;
61 __le16 security_code;
62 __u8 fw_version;
63 } fw;
64};
65
66#define DELCOM_GREEN_LED 0
67#define DELCOM_RED_LED 1
68#define DELCOM_BLUE_LED 2
69
70struct hidled_device;
71struct hidled_rgb;
72
73struct hidled_config {
74 enum hidled_type type;
75 const char *name;
76 const char *short_name;
77 enum led_brightness max_brightness;
78 int num_leds;
79 size_t report_size;
80 enum hidled_report_type report_type;
81 int (*init)(struct hidled_device *ldev);
82 int (*write)(struct led_classdev *cdev, enum led_brightness br);
83};
84
85struct hidled_led {
86 struct led_classdev cdev;
87 struct hidled_rgb *rgb;
88 char name[32];
89};
90
91struct hidled_rgb {
92 struct hidled_device *ldev;
93 struct hidled_led red;
94 struct hidled_led green;
95 struct hidled_led blue;
96 u8 num;
97};
98
99struct hidled_device {
100 const struct hidled_config *config;
101 struct hid_device *hdev;
102 struct hidled_rgb *rgb;
103 struct mutex lock;
104};
105
106#define MAX_REPORT_SIZE 16
107
108#define to_hidled_led(arg) container_of(arg, struct hidled_led, cdev)
109
110static bool riso_kagaku_switch_green_blue;
111module_param(riso_kagaku_switch_green_blue, bool, S_IRUGO | S_IWUSR);
112MODULE_PARM_DESC(riso_kagaku_switch_green_blue,
113 "switch green and blue RGB component for Riso Kagaku devices");
114
115static int hidled_send(struct hidled_device *ldev, __u8 *buf)
116{
117 int ret;
118
119 mutex_lock(&ldev->lock);
120
121 if (ldev->config->report_type == RAW_REQUEST)
122 ret = hid_hw_raw_request(ldev->hdev, buf[0], buf,
123 ldev->config->report_size,
124 HID_FEATURE_REPORT,
125 HID_REQ_SET_REPORT);
126 else if (ldev->config->report_type == OUTPUT_REPORT)
127 ret = hid_hw_output_report(ldev->hdev, buf,
128 ldev->config->report_size);
129 else
130 ret = -EINVAL;
131
132 mutex_unlock(&ldev->lock);
133
134 if (ret < 0)
135 return ret;
136
137 return ret == ldev->config->report_size ? 0 : -EMSGSIZE;
138}
139
140/* reading data is supported for report type RAW_REQUEST only */
141static int hidled_recv(struct hidled_device *ldev, __u8 *buf)
142{
143 int ret;
144
145 if (ldev->config->report_type != RAW_REQUEST)
146 return -EINVAL;
147
148 mutex_lock(&ldev->lock);
149
150 ret = hid_hw_raw_request(ldev->hdev, buf[0], buf,
151 ldev->config->report_size,
152 HID_FEATURE_REPORT,
153 HID_REQ_SET_REPORT);
154 if (ret < 0)
155 goto err;
156
157 ret = hid_hw_raw_request(ldev->hdev, buf[0], buf,
158 ldev->config->report_size,
159 HID_FEATURE_REPORT,
160 HID_REQ_GET_REPORT);
161err:
162 mutex_unlock(&ldev->lock);
163
164 return ret < 0 ? ret : 0;
165}
166
167static u8 riso_kagaku_index(struct hidled_rgb *rgb)
168{
169 enum led_brightness r, g, b;
170
171 r = rgb->red.cdev.brightness;
172 g = rgb->green.cdev.brightness;
173 b = rgb->blue.cdev.brightness;
174
175 if (riso_kagaku_switch_green_blue)
176 return RISO_KAGAKU_IX(r, b, g);
177 else
178 return RISO_KAGAKU_IX(r, g, b);
179}
180
181static int riso_kagaku_write(struct led_classdev *cdev, enum led_brightness br)
182{
183 struct hidled_led *led = to_hidled_led(cdev);
184 struct hidled_rgb *rgb = led->rgb;
185 __u8 buf[MAX_REPORT_SIZE] = {};
186
187 buf[1] = riso_kagaku_index(rgb);
188
189 return hidled_send(rgb->ldev, buf);
190}
191
192static int dream_cheeky_write(struct led_classdev *cdev, enum led_brightness br)
193{
194 struct hidled_led *led = to_hidled_led(cdev);
195 struct hidled_rgb *rgb = led->rgb;
196 __u8 buf[MAX_REPORT_SIZE] = {};
197
198 buf[1] = rgb->red.cdev.brightness;
199 buf[2] = rgb->green.cdev.brightness;
200 buf[3] = rgb->blue.cdev.brightness;
201 buf[7] = 0x1a;
202 buf[8] = 0x05;
203
204 return hidled_send(rgb->ldev, buf);
205}
206
207static int dream_cheeky_init(struct hidled_device *ldev)
208{
209 __u8 buf[MAX_REPORT_SIZE] = {};
210
211 /* Dream Cheeky magic */
212 buf[1] = 0x1f;
213 buf[2] = 0x02;
214 buf[4] = 0x5f;
215 buf[7] = 0x1a;
216 buf[8] = 0x03;
217
218 return hidled_send(ldev, buf);
219}
220
221static int _thingm_write(struct led_classdev *cdev, enum led_brightness br,
222 u8 offset)
223{
224 struct hidled_led *led = to_hidled_led(cdev);
225 __u8 buf[MAX_REPORT_SIZE] = { 1, 'c' };
226
227 buf[2] = led->rgb->red.cdev.brightness;
228 buf[3] = led->rgb->green.cdev.brightness;
229 buf[4] = led->rgb->blue.cdev.brightness;
230 buf[7] = led->rgb->num + offset;
231
232 return hidled_send(led->rgb->ldev, buf);
233}
234
235static int thingm_write_v1(struct led_classdev *cdev, enum led_brightness br)
236{
237 return _thingm_write(cdev, br, 0);
238}
239
240static int thingm_write(struct led_classdev *cdev, enum led_brightness br)
241{
242 return _thingm_write(cdev, br, 1);
243}
244
245static const struct hidled_config hidled_config_thingm_v1 = {
246 .name = "ThingM blink(1) v1",
247 .short_name = "thingm",
248 .max_brightness = 255,
249 .num_leds = 1,
250 .report_size = 9,
251 .report_type = RAW_REQUEST,
252 .write = thingm_write_v1,
253};
254
255static int thingm_init(struct hidled_device *ldev)
256{
257 __u8 buf[MAX_REPORT_SIZE] = { 1, 'v' };
258 int ret;
259
260 ret = hidled_recv(ldev, buf);
261 if (ret)
262 return ret;
263
264 /* Check for firmware major version 1 */
265 if (buf[3] == '1')
266 ldev->config = &hidled_config_thingm_v1;
267
268 return 0;
269}
270
271static inline int delcom_get_lednum(const struct hidled_led *led)
272{
273 if (led == &led->rgb->red)
274 return DELCOM_RED_LED;
275 else if (led == &led->rgb->green)
276 return DELCOM_GREEN_LED;
277 else
278 return DELCOM_BLUE_LED;
279}
280
281static int delcom_enable_led(struct hidled_led *led)
282{
283 union delcom_packet dp = { .tx.major_cmd = 101, .tx.minor_cmd = 12 };
284
285 dp.tx.data_lsb = 1 << delcom_get_lednum(led);
286 dp.tx.data_msb = 0;
287
288 return hidled_send(led->rgb->ldev, dp.data);
289}
290
291static int delcom_set_pwm(struct hidled_led *led)
292{
293 union delcom_packet dp = { .tx.major_cmd = 101, .tx.minor_cmd = 34 };
294
295 dp.tx.data_lsb = delcom_get_lednum(led);
296 dp.tx.data_msb = led->cdev.brightness;
297
298 return hidled_send(led->rgb->ldev, dp.data);
299}
300
301static int delcom_write(struct led_classdev *cdev, enum led_brightness br)
302{
303 struct hidled_led *led = to_hidled_led(cdev);
304 int ret;
305
306 /*
307 * enable LED
308 * We can't do this in the init function already because the device
309 * is internally reset later.
310 */
311 ret = delcom_enable_led(led);
312 if (ret)
313 return ret;
314
315 return delcom_set_pwm(led);
316}
317
318static int delcom_init(struct hidled_device *ldev)
319{
320 union delcom_packet dp = { .rx.cmd = 104 };
321 int ret;
322
323 ret = hidled_recv(ldev, dp.data);
324 if (ret)
325 return ret;
326 /*
327 * Several Delcom devices share the same USB VID/PID
328 * Check for family id 2 for Visual Signal Indicator
329 */
330 return le16_to_cpu(dp.fw.family_code) == 2 ? 0 : -ENODEV;
331}
332
333static int luxafor_write(struct led_classdev *cdev, enum led_brightness br)
334{
335 struct hidled_led *led = to_hidled_led(cdev);
336 __u8 buf[MAX_REPORT_SIZE] = { [1] = 1 };
337
338 buf[2] = led->rgb->num + 1;
339 buf[3] = led->rgb->red.cdev.brightness;
340 buf[4] = led->rgb->green.cdev.brightness;
341 buf[5] = led->rgb->blue.cdev.brightness;
342
343 return hidled_send(led->rgb->ldev, buf);
344}
345
346static const struct hidled_config hidled_configs[] = {
347 {
348 .type = RISO_KAGAKU,
349 .name = "Riso Kagaku Webmail Notifier",
350 .short_name = "riso_kagaku",
351 .max_brightness = 1,
352 .num_leds = 1,
353 .report_size = 6,
354 .report_type = OUTPUT_REPORT,
355 .write = riso_kagaku_write,
356 },
357 {
358 .type = DREAM_CHEEKY,
359 .name = "Dream Cheeky Webmail Notifier",
360 .short_name = "dream_cheeky",
361 .max_brightness = 31,
362 .num_leds = 1,
363 .report_size = 9,
364 .report_type = RAW_REQUEST,
365 .init = dream_cheeky_init,
366 .write = dream_cheeky_write,
367 },
368 {
369 .type = THINGM,
370 .name = "ThingM blink(1)",
371 .short_name = "thingm",
372 .max_brightness = 255,
373 .num_leds = 2,
374 .report_size = 9,
375 .report_type = RAW_REQUEST,
376 .init = thingm_init,
377 .write = thingm_write,
378 },
379 {
380 .type = DELCOM,
381 .name = "Delcom Visual Signal Indicator G2",
382 .short_name = "delcom",
383 .max_brightness = 100,
384 .num_leds = 1,
385 .report_size = 8,
386 .report_type = RAW_REQUEST,
387 .init = delcom_init,
388 .write = delcom_write,
389 },
390 {
391 .type = LUXAFOR,
392 .name = "Greynut Luxafor",
393 .short_name = "luxafor",
394 .max_brightness = 255,
395 .num_leds = 6,
396 .report_size = 9,
397 .report_type = OUTPUT_REPORT,
398 .write = luxafor_write,
399 },
400};
401
402static int hidled_init_led(struct hidled_led *led, const char *color_name,
403 struct hidled_rgb *rgb, unsigned int minor)
404{
405 const struct hidled_config *config = rgb->ldev->config;
406
407 if (config->num_leds > 1)
408 snprintf(led->name, sizeof(led->name), "%s%u:%s:led%u",
409 config->short_name, minor, color_name, rgb->num);
410 else
411 snprintf(led->name, sizeof(led->name), "%s%u:%s",
412 config->short_name, minor, color_name);
413 led->cdev.name = led->name;
414 led->cdev.max_brightness = config->max_brightness;
415 led->cdev.brightness_set_blocking = config->write;
416 led->cdev.flags = LED_HW_PLUGGABLE;
417 led->rgb = rgb;
418
419 return devm_led_classdev_register(&rgb->ldev->hdev->dev, &led->cdev);
420}
421
422static int hidled_init_rgb(struct hidled_rgb *rgb, unsigned int minor)
423{
424 int ret;
425
426 /* Register the red diode */
427 ret = hidled_init_led(&rgb->red, "red", rgb, minor);
428 if (ret)
429 return ret;
430
431 /* Register the green diode */
432 ret = hidled_init_led(&rgb->green, "green", rgb, minor);
433 if (ret)
434 return ret;
435
436 /* Register the blue diode */
437 return hidled_init_led(&rgb->blue, "blue", rgb, minor);
438}
439
440static int hidled_probe(struct hid_device *hdev, const struct hid_device_id *id)
441{
442 struct hidled_device *ldev;
443 unsigned int minor;
444 int ret, i;
445
446 ldev = devm_kzalloc(&hdev->dev, sizeof(*ldev), GFP_KERNEL);
447 if (!ldev)
448 return -ENOMEM;
449
450 ret = hid_parse(hdev);
451 if (ret)
452 return ret;
453
454 ldev->hdev = hdev;
455 mutex_init(&ldev->lock);
456
457 for (i = 0; !ldev->config && i < ARRAY_SIZE(hidled_configs); i++)
458 if (hidled_configs[i].type == id->driver_data)
459 ldev->config = &hidled_configs[i];
460
461 if (!ldev->config)
462 return -EINVAL;
463
464 if (ldev->config->init) {
465 ret = ldev->config->init(ldev);
466 if (ret)
467 return ret;
468 }
469
470 ldev->rgb = devm_kcalloc(&hdev->dev, ldev->config->num_leds,
471 sizeof(struct hidled_rgb), GFP_KERNEL);
472 if (!ldev->rgb)
473 return -ENOMEM;
474
475 ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
476 if (ret)
477 return ret;
478
479 minor = ((struct hidraw *) hdev->hidraw)->minor;
480
481 for (i = 0; i < ldev->config->num_leds; i++) {
482 ldev->rgb[i].ldev = ldev;
483 ldev->rgb[i].num = i;
484 ret = hidled_init_rgb(&ldev->rgb[i], minor);
485 if (ret) {
486 hid_hw_stop(hdev);
487 return ret;
488 }
489 }
490
491 hid_info(hdev, "%s initialized\n", ldev->config->name);
492
493 return 0;
494}
495
496static const struct hid_device_id hidled_table[] = {
497 { HID_USB_DEVICE(USB_VENDOR_ID_RISO_KAGAKU,
498 USB_DEVICE_ID_RI_KA_WEBMAIL), .driver_data = RISO_KAGAKU },
499 { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY,
500 USB_DEVICE_ID_DREAM_CHEEKY_WN), .driver_data = DREAM_CHEEKY },
501 { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY,
502 USB_DEVICE_ID_DREAM_CHEEKY_FA), .driver_data = DREAM_CHEEKY },
503 { HID_USB_DEVICE(USB_VENDOR_ID_THINGM,
504 USB_DEVICE_ID_BLINK1), .driver_data = THINGM },
505 { HID_USB_DEVICE(USB_VENDOR_ID_DELCOM,
506 USB_DEVICE_ID_DELCOM_VISUAL_IND), .driver_data = DELCOM },
507 { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP,
508 USB_DEVICE_ID_LUXAFOR), .driver_data = LUXAFOR },
509 { }
510};
511MODULE_DEVICE_TABLE(hid, hidled_table);
512
513static struct hid_driver hidled_driver = {
514 .name = "hid-led",
515 .probe = hidled_probe,
516 .id_table = hidled_table,
517};
518
519module_hid_driver(hidled_driver);
520
521MODULE_LICENSE("GPL");
522MODULE_AUTHOR("Heiner Kallweit <hkallweit1@gmail.com>");
523MODULE_DESCRIPTION("Simple USB RGB LED driver");
diff --git a/drivers/hid/hid-thingm.c b/drivers/hid/hid-thingm.c
deleted file mode 100644
index 9ad9c6ec5bba..000000000000
--- a/drivers/hid/hid-thingm.c
+++ /dev/null
@@ -1,263 +0,0 @@
1/*
2 * ThingM blink(1) USB RGB LED driver
3 *
4 * Copyright 2013-2014 Savoir-faire Linux Inc.
5 * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, version 2.
10 */
11
12#include <linux/hid.h>
13#include <linux/hidraw.h>
14#include <linux/leds.h>
15#include <linux/module.h>
16#include <linux/mutex.h>
17
18#include "hid-ids.h"
19
20#define REPORT_ID 1
21#define REPORT_SIZE 9
22
23/* Firmware major number of supported devices */
24#define THINGM_MAJOR_MK1 '1'
25#define THINGM_MAJOR_MK2 '2'
26
27struct thingm_fwinfo {
28 char major;
29 unsigned numrgb;
30 unsigned first;
31};
32
33static const struct thingm_fwinfo thingm_fwinfo[] = {
34 {
35 .major = THINGM_MAJOR_MK1,
36 .numrgb = 1,
37 .first = 0,
38 }, {
39 .major = THINGM_MAJOR_MK2,
40 .numrgb = 2,
41 .first = 1,
42 }
43};
44
45/* A red, green or blue channel, part of an RGB chip */
46struct thingm_led {
47 struct thingm_rgb *rgb;
48 struct led_classdev ldev;
49 char name[32];
50};
51
52/* Basically a WS2812 5050 RGB LED chip */
53struct thingm_rgb {
54 struct thingm_device *tdev;
55 struct thingm_led red;
56 struct thingm_led green;
57 struct thingm_led blue;
58 u8 num;
59};
60
61struct thingm_device {
62 struct hid_device *hdev;
63 struct {
64 char major;
65 char minor;
66 } version;
67 const struct thingm_fwinfo *fwinfo;
68 struct mutex lock;
69 struct thingm_rgb *rgb;
70};
71
72static int thingm_send(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
73{
74 int ret;
75
76 hid_dbg(tdev->hdev, "-> %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
77 buf[0], buf[1], buf[2], buf[3], buf[4],
78 buf[5], buf[6], buf[7], buf[8]);
79
80 mutex_lock(&tdev->lock);
81
82 ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
83 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
84
85 mutex_unlock(&tdev->lock);
86
87 return ret < 0 ? ret : 0;
88}
89
90static int thingm_recv(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
91{
92 int ret;
93
94 /*
95 * A read consists of two operations: sending the read command
96 * and the actual read from the device. Use the mutex to protect
97 * the full sequence of both operations.
98 */
99 mutex_lock(&tdev->lock);
100
101 ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
102 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
103 if (ret < 0)
104 goto err;
105
106 ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
107 HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
108 if (ret < 0)
109 goto err;
110
111 ret = 0;
112
113 hid_dbg(tdev->hdev, "<- %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
114 buf[0], buf[1], buf[2], buf[3], buf[4],
115 buf[5], buf[6], buf[7], buf[8]);
116err:
117 mutex_unlock(&tdev->lock);
118 return ret;
119}
120
121static int thingm_version(struct thingm_device *tdev)
122{
123 u8 buf[REPORT_SIZE] = { REPORT_ID, 'v', 0, 0, 0, 0, 0, 0, 0 };
124 int err;
125
126 err = thingm_recv(tdev, buf);
127 if (err)
128 return err;
129
130 tdev->version.major = buf[3];
131 tdev->version.minor = buf[4];
132
133 return 0;
134}
135
136static int thingm_write_color(struct thingm_rgb *rgb)
137{
138 u8 buf[REPORT_SIZE] = { REPORT_ID, 'c', 0, 0, 0, 0, 0, rgb->num, 0 };
139
140 buf[2] = rgb->red.ldev.brightness;
141 buf[3] = rgb->green.ldev.brightness;
142 buf[4] = rgb->blue.ldev.brightness;
143
144 return thingm_send(rgb->tdev, buf);
145}
146
147static int thingm_led_set(struct led_classdev *ldev,
148 enum led_brightness brightness)
149{
150 struct thingm_led *led = container_of(ldev, struct thingm_led, ldev);
151
152 return thingm_write_color(led->rgb);
153}
154
155static int thingm_init_led(struct thingm_led *led, const char *color_name,
156 struct thingm_rgb *rgb, int minor)
157{
158 snprintf(led->name, sizeof(led->name), "thingm%d:%s:led%d",
159 minor, color_name, rgb->num);
160 led->ldev.name = led->name;
161 led->ldev.max_brightness = 255;
162 led->ldev.brightness_set_blocking = thingm_led_set;
163 led->ldev.flags = LED_HW_PLUGGABLE;
164 led->rgb = rgb;
165 return devm_led_classdev_register(&rgb->tdev->hdev->dev, &led->ldev);
166}
167
168static int thingm_init_rgb(struct thingm_rgb *rgb)
169{
170 const int minor = ((struct hidraw *) rgb->tdev->hdev->hidraw)->minor;
171 int err;
172
173 /* Register the red diode */
174 err = thingm_init_led(&rgb->red, "red", rgb, minor);
175 if (err)
176 return err;
177
178 /* Register the green diode */
179 err = thingm_init_led(&rgb->green, "green", rgb, minor);
180 if (err)
181 return err;
182
183 /* Register the blue diode */
184 return thingm_init_led(&rgb->blue, "blue", rgb, minor);
185}
186
187static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
188{
189 struct thingm_device *tdev;
190 int i, err;
191
192 tdev = devm_kzalloc(&hdev->dev, sizeof(struct thingm_device),
193 GFP_KERNEL);
194 if (!tdev)
195 return -ENOMEM;
196
197 tdev->hdev = hdev;
198 hid_set_drvdata(hdev, tdev);
199
200 err = hid_parse(hdev);
201 if (err)
202 return err;
203
204 mutex_init(&tdev->lock);
205
206 err = thingm_version(tdev);
207 if (err)
208 return err;
209
210 hid_dbg(hdev, "firmware version: %c.%c\n",
211 tdev->version.major, tdev->version.minor);
212
213 for (i = 0; i < ARRAY_SIZE(thingm_fwinfo) && !tdev->fwinfo; ++i)
214 if (thingm_fwinfo[i].major == tdev->version.major)
215 tdev->fwinfo = &thingm_fwinfo[i];
216
217 if (!tdev->fwinfo) {
218 hid_err(hdev, "unsupported firmware %c\n", tdev->version.major);
219 return -ENODEV;
220 }
221
222 tdev->rgb = devm_kzalloc(&hdev->dev,
223 sizeof(struct thingm_rgb) * tdev->fwinfo->numrgb,
224 GFP_KERNEL);
225 if (!tdev->rgb)
226 return -ENOMEM;
227
228 err = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
229 if (err)
230 return err;
231
232 for (i = 0; i < tdev->fwinfo->numrgb; ++i) {
233 struct thingm_rgb *rgb = tdev->rgb + i;
234
235 rgb->tdev = tdev;
236 rgb->num = tdev->fwinfo->first + i;
237 err = thingm_init_rgb(rgb);
238 if (err) {
239 hid_hw_stop(hdev);
240 return err;
241 }
242 }
243
244 return 0;
245}
246
247static const struct hid_device_id thingm_table[] = {
248 { HID_USB_DEVICE(USB_VENDOR_ID_THINGM, USB_DEVICE_ID_BLINK1) },
249 { }
250};
251MODULE_DEVICE_TABLE(hid, thingm_table);
252
253static struct hid_driver thingm_driver = {
254 .name = "thingm",
255 .probe = thingm_probe,
256 .id_table = thingm_table,
257};
258
259module_hid_driver(thingm_driver);
260
261MODULE_LICENSE("GPL");
262MODULE_AUTHOR("Vivien Didelot <vivien.didelot@savoirfairelinux.com>");
263MODULE_DESCRIPTION("ThingM blink(1) USB RGB LED driver");
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index 2e021ba8ff05..b3ec4f2de875 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -1020,6 +1020,7 @@ static int i2c_hid_probe(struct i2c_client *client,
1020 pm_runtime_get_noresume(&client->dev); 1020 pm_runtime_get_noresume(&client->dev);
1021 pm_runtime_set_active(&client->dev); 1021 pm_runtime_set_active(&client->dev);
1022 pm_runtime_enable(&client->dev); 1022 pm_runtime_enable(&client->dev);
1023 device_enable_async_suspend(&client->dev);
1023 1024
1024 ret = i2c_hid_fetch_hid_descriptor(ihid); 1025 ret = i2c_hid_fetch_hid_descriptor(ihid);
1025 if (ret < 0) 1026 if (ret < 0)
@@ -1106,6 +1107,14 @@ static int i2c_hid_remove(struct i2c_client *client)
1106 return 0; 1107 return 0;
1107} 1108}
1108 1109
1110static void i2c_hid_shutdown(struct i2c_client *client)
1111{
1112 struct i2c_hid *ihid = i2c_get_clientdata(client);
1113
1114 i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
1115 free_irq(client->irq, ihid);
1116}
1117
1109#ifdef CONFIG_PM_SLEEP 1118#ifdef CONFIG_PM_SLEEP
1110static int i2c_hid_suspend(struct device *dev) 1119static int i2c_hid_suspend(struct device *dev)
1111{ 1120{
@@ -1230,7 +1239,7 @@ static struct i2c_driver i2c_hid_driver = {
1230 1239
1231 .probe = i2c_hid_probe, 1240 .probe = i2c_hid_probe,
1232 .remove = i2c_hid_remove, 1241 .remove = i2c_hid_remove,
1233 1242 .shutdown = i2c_hid_shutdown,
1234 .id_table = i2c_hid_id_table, 1243 .id_table = i2c_hid_id_table,
1235}; 1244};
1236 1245
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 16b6f11a0700..99ec3ff7563b 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -51,10 +51,26 @@ struct uhid_device {
51 u32 report_id; 51 u32 report_id;
52 u32 report_type; 52 u32 report_type;
53 struct uhid_event report_buf; 53 struct uhid_event report_buf;
54 struct work_struct worker;
54}; 55};
55 56
56static struct miscdevice uhid_misc; 57static struct miscdevice uhid_misc;
57 58
59static void uhid_device_add_worker(struct work_struct *work)
60{
61 struct uhid_device *uhid = container_of(work, struct uhid_device, worker);
62 int ret;
63
64 ret = hid_add_device(uhid->hid);
65 if (ret) {
66 hid_err(uhid->hid, "Cannot register HID device: error %d\n", ret);
67
68 hid_destroy_device(uhid->hid);
69 uhid->hid = NULL;
70 uhid->running = false;
71 }
72}
73
58static void uhid_queue(struct uhid_device *uhid, struct uhid_event *ev) 74static void uhid_queue(struct uhid_device *uhid, struct uhid_event *ev)
59{ 75{
60 __u8 newhead; 76 __u8 newhead;
@@ -498,18 +514,14 @@ static int uhid_dev_create2(struct uhid_device *uhid,
498 uhid->hid = hid; 514 uhid->hid = hid;
499 uhid->running = true; 515 uhid->running = true;
500 516
501 ret = hid_add_device(hid); 517 /* Adding of a HID device is done through a worker, to allow HID drivers
502 if (ret) { 518 * which use feature requests during .probe to work, without they would
503 hid_err(hid, "Cannot register HID device\n"); 519 * be blocked on devlock, which is held by uhid_char_write.
504 goto err_hid; 520 */
505 } 521 schedule_work(&uhid->worker);
506 522
507 return 0; 523 return 0;
508 524
509err_hid:
510 hid_destroy_device(hid);
511 uhid->hid = NULL;
512 uhid->running = false;
513err_free: 525err_free:
514 kfree(uhid->rd_data); 526 kfree(uhid->rd_data);
515 uhid->rd_data = NULL; 527 uhid->rd_data = NULL;
@@ -550,6 +562,8 @@ static int uhid_dev_destroy(struct uhid_device *uhid)
550 uhid->running = false; 562 uhid->running = false;
551 wake_up_interruptible(&uhid->report_wait); 563 wake_up_interruptible(&uhid->report_wait);
552 564
565 cancel_work_sync(&uhid->worker);
566
553 hid_destroy_device(uhid->hid); 567 hid_destroy_device(uhid->hid);
554 kfree(uhid->rd_data); 568 kfree(uhid->rd_data);
555 569
@@ -612,6 +626,7 @@ static int uhid_char_open(struct inode *inode, struct file *file)
612 init_waitqueue_head(&uhid->waitq); 626 init_waitqueue_head(&uhid->waitq);
613 init_waitqueue_head(&uhid->report_wait); 627 init_waitqueue_head(&uhid->report_wait);
614 uhid->running = false; 628 uhid->running = false;
629 INIT_WORK(&uhid->worker, uhid_device_add_worker);
615 630
616 file->private_data = uhid; 631 file->private_data = uhid;
617 nonseekable_open(inode, file); 632 nonseekable_open(inode, file);
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index 6e705971d637..eb8f8d37cd95 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -79,15 +79,6 @@ config USB_LCD
79 To compile this driver as a module, choose M here: the 79 To compile this driver as a module, choose M here: the
80 module will be called usblcd. 80 module will be called usblcd.
81 81
82config USB_LED
83 tristate "USB LED driver support"
84 help
85 Say Y here if you want to connect an USBLED device to your
86 computer's USB port.
87
88 To compile this driver as a module, choose M here: the
89 module will be called usbled.
90
91config USB_CYPRESS_CY7C63 82config USB_CYPRESS_CY7C63
92 tristate "Cypress CY7C63xxx USB driver support" 83 tristate "Cypress CY7C63xxx USB driver support"
93 help 84 help
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 2769cf6351b4..3d79faaad2fb 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o
15obj-$(CONFIG_USB_ISIGHTFW) += isight_firmware.o 15obj-$(CONFIG_USB_ISIGHTFW) += isight_firmware.o
16obj-$(CONFIG_USB_LCD) += usblcd.o 16obj-$(CONFIG_USB_LCD) += usblcd.o
17obj-$(CONFIG_USB_LD) += ldusb.o 17obj-$(CONFIG_USB_LD) += ldusb.o
18obj-$(CONFIG_USB_LED) += usbled.o
19obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o 18obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o
20obj-$(CONFIG_USB_RIO500) += rio500.o 19obj-$(CONFIG_USB_RIO500) += rio500.o
21obj-$(CONFIG_USB_TEST) += usbtest.o 20obj-$(CONFIG_USB_TEST) += usbtest.o
diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c
deleted file mode 100644
index bdef0d6eb91d..000000000000
--- a/drivers/usb/misc/usbled.c
+++ /dev/null
@@ -1,273 +0,0 @@
1/*
2 * USB LED driver
3 *
4 * Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, version 2.
9 *
10 */
11
12#include <linux/kernel.h>
13#include <linux/errno.h>
14#include <linux/slab.h>
15#include <linux/module.h>
16#include <linux/usb.h>
17
18
19#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com"
20#define DRIVER_DESC "USB LED Driver"
21
22enum led_type {
23 DELCOM_VISUAL_SIGNAL_INDICATOR,
24 DREAM_CHEEKY_WEBMAIL_NOTIFIER,
25 RISO_KAGAKU_LED
26};
27
28/* the Webmail LED made by RISO KAGAKU CORP. decodes a color index
29 internally, we want to keep the red+green+blue sysfs api, so we decode
30 from 1-bit RGB to the riso kagaku color index according to this table... */
31
32static unsigned const char riso_kagaku_tbl[] = {
33/* R+2G+4B -> riso kagaku color index */
34 [0] = 0, /* black */
35 [1] = 2, /* red */
36 [2] = 1, /* green */
37 [3] = 5, /* yellow */
38 [4] = 3, /* blue */
39 [5] = 6, /* magenta */
40 [6] = 4, /* cyan */
41 [7] = 7 /* white */
42};
43
44#define RISO_KAGAKU_IX(r,g,b) riso_kagaku_tbl[((r)?1:0)+((g)?2:0)+((b)?4:0)]
45
46/* table of devices that work with this driver */
47static const struct usb_device_id id_table[] = {
48 { USB_DEVICE(0x0fc5, 0x1223),
49 .driver_info = DELCOM_VISUAL_SIGNAL_INDICATOR },
50 { USB_DEVICE(0x1d34, 0x0004),
51 .driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER },
52 { USB_DEVICE(0x1d34, 0x000a),
53 .driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER },
54 { USB_DEVICE(0x1294, 0x1320),
55 .driver_info = RISO_KAGAKU_LED },
56 { },
57};
58MODULE_DEVICE_TABLE(usb, id_table);
59
60struct usb_led {
61 struct usb_device *udev;
62 unsigned char blue;
63 unsigned char red;
64 unsigned char green;
65 enum led_type type;
66};
67
68static void change_color(struct usb_led *led)
69{
70 int retval = 0;
71 unsigned char *buffer;
72 int actlength;
73
74 buffer = kmalloc(8, GFP_KERNEL);
75 if (!buffer) {
76 dev_err(&led->udev->dev, "out of memory\n");
77 return;
78 }
79
80 switch (led->type) {
81 case DELCOM_VISUAL_SIGNAL_INDICATOR: {
82 unsigned char color = 0x07;
83
84 if (led->blue)
85 color &= ~0x04;
86 if (led->red)
87 color &= ~0x02;
88 if (led->green)
89 color &= ~0x01;
90 dev_dbg(&led->udev->dev,
91 "blue = %d, red = %d, green = %d, color = %.2x\n",
92 led->blue, led->red, led->green, color);
93
94 retval = usb_control_msg(led->udev,
95 usb_sndctrlpipe(led->udev, 0),
96 0x12,
97 0xc8,
98 (0x02 * 0x100) + 0x0a,
99 (0x00 * 0x100) + color,
100 buffer,
101 8,
102 2000);
103 break;
104 }
105
106 case DREAM_CHEEKY_WEBMAIL_NOTIFIER:
107 dev_dbg(&led->udev->dev,
108 "red = %d, green = %d, blue = %d\n",
109 led->red, led->green, led->blue);
110
111 buffer[0] = led->red;
112 buffer[1] = led->green;
113 buffer[2] = led->blue;
114 buffer[3] = buffer[4] = buffer[5] = 0;
115 buffer[6] = 0x1a;
116 buffer[7] = 0x05;
117
118 retval = usb_control_msg(led->udev,
119 usb_sndctrlpipe(led->udev, 0),
120 0x09,
121 0x21,
122 0x200,
123 0,
124 buffer,
125 8,
126 2000);
127 break;
128
129 case RISO_KAGAKU_LED:
130 buffer[0] = RISO_KAGAKU_IX(led->red, led->green, led->blue);
131 buffer[1] = 0;
132 buffer[2] = 0;
133 buffer[3] = 0;
134 buffer[4] = 0;
135
136 retval = usb_interrupt_msg(led->udev,
137 usb_sndctrlpipe(led->udev, 2),
138 buffer, 5, &actlength, 1000 /*ms timeout*/);
139 break;
140
141 default:
142 dev_err(&led->udev->dev, "unknown device type %d\n", led->type);
143 }
144
145 if (retval)
146 dev_dbg(&led->udev->dev, "retval = %d\n", retval);
147 kfree(buffer);
148}
149
150#define show_set(value) \
151static ssize_t show_##value(struct device *dev, struct device_attribute *attr,\
152 char *buf) \
153{ \
154 struct usb_interface *intf = to_usb_interface(dev); \
155 struct usb_led *led = usb_get_intfdata(intf); \
156 \
157 return sprintf(buf, "%d\n", led->value); \
158} \
159static ssize_t set_##value(struct device *dev, struct device_attribute *attr,\
160 const char *buf, size_t count) \
161{ \
162 struct usb_interface *intf = to_usb_interface(dev); \
163 struct usb_led *led = usb_get_intfdata(intf); \
164 int temp = simple_strtoul(buf, NULL, 10); \
165 \
166 led->value = temp; \
167 change_color(led); \
168 return count; \
169} \
170static DEVICE_ATTR(value, S_IRUGO | S_IWUSR, show_##value, set_##value);
171show_set(blue);
172show_set(red);
173show_set(green);
174
175static int led_probe(struct usb_interface *interface,
176 const struct usb_device_id *id)
177{
178 struct usb_device *udev = interface_to_usbdev(interface);
179 struct usb_led *dev = NULL;
180 int retval = -ENOMEM;
181
182 dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL);
183 if (dev == NULL) {
184 dev_err(&interface->dev, "out of memory\n");
185 goto error_mem;
186 }
187
188 dev->udev = usb_get_dev(udev);
189 dev->type = id->driver_info;
190
191 usb_set_intfdata(interface, dev);
192
193 retval = device_create_file(&interface->dev, &dev_attr_blue);
194 if (retval)
195 goto error;
196 retval = device_create_file(&interface->dev, &dev_attr_red);
197 if (retval)
198 goto error;
199 retval = device_create_file(&interface->dev, &dev_attr_green);
200 if (retval)
201 goto error;
202
203 if (dev->type == DREAM_CHEEKY_WEBMAIL_NOTIFIER) {
204 unsigned char *enable;
205
206 enable = kmemdup("\x1f\x02\0\x5f\0\0\x1a\x03", 8, GFP_KERNEL);
207 if (!enable) {
208 dev_err(&interface->dev, "out of memory\n");
209 retval = -ENOMEM;
210 goto error;
211 }
212
213 retval = usb_control_msg(udev,
214 usb_sndctrlpipe(udev, 0),
215 0x09,
216 0x21,
217 0x200,
218 0,
219 enable,
220 8,
221 2000);
222
223 kfree(enable);
224 if (retval != 8)
225 goto error;
226 }
227
228 dev_info(&interface->dev, "USB LED device now attached\n");
229 return 0;
230
231error:
232 device_remove_file(&interface->dev, &dev_attr_blue);
233 device_remove_file(&interface->dev, &dev_attr_red);
234 device_remove_file(&interface->dev, &dev_attr_green);
235 usb_set_intfdata(interface, NULL);
236 usb_put_dev(dev->udev);
237 kfree(dev);
238error_mem:
239 return retval;
240}
241
242static void led_disconnect(struct usb_interface *interface)
243{
244 struct usb_led *dev;
245
246 dev = usb_get_intfdata(interface);
247
248 device_remove_file(&interface->dev, &dev_attr_blue);
249 device_remove_file(&interface->dev, &dev_attr_red);
250 device_remove_file(&interface->dev, &dev_attr_green);
251
252 /* first remove the files, then set the pointer to NULL */
253 usb_set_intfdata(interface, NULL);
254
255 usb_put_dev(dev->udev);
256
257 kfree(dev);
258
259 dev_info(&interface->dev, "USB LED now disconnected\n");
260}
261
262static struct usb_driver led_driver = {
263 .name = "usbled",
264 .probe = led_probe,
265 .disconnect = led_disconnect,
266 .id_table = id_table,
267};
268
269module_usb_driver(led_driver);
270
271MODULE_AUTHOR(DRIVER_AUTHOR);
272MODULE_DESCRIPTION(DRIVER_DESC);
273MODULE_LICENSE("GPL");