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.
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.
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:
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
......@@ -105,6 +110,12 @@ the request was handled successfully.
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.
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:
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
......
......@@ -175,6 +175,15 @@ config HID_PRODIKEYS
multimedia keyboard, but will lack support for the musical keyboard
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
tristate "Cypress mouse and barcode readers" if EXPERT
depends on HID
......@@ -608,25 +617,27 @@ config HID_SAMSUNG
Support for Samsung InfraRed remote control or keyboards.
config HID_SONY
tristate "Sony PS2/3 accessories"
tristate "Sony PS2/3/4 accessories"
depends on USB_HID
depends on NEW_LEDS
depends on LEDS_CLASS
select POWER_SUPPLY
---help---
Support for
* Sony PS3 6-axis controllers
* Sony PS4 DualShock 4 controllers
* Buzz controllers
* Sony PS3 Blue-ray Disk Remote Control (Bluetooth)
* Logitech Harmony adapter for Sony Playstation 3 (Bluetooth)
config SONY_FF
bool "Sony PS2/3 accessories force feedback support"
bool "Sony PS2/3/4 accessories force feedback support"
depends on HID_SONY
select INPUT_FF_MEMLESS
---help---
Say Y here if you have a Sony PS2/3 accessory and want to enable force
feedback support for it.
Say Y here if you have a Sony PS2/3/4 accessory and want to enable
force feedback support for it.
config HID_SPEEDLINK
tristate "Speedlink VAD Cezanne mouse support"
......
......@@ -41,6 +41,7 @@ obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.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_DRAGONRISE) += hid-dr.o
obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o
......
......@@ -1248,6 +1248,11 @@ void hid_output_report(struct hid_report *report, __u8 *data)
}
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()
*/
......@@ -1258,7 +1263,7 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
* 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);
}
......@@ -1314,6 +1319,41 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
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 interrupt)
{
......@@ -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_AK1D) },
{ 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_2) },
{ 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[] = {
{ 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_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_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
{ 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)
if (hid_ignore(hdev))
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
* for the driver-specific modifications.
......
This diff is collapsed.
......@@ -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 = {
.parse = mousevsc_hid_parse,
.open = mousevsc_hid_open,
.close = mousevsc_hid_close,
.start = mousevsc_hid_start,
.stop = mousevsc_hid_stop,
.raw_request = mousevsc_hid_raw_request,
};
static struct hid_driver mousevsc_hid_driver;
......
......@@ -67,6 +67,9 @@
#define USB_VENDOR_ID_ALPS 0x0433
#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_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d
......@@ -242,6 +245,7 @@
#define USB_VENDOR_ID_CYGNAL 0x10c4
#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a
#define USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH 0x81b9
#define USB_DEVICE_ID_CYGNAL_CP2112 0xea90
#define USB_DEVICE_ID_CYGNAL_RADIO_SI4713 0x8244
......@@ -616,6 +620,7 @@
#define USB_VENDOR_ID_MICROSOFT 0x045e
#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_MS_NE4K 0x00db
#define USB_DEVICE_ID_MS_NE4K_JP 0x00dc
......
......@@ -350,9 +350,9 @@ static int hidinput_get_battery_property(struct power_supply *psy,
ret = -ENOMEM;
break;
}
ret = dev->hid_get_raw_report(dev, dev->battery_report_id,
buf, 2,
dev->battery_report_type);
ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 2,
dev->battery_report_type,
HID_REQ_GET_REPORT);
if (ret != 2) {
ret = -ENODATA;
......@@ -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 0x19c: map_key_clear(KEY_LOGOFF); 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 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
case 0x1ab: map_key_clear(KEY_SPELLCHECK); 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 0x1b7: map_key_clear(KEY_AUDIO); break;
case 0x1b8: map_key_clear(KEY_VIDEO); break;
......@@ -1150,7 +1153,7 @@ static void hidinput_led_worker(struct work_struct *work)
led_work);
struct hid_field *field;
struct hid_report *report;
int len;
int len, ret;
__u8 *buf;
field = hidinput_get_led_field(hid);
......@@ -1184,7 +1187,10 @@ static void hidinput_led_worker(struct work_struct *work)
hid_output_report(report, buf);
/* 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);
}
......@@ -1263,10 +1269,7 @@ static struct hid_input *hidinput_allocate(struct hid_device *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->close = hidinput_close;
input_dev->setkeycode = hidinput_setkeycode;
......
......@@ -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) {
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) {
/* 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)
buf[1] = 0xB2;
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[] = {
0x19, 0xE0, /* USAGE_MINIMUM (Left Control) */
0x29, 0xE7, /* USAGE_MAXIMUM (Right GUI) */
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) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
......@@ -60,6 +52,18 @@ static const char kbd_descriptor[] = {
0x19, 0x00, /* USAGE_MINIMUM (no event) */
0x2A, 0xFF, 0x00, /* USAGE_MAXIMUM (reserved) */
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
};
......@@ -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 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 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,
}
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->bus = BUS_USB;
......@@ -540,14 +540,35 @@ static void logi_dj_ll_close(struct hid_device *hid)
dbg_hid("%s:%s\n", __func__, hid->phys);
}
static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
size_t count,
unsigned char report_type)
static int logi_dj_ll_raw_request(struct hid_device *hid,
unsigned char reportnum, __u8 *buf,
size_t count, unsigned char report_type,
int reqtype)
{
/* Called by hid raw to send data */
dbg_hid("%s\n", __func__);
struct dj_device *djdev = hid->driver_data;
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)
......@@ -613,58 +634,6 @@ static int logi_dj_ll_parse(struct hid_device *hid)
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)
{
dbg_hid("%s\n", __func__);
......@@ -683,7 +652,7 @@ static struct hid_ll_driver logi_dj_ll_driver = {
.stop = logi_dj_ll_stop,
.open = logi_dj_ll_open,
.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,
* but there seems to be no other way of switching the mode.
* Thus the super-ugly hacky success check below.
*/
ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature),
HID_FEATURE_REPORT);
ret = hid_hw_raw_request(hdev, feature[0], feature, sizeof(feature),
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret != -EIO && ret != sizeof(feature)) {
hid_err(hdev, "unable to request touch data (%d)\n", ret);
goto err_stop_hw;
......
......@@ -62,9 +62,48 @@ static int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage,
{
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) {
case 0xfd06: ms_map_key_clear(KEY_CHAT); 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:
set_bit(EV_REP, input->evbit);
ms_map_key_clear(KEY_F13);
......@@ -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,
unsigned long **bit, int *max)
{
if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
return 0;
set_bit(EV_REP, hi->input->evbit);
switch (usage->hid & HID_USAGE) {
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,
{
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
return 0;
if (quirks & MS_ERGONOMY) {
int ret = ms_ergonomy_kb_quirk(hi, usage, bit, max);
if (ret)
......@@ -134,14 +173,39 @@ static int ms_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
struct input_dev *input;
if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
!usage->type)
return 0;
input = field->hidinput->input;
/* 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)) {
struct input_dev *input = field->hidinput->input;
static unsigned int last_key = 0;
unsigned int key = 0;
switch (value) {
......@@ -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[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV),
.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),
.driver_data = MS_ERGONOMY },
{ 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,
buf[0], buf[1], buf[2], buf[3], buf[4],
buf[5], buf[6], buf[7], buf[8]);
ret = data->hdev->hid_output_raw_report(data->hdev, buf,
BLINK1_CMD_SIZE, HID_FEATURE_REPORT);
ret = hid_hw_raw_request(data->hdev, buf[0], buf, BLINK1_CMD_SIZE,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
return ret < 0 ? ret : 0;
}
......
......@@ -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[1] = 0;
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
HID_FEATURE_REPORT);
ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret < 0)
goto err;
......@@ -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[2] = i;
ret = hdev->hid_output_raw_report(hdev, rep_data, 67,
HID_FEATURE_REPORT);
ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 67,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
}
rep_data[0] = WAC_CMD_ICON_START_STOP;
rep_data[1] = 0;
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
HID_FEATURE_REPORT);
ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
err:
return;
......@@ -183,7 +183,8 @@ static void wacom_leds_set_brightness(struct led_classdev *led_dev,
buf[3] = value;
/* use fixed brightness for OLEDs */
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);
}
......@@ -339,8 +340,8 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
rep_data[0] = 0x03 ; rep_data[1] = 0x00;
limit = 3;
do {
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
HID_FEATURE_REPORT);
ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
} while (ret < 0 && limit-- > 0);
if (ret >= 0) {
......@@ -352,8 +353,9 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
rep_data[1] = 0x00;
limit = 3;
do {
ret = hdev->hid_output_raw_report(hdev,
rep_data, 2, HID_FEATURE_REPORT);
ret = hid_hw_raw_request(hdev, rep_data[0],
rep_data, 2, HID_FEATURE_REPORT,
HID_REQ_SET_REPORT);
} while (ret < 0 && limit-- > 0);
if (ret >= 0) {
......@@ -378,8 +380,8 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
rep_data[0] = 0x03;
rep_data[1] = wdata->features;
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
HID_FEATURE_REPORT);
ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret >= 0)
wdata->high_speed = speed;
break;
......
......@@ -28,14 +28,14 @@ static int wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
__u8 *buf;
int ret;
if (!hdev->hid_output_raw_report)
if (!hdev->ll_driver->output_report)
return -ENODEV;
buf = kmemdup(buffer, count, GFP_KERNEL);
if (!buf)
return -ENOMEM;
ret = hdev->hid_output_raw_report(hdev, buf, count, HID_OUTPUT_REPORT);
ret = hid_hw_output_report(hdev, buf, count);
kfree(buf);
return ret;
......
......@@ -123,10 +123,6 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
dev = hidraw_table[minor]->hid;
if (!dev->hid_output_raw_report) {
ret = -ENODEV;
goto out;
}
if (count > HID_MAX_BUFFER_SIZE) {
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,
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:
kfree(buf);
out:
......@@ -189,7 +199,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
dev = hidraw_table[minor]->hid;
if (!dev->hid_get_raw_report) {
if (!dev->ll_driver->raw_request) {
ret = -ENODEV;
goto out;
}
......@@ -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,
* 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)) {
ret = -EFAULT;
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)
goto out_free;
......
......@@ -25,6 +25,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/err.h>
......@@ -256,18 +257,27 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType,
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);
u8 *args = ihid->argsbuf;
const struct i2c_hid_cmd * hidcmd = &hid_set_report_cmd;
const struct i2c_hid_cmd *hidcmd;
int ret;
u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister);
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 */ +
(reportID ? 1 : 0) /* reportID */ +
data_len /* buf */;
......@@ -278,6 +288,9 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
i2c_hid_dbg(ihid, "%s\n", __func__);
if (!use_data && maxOutputLength == 0)
return -ENOSYS;
if (reportID >= 0x0F) {
args[index++] = reportID;
reportID = 0x0F;
......@@ -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
* support the output register
*/
if (reportType == 0x03 || maxOutputLength == 0) {
if (use_data) {
args[index++] = dataRegister & 0xFF;
args[index++] = dataRegister >> 8;
hidcmd = &hid_set_report_cmd;
} else {
args[index++] = outputRegister & 0xFF;
args[index++] = outputRegister >> 8;
......@@ -454,10 +468,18 @@ static void i2c_hid_init_reports(struct hid_device *hid)
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,
&hid->report_enum[HID_FEATURE_REPORT].report_list, list)
i2c_hid_init_report(report, inbuf, ihid->bufsize);
pm_runtime_put(&client->dev);
kfree(inbuf);
}
......@@ -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,
size_t count, unsigned char report_type)
size_t count, unsigned char report_type, bool use_data)
{
struct i2c_client *client = hid->driver_data;
int report_id = buf[0];
......@@ -564,9 +586,9 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
count--;
}
ret = i2c_hid_set_report(client,
ret = i2c_hid_set_or_send_report(client,
report_type == HID_FEATURE_REPORT ? 0x03 : 0x02,
report_id, buf, count);
report_id, buf, count, use_data);
if (report_id && ret >= 0)
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,
return ret;
}
static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep,
int reqtype)
static int i2c_hid_output_report(struct hid_device *hid, __u8 *buf,
size_t count)
{
struct i2c_client *client = hid->driver_data;
char *buf;
int ret;
int len = i2c_hid_get_report_length(rep) - 2;
buf = hid_alloc_report_buf(rep, GFP_KERNEL);
if (!buf)
return;
return i2c_hid_output_raw_report(hid, buf, count, HID_OUTPUT_REPORT,
false);
}
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) {
case HID_REQ_GET_REPORT:
ret = i2c_hid_get_raw_report(hid, rep->id, buf, len, rep->type);
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;
return i2c_hid_get_raw_report(hid, reportnum, buf, len, rtype);
case HID_REQ_SET_REPORT:
hid_output_report(rep, buf);
i2c_hid_output_raw_report(hid, buf, len, rep->type);
break;
if (buf[0] != reportnum)
return -EINVAL;
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)
......@@ -703,8 +718,8 @@ static int i2c_hid_open(struct hid_device *hid)
mutex_lock(&i2c_hid_open_mut);
if (!hid->open++) {
ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
if (ret) {
ret = pm_runtime_get_sync(&client->dev);
if (ret < 0) {
hid->open--;
goto done;
}
......@@ -712,7 +727,7 @@ static int i2c_hid_open(struct hid_device *hid)
}
done:
mutex_unlock(&i2c_hid_open_mut);
return ret;
return ret < 0 ? ret : 0;
}
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);
/* Save some power */
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
pm_runtime_put(&client->dev);
}
mutex_unlock(&i2c_hid_open_mut);
}
......@@ -738,19 +753,18 @@ static int i2c_hid_power(struct hid_device *hid, int lvl)
{
struct i2c_client *client = hid->driver_data;
struct i2c_hid *ihid = i2c_get_clientdata(client);
int ret = 0;
i2c_hid_dbg(ihid, "%s lvl:%d\n", __func__, lvl);
switch (lvl) {
case PM_HINT_FULLON:
ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
pm_runtime_get_sync(&client->dev);
break;
case PM_HINT_NORMAL:
ret = i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
pm_runtime_put(&client->dev);
break;
}
return ret;
return 0;
}
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,
.close = i2c_hid_close,
.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)
......@@ -973,13 +988,17 @@ static int i2c_hid_probe(struct i2c_client *client,
if (ret < 0)
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);
if (ret < 0)
goto err;
goto err_pm;
ret = i2c_hid_init_irq(client);
if (ret < 0)
goto err;
goto err_pm;
hid = hid_allocate_device();
if (IS_ERR(hid)) {
......@@ -991,8 +1010,6 @@ static int i2c_hid_probe(struct i2c_client *client,
hid->driver_data = client;
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;
ACPI_COMPANION_SET(&hid->dev, ACPI_COMPANION(&client->dev));
hid->bus = BUS_I2C;
......@@ -1010,6 +1027,7 @@ static int i2c_hid_probe(struct i2c_client *client,
goto err_mem_free;
}
pm_runtime_put(&client->dev);
return 0;
err_mem_free:
......@@ -1018,6 +1036,10 @@ static int i2c_hid_probe(struct i2c_client *client,
err_irq:
free_irq(client->irq, ihid);
err_pm:
pm_runtime_put_noidle(&client->dev);
pm_runtime_disable(&client->dev);
err:
i2c_hid_free_buffers(ihid);
kfree(ihid);
......@@ -1029,6 +1051,11 @@ static int i2c_hid_remove(struct i2c_client *client)
struct i2c_hid *ihid = i2c_get_clientdata(client);
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_destroy_device(hid);
......@@ -1074,7 +1101,31 @@ static int i2c_hid_resume(struct device *dev)
}
#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[] = {
{ "hid", 0 },
......
......@@ -244,12 +244,35 @@ static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t 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 = {
.start = uhid_hid_start,
.stop = uhid_hid_stop,
.open = uhid_hid_open,
.close = uhid_hid_close,
.parse = uhid_hid_parse,
.output_report = uhid_hid_output_report,
.raw_request = uhid_raw_request,
};
#ifdef CONFIG_COMPAT
......@@ -377,8 +400,6 @@ static int uhid_dev_create(struct uhid_device *uhid,
hid->uniq[63] = 0;
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->vendor = ev->u.create.vendor;
hid->product = ev->u.create.product;
......@@ -407,6 +428,67 @@ static int uhid_dev_create(struct uhid_device *uhid,
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)
{
if (!uhid->running)
......@@ -435,6 +517,17 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
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,
struct uhid_event *ev)
{
......@@ -571,12 +664,18 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
case UHID_CREATE:
ret = uhid_dev_create(uhid, &uhid->input_buf);
break;
case UHID_CREATE2:
ret = uhid_dev_create2(uhid, &uhid->input_buf);
break;
case UHID_DESTROY:
ret = uhid_dev_destroy(uhid);
break;
case UHID_INPUT:
ret = uhid_dev_input(uhid, &uhid->input_buf);
break;
case UHID_INPUT2:
ret = uhid_dev_input2(uhid, &uhid->input_buf);
break;
case UHID_FEATURE_ANSWER:
ret = uhid_dev_feature_answer(uhid, &uhid->input_buf);
break;
......
......@@ -884,52 +884,66 @@ static int usbhid_get_raw_report(struct hid_device *hid,
return ret;
}
static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count,
unsigned char report_type)
static int usbhid_set_raw_report(struct hid_device *hid, unsigned int reportnum,
__u8 *buf, size_t count, unsigned char rtype)
{
struct usbhid_device *usbhid = hid->driver_data;
struct usb_device *dev = hid_to_usb_dev(hid);
struct usb_interface *intf = usbhid->intf;
struct usb_host_interface *interface = intf->cur_altsetting;
int ret;
int ret, skipped_report_id = 0;
if (usbhid->urbout && report_type != HID_FEATURE_REPORT) {
int actual_length;
int skipped_report_id = 0;
/* Byte 0 is the report number. Report data starts at byte 1.*/
if ((rtype == HID_OUTPUT_REPORT) &&
(hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORT_ID))
buf[0] = 0;
else
buf[0] = reportnum;
if (buf[0] == 0x0) {
/* Don't send the Report ID */
buf++;
count--;
skipped_report_id = 1;
}
if (buf[0] == 0x0) {
/* Don't send the Report ID */
buf++;
count--;
skipped_report_id = 1;
}
ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
buf, count, &actual_length,
USB_CTRL_SET_TIMEOUT);
/* return the number of bytes transferred */
if (ret == 0) {
ret = actual_length;
/* count also the report id */
if (skipped_report_id)
ret++;
}
} else {
int skipped_report_id = 0;
int report_id = buf[0];
if (buf[0] == 0x0) {
/* Don't send the Report ID */
buf++;
count--;
skipped_report_id = 1;
}
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
HID_REQ_SET_REPORT,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
((report_type + 1) << 8) | report_id,
((rtype + 1) << 8) | reportnum,
interface->desc.bInterfaceNumber, buf, count,
USB_CTRL_SET_TIMEOUT);
/* count also the report id, if this was a numbered report. */
if (ret > 0 && skipped_report_id)
/* count also the report id, if this was a numbered report. */
if (ret > 0 && skipped_report_id)
ret++;
return ret;
}
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) {
/* Don't send the Report ID */
buf++;
count--;
skipped_report_id = 1;
}
ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
buf, count, &actual_length,
USB_CTRL_SET_TIMEOUT);
/* return the number of bytes transferred */
if (ret == 0) {
ret = actual_length;
/* count also the report id */
if (skipped_report_id)
ret++;
}
......@@ -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,
int reqtype)
{
......@@ -1223,6 +1251,8 @@ static struct hid_ll_driver usb_hid_driver = {
.power = usbhid_power,
.request = usbhid_request,
.wait = usbhid_wait_io,
.raw_request = usbhid_raw_request,
.output_report = usbhid_output_report,
.idle = usbhid_idle,
};
......@@ -1253,8 +1283,6 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
usb_set_intfdata(intf, hid);
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;
#ifdef CONFIG_USB_HIDDEV
hid->hiddev_connect = hiddev_connect;
......
......@@ -38,29 +38,40 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
if (state) {
if (sensor_hub_device_open(st->hsdev))
return -EIO;
state_val =
HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM;
report_val =
HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM;
state_val = hid_sensor_get_usage_index(st->hsdev,
st->power_state.report_id,
st->power_state.index,
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 {
sensor_hub_device_close(st->hsdev);
state_val =
HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM;
report_val =
HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM;
state_val = hid_sensor_get_usage_index(st->hsdev,
st->power_state.report_id,
st->power_state.index,
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;
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,
if (state_val >= 0) {
state_val += st->power_state.logical_minimum;
sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
st->power_state.index,
(s32)state_val);
}
sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
if (report_val >= 0) {
report_val += st->report_state.logical_minimum;
sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
st->report_state.index,
(s32)report_val);
}
return 0;
}
......
......@@ -51,13 +51,15 @@ struct hid_sensor_hub_attribute_info {
* @hdev: Stores the hid instance.
* @vendor_id: Vendor 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_device *hdev;
u32 vendor_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,
int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
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
......@@ -140,15 +140,15 @@
#define HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS 0x1000
/* Power state enumerations */
#define HID_USAGE_SENSOR_PROP_POWER_STATE_UNDEFINED_ENUM 0x00
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM 0x01
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D1_LOW_POWER_ENUM 0x02
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D2_STANDBY_WITH_WAKE_ENUM 0x03
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D3_SLEEP_WITH_WAKE_ENUM 0x04
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM 0x05
#define HID_USAGE_SENSOR_PROP_POWER_STATE_UNDEFINED_ENUM 0x200850
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM 0x200851
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D1_LOW_POWER_ENUM 0x200852
#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 0x200854
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM 0x200855
/* Report State enumerations */
#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM 0x00
#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x01
#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM 0x200840
#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x200841
#endif
......@@ -201,6 +201,7 @@ struct hid_item {
#define HID_GD_VBRZ 0x00010045
#define HID_GD_VNO 0x00010046
#define HID_GD_FEATURE 0x00010047
#define HID_GD_SYSTEM_CONTROL 0x00010080
#define HID_GD_UP 0x00010090
#define HID_GD_DOWN 0x00010091
#define HID_GD_RIGHT 0x00010092
......@@ -208,6 +209,8 @@ struct hid_item {
#define HID_DC_BATTERYSTRENGTH 0x00060020
#define HID_CP_CONSUMER_CONTROL 0x000c0001
#define HID_DG_DIGITIZER 0x000d0001
#define HID_DG_PEN 0x000d0002
#define HID_DG_LIGHTPEN 0x000d0003
......@@ -287,6 +290,8 @@ struct hid_item {
#define HID_QUIRK_NO_EMPTY_INPUT 0x00000100
#define HID_QUIRK_NO_INIT_INPUT_REPORTS 0x00000200
#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_NO_INIT_REPORTS 0x20000000
#define HID_QUIRK_NO_IGNORE 0x40000000
......@@ -508,12 +513,6 @@ struct hid_device { /* device report descriptor */
struct hid_usage *, __s32);
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 */
unsigned short debug;
struct dentry *debug_dir;
......@@ -675,11 +674,12 @@ struct hid_driver {
* @stop: called on remove
* @open: called by input layer on open
* @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,
* shouldn't allocate anything to not leak memory
* @request: send report request to device (e.g. feature report)
* @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
*/
struct hid_ll_driver {
......@@ -691,17 +691,20 @@ struct hid_ll_driver {
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);
void (*request)(struct hid_device *hdev,
struct hid_report *report, int reqtype);
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
......@@ -752,6 +755,7 @@ struct hid_field *hidinput_get_led_field(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);
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);
struct hid_device *hid_allocate_device(void);
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,
struct hid_report *report, int reqtype)
{
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 @@
#include <linux/input.h>
#include <linux/types.h>
#include <linux/hid.h>
enum uhid_event_type {
UHID_CREATE,
......@@ -34,6 +35,8 @@ enum uhid_event_type {
UHID_INPUT,
UHID_FEATURE,
UHID_FEATURE_ANSWER,
UHID_CREATE2,
UHID_INPUT2,
};
struct uhid_create_req {
......@@ -50,6 +53,19 @@ struct uhid_create_req {
__u32 country;
} __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
enum uhid_report_type {
......@@ -63,6 +79,11 @@ struct uhid_input_req {
__u16 size;
} __attribute__((__packed__));
struct uhid_input2_req {
__u16 size;
__u8 data[UHID_DATA_MAX];
} __attribute__((__packed__));
struct uhid_output_req {
__u8 data[UHID_DATA_MAX];
__u16 size;
......@@ -100,6 +121,8 @@ struct uhid_event {
struct uhid_output_ev_req output_ev;
struct uhid_feature_req feature;
struct uhid_feature_answer_req feature_answer;
struct uhid_create2_req create2;
struct uhid_input2_req input2;
} u;
} __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