Commit 0f1b1e6d authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid

Pull HID updates from Jiri Kosina:
 - substantial cleanup of the generic and transport layers, in the
   direction of an ultimate goal of making struct hid_device completely
   transport independent, by Benjamin Tissoires
 - cp2112 driver from David Barksdale
 - a lot of fixes and new hardware support (Dualshock 4) to hid-sony
   driver, by Frank Praznik
 - support for Win 8.1 multitouch protocol by Andrew Duggan
 - other smaller fixes / device ID additions

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (75 commits)
  HID: sony: fix force feedback mismerge
  HID: sony: Set the quriks flag for Bluetooth controllers
  HID: sony: Fix Sixaxis cable state detection
  HID: uhid: Add UHID_CREATE2 + UHID_INPUT2
  HID: hyperv: fix _raw_request() prototype
  HID: hyperv: Implement a stub raw_request() entry point
  HID: hid-sensor-hub: fix sleeping function called from invalid context
  HID: multitouch: add support for Win 8.1 multitouch touchpads
  HID: remove hid_output_raw_report transport implementations
  HID: sony: do not rely on hid_output_raw_report
  HID: cp2112: remove the last hid_output_raw_report() call
  HID: cp2112: remove various hid_out_raw_report calls
  HID: multitouch: add support of other generic collections in hid-mt
  HID: multitouch: remove pen special handling
  HID: multitouch: remove registered devices with default behavior
  HID: hidp: Add a comment that some devices depend on the current behavior of uniq
  HID: sony: Prevent duplicate controller connections.
  HID: sony: Perform a boundry check on the sixaxis battery level index.
  HID: sony: Fix work queue issues
  HID: sony: Fix multi-line comment styling
  ...
parents 159d8133 3ae821ef
This diff is collapsed.
...@@ -93,6 +93,11 @@ the request was handled successfully. ...@@ -93,6 +93,11 @@ the request was handled successfully.
event to the kernel. The payload is of type struct uhid_create_req and event to the kernel. The payload is of type struct uhid_create_req and
contains information about your device. You can start I/O now. contains information about your device. You can start I/O now.
UHID_CREATE2:
Same as UHID_CREATE, but the HID report descriptor data (rd_data) is an array
inside struct uhid_create2_req, instead of a pointer to a separate array.
Enables use from languages that don't support pointers, e.g. Python.
UHID_DESTROY: UHID_DESTROY:
This destroys the internal HID device. No further I/O will be accepted. There This destroys the internal HID device. No further I/O will be accepted. There
may still be pending messages that you can receive with read() but no further may still be pending messages that you can receive with read() but no further
...@@ -105,6 +110,12 @@ the request was handled successfully. ...@@ -105,6 +110,12 @@ the request was handled successfully.
contains a data-payload. This is the raw data that you read from your device. contains a data-payload. This is the raw data that you read from your device.
The kernel will parse the HID reports and react on it. The kernel will parse the HID reports and react on it.
UHID_INPUT2:
Same as UHID_INPUT, but the data array is the last field of uhid_input2_req.
Enables userspace to write only the required bytes to kernel (ev.type +
ev.u.input2.size + the part of the data array that matters), instead of
the entire struct uhid_input2_req.
UHID_FEATURE_ANSWER: UHID_FEATURE_ANSWER:
If you receive a UHID_FEATURE request you must answer with this request. You If you receive a UHID_FEATURE request you must answer with this request. You
must copy the "id" field from the request into the answer. Set the "err" field must copy the "id" field from the request into the answer. Set the "err" field
......
...@@ -175,6 +175,15 @@ config HID_PRODIKEYS ...@@ -175,6 +175,15 @@ config HID_PRODIKEYS
multimedia keyboard, but will lack support for the musical keyboard multimedia keyboard, but will lack support for the musical keyboard
and some additional multimedia keys. and some additional multimedia keys.
config HID_CP2112
tristate "Silicon Labs CP2112 HID USB-to-SMBus Bridge support"
depends on USB_HID && I2C && GPIOLIB
---help---
Support for Silicon Labs CP2112 HID USB to SMBus Master Bridge.
This is a HID device driver which registers as an i2c adapter
and gpiochip to expose these functions of the CP2112. The
customizable USB descriptor fields are exposed as sysfs attributes.
config HID_CYPRESS config HID_CYPRESS
tristate "Cypress mouse and barcode readers" if EXPERT tristate "Cypress mouse and barcode readers" if EXPERT
depends on HID depends on HID
...@@ -608,25 +617,27 @@ config HID_SAMSUNG ...@@ -608,25 +617,27 @@ config HID_SAMSUNG
Support for Samsung InfraRed remote control or keyboards. Support for Samsung InfraRed remote control or keyboards.
config HID_SONY config HID_SONY
tristate "Sony PS2/3 accessories" tristate "Sony PS2/3/4 accessories"
depends on USB_HID depends on USB_HID
depends on NEW_LEDS depends on NEW_LEDS
depends on LEDS_CLASS depends on LEDS_CLASS
select POWER_SUPPLY
---help--- ---help---
Support for Support for
* Sony PS3 6-axis controllers * Sony PS3 6-axis controllers
* Sony PS4 DualShock 4 controllers
* Buzz controllers * Buzz controllers
* Sony PS3 Blue-ray Disk Remote Control (Bluetooth) * Sony PS3 Blue-ray Disk Remote Control (Bluetooth)
* Logitech Harmony adapter for Sony Playstation 3 (Bluetooth) * Logitech Harmony adapter for Sony Playstation 3 (Bluetooth)
config SONY_FF config SONY_FF
bool "Sony PS2/3 accessories force feedback support" bool "Sony PS2/3/4 accessories force feedback support"
depends on HID_SONY depends on HID_SONY
select INPUT_FF_MEMLESS select INPUT_FF_MEMLESS
---help--- ---help---
Say Y here if you have a Sony PS2/3 accessory and want to enable force Say Y here if you have a Sony PS2/3/4 accessory and want to enable
feedback support for it. force feedback support for it.
config HID_SPEEDLINK config HID_SPEEDLINK
tristate "Speedlink VAD Cezanne mouse support" tristate "Speedlink VAD Cezanne mouse support"
......
...@@ -41,6 +41,7 @@ obj-$(CONFIG_HID_AUREAL) += hid-aureal.o ...@@ -41,6 +41,7 @@ obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CP2112) += hid-cp2112.o
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o
obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o
......
...@@ -1248,6 +1248,11 @@ void hid_output_report(struct hid_report *report, __u8 *data) ...@@ -1248,6 +1248,11 @@ void hid_output_report(struct hid_report *report, __u8 *data)
} }
EXPORT_SYMBOL_GPL(hid_output_report); EXPORT_SYMBOL_GPL(hid_output_report);
static int hid_report_len(struct hid_report *report)
{
return ((report->size - 1) >> 3) + 1 + (report->id > 0) + 7;
}
/* /*
* Allocator for buffer that is going to be passed to hid_output_report() * Allocator for buffer that is going to be passed to hid_output_report()
*/ */
...@@ -1258,7 +1263,7 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags) ...@@ -1258,7 +1263,7 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
* of implement() working on 8 byte chunks * of implement() working on 8 byte chunks
*/ */
int len = ((report->size - 1) >> 3) + 1 + (report->id > 0) + 7; int len = hid_report_len(report);
return kmalloc(len, flags); return kmalloc(len, flags);
} }
...@@ -1314,6 +1319,41 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum, ...@@ -1314,6 +1319,41 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
return report; return report;
} }
/*
* Implement a generic .request() callback, using .raw_request()
* DO NOT USE in hid drivers directly, but through hid_hw_request instead.
*/
void __hid_request(struct hid_device *hid, struct hid_report *report,
int reqtype)
{
char *buf;
int ret;
int len;
buf = hid_alloc_report_buf(report, GFP_KERNEL);
if (!buf)
return;
len = hid_report_len(report);
if (reqtype == HID_REQ_SET_REPORT)
hid_output_report(report, buf);
ret = hid->ll_driver->raw_request(hid, report->id, buf, len,
report->type, reqtype);
if (ret < 0) {
dbg_hid("unable to complete request: %d\n", ret);
goto out;
}
if (reqtype == HID_REQ_GET_REPORT)
hid_input_report(hid, report->type, buf, ret, 0);
out:
kfree(buf);
}
EXPORT_SYMBOL_GPL(__hid_request);
int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
int interrupt) int interrupt)
{ {
...@@ -1693,6 +1733,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1693,6 +1733,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
...@@ -1782,6 +1823,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1782,6 +1823,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) },
...@@ -2433,6 +2475,14 @@ int hid_add_device(struct hid_device *hdev) ...@@ -2433,6 +2475,14 @@ int hid_add_device(struct hid_device *hdev)
if (hid_ignore(hdev)) if (hid_ignore(hdev))
return -ENODEV; return -ENODEV;
/*
* Check for the mandatory transport channel.
*/
if (!hdev->ll_driver->raw_request) {
hid_err(hdev, "transport driver missing .raw_request()\n");
return -EINVAL;
}
/* /*
* Read the device report descriptor once and use as template * Read the device report descriptor once and use as template
* for the driver-specific modifications. * for the driver-specific modifications.
......
This diff is collapsed.
...@@ -460,12 +460,22 @@ static void mousevsc_hid_stop(struct hid_device *hid) ...@@ -460,12 +460,22 @@ static void mousevsc_hid_stop(struct hid_device *hid)
{ {
} }
static int mousevsc_hid_raw_request(struct hid_device *hid,
unsigned char report_num,
__u8 *buf, size_t len,
unsigned char rtype,
int reqtype)
{
return 0;
}
static struct hid_ll_driver mousevsc_ll_driver = { static struct hid_ll_driver mousevsc_ll_driver = {
.parse = mousevsc_hid_parse, .parse = mousevsc_hid_parse,
.open = mousevsc_hid_open, .open = mousevsc_hid_open,
.close = mousevsc_hid_close, .close = mousevsc_hid_close,
.start = mousevsc_hid_start, .start = mousevsc_hid_start,
.stop = mousevsc_hid_stop, .stop = mousevsc_hid_stop,
.raw_request = mousevsc_hid_raw_request,
}; };
static struct hid_driver mousevsc_hid_driver; static struct hid_driver mousevsc_hid_driver;
......
...@@ -67,6 +67,9 @@ ...@@ -67,6 +67,9 @@
#define USB_VENDOR_ID_ALPS 0x0433 #define USB_VENDOR_ID_ALPS 0x0433
#define USB_DEVICE_ID_IBM_GAMEPAD 0x1101 #define USB_DEVICE_ID_IBM_GAMEPAD 0x1101
#define USB_VENDOR_ID_ANTON 0x1130
#define USB_DEVICE_ID_ANTON_TOUCH_PAD 0x3101
#define USB_VENDOR_ID_APPLE 0x05ac #define USB_VENDOR_ID_APPLE 0x05ac
#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304 #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d #define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d
...@@ -242,6 +245,7 @@ ...@@ -242,6 +245,7 @@
#define USB_VENDOR_ID_CYGNAL 0x10c4 #define USB_VENDOR_ID_CYGNAL 0x10c4
#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a #define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a
#define USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH 0x81b9 #define USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH 0x81b9
#define USB_DEVICE_ID_CYGNAL_CP2112 0xea90
#define USB_DEVICE_ID_CYGNAL_RADIO_SI4713 0x8244 #define USB_DEVICE_ID_CYGNAL_RADIO_SI4713 0x8244
...@@ -616,6 +620,7 @@ ...@@ -616,6 +620,7 @@
#define USB_VENDOR_ID_MICROSOFT 0x045e #define USB_VENDOR_ID_MICROSOFT 0x045e
#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b #define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
#define USB_DEVICE_ID_MS_OFFICE_KB 0x0048
#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d #define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
#define USB_DEVICE_ID_MS_NE4K 0x00db #define USB_DEVICE_ID_MS_NE4K 0x00db
#define USB_DEVICE_ID_MS_NE4K_JP 0x00dc #define USB_DEVICE_ID_MS_NE4K_JP 0x00dc
......
...@@ -350,9 +350,9 @@ static int hidinput_get_battery_property(struct power_supply *psy, ...@@ -350,9 +350,9 @@ static int hidinput_get_battery_property(struct power_supply *psy,
ret = -ENOMEM; ret = -ENOMEM;
break; break;
} }
ret = dev->hid_get_raw_report(dev, dev->battery_report_id, ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 2,
buf, 2, dev->battery_report_type,
dev->battery_report_type); HID_REQ_GET_REPORT);
if (ret != 2) { if (ret != 2) {
ret = -ENODATA; ret = -ENODATA;
...@@ -789,10 +789,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -789,10 +789,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x199: map_key_clear(KEY_CHAT); break; case 0x199: map_key_clear(KEY_CHAT); break;
case 0x19c: map_key_clear(KEY_LOGOFF); break; case 0x19c: map_key_clear(KEY_LOGOFF); break;
case 0x19e: map_key_clear(KEY_COFFEE); break; case 0x19e: map_key_clear(KEY_COFFEE); break;
case 0x1a3: map_key_clear(KEY_NEXT); break;
case 0x1a4: map_key_clear(KEY_PREVIOUS); break;
case 0x1a6: map_key_clear(KEY_HELP); break; case 0x1a6: map_key_clear(KEY_HELP); break;
case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
case 0x1ab: map_key_clear(KEY_SPELLCHECK); break; case 0x1ab: map_key_clear(KEY_SPELLCHECK); break;
case 0x1ae: map_key_clear(KEY_KEYBOARD); break; case 0x1ae: map_key_clear(KEY_KEYBOARD); break;
case 0x1b4: map_key_clear(KEY_FILE); break;
case 0x1b6: map_key_clear(KEY_IMAGES); break; case 0x1b6: map_key_clear(KEY_IMAGES); break;
case 0x1b7: map_key_clear(KEY_AUDIO); break; case 0x1b7: map_key_clear(KEY_AUDIO); break;
case 0x1b8: map_key_clear(KEY_VIDEO); break; case 0x1b8: map_key_clear(KEY_VIDEO); break;
...@@ -1150,7 +1153,7 @@ static void hidinput_led_worker(struct work_struct *work) ...@@ -1150,7 +1153,7 @@ static void hidinput_led_worker(struct work_struct *work)
led_work); led_work);
struct hid_field *field; struct hid_field *field;
struct hid_report *report; struct hid_report *report;
int len; int len, ret;
__u8 *buf; __u8 *buf;
field = hidinput_get_led_field(hid); field = hidinput_get_led_field(hid);
...@@ -1184,7 +1187,10 @@ static void hidinput_led_worker(struct work_struct *work) ...@@ -1184,7 +1187,10 @@ static void hidinput_led_worker(struct work_struct *work)
hid_output_report(report, buf); hid_output_report(report, buf);
/* synchronous output report */ /* synchronous output report */
hid->hid_output_raw_report(hid, buf, len, HID_OUTPUT_REPORT); ret = hid_hw_output_report(hid, buf, len);
if (ret == -ENOSYS)
hid_hw_raw_request(hid, report->id, buf, len, HID_OUTPUT_REPORT,
HID_REQ_SET_REPORT);
kfree(buf); kfree(buf);
} }
...@@ -1263,9 +1269,6 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid) ...@@ -1263,9 +1269,6 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
} }
input_set_drvdata(input_dev, hid); input_set_drvdata(input_dev, hid);
if (hid->ll_driver->hidinput_input_event)
input_dev->event = hid->ll_driver->hidinput_input_event;
else if (hid->ll_driver->request || hid->hid_output_raw_report)
input_dev->event = hidinput_input_event; input_dev->event = hidinput_input_event;
input_dev->open = hidinput_open; input_dev->open = hidinput_open;
input_dev->close = hidinput_close; input_dev->close = hidinput_close;
......
...@@ -692,7 +692,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -692,7 +692,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) { if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret >= 0) { if (ret >= 0) {
/* insert a little delay of 10 jiffies ~ 40ms */ /* insert a little delay of 10 jiffies ~ 40ms */
...@@ -704,7 +705,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -704,7 +705,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
buf[1] = 0xB2; buf[1] = 0xB2;
get_random_bytes(&buf[2], 2); get_random_bytes(&buf[2], 2);
ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT); ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
} }
} }
......
...@@ -44,14 +44,6 @@ static const char kbd_descriptor[] = { ...@@ -44,14 +44,6 @@ static const char kbd_descriptor[] = {
0x19, 0xE0, /* USAGE_MINIMUM (Left Control) */ 0x19, 0xE0, /* USAGE_MINIMUM (Left Control) */
0x29, 0xE7, /* USAGE_MAXIMUM (Right GUI) */ 0x29, 0xE7, /* USAGE_MAXIMUM (Right GUI) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */ 0x81, 0x02, /* INPUT (Data,Var,Abs) */
0x95, 0x05, /* REPORT COUNT (5) */
0x05, 0x08, /* USAGE PAGE (LED page) */
0x19, 0x01, /* USAGE MINIMUM (1) */
0x29, 0x05, /* USAGE MAXIMUM (5) */
0x91, 0x02, /* OUTPUT (Data, Variable, Absolute) */
0x95, 0x01, /* REPORT COUNT (1) */
0x75, 0x03, /* REPORT SIZE (3) */
0x91, 0x01, /* OUTPUT (Constant) */
0x95, 0x06, /* REPORT_COUNT (6) */ 0x95, 0x06, /* REPORT_COUNT (6) */
0x75, 0x08, /* REPORT_SIZE (8) */ 0x75, 0x08, /* REPORT_SIZE (8) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
...@@ -60,6 +52,18 @@ static const char kbd_descriptor[] = { ...@@ -60,6 +52,18 @@ static const char kbd_descriptor[] = {
0x19, 0x00, /* USAGE_MINIMUM (no event) */ 0x19, 0x00, /* USAGE_MINIMUM (no event) */
0x2A, 0xFF, 0x00, /* USAGE_MAXIMUM (reserved) */ 0x2A, 0xFF, 0x00, /* USAGE_MAXIMUM (reserved) */
0x81, 0x00, /* INPUT (Data,Ary,Abs) */ 0x81, 0x00, /* INPUT (Data,Ary,Abs) */
0x85, 0x0e, /* REPORT_ID (14) */
0x05, 0x08, /* USAGE PAGE (LED page) */
0x95, 0x05, /* REPORT COUNT (5) */
0x75, 0x01, /* REPORT SIZE (1) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
0x19, 0x01, /* USAGE MINIMUM (1) */
0x29, 0x05, /* USAGE MAXIMUM (5) */
0x91, 0x02, /* OUTPUT (Data, Variable, Absolute) */
0x95, 0x01, /* REPORT COUNT (1) */
0x75, 0x03, /* REPORT SIZE (3) */
0x91, 0x01, /* OUTPUT (Constant) */
0xC0 0xC0
}; };
...@@ -189,9 +193,6 @@ static const u8 hid_reportid_size_map[NUMBER_OF_HID_REPORTS] = { ...@@ -189,9 +193,6 @@ static const u8 hid_reportid_size_map[NUMBER_OF_HID_REPORTS] = {
static struct hid_ll_driver logi_dj_ll_driver; static struct hid_ll_driver logi_dj_ll_driver;
static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
size_t count,
unsigned char report_type);
static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev); static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev, static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
...@@ -258,7 +259,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev, ...@@ -258,7 +259,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
} }
dj_hiddev->ll_driver = &logi_dj_ll_driver; dj_hiddev->ll_driver = &logi_dj_ll_driver;
dj_hiddev->hid_output_raw_report = logi_dj_output_hidraw_report;
dj_hiddev->dev.parent = &djrcv_hdev->dev; dj_hiddev->dev.parent = &djrcv_hdev->dev;
dj_hiddev->bus = BUS_USB; dj_hiddev->bus = BUS_USB;
...@@ -540,14 +540,35 @@ static void logi_dj_ll_close(struct hid_device *hid) ...@@ -540,14 +540,35 @@ static void logi_dj_ll_close(struct hid_device *hid)
dbg_hid("%s:%s\n", __func__, hid->phys); dbg_hid("%s:%s\n", __func__, hid->phys);
} }
static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf, static int logi_dj_ll_raw_request(struct hid_device *hid,
size_t count, unsigned char reportnum, __u8 *buf,
unsigned char report_type) size_t count, unsigned char report_type,
int reqtype)
{ {
/* Called by hid raw to send data */ struct dj_device *djdev = hid->driver_data;
dbg_hid("%s\n", __func__); struct dj_receiver_dev *djrcv_dev = djdev->dj_receiver_dev;
u8 *out_buf;
int ret;
return 0; if (buf[0] != REPORT_TYPE_LEDS)
return -EINVAL;
out_buf = kzalloc(DJREPORT_SHORT_LENGTH, GFP_ATOMIC);
if (!out_buf)
return -ENOMEM;
if (count < DJREPORT_SHORT_LENGTH - 2)
count = DJREPORT_SHORT_LENGTH - 2;
out_buf[0] = REPORT_ID_DJ_SHORT;
out_buf[1] = djdev->device_index;
memcpy(out_buf + 2, buf, count);
ret = hid_hw_raw_request(djrcv_dev->hdev, out_buf[0], out_buf,
DJREPORT_SHORT_LENGTH, report_type, reqtype);
kfree(out_buf);
return ret;
} }
static void rdcat(char *rdesc, unsigned int *rsize, const char *data, unsigned int size) static void rdcat(char *rdesc, unsigned int *rsize, const char *data, unsigned int size)
...@@ -613,58 +634,6 @@ static int logi_dj_ll_parse(struct hid_device *hid) ...@@ -613,58 +634,6 @@ static int logi_dj_ll_parse(struct hid_device *hid)
return retval; return retval;
} }
static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
unsigned int code, int value)
{
/* Sent by the input layer to handle leds and Force Feedback */
struct hid_device *dj_hiddev = input_get_drvdata(dev);
struct dj_device *dj_dev = dj_hiddev->driver_data;
struct dj_receiver_dev *djrcv_dev =
dev_get_drvdata(dj_hiddev->dev.parent);
struct hid_device *dj_rcv_hiddev = djrcv_dev->hdev;
struct hid_report_enum *output_report_enum;
struct hid_field *field;
struct hid_report *report;
unsigned char *data;
int offset;
dbg_hid("%s: %s, type:%d | code:%d | value:%d\n",
__func__, dev->phys, type, code, value);
if (type != EV_LED)
return -1;
offset = hidinput_find_field(dj_hiddev, type, code, &field);
if (offset == -1) {
dev_warn(&dev->dev, "event field not found\n");
return -1;
}
hid_set_field(field, offset, value);
data = hid_alloc_report_buf(field->report, GFP_ATOMIC);
if (!data) {
dev_warn(&dev->dev, "failed to allocate report buf memory\n");
return -1;
}
hid_output_report(field->report, &data[0]);
output_report_enum = &dj_rcv_hiddev->report_enum[HID_OUTPUT_REPORT];
report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT];
hid_set_field(report->field[0], 0, dj_dev->device_index);
hid_set_field(report->field[0], 1, REPORT_TYPE_LEDS);
hid_set_field(report->field[0], 2, data[1]);
hid_hw_request(dj_rcv_hiddev, report, HID_REQ_SET_REPORT);
kfree(data);
return 0;
}
static int logi_dj_ll_start(struct hid_device *hid) static int logi_dj_ll_start(struct hid_device *hid)
{ {
dbg_hid("%s\n", __func__); dbg_hid("%s\n", __func__);
...@@ -683,7 +652,7 @@ static struct hid_ll_driver logi_dj_ll_driver = { ...@@ -683,7 +652,7 @@ static struct hid_ll_driver logi_dj_ll_driver = {
.stop = logi_dj_ll_stop, .stop = logi_dj_ll_stop,
.open = logi_dj_ll_open, .open = logi_dj_ll_open,
.close = logi_dj_ll_close, .close = logi_dj_ll_close,
.hidinput_input_event = logi_dj_ll_input_event, .raw_request = logi_dj_ll_raw_request,
}; };
......
...@@ -538,8 +538,8 @@ static int magicmouse_probe(struct hid_device *hdev, ...@@ -538,8 +538,8 @@ static int magicmouse_probe(struct hid_device *hdev,
* but there seems to be no other way of switching the mode. * but there seems to be no other way of switching the mode.
* Thus the super-ugly hacky success check below. * Thus the super-ugly hacky success check below.
*/ */
ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature), ret = hid_hw_raw_request(hdev, feature[0], feature, sizeof(feature),
HID_FEATURE_REPORT); HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret != -EIO && ret != sizeof(feature)) { if (ret != -EIO && ret != sizeof(feature)) {
hid_err(hdev, "unable to request touch data (%d)\n", ret); hid_err(hdev, "unable to request touch data (%d)\n", ret);
goto err_stop_hw; goto err_stop_hw;
......
...@@ -62,9 +62,48 @@ static int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage, ...@@ -62,9 +62,48 @@ static int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage,
{ {
struct input_dev *input = hi->input; struct input_dev *input = hi->input;
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) {
switch (usage->hid & HID_USAGE) {
/*
* Microsoft uses these 2 reserved usage ids for 2 keys on
* the MS office kb labelled "Office Home" and "Task Pane".
*/
case 0x29d:
ms_map_key_clear(KEY_PROG1);
return 1;
case 0x29e:
ms_map_key_clear(KEY_PROG2);
return 1;
}
return 0;
}
if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
return 0;
switch (usage->hid & HID_USAGE) { switch (usage->hid & HID_USAGE) {
case 0xfd06: ms_map_key_clear(KEY_CHAT); break; case 0xfd06: ms_map_key_clear(KEY_CHAT); break;
case 0xfd07: ms_map_key_clear(KEY_PHONE); break; case 0xfd07: ms_map_key_clear(KEY_PHONE); break;
case 0xff00:
/* Special keypad keys */
ms_map_key_clear(KEY_KPEQUAL);
set_bit(KEY_KPLEFTPAREN, input->keybit);
set_bit(KEY_KPRIGHTPAREN, input->keybit);
break;
case 0xff01:
/* Scroll wheel */
hid_map_usage_clear(hi, usage, bit, max, EV_REL, REL_WHEEL);
break;
case 0xff02:
/*
* This byte contains a copy of the modifier keys byte of a
* standard hid keyboard report, as send by interface 0
* (this usage is found on interface 1).
*
* This byte only gets send when another key in the same report
* changes state, and as such is useless, ignore it.
*/
return -1;
case 0xff05: case 0xff05:
set_bit(EV_REP, input->evbit); set_bit(EV_REP, input->evbit);
ms_map_key_clear(KEY_F13); ms_map_key_clear(KEY_F13);
...@@ -83,6 +122,9 @@ static int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage, ...@@ -83,6 +122,9 @@ static int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage,
static int ms_presenter_8k_quirk(struct hid_input *hi, struct hid_usage *usage, static int ms_presenter_8k_quirk(struct hid_input *hi, struct hid_usage *usage,
unsigned long **bit, int *max) unsigned long **bit, int *max)
{ {
if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
return 0;
set_bit(EV_REP, hi->input->evbit); set_bit(EV_REP, hi->input->evbit);
switch (usage->hid & HID_USAGE) { switch (usage->hid & HID_USAGE) {
case 0xfd08: ms_map_key_clear(KEY_FORWARD); break; case 0xfd08: ms_map_key_clear(KEY_FORWARD); break;
...@@ -102,9 +144,6 @@ static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -102,9 +144,6 @@ static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi,
{ {
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
return 0;
if (quirks & MS_ERGONOMY) { if (quirks & MS_ERGONOMY) {
int ret = ms_ergonomy_kb_quirk(hi, usage, bit, max); int ret = ms_ergonomy_kb_quirk(hi, usage, bit, max);
if (ret) if (ret)
...@@ -134,14 +173,39 @@ static int ms_event(struct hid_device *hdev, struct hid_field *field, ...@@ -134,14 +173,39 @@ static int ms_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value) struct hid_usage *usage, __s32 value)
{ {
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
struct input_dev *input;
if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput || if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
!usage->type) !usage->type)
return 0; return 0;
input = field->hidinput->input;
/* Handling MS keyboards special buttons */ /* Handling MS keyboards special buttons */
if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff00)) {
/* Special keypad keys */
input_report_key(input, KEY_KPEQUAL, value & 0x01);
input_report_key(input, KEY_KPLEFTPAREN, value & 0x02);
input_report_key(input, KEY_KPRIGHTPAREN, value & 0x04);
return 1;
}
if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff01)) {
/* Scroll wheel */
int step = ((value & 0x60) >> 5) + 1;
switch (value & 0x1f) {
case 0x01:
input_report_rel(input, REL_WHEEL, step);
break;
case 0x1f:
input_report_rel(input, REL_WHEEL, -step);
break;
}
return 1;
}
if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff05)) { if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff05)) {
struct input_dev *input = field->hidinput->input;
static unsigned int last_key = 0; static unsigned int last_key = 0;
unsigned int key = 0; unsigned int key = 0;
switch (value) { switch (value) {
...@@ -194,6 +258,8 @@ static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -194,6 +258,8 @@ static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id)
static const struct hid_device_id ms_devices[] = { static const struct hid_device_id ms_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV), { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV),
.driver_data = MS_HIDINPUT }, .driver_data = MS_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB),
.driver_data = MS_ERGONOMY },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K), { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K),
.driver_data = MS_ERGONOMY }, .driver_data = MS_ERGONOMY },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP), { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP),
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -48,8 +48,8 @@ static int blink1_send_command(struct blink1_data *data, ...@@ -48,8 +48,8 @@ static int blink1_send_command(struct blink1_data *data,
buf[0], buf[1], buf[2], buf[3], buf[4], buf[0], buf[1], buf[2], buf[3], buf[4],
buf[5], buf[6], buf[7], buf[8]); buf[5], buf[6], buf[7], buf[8]);
ret = data->hdev->hid_output_raw_report(data->hdev, buf, ret = hid_hw_raw_request(data->hdev, buf[0], buf, BLINK1_CMD_SIZE,
BLINK1_CMD_SIZE, HID_FEATURE_REPORT); HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
return ret < 0 ? ret : 0; return ret < 0 ? ret : 0;
} }
......
...@@ -128,8 +128,8 @@ static void wacom_set_image(struct hid_device *hdev, const char *image, ...@@ -128,8 +128,8 @@ static void wacom_set_image(struct hid_device *hdev, const char *image,
rep_data[0] = WAC_CMD_ICON_START_STOP; rep_data[0] = WAC_CMD_ICON_START_STOP;
rep_data[1] = 0; rep_data[1] = 0;
ret = hdev->hid_output_raw_report(hdev, rep_data, 2, ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
HID_FEATURE_REPORT); HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret < 0) if (ret < 0)
goto err; goto err;
...@@ -143,15 +143,15 @@ static void wacom_set_image(struct hid_device *hdev, const char *image, ...@@ -143,15 +143,15 @@ static void wacom_set_image(struct hid_device *hdev, const char *image,
rep_data[j + 3] = p[(i << 6) + j]; rep_data[j + 3] = p[(i << 6) + j];
rep_data[2] = i; rep_data[2] = i;
ret = hdev->hid_output_raw_report(hdev, rep_data, 67, ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 67,
HID_FEATURE_REPORT); HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
} }
rep_data[0] = WAC_CMD_ICON_START_STOP; rep_data[0] = WAC_CMD_ICON_START_STOP;
rep_data[1] = 0; rep_data[1] = 0;
ret = hdev->hid_output_raw_report(hdev, rep_data, 2, ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
HID_FEATURE_REPORT); HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
err: err:
return; return;
...@@ -183,7 +183,8 @@ static void wacom_leds_set_brightness(struct led_classdev *led_dev, ...@@ -183,7 +183,8 @@ static void wacom_leds_set_brightness(struct led_classdev *led_dev,
buf[3] = value; buf[3] = value;
/* use fixed brightness for OLEDs */ /* use fixed brightness for OLEDs */
buf[4] = 0x08; buf[4] = 0x08;
hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT); hid_hw_raw_request(hdev, buf[0], buf, 9, HID_FEATURE_REPORT,
HID_REQ_SET_REPORT);
kfree(buf); kfree(buf);
} }
...@@ -339,8 +340,8 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed) ...@@ -339,8 +340,8 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
rep_data[0] = 0x03 ; rep_data[1] = 0x00; rep_data[0] = 0x03 ; rep_data[1] = 0x00;
limit = 3; limit = 3;
do { do {
ret = hdev->hid_output_raw_report(hdev, rep_data, 2, ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
HID_FEATURE_REPORT); HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
} while (ret < 0 && limit-- > 0); } while (ret < 0 && limit-- > 0);
if (ret >= 0) { if (ret >= 0) {
...@@ -352,8 +353,9 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed) ...@@ -352,8 +353,9 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
rep_data[1] = 0x00; rep_data[1] = 0x00;
limit = 3; limit = 3;
do { do {
ret = hdev->hid_output_raw_report(hdev, ret = hid_hw_raw_request(hdev, rep_data[0],
rep_data, 2, HID_FEATURE_REPORT); rep_data, 2, HID_FEATURE_REPORT,
HID_REQ_SET_REPORT);
} while (ret < 0 && limit-- > 0); } while (ret < 0 && limit-- > 0);
if (ret >= 0) { if (ret >= 0) {
...@@ -378,8 +380,8 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed) ...@@ -378,8 +380,8 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
rep_data[0] = 0x03; rep_data[0] = 0x03;
rep_data[1] = wdata->features; rep_data[1] = wdata->features;
ret = hdev->hid_output_raw_report(hdev, rep_data, 2, ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
HID_FEATURE_REPORT); HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret >= 0) if (ret >= 0)
wdata->high_speed = speed; wdata->high_speed = speed;
break; break;
......
...@@ -28,14 +28,14 @@ static int wiimote_hid_send(struct hid_device *hdev, __u8 *buffer, ...@@ -28,14 +28,14 @@ static int wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
__u8 *buf; __u8 *buf;
int ret; int ret;
if (!hdev->hid_output_raw_report) if (!hdev->ll_driver->output_report)
return -ENODEV; return -ENODEV;
buf = kmemdup(buffer, count, GFP_KERNEL); buf = kmemdup(buffer, count, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
ret = hdev->hid_output_raw_report(hdev, buf, count, HID_OUTPUT_REPORT); ret = hid_hw_output_report(hdev, buf, count);
kfree(buf); kfree(buf);
return ret; return ret;
......
...@@ -123,10 +123,6 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, ...@@ -123,10 +123,6 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
dev = hidraw_table[minor]->hid; dev = hidraw_table[minor]->hid;
if (!dev->hid_output_raw_report) {
ret = -ENODEV;
goto out;
}
if (count > HID_MAX_BUFFER_SIZE) { if (count > HID_MAX_BUFFER_SIZE) {
hid_warn(dev, "pid %d passed too large report\n", hid_warn(dev, "pid %d passed too large report\n",
...@@ -153,7 +149,21 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, ...@@ -153,7 +149,21 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
goto out_free; goto out_free;
} }
ret = dev->hid_output_raw_report(dev, buf, count, report_type); if ((report_type == HID_OUTPUT_REPORT) &&
!(dev->quirks & HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP)) {
ret = hid_hw_output_report(dev, buf, count);
/*
* compatibility with old implementation of USB-HID and I2C-HID:
* if the device does not support receiving output reports,
* on an interrupt endpoint, fallback to SET_REPORT HID command.
*/
if (ret != -ENOSYS)
goto out_free;
}
ret = hid_hw_raw_request(dev, buf[0], buf, count, report_type,
HID_REQ_SET_REPORT);
out_free: out_free:
kfree(buf); kfree(buf);
out: out:
...@@ -189,7 +199,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t ...@@ -189,7 +199,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
dev = hidraw_table[minor]->hid; dev = hidraw_table[minor]->hid;
if (!dev->hid_get_raw_report) { if (!dev->ll_driver->raw_request) {
ret = -ENODEV; ret = -ENODEV;
goto out; goto out;
} }
...@@ -216,14 +226,15 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t ...@@ -216,14 +226,15 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
/* /*
* Read the first byte from the user. This is the report number, * Read the first byte from the user. This is the report number,
* which is passed to dev->hid_get_raw_report(). * which is passed to hid_hw_raw_request().
*/ */
if (copy_from_user(&report_number, buffer, 1)) { if (copy_from_user(&report_number, buffer, 1)) {
ret = -EFAULT; ret = -EFAULT;
goto out_free; goto out_free;
} }
ret = dev->hid_get_raw_report(dev, report_number, buf, count, report_type); ret = hid_hw_raw_request(dev, report_number, buf, count, report_type,
HID_REQ_GET_REPORT);
if (ret < 0) if (ret < 0)
goto out_free; goto out_free;
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/err.h> #include <linux/err.h>
...@@ -256,18 +257,27 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType, ...@@ -256,18 +257,27 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType,
return 0; return 0;
} }
static int i2c_hid_set_report(struct i2c_client *client, u8 reportType, /**
u8 reportID, unsigned char *buf, size_t data_len) * i2c_hid_set_or_send_report: forward an incoming report to the device
* @client: the i2c_client of the device
* @reportType: 0x03 for HID_FEATURE_REPORT ; 0x02 for HID_OUTPUT_REPORT
* @reportID: the report ID
* @buf: the actual data to transfer, without the report ID
* @len: size of buf
* @use_data: true: use SET_REPORT HID command, false: send plain OUTPUT report
*/
static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType,
u8 reportID, unsigned char *buf, size_t data_len, bool use_data)
{ {
struct i2c_hid *ihid = i2c_get_clientdata(client); struct i2c_hid *ihid = i2c_get_clientdata(client);
u8 *args = ihid->argsbuf; u8 *args = ihid->argsbuf;
const struct i2c_hid_cmd * hidcmd = &hid_set_report_cmd; const struct i2c_hid_cmd *hidcmd;
int ret; int ret;
u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister); u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister); u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister);
u16 maxOutputLength = le16_to_cpu(ihid->hdesc.wMaxOutputLength); u16 maxOutputLength = le16_to_cpu(ihid->hdesc.wMaxOutputLength);
/* hidraw already checked that data_len < HID_MAX_BUFFER_SIZE */ /* hid_hw_* already checked that data_len < HID_MAX_BUFFER_SIZE */
u16 size = 2 /* size */ + u16 size = 2 /* size */ +
(reportID ? 1 : 0) /* reportID */ + (reportID ? 1 : 0) /* reportID */ +
data_len /* buf */; data_len /* buf */;
...@@ -278,6 +288,9 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType, ...@@ -278,6 +288,9 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
i2c_hid_dbg(ihid, "%s\n", __func__); i2c_hid_dbg(ihid, "%s\n", __func__);
if (!use_data && maxOutputLength == 0)
return -ENOSYS;
if (reportID >= 0x0F) { if (reportID >= 0x0F) {
args[index++] = reportID; args[index++] = reportID;
reportID = 0x0F; reportID = 0x0F;
...@@ -287,9 +300,10 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType, ...@@ -287,9 +300,10 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
* use the data register for feature reports or if the device does not * use the data register for feature reports or if the device does not
* support the output register * support the output register
*/ */
if (reportType == 0x03 || maxOutputLength == 0) { if (use_data) {
args[index++] = dataRegister & 0xFF; args[index++] = dataRegister & 0xFF;
args[index++] = dataRegister >> 8; args[index++] = dataRegister >> 8;
hidcmd = &hid_set_report_cmd;
} else { } else {
args[index++] = outputRegister & 0xFF; args[index++] = outputRegister & 0xFF;
args[index++] = outputRegister >> 8; args[index++] = outputRegister >> 8;
...@@ -454,10 +468,18 @@ static void i2c_hid_init_reports(struct hid_device *hid) ...@@ -454,10 +468,18 @@ static void i2c_hid_init_reports(struct hid_device *hid)
return; return;
} }
/*
* The device must be powered on while we fetch initial reports
* from it.
*/
pm_runtime_get_sync(&client->dev);
list_for_each_entry(report, list_for_each_entry(report,
&hid->report_enum[HID_FEATURE_REPORT].report_list, list) &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
i2c_hid_init_report(report, inbuf, ihid->bufsize); i2c_hid_init_report(report, inbuf, ihid->bufsize);
pm_runtime_put(&client->dev);
kfree(inbuf); kfree(inbuf);
} }
...@@ -550,7 +572,7 @@ static int i2c_hid_get_raw_report(struct hid_device *hid, ...@@ -550,7 +572,7 @@ static int i2c_hid_get_raw_report(struct hid_device *hid,
} }
static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
size_t count, unsigned char report_type) size_t count, unsigned char report_type, bool use_data)
{ {
struct i2c_client *client = hid->driver_data; struct i2c_client *client = hid->driver_data;
int report_id = buf[0]; int report_id = buf[0];
...@@ -564,9 +586,9 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, ...@@ -564,9 +586,9 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
count--; count--;
} }
ret = i2c_hid_set_report(client, ret = i2c_hid_set_or_send_report(client,
report_type == HID_FEATURE_REPORT ? 0x03 : 0x02, report_type == HID_FEATURE_REPORT ? 0x03 : 0x02,
report_id, buf, count); report_id, buf, count, use_data);
if (report_id && ret >= 0) if (report_id && ret >= 0)
ret++; /* add report_id to the number of transfered bytes */ ret++; /* add report_id to the number of transfered bytes */
...@@ -574,34 +596,27 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, ...@@ -574,34 +596,27 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
return ret; return ret;
} }
static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep, static int i2c_hid_output_report(struct hid_device *hid, __u8 *buf,
int reqtype) size_t count)
{ {
struct i2c_client *client = hid->driver_data; return i2c_hid_output_raw_report(hid, buf, count, HID_OUTPUT_REPORT,
char *buf; false);
int ret; }
int len = i2c_hid_get_report_length(rep) - 2;
buf = hid_alloc_report_buf(rep, GFP_KERNEL);
if (!buf)
return;
static int i2c_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
__u8 *buf, size_t len, unsigned char rtype,
int reqtype)
{
switch (reqtype) { switch (reqtype) {
case HID_REQ_GET_REPORT: case HID_REQ_GET_REPORT:
ret = i2c_hid_get_raw_report(hid, rep->id, buf, len, rep->type); return i2c_hid_get_raw_report(hid, reportnum, buf, len, rtype);
if (ret < 0)
dev_err(&client->dev, "%s: unable to get report: %d\n",
__func__, ret);
else
hid_input_report(hid, rep->type, buf, ret, 0);
break;
case HID_REQ_SET_REPORT: case HID_REQ_SET_REPORT:
hid_output_report(rep, buf); if (buf[0] != reportnum)
i2c_hid_output_raw_report(hid, buf, len, rep->type); return -EINVAL;
break; return i2c_hid_output_raw_report(hid, buf, len, rtype, true);
default:
return -EIO;
} }
kfree(buf);
} }
static int i2c_hid_parse(struct hid_device *hid) static int i2c_hid_parse(struct hid_device *hid)
...@@ -703,8 +718,8 @@ static int i2c_hid_open(struct hid_device *hid) ...@@ -703,8 +718,8 @@ static int i2c_hid_open(struct hid_device *hid)
mutex_lock(&i2c_hid_open_mut); mutex_lock(&i2c_hid_open_mut);
if (!hid->open++) { if (!hid->open++) {
ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); ret = pm_runtime_get_sync(&client->dev);
if (ret) { if (ret < 0) {
hid->open--; hid->open--;
goto done; goto done;
} }
...@@ -712,7 +727,7 @@ static int i2c_hid_open(struct hid_device *hid) ...@@ -712,7 +727,7 @@ static int i2c_hid_open(struct hid_device *hid)
} }
done: done:
mutex_unlock(&i2c_hid_open_mut); mutex_unlock(&i2c_hid_open_mut);
return ret; return ret < 0 ? ret : 0;
} }
static void i2c_hid_close(struct hid_device *hid) static void i2c_hid_close(struct hid_device *hid)
...@@ -729,7 +744,7 @@ static void i2c_hid_close(struct hid_device *hid) ...@@ -729,7 +744,7 @@ static void i2c_hid_close(struct hid_device *hid)
clear_bit(I2C_HID_STARTED, &ihid->flags); clear_bit(I2C_HID_STARTED, &ihid->flags);
/* Save some power */ /* Save some power */
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); pm_runtime_put(&client->dev);
} }
mutex_unlock(&i2c_hid_open_mut); mutex_unlock(&i2c_hid_open_mut);
} }
...@@ -738,19 +753,18 @@ static int i2c_hid_power(struct hid_device *hid, int lvl) ...@@ -738,19 +753,18 @@ static int i2c_hid_power(struct hid_device *hid, int lvl)
{ {
struct i2c_client *client = hid->driver_data; struct i2c_client *client = hid->driver_data;
struct i2c_hid *ihid = i2c_get_clientdata(client); struct i2c_hid *ihid = i2c_get_clientdata(client);
int ret = 0;
i2c_hid_dbg(ihid, "%s lvl:%d\n", __func__, lvl); i2c_hid_dbg(ihid, "%s lvl:%d\n", __func__, lvl);
switch (lvl) { switch (lvl) {
case PM_HINT_FULLON: case PM_HINT_FULLON:
ret = i2c_hid_set_power(client, I2C_HID_PWR_ON); pm_runtime_get_sync(&client->dev);
break; break;
case PM_HINT_NORMAL: case PM_HINT_NORMAL:
ret = i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); pm_runtime_put(&client->dev);
break; break;
} }
return ret; return 0;
} }
static struct hid_ll_driver i2c_hid_ll_driver = { static struct hid_ll_driver i2c_hid_ll_driver = {
...@@ -760,7 +774,8 @@ static struct hid_ll_driver i2c_hid_ll_driver = { ...@@ -760,7 +774,8 @@ static struct hid_ll_driver i2c_hid_ll_driver = {
.open = i2c_hid_open, .open = i2c_hid_open,
.close = i2c_hid_close, .close = i2c_hid_close,
.power = i2c_hid_power, .power = i2c_hid_power,
.request = i2c_hid_request, .output_report = i2c_hid_output_report,
.raw_request = i2c_hid_raw_request,
}; };
static int i2c_hid_init_irq(struct i2c_client *client) static int i2c_hid_init_irq(struct i2c_client *client)
...@@ -973,13 +988,17 @@ static int i2c_hid_probe(struct i2c_client *client, ...@@ -973,13 +988,17 @@ static int i2c_hid_probe(struct i2c_client *client,
if (ret < 0) if (ret < 0)
goto err; goto err;
pm_runtime_get_noresume(&client->dev);
pm_runtime_set_active(&client->dev);
pm_runtime_enable(&client->dev);
ret = i2c_hid_fetch_hid_descriptor(ihid); ret = i2c_hid_fetch_hid_descriptor(ihid);
if (ret < 0) if (ret < 0)
goto err; goto err_pm;
ret = i2c_hid_init_irq(client); ret = i2c_hid_init_irq(client);
if (ret < 0) if (ret < 0)
goto err; goto err_pm;
hid = hid_allocate_device(); hid = hid_allocate_device();
if (IS_ERR(hid)) { if (IS_ERR(hid)) {
...@@ -991,8 +1010,6 @@ static int i2c_hid_probe(struct i2c_client *client, ...@@ -991,8 +1010,6 @@ static int i2c_hid_probe(struct i2c_client *client,
hid->driver_data = client; hid->driver_data = client;
hid->ll_driver = &i2c_hid_ll_driver; hid->ll_driver = &i2c_hid_ll_driver;
hid->hid_get_raw_report = i2c_hid_get_raw_report;
hid->hid_output_raw_report = i2c_hid_output_raw_report;
hid->dev.parent = &client->dev; hid->dev.parent = &client->dev;
ACPI_COMPANION_SET(&hid->dev, ACPI_COMPANION(&client->dev)); ACPI_COMPANION_SET(&hid->dev, ACPI_COMPANION(&client->dev));
hid->bus = BUS_I2C; hid->bus = BUS_I2C;
...@@ -1010,6 +1027,7 @@ static int i2c_hid_probe(struct i2c_client *client, ...@@ -1010,6 +1027,7 @@ static int i2c_hid_probe(struct i2c_client *client,
goto err_mem_free; goto err_mem_free;
} }
pm_runtime_put(&client->dev);
return 0; return 0;
err_mem_free: err_mem_free:
...@@ -1018,6 +1036,10 @@ static int i2c_hid_probe(struct i2c_client *client, ...@@ -1018,6 +1036,10 @@ static int i2c_hid_probe(struct i2c_client *client,
err_irq: err_irq:
free_irq(client->irq, ihid); free_irq(client->irq, ihid);
err_pm:
pm_runtime_put_noidle(&client->dev);
pm_runtime_disable(&client->dev);
err: err:
i2c_hid_free_buffers(ihid); i2c_hid_free_buffers(ihid);
kfree(ihid); kfree(ihid);
...@@ -1029,6 +1051,11 @@ static int i2c_hid_remove(struct i2c_client *client) ...@@ -1029,6 +1051,11 @@ static int i2c_hid_remove(struct i2c_client *client)
struct i2c_hid *ihid = i2c_get_clientdata(client); struct i2c_hid *ihid = i2c_get_clientdata(client);
struct hid_device *hid; struct hid_device *hid;
pm_runtime_get_sync(&client->dev);
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
pm_runtime_put_noidle(&client->dev);
hid = ihid->hid; hid = ihid->hid;
hid_destroy_device(hid); hid_destroy_device(hid);
...@@ -1074,7 +1101,31 @@ static int i2c_hid_resume(struct device *dev) ...@@ -1074,7 +1101,31 @@ static int i2c_hid_resume(struct device *dev)
} }
#endif #endif
static SIMPLE_DEV_PM_OPS(i2c_hid_pm, i2c_hid_suspend, i2c_hid_resume); #ifdef CONFIG_PM_RUNTIME
static int i2c_hid_runtime_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
disable_irq(client->irq);
return 0;
}
static int i2c_hid_runtime_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
enable_irq(client->irq);
i2c_hid_set_power(client, I2C_HID_PWR_ON);
return 0;
}
#endif
static const struct dev_pm_ops i2c_hid_pm = {
SET_SYSTEM_SLEEP_PM_OPS(i2c_hid_suspend, i2c_hid_resume)
SET_RUNTIME_PM_OPS(i2c_hid_runtime_suspend, i2c_hid_runtime_resume,
NULL)
};
static const struct i2c_device_id i2c_hid_id_table[] = { static const struct i2c_device_id i2c_hid_id_table[] = {
{ "hid", 0 }, { "hid", 0 },
......
...@@ -244,12 +244,35 @@ static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count, ...@@ -244,12 +244,35 @@ static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
return count; return count;
} }
static int uhid_hid_output_report(struct hid_device *hid, __u8 *buf,
size_t count)
{
return uhid_hid_output_raw(hid, buf, count, HID_OUTPUT_REPORT);
}
static int uhid_raw_request(struct hid_device *hid, unsigned char reportnum,
__u8 *buf, size_t len, unsigned char rtype,
int reqtype)
{
switch (reqtype) {
case HID_REQ_GET_REPORT:
return uhid_hid_get_raw(hid, reportnum, buf, len, rtype);
case HID_REQ_SET_REPORT:
/* TODO: implement proper SET_REPORT functionality */
return -ENOSYS;
default:
return -EIO;
}
}
static struct hid_ll_driver uhid_hid_driver = { static struct hid_ll_driver uhid_hid_driver = {
.start = uhid_hid_start, .start = uhid_hid_start,
.stop = uhid_hid_stop, .stop = uhid_hid_stop,
.open = uhid_hid_open, .open = uhid_hid_open,
.close = uhid_hid_close, .close = uhid_hid_close,
.parse = uhid_hid_parse, .parse = uhid_hid_parse,
.output_report = uhid_hid_output_report,
.raw_request = uhid_raw_request,
}; };
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
...@@ -377,8 +400,6 @@ static int uhid_dev_create(struct uhid_device *uhid, ...@@ -377,8 +400,6 @@ static int uhid_dev_create(struct uhid_device *uhid,
hid->uniq[63] = 0; hid->uniq[63] = 0;
hid->ll_driver = &uhid_hid_driver; hid->ll_driver = &uhid_hid_driver;
hid->hid_get_raw_report = uhid_hid_get_raw;
hid->hid_output_raw_report = uhid_hid_output_raw;
hid->bus = ev->u.create.bus; hid->bus = ev->u.create.bus;
hid->vendor = ev->u.create.vendor; hid->vendor = ev->u.create.vendor;
hid->product = ev->u.create.product; hid->product = ev->u.create.product;
...@@ -407,6 +428,67 @@ static int uhid_dev_create(struct uhid_device *uhid, ...@@ -407,6 +428,67 @@ static int uhid_dev_create(struct uhid_device *uhid,
return ret; return ret;
} }
static int uhid_dev_create2(struct uhid_device *uhid,
const struct uhid_event *ev)
{
struct hid_device *hid;
int ret;
if (uhid->running)
return -EALREADY;
uhid->rd_size = ev->u.create2.rd_size;
if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE)
return -EINVAL;
uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL);
if (!uhid->rd_data)
return -ENOMEM;
memcpy(uhid->rd_data, ev->u.create2.rd_data, uhid->rd_size);
hid = hid_allocate_device();
if (IS_ERR(hid)) {
ret = PTR_ERR(hid);
goto err_free;
}
strncpy(hid->name, ev->u.create2.name, 127);
hid->name[127] = 0;
strncpy(hid->phys, ev->u.create2.phys, 63);
hid->phys[63] = 0;
strncpy(hid->uniq, ev->u.create2.uniq, 63);
hid->uniq[63] = 0;
hid->ll_driver = &uhid_hid_driver;
hid->bus = ev->u.create2.bus;
hid->vendor = ev->u.create2.vendor;
hid->product = ev->u.create2.product;
hid->version = ev->u.create2.version;
hid->country = ev->u.create2.country;
hid->driver_data = uhid;
hid->dev.parent = uhid_misc.this_device;
uhid->hid = hid;
uhid->running = true;
ret = hid_add_device(hid);
if (ret) {
hid_err(hid, "Cannot register HID device\n");
goto err_hid;
}
return 0;
err_hid:
hid_destroy_device(hid);
uhid->hid = NULL;
uhid->running = false;
err_free:
kfree(uhid->rd_data);
return ret;
}
static int uhid_dev_destroy(struct uhid_device *uhid) static int uhid_dev_destroy(struct uhid_device *uhid)
{ {
if (!uhid->running) if (!uhid->running)
...@@ -435,6 +517,17 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev) ...@@ -435,6 +517,17 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
return 0; return 0;
} }
static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev)
{
if (!uhid->running)
return -EINVAL;
hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data,
min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0);
return 0;
}
static int uhid_dev_feature_answer(struct uhid_device *uhid, static int uhid_dev_feature_answer(struct uhid_device *uhid,
struct uhid_event *ev) struct uhid_event *ev)
{ {
...@@ -571,12 +664,18 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer, ...@@ -571,12 +664,18 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
case UHID_CREATE: case UHID_CREATE:
ret = uhid_dev_create(uhid, &uhid->input_buf); ret = uhid_dev_create(uhid, &uhid->input_buf);
break; break;
case UHID_CREATE2:
ret = uhid_dev_create2(uhid, &uhid->input_buf);
break;
case UHID_DESTROY: case UHID_DESTROY:
ret = uhid_dev_destroy(uhid); ret = uhid_dev_destroy(uhid);
break; break;
case UHID_INPUT: case UHID_INPUT:
ret = uhid_dev_input(uhid, &uhid->input_buf); ret = uhid_dev_input(uhid, &uhid->input_buf);
break; break;
case UHID_INPUT2:
ret = uhid_dev_input2(uhid, &uhid->input_buf);
break;
case UHID_FEATURE_ANSWER: case UHID_FEATURE_ANSWER:
ret = uhid_dev_feature_answer(uhid, &uhid->input_buf); ret = uhid_dev_feature_answer(uhid, &uhid->input_buf);
break; break;
......
...@@ -884,18 +884,21 @@ static int usbhid_get_raw_report(struct hid_device *hid, ...@@ -884,18 +884,21 @@ static int usbhid_get_raw_report(struct hid_device *hid,
return ret; return ret;
} }
static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count, static int usbhid_set_raw_report(struct hid_device *hid, unsigned int reportnum,
unsigned char report_type) __u8 *buf, size_t count, unsigned char rtype)
{ {
struct usbhid_device *usbhid = hid->driver_data; struct usbhid_device *usbhid = hid->driver_data;
struct usb_device *dev = hid_to_usb_dev(hid); struct usb_device *dev = hid_to_usb_dev(hid);
struct usb_interface *intf = usbhid->intf; struct usb_interface *intf = usbhid->intf;
struct usb_host_interface *interface = intf->cur_altsetting; struct usb_host_interface *interface = intf->cur_altsetting;
int ret; int ret, skipped_report_id = 0;
if (usbhid->urbout && report_type != HID_FEATURE_REPORT) { /* Byte 0 is the report number. Report data starts at byte 1.*/
int actual_length; if ((rtype == HID_OUTPUT_REPORT) &&
int skipped_report_id = 0; (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORT_ID))
buf[0] = 0;
else
buf[0] = reportnum;
if (buf[0] == 0x0) { if (buf[0] == 0x0) {
/* Don't send the Report ID */ /* Don't send the Report ID */
...@@ -903,33 +906,44 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co ...@@ -903,33 +906,44 @@ static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t co
count--; count--;
skipped_report_id = 1; skipped_report_id = 1;
} }
ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
buf, count, &actual_length, ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
HID_REQ_SET_REPORT,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
((rtype + 1) << 8) | reportnum,
interface->desc.bInterfaceNumber, buf, count,
USB_CTRL_SET_TIMEOUT); USB_CTRL_SET_TIMEOUT);
/* return the number of bytes transferred */ /* count also the report id, if this was a numbered report. */
if (ret == 0) { if (ret > 0 && skipped_report_id)
ret = actual_length;
/* count also the report id */
if (skipped_report_id)
ret++; ret++;
}
} else { return ret;
int skipped_report_id = 0; }
int report_id = buf[0];
static int usbhid_output_report(struct hid_device *hid, __u8 *buf, size_t count)
{
struct usbhid_device *usbhid = hid->driver_data;
struct usb_device *dev = hid_to_usb_dev(hid);
int actual_length, skipped_report_id = 0, ret;
if (!usbhid->urbout)
return -ENOSYS;
if (buf[0] == 0x0) { if (buf[0] == 0x0) {
/* Don't send the Report ID */ /* Don't send the Report ID */
buf++; buf++;
count--; count--;
skipped_report_id = 1; skipped_report_id = 1;
} }
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
HID_REQ_SET_REPORT, ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, buf, count, &actual_length,
((report_type + 1) << 8) | report_id,
interface->desc.bInterfaceNumber, buf, count,
USB_CTRL_SET_TIMEOUT); USB_CTRL_SET_TIMEOUT);
/* count also the report id, if this was a numbered report. */ /* return the number of bytes transferred */
if (ret > 0 && skipped_report_id) if (ret == 0) {
ret = actual_length;
/* count also the report id */
if (skipped_report_id)
ret++; ret++;
} }
...@@ -1200,6 +1214,20 @@ static void usbhid_request(struct hid_device *hid, struct hid_report *rep, int r ...@@ -1200,6 +1214,20 @@ static void usbhid_request(struct hid_device *hid, struct hid_report *rep, int r
} }
} }
static int usbhid_raw_request(struct hid_device *hid, unsigned char reportnum,
__u8 *buf, size_t len, unsigned char rtype,
int reqtype)
{
switch (reqtype) {
case HID_REQ_GET_REPORT:
return usbhid_get_raw_report(hid, reportnum, buf, len, rtype);
case HID_REQ_SET_REPORT:
return usbhid_set_raw_report(hid, reportnum, buf, len, rtype);
default:
return -EIO;
}
}
static int usbhid_idle(struct hid_device *hid, int report, int idle, static int usbhid_idle(struct hid_device *hid, int report, int idle,
int reqtype) int reqtype)
{ {
...@@ -1223,6 +1251,8 @@ static struct hid_ll_driver usb_hid_driver = { ...@@ -1223,6 +1251,8 @@ static struct hid_ll_driver usb_hid_driver = {
.power = usbhid_power, .power = usbhid_power,
.request = usbhid_request, .request = usbhid_request,
.wait = usbhid_wait_io, .wait = usbhid_wait_io,
.raw_request = usbhid_raw_request,
.output_report = usbhid_output_report,
.idle = usbhid_idle, .idle = usbhid_idle,
}; };
...@@ -1253,8 +1283,6 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id * ...@@ -1253,8 +1283,6 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
usb_set_intfdata(intf, hid); usb_set_intfdata(intf, hid);
hid->ll_driver = &usb_hid_driver; hid->ll_driver = &usb_hid_driver;
hid->hid_get_raw_report = usbhid_get_raw_report;
hid->hid_output_raw_report = usbhid_output_raw_report;
hid->ff_init = hid_pidff_init; hid->ff_init = hid_pidff_init;
#ifdef CONFIG_USB_HIDDEV #ifdef CONFIG_USB_HIDDEV
hid->hiddev_connect = hiddev_connect; hid->hiddev_connect = hiddev_connect;
......
...@@ -38,29 +38,40 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, ...@@ -38,29 +38,40 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
if (state) { if (state) {
if (sensor_hub_device_open(st->hsdev)) if (sensor_hub_device_open(st->hsdev))
return -EIO; return -EIO;
state_val = state_val = hid_sensor_get_usage_index(st->hsdev,
HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM; st->power_state.report_id,
report_val = st->power_state.index,
HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM; HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM);
report_val = hid_sensor_get_usage_index(st->hsdev,
st->report_state.report_id,
st->report_state.index,
HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM);
} else { } else {
sensor_hub_device_close(st->hsdev); sensor_hub_device_close(st->hsdev);
state_val = state_val = hid_sensor_get_usage_index(st->hsdev,
HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM; st->power_state.report_id,
report_val = st->power_state.index,
HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM; HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM);
report_val = hid_sensor_get_usage_index(st->hsdev,
st->report_state.report_id,
st->report_state.index,
HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM);
} }
st->data_ready = state; st->data_ready = state;
if (state_val >= 0) {
state_val += st->power_state.logical_minimum; state_val += st->power_state.logical_minimum;
report_val += st->report_state.logical_minimum;
sensor_hub_set_feature(st->hsdev, st->power_state.report_id, sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
st->power_state.index, st->power_state.index,
(s32)state_val); (s32)state_val);
}
if (report_val >= 0) {
report_val += st->report_state.logical_minimum;
sensor_hub_set_feature(st->hsdev, st->report_state.report_id, sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
st->report_state.index, st->report_state.index,
(s32)report_val); (s32)report_val);
}
return 0; return 0;
} }
......
...@@ -51,13 +51,15 @@ struct hid_sensor_hub_attribute_info { ...@@ -51,13 +51,15 @@ struct hid_sensor_hub_attribute_info {
* @hdev: Stores the hid instance. * @hdev: Stores the hid instance.
* @vendor_id: Vendor id of hub device. * @vendor_id: Vendor id of hub device.
* @product_id: Product id of hub device. * @product_id: Product id of hub device.
* @ref_cnt: Number of MFD clients have opened this device * @start_collection_index: Starting index for a phy type collection
* @end_collection_index: Last index for a phy type collection
*/ */
struct hid_sensor_hub_device { struct hid_sensor_hub_device {
struct hid_device *hdev; struct hid_device *hdev;
u32 vendor_id; u32 vendor_id;
u32 product_id; u32 product_id;
int ref_cnt; int start_collection_index;
int end_collection_index;
}; };
/** /**
...@@ -218,4 +220,7 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, ...@@ -218,4 +220,7 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st, int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
int *val1, int *val2); int *val1, int *val2);
int hid_sensor_get_usage_index(struct hid_sensor_hub_device *hsdev,
u32 report_id, int field_index, u32 usage_id);
#endif #endif
...@@ -140,15 +140,15 @@ ...@@ -140,15 +140,15 @@
#define HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS 0x1000 #define HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS 0x1000
/* Power state enumerations */ /* Power state enumerations */
#define HID_USAGE_SENSOR_PROP_POWER_STATE_UNDEFINED_ENUM 0x00 #define HID_USAGE_SENSOR_PROP_POWER_STATE_UNDEFINED_ENUM 0x200850
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM 0x01 #define HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM 0x200851
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D1_LOW_POWER_ENUM 0x02 #define HID_USAGE_SENSOR_PROP_POWER_STATE_D1_LOW_POWER_ENUM 0x200852
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D2_STANDBY_WITH_WAKE_ENUM 0x03 #define HID_USAGE_SENSOR_PROP_POWER_STATE_D2_STANDBY_WITH_WAKE_ENUM 0x200853
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D3_SLEEP_WITH_WAKE_ENUM 0x04 #define HID_USAGE_SENSOR_PROP_POWER_STATE_D3_SLEEP_WITH_WAKE_ENUM 0x200854
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM 0x05 #define HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM 0x200855
/* Report State enumerations */ /* Report State enumerations */
#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM 0x00 #define HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM 0x200840
#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x01 #define HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x200841
#endif #endif
...@@ -201,6 +201,7 @@ struct hid_item { ...@@ -201,6 +201,7 @@ struct hid_item {
#define HID_GD_VBRZ 0x00010045 #define HID_GD_VBRZ 0x00010045
#define HID_GD_VNO 0x00010046 #define HID_GD_VNO 0x00010046
#define HID_GD_FEATURE 0x00010047 #define HID_GD_FEATURE 0x00010047
#define HID_GD_SYSTEM_CONTROL 0x00010080
#define HID_GD_UP 0x00010090 #define HID_GD_UP 0x00010090
#define HID_GD_DOWN 0x00010091 #define HID_GD_DOWN 0x00010091
#define HID_GD_RIGHT 0x00010092 #define HID_GD_RIGHT 0x00010092
...@@ -208,6 +209,8 @@ struct hid_item { ...@@ -208,6 +209,8 @@ struct hid_item {
#define HID_DC_BATTERYSTRENGTH 0x00060020 #define HID_DC_BATTERYSTRENGTH 0x00060020
#define HID_CP_CONSUMER_CONTROL 0x000c0001
#define HID_DG_DIGITIZER 0x000d0001 #define HID_DG_DIGITIZER 0x000d0001
#define HID_DG_PEN 0x000d0002 #define HID_DG_PEN 0x000d0002
#define HID_DG_LIGHTPEN 0x000d0003 #define HID_DG_LIGHTPEN 0x000d0003
...@@ -287,6 +290,8 @@ struct hid_item { ...@@ -287,6 +290,8 @@ struct hid_item {
#define HID_QUIRK_NO_EMPTY_INPUT 0x00000100 #define HID_QUIRK_NO_EMPTY_INPUT 0x00000100
#define HID_QUIRK_NO_INIT_INPUT_REPORTS 0x00000200 #define HID_QUIRK_NO_INIT_INPUT_REPORTS 0x00000200
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
#define HID_QUIRK_SKIP_OUTPUT_REPORT_ID 0x00020000
#define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP 0x00040000
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000 #define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
#define HID_QUIRK_NO_INIT_REPORTS 0x20000000 #define HID_QUIRK_NO_INIT_REPORTS 0x20000000
#define HID_QUIRK_NO_IGNORE 0x40000000 #define HID_QUIRK_NO_IGNORE 0x40000000
...@@ -508,12 +513,6 @@ struct hid_device { /* device report descriptor */ ...@@ -508,12 +513,6 @@ struct hid_device { /* device report descriptor */
struct hid_usage *, __s32); struct hid_usage *, __s32);
void (*hiddev_report_event) (struct hid_device *, struct hid_report *); void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
/* handler for raw input (Get_Report) data, used by hidraw */
int (*hid_get_raw_report) (struct hid_device *, unsigned char, __u8 *, size_t, unsigned char);
/* handler for raw output data, used by hidraw */
int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t, unsigned char);
/* debugging support via debugfs */ /* debugging support via debugfs */
unsigned short debug; unsigned short debug;
struct dentry *debug_dir; struct dentry *debug_dir;
...@@ -675,11 +674,12 @@ struct hid_driver { ...@@ -675,11 +674,12 @@ struct hid_driver {
* @stop: called on remove * @stop: called on remove
* @open: called by input layer on open * @open: called by input layer on open
* @close: called by input layer on close * @close: called by input layer on close
* @hidinput_input_event: event input event (e.g. ff or leds)
* @parse: this method is called only once to parse the device data, * @parse: this method is called only once to parse the device data,
* shouldn't allocate anything to not leak memory * shouldn't allocate anything to not leak memory
* @request: send report request to device (e.g. feature report) * @request: send report request to device (e.g. feature report)
* @wait: wait for buffered io to complete (send/recv reports) * @wait: wait for buffered io to complete (send/recv reports)
* @raw_request: send raw report request to device (e.g. feature report)
* @output_report: send output report to device
* @idle: send idle request to device * @idle: send idle request to device
*/ */
struct hid_ll_driver { struct hid_ll_driver {
...@@ -691,17 +691,20 @@ struct hid_ll_driver { ...@@ -691,17 +691,20 @@ struct hid_ll_driver {
int (*power)(struct hid_device *hdev, int level); int (*power)(struct hid_device *hdev, int level);
int (*hidinput_input_event) (struct input_dev *idev, unsigned int type,
unsigned int code, int value);
int (*parse)(struct hid_device *hdev); int (*parse)(struct hid_device *hdev);
void (*request)(struct hid_device *hdev, void (*request)(struct hid_device *hdev,
struct hid_report *report, int reqtype); struct hid_report *report, int reqtype);
int (*wait)(struct hid_device *hdev); int (*wait)(struct hid_device *hdev);
int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype);
int (*raw_request) (struct hid_device *hdev, unsigned char reportnum,
__u8 *buf, size_t len, unsigned char rtype,
int reqtype);
int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len);
int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype);
}; };
#define PM_HINT_FULLON 1<<5 #define PM_HINT_FULLON 1<<5
...@@ -752,6 +755,7 @@ struct hid_field *hidinput_get_led_field(struct hid_device *hid); ...@@ -752,6 +755,7 @@ struct hid_field *hidinput_get_led_field(struct hid_device *hid);
unsigned int hidinput_count_leds(struct hid_device *hid); unsigned int hidinput_count_leds(struct hid_device *hid);
__s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code); __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code);
void hid_output_report(struct hid_report *report, __u8 *data); void hid_output_report(struct hid_report *report, __u8 *data);
void __hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype);
u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags); u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags);
struct hid_device *hid_allocate_device(void); struct hid_device *hid_allocate_device(void);
struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id); struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
...@@ -964,7 +968,55 @@ static inline void hid_hw_request(struct hid_device *hdev, ...@@ -964,7 +968,55 @@ static inline void hid_hw_request(struct hid_device *hdev,
struct hid_report *report, int reqtype) struct hid_report *report, int reqtype)
{ {
if (hdev->ll_driver->request) if (hdev->ll_driver->request)
hdev->ll_driver->request(hdev, report, reqtype); return hdev->ll_driver->request(hdev, report, reqtype);
__hid_request(hdev, report, reqtype);
}
/**
* hid_hw_raw_request - send report request to device
*
* @hdev: hid device
* @reportnum: report ID
* @buf: in/out data to transfer
* @len: length of buf
* @rtype: HID report type
* @reqtype: HID_REQ_GET_REPORT or HID_REQ_SET_REPORT
*
* @return: count of data transfered, negative if error
*
* Same behavior as hid_hw_request, but with raw buffers instead.
*/
static inline int hid_hw_raw_request(struct hid_device *hdev,
unsigned char reportnum, __u8 *buf,
size_t len, unsigned char rtype, int reqtype)
{
if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf)
return -EINVAL;
return hdev->ll_driver->raw_request(hdev, reportnum, buf, len,
rtype, reqtype);
}
/**
* hid_hw_output_report - send output report to device
*
* @hdev: hid device
* @buf: raw data to transfer
* @len: length of buf
*
* @return: count of data transfered, negative if error
*/
static inline int hid_hw_output_report(struct hid_device *hdev, __u8 *buf,
size_t len)
{
if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf)
return -EINVAL;
if (hdev->ll_driver->output_report)
return hdev->ll_driver->output_report(hdev, buf, len);
return -ENOSYS;
} }
/** /**
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/hid.h>
enum uhid_event_type { enum uhid_event_type {
UHID_CREATE, UHID_CREATE,
...@@ -34,6 +35,8 @@ enum uhid_event_type { ...@@ -34,6 +35,8 @@ enum uhid_event_type {
UHID_INPUT, UHID_INPUT,
UHID_FEATURE, UHID_FEATURE,
UHID_FEATURE_ANSWER, UHID_FEATURE_ANSWER,
UHID_CREATE2,
UHID_INPUT2,
}; };
struct uhid_create_req { struct uhid_create_req {
...@@ -50,6 +53,19 @@ struct uhid_create_req { ...@@ -50,6 +53,19 @@ struct uhid_create_req {
__u32 country; __u32 country;
} __attribute__((__packed__)); } __attribute__((__packed__));
struct uhid_create2_req {
__u8 name[128];
__u8 phys[64];
__u8 uniq[64];
__u16 rd_size;
__u16 bus;
__u32 vendor;
__u32 product;
__u32 version;
__u32 country;
__u8 rd_data[HID_MAX_DESCRIPTOR_SIZE];
} __attribute__((__packed__));
#define UHID_DATA_MAX 4096 #define UHID_DATA_MAX 4096
enum uhid_report_type { enum uhid_report_type {
...@@ -63,6 +79,11 @@ struct uhid_input_req { ...@@ -63,6 +79,11 @@ struct uhid_input_req {
__u16 size; __u16 size;
} __attribute__((__packed__)); } __attribute__((__packed__));
struct uhid_input2_req {
__u16 size;
__u8 data[UHID_DATA_MAX];
} __attribute__((__packed__));
struct uhid_output_req { struct uhid_output_req {
__u8 data[UHID_DATA_MAX]; __u8 data[UHID_DATA_MAX];
__u16 size; __u16 size;
...@@ -100,6 +121,8 @@ struct uhid_event { ...@@ -100,6 +121,8 @@ struct uhid_event {
struct uhid_output_ev_req output_ev; struct uhid_output_ev_req output_ev;
struct uhid_feature_req feature; struct uhid_feature_req feature;
struct uhid_feature_answer_req feature_answer; struct uhid_feature_answer_req feature_answer;
struct uhid_create2_req create2;
struct uhid_input2_req input2;
} u; } u;
} __attribute__((__packed__)); } __attribute__((__packed__));
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment