Commit d6a611f5 authored by Jiri Kosina's avatar Jiri Kosina

Merge branch 'for-3.15/hid-core-ll-transport-cleanup' into for-3.15/hid-cp2112

parents 5a673fce 53182517
This diff is collapsed.
...@@ -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,44 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum, ...@@ -1314,6 +1319,44 @@ 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;
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 hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
int interrupt) int interrupt)
{ {
......
...@@ -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;
...@@ -1184,7 +1184,7 @@ static void hidinput_led_worker(struct work_struct *work) ...@@ -1184,7 +1184,7 @@ 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); hid_output_raw_report(hid, buf, len, HID_OUTPUT_REPORT);
kfree(buf); kfree(buf);
} }
...@@ -1263,9 +1263,7 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid) ...@@ -1263,9 +1263,7 @@ 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) if (hid->ll_driver->request || hid->hid_output_raw_report)
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;
......
...@@ -706,7 +706,8 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev) ...@@ -706,7 +706,8 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev)
if (!buf) if (!buf)
return -ENOMEM; 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) if (ret < 0)
hid_err(hdev, "can't set operational mode\n"); hid_err(hdev, "can't set operational mode\n");
...@@ -719,7 +720,8 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev) ...@@ -719,7 +720,8 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev)
static int sixaxis_set_operational_bt(struct hid_device *hdev) static int sixaxis_set_operational_bt(struct hid_device *hdev)
{ {
unsigned char buf[] = { 0xf4, 0x42, 0x03, 0x00, 0x00 }; 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) static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds)
...@@ -941,8 +943,7 @@ static void sixaxis_state_worker(struct work_struct *work) ...@@ -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[2] << 3;
buf[10] |= sc->led_state[3] << 4; buf[10] |= sc->led_state[3] << 4;
sc->hdev->hid_output_raw_report(sc->hdev, buf, sizeof(buf), hid_output_raw_report(sc->hdev, buf, sizeof(buf), HID_OUTPUT_REPORT);
HID_OUTPUT_REPORT);
} }
static void dualshock4_state_worker(struct work_struct *work) static void dualshock4_state_worker(struct work_struct *work)
......
...@@ -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;
......
...@@ -153,7 +153,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, ...@@ -153,7 +153,7 @@ 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); ret = hid_output_raw_report(dev, buf, count, report_type);
out_free: out_free:
kfree(buf); kfree(buf);
out: out:
...@@ -189,7 +189,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t ...@@ -189,7 +189,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 +216,15 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t ...@@ -216,14 +216,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;
......
...@@ -256,18 +256,27 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType, ...@@ -256,18 +256,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 +287,9 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType, ...@@ -278,6 +287,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 +299,10 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType, ...@@ -287,9 +299,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;
...@@ -550,7 +563,7 @@ static int i2c_hid_get_raw_report(struct hid_device *hid, ...@@ -550,7 +563,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 +577,9 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, ...@@ -564,9 +577,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 +587,40 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf, ...@@ -574,34 +587,40 @@ 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_raw_report(struct hid_device *hid, __u8 *buf,
int reqtype) size_t count, unsigned char report_type)
{ {
struct i2c_client *client = hid->driver_data; struct i2c_client *client = hid->driver_data;
char *buf; struct i2c_hid *ihid = i2c_get_clientdata(client);
int ret; bool data = true; /* SET_REPORT */
int len = i2c_hid_get_report_length(rep) - 2;
buf = kzalloc(len, GFP_KERNEL); if (report_type == HID_OUTPUT_REPORT)
if (!buf) data = le16_to_cpu(ihid->hdesc.wMaxOutputLength) == 0;
return;
return i2c_hid_output_raw_report(hid, buf, count, report_type, data);
}
static int i2c_hid_output_report(struct hid_device *hid, __u8 *buf,
size_t count)
{
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) { 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)
...@@ -760,7 +779,8 @@ static struct hid_ll_driver i2c_hid_ll_driver = { ...@@ -760,7 +779,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)
...@@ -1005,8 +1025,7 @@ static int i2c_hid_probe(struct i2c_client *client, ...@@ -1005,8 +1025,7 @@ 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->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;
......
...@@ -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,7 +400,6 @@ static int uhid_dev_create(struct uhid_device *uhid, ...@@ -377,7 +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->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;
......
...@@ -884,58 +884,78 @@ static int usbhid_get_raw_report(struct hid_device *hid, ...@@ -884,58 +884,78 @@ 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) {
int actual_length;
int skipped_report_id = 0;
/* Byte 0 is the report number. Report data starts at byte 1.*/
buf[0] = reportnum;
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_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++;
} }
return ret; return ret;
} }
static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf,
size_t count, unsigned char report_type)
{
struct usbhid_device *usbhid = hid->driver_data;
if (usbhid->urbout && report_type != HID_FEATURE_REPORT)
return usbhid_output_report(hid, buf, count);
return usbhid_set_raw_report(hid, buf[0], buf, count, report_type);
}
static void usbhid_restart_queues(struct usbhid_device *usbhid) static void usbhid_restart_queues(struct usbhid_device *usbhid)
{ {
if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl)) if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl))
...@@ -1200,6 +1220,20 @@ static void usbhid_request(struct hid_device *hid, struct hid_report *rep, int r ...@@ -1200,6 +1220,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 +1257,8 @@ static struct hid_ll_driver usb_hid_driver = { ...@@ -1223,6 +1257,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,7 +1289,6 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id * ...@@ -1253,7 +1289,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->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
......
...@@ -508,9 +508,6 @@ struct hid_device { /* device report descriptor */ ...@@ -508,9 +508,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 */ /* handler for raw output data, used by hidraw */
int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t, unsigned char); int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t, unsigned char);
...@@ -675,11 +672,12 @@ struct hid_driver { ...@@ -675,11 +672,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 +689,20 @@ struct hid_ll_driver { ...@@ -691,17 +689,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 +753,7 @@ struct hid_field *hidinput_get_led_field(struct hid_device *hid); ...@@ -752,6 +753,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 +966,74 @@ static inline void hid_hw_request(struct hid_device *hdev, ...@@ -964,7 +966,74 @@ 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;
if (hdev->ll_driver->raw_request)
return hdev->ll_driver->raw_request(hdev, reportnum, buf, len,
rtype, reqtype);
return -ENOSYS;
}
/**
* 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;
}
/**
* hid_output_raw_report - send an output or a feature report to the device
*
* @hdev: hid device
* @buf: raw data to transfer
* @len: length of buf
* @report_type: HID_FEATURE_REPORT or HID_OUTPUT_REPORT
*
* @return: count of data transfered, negative if error
*/
static inline int hid_output_raw_report(struct hid_device *hdev, __u8 *buf,
size_t len, unsigned char report_type)
{
return hdev->hid_output_raw_report(hdev, buf, len, report_type);
} }
/** /**
......
...@@ -223,51 +223,6 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb) ...@@ -223,51 +223,6 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
input_sync(dev); input_sync(dev);
} }
static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
{
unsigned char hdr;
u8 *buf;
int rsize, ret;
buf = hid_alloc_report_buf(report, GFP_ATOMIC);
if (!buf)
return -EIO;
hid_output_report(report, buf);
hdr = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
ret = hidp_send_intr_message(session, hdr, buf, rsize);
kfree(buf);
return ret;
}
static int hidp_hidinput_event(struct input_dev *dev, unsigned int type,
unsigned int code, int value)
{
struct hid_device *hid = input_get_drvdata(dev);
struct hidp_session *session = hid->driver_data;
struct hid_field *field;
int offset;
BT_DBG("session %p type %d code %d value %d",
session, type, code, value);
if (type != EV_LED)
return -1;
offset = hidinput_find_field(hid, type, code, &field);
if (offset == -1) {
hid_warn(dev, "event field not found\n");
return -1;
}
hid_set_field(field, offset, value);
return hidp_send_report(session, field->report);
}
static int hidp_get_raw_report(struct hid_device *hid, static int hidp_get_raw_report(struct hid_device *hid,
unsigned char report_number, unsigned char report_number,
unsigned char *data, size_t count, unsigned char *data, size_t count,
...@@ -353,17 +308,24 @@ static int hidp_get_raw_report(struct hid_device *hid, ...@@ -353,17 +308,24 @@ static int hidp_get_raw_report(struct hid_device *hid,
return ret; return ret;
} }
static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count, static int hidp_set_raw_report(struct hid_device *hid, unsigned char reportnum,
unsigned char *data, size_t count,
unsigned char report_type) unsigned char report_type)
{ {
struct hidp_session *session = hid->driver_data; struct hidp_session *session = hid->driver_data;
int ret; int ret;
if (report_type == HID_OUTPUT_REPORT) { switch (report_type) {
report_type = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT; case HID_FEATURE_REPORT:
return hidp_send_intr_message(session, report_type, report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
data, count); break;
} else if (report_type != HID_FEATURE_REPORT) { case HID_INPUT_REPORT:
report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_INPUT;
break;
case HID_OUTPUT_REPORT:
report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUPUT;
break;
default:
return -EINVAL; return -EINVAL;
} }
...@@ -371,8 +333,8 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s ...@@ -371,8 +333,8 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s
return -ERESTARTSYS; return -ERESTARTSYS;
/* Set up our wait, and send the report request to the device. */ /* Set up our wait, and send the report request to the device. */
data[0] = reportnum;
set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags); set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
ret = hidp_send_ctrl_message(session, report_type, data, count); ret = hidp_send_ctrl_message(session, report_type, data, count);
if (ret) if (ret)
goto err; goto err;
...@@ -411,6 +373,41 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s ...@@ -411,6 +373,41 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s
return ret; return ret;
} }
static int hidp_output_report(struct hid_device *hid, __u8 *data, size_t count)
{
struct hidp_session *session = hid->driver_data;
return hidp_send_intr_message(session,
HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT,
data, count);
}
static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data,
size_t count, unsigned char report_type)
{
if (report_type == HID_OUTPUT_REPORT) {
return hidp_output_report(hid, data, count);
} else if (report_type != HID_FEATURE_REPORT) {
return -EINVAL;
}
return hidp_set_raw_report(hid, data[0], data, count, report_type);
}
static int hidp_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 hidp_get_raw_report(hid, reportnum, buf, len, rtype);
case HID_REQ_SET_REPORT:
return hidp_set_raw_report(hid, reportnum, buf, len, rtype);
default:
return -EIO;
}
}
static void hidp_idle_timeout(unsigned long arg) static void hidp_idle_timeout(unsigned long arg)
{ {
struct hidp_session *session = (struct hidp_session *) arg; struct hidp_session *session = (struct hidp_session *) arg;
...@@ -727,7 +724,8 @@ static struct hid_ll_driver hidp_hid_driver = { ...@@ -727,7 +724,8 @@ static struct hid_ll_driver hidp_hid_driver = {
.stop = hidp_stop, .stop = hidp_stop,
.open = hidp_open, .open = hidp_open,
.close = hidp_close, .close = hidp_close,
.hidinput_input_event = hidp_hidinput_event, .raw_request = hidp_raw_request,
.output_report = hidp_output_report,
}; };
/* This function sets up the hid device. It does not add it /* This function sets up the hid device. It does not add it
...@@ -775,7 +773,6 @@ static int hidp_setup_hid(struct hidp_session *session, ...@@ -775,7 +773,6 @@ static int hidp_setup_hid(struct hidp_session *session,
hid->dev.parent = &session->conn->hcon->dev; hid->dev.parent = &session->conn->hcon->dev;
hid->ll_driver = &hidp_hid_driver; hid->ll_driver = &hidp_hid_driver;
hid->hid_get_raw_report = hidp_get_raw_report;
hid->hid_output_raw_report = hidp_output_raw_report; hid->hid_output_raw_report = hidp_output_raw_report;
/* True if device is blacklisted in drivers/hid/hid-core.c */ /* True if device is blacklisted in drivers/hid/hid-core.c */
......
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