Merge branch 'for-3.15/hid-core-ll-transport-cleanup' into for-3.15/sony
This commit is contained in:
commit
b95dd3ca03
|
@ -283,7 +283,8 @@ The available HID callbacks are:
|
|||
int reqtype)
|
||||
Same as ->request() but provides the report as raw buffer. This request shall
|
||||
be synchronous. A transport driver must not use ->wait() to complete such
|
||||
requests.
|
||||
requests. This request is mandatory and hid core will reject the device if
|
||||
it is missing.
|
||||
|
||||
- int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len)
|
||||
Send raw output report via intr channel. Used by some HID device drivers
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
@ -1692,6 +1732,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) },
|
||||
|
@ -2428,6 +2469,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.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -455,12 +455,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;
|
||||
|
|
|
@ -240,6 +240,7 @@
|
|||
|
||||
#define USB_VENDOR_ID_CYGNAL 0x10c4
|
||||
#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a
|
||||
#define USB_DEVICE_ID_CYGNAL_CP2112 0xea90
|
||||
|
||||
#define USB_VENDOR_ID_CYPRESS 0x04b4
|
||||
#define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001
|
||||
|
|
|
@ -1150,7 +1150,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 +1184,10 @@ static void hidinput_led_worker(struct work_struct *work)
|
|||
|
||||
hid_output_report(report, buf);
|
||||
/* synchronous output report */
|
||||
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,8 +1266,7 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
|
|||
}
|
||||
|
||||
input_set_drvdata(input_dev, hid);
|
||||
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,8 +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 = 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 */
|
||||
|
@ -705,8 +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 = 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -193,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,
|
||||
|
@ -262,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;
|
||||
|
@ -544,9 +540,10 @@ 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)
|
||||
{
|
||||
struct dj_device *djdev = hid->driver_data;
|
||||
struct dj_receiver_dev *djrcv_dev = djdev->dj_receiver_dev;
|
||||
|
@ -567,15 +564,8 @@ static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
|
|||
out_buf[1] = djdev->device_index;
|
||||
memcpy(out_buf + 2, buf, count);
|
||||
|
||||
/*
|
||||
* hid-generic calls us with hid_output_raw_report(), but the LEDs
|
||||
* are set through a SET_REPORT command. It works for USB-HID devices
|
||||
* because usbhid either calls a SET_REPORT or directly send the output
|
||||
* report depending if the device presents an urbout.
|
||||
* Let be simple, send a SET_REPORT request.
|
||||
*/
|
||||
ret = hid_hw_raw_request(djrcv_dev->hdev, out_buf[0], out_buf,
|
||||
DJREPORT_SHORT_LENGTH, report_type, HID_REQ_SET_REPORT);
|
||||
DJREPORT_SHORT_LENGTH, report_type, reqtype);
|
||||
|
||||
kfree(out_buf);
|
||||
return ret;
|
||||
|
@ -662,6 +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,
|
||||
.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 = 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;
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include <linux/hid.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
@ -1006,45 +1005,6 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The Sony Sixaxis does not handle HID Output Reports on the Interrupt EP
|
||||
* like it should according to usbhid/hid-core.c::usbhid_output_raw_report()
|
||||
* so we need to override that forcing HID Output Reports on the Control EP.
|
||||
*
|
||||
* There is also another issue about HID Output Reports via USB, the Sixaxis
|
||||
* does not want the report_id as part of the data packet, so we have to
|
||||
* discard buf[0] when sending the actual control message, even for numbered
|
||||
* reports, humpf!
|
||||
*/
|
||||
static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
|
||||
size_t count, unsigned char report_type)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(hid->dev.parent);
|
||||
struct usb_device *dev = interface_to_usbdev(intf);
|
||||
struct usb_host_interface *interface = intf->cur_altsetting;
|
||||
int report_id = buf[0];
|
||||
int ret;
|
||||
|
||||
if (report_type == HID_OUTPUT_REPORT) {
|
||||
/* Don't send the Report ID */
|
||||
buf++;
|
||||
count--;
|
||||
}
|
||||
|
||||
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,
|
||||
interface->desc.bInterfaceNumber, buf, count,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
|
||||
/* Count also the Report ID, in case of an Output report. */
|
||||
if (ret > 0 && report_type == HID_OUTPUT_REPORT)
|
||||
ret++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
|
||||
* to "operational". Without this, the ps3 controller will not report any
|
||||
|
@ -1072,8 +1032,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 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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1305,11 +1265,8 @@ static void sixaxis_state_worker(struct work_struct *work)
|
|||
buf[10] |= sc->led_state[2] << 3;
|
||||
buf[10] |= sc->led_state[3] << 4;
|
||||
|
||||
if (sc->quirks & SIXAXIS_CONTROLLER_USB)
|
||||
hid_output_raw_report(sc->hdev, buf, sizeof(buf), HID_OUTPUT_REPORT);
|
||||
else
|
||||
hid_hw_raw_request(sc->hdev, 0x01, buf, sizeof(buf),
|
||||
HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
|
||||
hid_hw_raw_request(sc->hdev, 0x01, buf, sizeof(buf), HID_OUTPUT_REPORT,
|
||||
HID_REQ_SET_REPORT);
|
||||
}
|
||||
|
||||
static void dualshock4_state_worker(struct work_struct *work)
|
||||
|
@ -1659,7 +1616,18 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
}
|
||||
|
||||
if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
|
||||
hdev->hid_output_raw_report = sixaxis_usb_output_raw_report;
|
||||
/*
|
||||
* The Sony Sixaxis does not handle HID Output Reports on the
|
||||
* Interrupt EP like it could, so we need to force HID Output
|
||||
* Reports to use HID_REQ_SET_REPORT on the Control EP.
|
||||
*
|
||||
* There is also another issue about HID Output Reports via USB,
|
||||
* the Sixaxis does not want the report_id as part of the data
|
||||
* packet, so we have to discard buf[0] when sending the actual
|
||||
* control message, even for numbered reports, humpf!
|
||||
*/
|
||||
hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
|
||||
hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID;
|
||||
ret = sixaxis_set_operational_usb(hdev);
|
||||
sc->worker_initialized = 1;
|
||||
INIT_WORK(&sc->state_worker, sixaxis_state_worker);
|
||||
|
|
|
@ -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 = 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,7 +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 = 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;
|
||||
|
||||
|
@ -142,14 +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 = 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 = 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;
|
||||
|
@ -181,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;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -337,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 = 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) {
|
||||
|
@ -350,8 +353,9 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
|
|||
rep_data[1] = 0x00;
|
||||
limit = 3;
|
||||
do {
|
||||
ret = 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) {
|
||||
|
@ -376,8 +380,8 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
|
|||
rep_data[0] = 0x03;
|
||||
rep_data[1] = wdata->features;
|
||||
|
||||
ret = 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 = 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 = 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:
|
||||
|
|
|
@ -256,18 +256,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 +287,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 +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
|
||||
* 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;
|
||||
|
@ -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,
|
||||
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 +577,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 +587,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 = kzalloc(len, 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)
|
||||
|
@ -760,7 +766,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)
|
||||
|
@ -1005,7 +1012,6 @@ static int i2c_hid_probe(struct i2c_client *client,
|
|||
|
||||
hid->driver_data = client;
|
||||
hid->ll_driver = &i2c_hid_ll_driver;
|
||||
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;
|
||||
|
|
|
@ -247,27 +247,22 @@ static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
|
|||
static int uhid_hid_output_report(struct hid_device *hid, __u8 *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct uhid_device *uhid = hid->driver_data;
|
||||
unsigned long flags;
|
||||
struct uhid_event *ev;
|
||||
return uhid_hid_output_raw(hid, buf, count, HID_OUTPUT_REPORT);
|
||||
}
|
||||
|
||||
if (count < 1 || count > UHID_DATA_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
ev = kzalloc(sizeof(*ev), GFP_KERNEL);
|
||||
if (!ev)
|
||||
return -ENOMEM;
|
||||
|
||||
ev->type = UHID_OUTPUT;
|
||||
ev->u.output.size = count;
|
||||
ev->u.output.rtype = UHID_OUTPUT_REPORT;
|
||||
memcpy(ev->u.output.data, buf, count);
|
||||
|
||||
spin_lock_irqsave(&uhid->qlock, flags);
|
||||
uhid_queue(uhid, ev);
|
||||
spin_unlock_irqrestore(&uhid->qlock, flags);
|
||||
|
||||
return count;
|
||||
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 = {
|
||||
|
@ -277,6 +272,7 @@ static struct hid_ll_driver uhid_hid_driver = {
|
|||
.close = uhid_hid_close,
|
||||
.parse = uhid_hid_parse,
|
||||
.output_report = uhid_hid_output_report,
|
||||
.raw_request = uhid_raw_request,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
@ -404,7 +400,6 @@ static int uhid_dev_create(struct uhid_device *uhid,
|
|||
hid->uniq[63] = 0;
|
||||
|
||||
hid->ll_driver = &uhid_hid_driver;
|
||||
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;
|
||||
|
|
|
@ -894,7 +894,12 @@ static int usbhid_set_raw_report(struct hid_device *hid, unsigned int reportnum,
|
|||
int ret, skipped_report_id = 0;
|
||||
|
||||
/* Byte 0 is the report number. Report data starts at byte 1.*/
|
||||
buf[0] = reportnum;
|
||||
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++;
|
||||
|
@ -922,7 +927,7 @@ static int usbhid_output_report(struct hid_device *hid, __u8 *buf, size_t count)
|
|||
int actual_length, skipped_report_id = 0, ret;
|
||||
|
||||
if (!usbhid->urbout)
|
||||
return -EIO;
|
||||
return -ENOSYS;
|
||||
|
||||
if (buf[0] == 0x0) {
|
||||
/* Don't send the Report ID */
|
||||
|
@ -945,17 +950,6 @@ static int usbhid_output_report(struct hid_device *hid, __u8 *buf, size_t count)
|
|||
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)
|
||||
{
|
||||
if (usbhid->urbout && !test_bit(HID_OUT_RUNNING, &usbhid->iofl))
|
||||
|
@ -1289,7 +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_output_raw_report = usbhid_output_raw_report;
|
||||
hid->ff_init = hid_pidff_init;
|
||||
#ifdef CONFIG_USB_HIDDEV
|
||||
hid->hiddev_connect = hiddev_connect;
|
||||
|
|
|
@ -287,6 +287,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,9 +510,6 @@ struct hid_device { /* device report descriptor */
|
|||
struct hid_usage *, __s32);
|
||||
void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
|
||||
|
||||
/* 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;
|
||||
|
@ -753,6 +752,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);
|
||||
|
@ -965,7 +965,9 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -986,11 +988,11 @@ 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 (hdev->ll_driver->raw_request)
|
||||
return hdev->ll_driver->raw_request(hdev, reportnum, buf, len,
|
||||
rtype, reqtype);
|
||||
if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
return -ENOSYS;
|
||||
return hdev->ll_driver->raw_request(hdev, reportnum, buf, len,
|
||||
rtype, reqtype);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1005,28 +1007,15 @@ static inline int hid_hw_raw_request(struct hid_device *hdev,
|
|||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* hid_hw_idle - send idle request to device
|
||||
*
|
||||
|
|
|
@ -382,18 +382,6 @@ static int hidp_output_report(struct hid_device *hid, __u8 *data, size_t count)
|
|||
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)
|
||||
|
@ -776,8 +764,6 @@ static int hidp_setup_hid(struct hidp_session *session,
|
|||
hid->dev.parent = &session->conn->hcon->dev;
|
||||
hid->ll_driver = &hidp_hid_driver;
|
||||
|
||||
hid->hid_output_raw_report = hidp_output_raw_report;
|
||||
|
||||
/* True if device is blacklisted in drivers/hid/hid-core.c */
|
||||
if (hid_ignore(hid)) {
|
||||
hid_destroy_device(session->hid);
|
||||
|
|
Loading…
Reference in New Issue