Skip to content

Commit

Permalink
Merge branch 'for-3.15/hid-core-ll-transport-cleanup' into for-3.15/h…
Browse files Browse the repository at this point in the history
…id-cp2112
  • Loading branch information
Jiri Kosina committed Feb 17, 2014
2 parents 5a673fc + 5318251 commit d6a611f
Show file tree
Hide file tree
Showing 16 changed files with 714 additions and 240 deletions.
316 changes: 316 additions & 0 deletions Documentation/hid/hid-transport.txt

Large diffs are not rendered by default.

45 changes: 44 additions & 1 deletion drivers/hid/hid-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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()
*/
Expand All @@ -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);
}
Expand Down Expand Up @@ -1314,6 +1319,44 @@ 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;

if (!hid->ll_driver->raw_request)
return;

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)
{
Expand Down
12 changes: 5 additions & 7 deletions drivers/hid/hid-input.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1184,7 +1184,7 @@ 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);
hid_output_raw_report(hid, buf, len, HID_OUTPUT_REPORT);
kfree(buf);
}

Expand Down Expand Up @@ -1263,9 +1263,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)
if (hid->ll_driver->request || hid->hid_output_raw_report)
input_dev->event = hidinput_input_event;
input_dev->open = hidinput_open;
input_dev->close = hidinput_close;
Expand Down
6 changes: 4 additions & 2 deletions drivers/hid/hid-lg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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);
}
}

Expand Down
111 changes: 40 additions & 71 deletions drivers/hid/hid-logitech-dj.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) */
Expand All @@ -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
};

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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__);
Expand All @@ -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,
};


Expand Down
4 changes: 2 additions & 2 deletions drivers/hid/hid-magicmouse.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 5 additions & 4 deletions drivers/hid/hid-sony.c
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,8 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev)
if (!buf)
return -ENOMEM;

ret = hdev->hid_get_raw_report(hdev, 0xf2, buf, 17, HID_FEATURE_REPORT);
ret = hid_hw_raw_request(hdev, 0xf2, buf, 17, HID_FEATURE_REPORT,
HID_REQ_GET_REPORT);

if (ret < 0)
hid_err(hdev, "can't set operational mode\n");
Expand All @@ -719,7 +720,8 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev)
static int sixaxis_set_operational_bt(struct hid_device *hdev)
{
unsigned char buf[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 };
return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
return hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
}

static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds)
Expand Down Expand Up @@ -941,8 +943,7 @@ static void sixaxis_state_worker(struct work_struct *work)
buf[10] |= sc->led_state[2] << 3;
buf[10] |= sc->led_state[3] << 4;

sc->hdev->hid_output_raw_report(sc->hdev, buf, sizeof(buf),
HID_OUTPUT_REPORT);
hid_output_raw_report(sc->hdev, buf, sizeof(buf), HID_OUTPUT_REPORT);
}

static void dualshock4_state_worker(struct work_struct *work)
Expand Down
4 changes: 2 additions & 2 deletions drivers/hid/hid-thingm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Loading

0 comments on commit d6a611f

Please sign in to comment.