mirror of
https://github.com/torvalds/linux.git
synced 2024-11-01 01:31:44 +00:00
Merge branch 'for-3.15/hid-core-ll-transport-cleanup' into for-3.15/sony
This commit is contained in:
commit
3371ac4b3b
316
Documentation/hid/hid-transport.txt
Normal file
316
Documentation/hid/hid-transport.txt
Normal file
@ -0,0 +1,316 @@
|
||||
HID I/O Transport Drivers
|
||||
===========================
|
||||
|
||||
The HID subsystem is independent of the underlying transport driver. Initially,
|
||||
only USB was supported, but other specifications adopted the HID design and
|
||||
provided new transport drivers. The kernel includes at least support for USB,
|
||||
Bluetooth, I2C and user-space I/O drivers.
|
||||
|
||||
1) HID Bus
|
||||
==========
|
||||
|
||||
The HID subsystem is designed as a bus. Any I/O subsystem may provide HID
|
||||
devices and register them with the HID bus. HID core then loads generic device
|
||||
drivers on top of it. The transport drivers are responsible of raw data
|
||||
transport and device setup/management. HID core is responsible of
|
||||
report-parsing, report interpretation and the user-space API. Device specifics
|
||||
and quirks are handled by all layers depending on the quirk.
|
||||
|
||||
+-----------+ +-----------+ +-----------+ +-----------+
|
||||
| Device #1 | | Device #i | | Device #j | | Device #k |
|
||||
+-----------+ +-----------+ +-----------+ +-----------+
|
||||
\\ // \\ //
|
||||
+------------+ +------------+
|
||||
| I/O Driver | | I/O Driver |
|
||||
+------------+ +------------+
|
||||
|| ||
|
||||
+------------------+ +------------------+
|
||||
| Transport Driver | | Transport Driver |
|
||||
+------------------+ +------------------+
|
||||
\___ ___/
|
||||
\ /
|
||||
+----------------+
|
||||
| HID Core |
|
||||
+----------------+
|
||||
/ | | \
|
||||
/ | | \
|
||||
____________/ | | \_________________
|
||||
/ | | \
|
||||
/ | | \
|
||||
+----------------+ +-----------+ +------------------+ +------------------+
|
||||
| Generic Driver | | MT Driver | | Custom Driver #1 | | Custom Driver #2 |
|
||||
+----------------+ +-----------+ +------------------+ +------------------+
|
||||
|
||||
Example Drivers:
|
||||
I/O: USB, I2C, Bluetooth-l2cap
|
||||
Transport: USB-HID, I2C-HID, BT-HIDP
|
||||
|
||||
Everything below "HID Core" is simplified in this graph as it is only of
|
||||
interest to HID device drivers. Transport drivers do not need to know the
|
||||
specifics.
|
||||
|
||||
1.1) Device Setup
|
||||
-----------------
|
||||
|
||||
I/O drivers normally provide hotplug detection or device enumeration APIs to the
|
||||
transport drivers. Transport drivers use this to find any suitable HID device.
|
||||
They allocate HID device objects and register them with HID core. Transport
|
||||
drivers are not required to register themselves with HID core. HID core is never
|
||||
aware of which transport drivers are available and is not interested in it. It
|
||||
is only interested in devices.
|
||||
|
||||
Transport drivers attach a constant "struct hid_ll_driver" object with each
|
||||
device. Once a device is registered with HID core, the callbacks provided via
|
||||
this struct are used by HID core to communicate with the device.
|
||||
|
||||
Transport drivers are responsible of detecting device failures and unplugging.
|
||||
HID core will operate a device as long as it is registered regardless of any
|
||||
device failures. Once transport drivers detect unplug or failure events, they
|
||||
must unregister the device from HID core and HID core will stop using the
|
||||
provided callbacks.
|
||||
|
||||
1.2) Transport Driver Requirements
|
||||
----------------------------------
|
||||
|
||||
The terms "asynchronous" and "synchronous" in this document describe the
|
||||
transmission behavior regarding acknowledgements. An asynchronous channel must
|
||||
not perform any synchronous operations like waiting for acknowledgements or
|
||||
verifications. Generally, HID calls operating on asynchronous channels must be
|
||||
running in atomic-context just fine.
|
||||
On the other hand, synchronous channels can be implemented by the transport
|
||||
driver in whatever way they like. They might just be the same as asynchronous
|
||||
channels, but they can also provide acknowledgement reports, automatic
|
||||
retransmission on failure, etc. in a blocking manner. If such functionality is
|
||||
required on asynchronous channels, a transport-driver must implement that via
|
||||
its own worker threads.
|
||||
|
||||
HID core requires transport drivers to follow a given design. A Transport
|
||||
driver must provide two bi-directional I/O channels to each HID device. These
|
||||
channels must not necessarily be bi-directional in the hardware itself. A
|
||||
transport driver might just provide 4 uni-directional channels. Or it might
|
||||
multiplex all four on a single physical channel. However, in this document we
|
||||
will describe them as two bi-directional channels as they have several
|
||||
properties in common.
|
||||
|
||||
- Interrupt Channel (intr): The intr channel is used for asynchronous data
|
||||
reports. No management commands or data acknowledgements are sent on this
|
||||
channel. Any unrequested incoming or outgoing data report must be sent on
|
||||
this channel and is never acknowledged by the remote side. Devices usually
|
||||
send their input events on this channel. Outgoing events are normally
|
||||
not send via intr, except if high throughput is required.
|
||||
- Control Channel (ctrl): The ctrl channel is used for synchronous requests and
|
||||
device management. Unrequested data input events must not be sent on this
|
||||
channel and are normally ignored. Instead, devices only send management
|
||||
events or answers to host requests on this channel.
|
||||
The control-channel is used for direct blocking queries to the device
|
||||
independent of any events on the intr-channel.
|
||||
Outgoing reports are usually sent on the ctrl channel via synchronous
|
||||
SET_REPORT requests.
|
||||
|
||||
Communication between devices and HID core is mostly done via HID reports. A
|
||||
report can be of one of three types:
|
||||
|
||||
- INPUT Report: Input reports provide data from device to host. This
|
||||
data may include button events, axis events, battery status or more. This
|
||||
data is generated by the device and sent to the host with or without
|
||||
requiring explicit requests. Devices can choose to send data continuously or
|
||||
only on change.
|
||||
- OUTPUT Report: Output reports change device states. They are sent from host
|
||||
to device and may include LED requests, rumble requests or more. Output
|
||||
reports are never sent from device to host, but a host can retrieve their
|
||||
current state.
|
||||
Hosts may choose to send output reports either continuously or only on
|
||||
change.
|
||||
- FEATURE Report: Feature reports are used for specific static device features
|
||||
and never reported spontaneously. A host can read and/or write them to access
|
||||
data like battery-state or device-settings.
|
||||
Feature reports are never sent without requests. A host must explicitly set
|
||||
or retrieve a feature report. This also means, feature reports are never sent
|
||||
on the intr channel as this channel is asynchronous.
|
||||
|
||||
INPUT and OUTPUT reports can be sent as pure data reports on the intr channel.
|
||||
For INPUT reports this is the usual operational mode. But for OUTPUT reports,
|
||||
this is rarely done as OUTPUT reports are normally quite scarce. But devices are
|
||||
free to make excessive use of asynchronous OUTPUT reports (for instance, custom
|
||||
HID audio speakers make great use of it).
|
||||
|
||||
Plain reports must not be sent on the ctrl channel, though. Instead, the ctrl
|
||||
channel provides synchronous GET/SET_REPORT requests. Plain reports are only
|
||||
allowed on the intr channel and are the only means of data there.
|
||||
|
||||
- GET_REPORT: A GET_REPORT request has a report ID as payload and is sent
|
||||
from host to device. The device must answer with a data report for the
|
||||
requested report ID on the ctrl channel as a synchronous acknowledgement.
|
||||
Only one GET_REPORT request can be pending for each device. This restriction
|
||||
is enforced by HID core as several transport drivers don't allow multiple
|
||||
simultaneous GET_REPORT requests.
|
||||
Note that data reports which are sent as answer to a GET_REPORT request are
|
||||
not handled as generic device events. That is, if a device does not operate
|
||||
in continuous data reporting mode, an answer to GET_REPORT does not replace
|
||||
the raw data report on the intr channel on state change.
|
||||
GET_REPORT is only used by custom HID device drivers to query device state.
|
||||
Normally, HID core caches any device state so this request is not necessary
|
||||
on devices that follow the HID specs except during device initialization to
|
||||
retrieve the current state.
|
||||
GET_REPORT requests can be sent for any of the 3 report types and shall
|
||||
return the current report state of the device. However, OUTPUT reports as
|
||||
payload may be blocked by the underlying transport driver if the
|
||||
specification does not allow them.
|
||||
- SET_REPORT: A SET_REPORT request has a report ID plus data as payload. It is
|
||||
sent from host to device and a device must update it's current report state
|
||||
according to the given data. Any of the 3 report types can be used. However,
|
||||
INPUT reports as payload might be blocked by the underlying transport driver
|
||||
if the specification does not allow them.
|
||||
A device must answer with a synchronous acknowledgement. However, HID core
|
||||
does not require transport drivers to forward this acknowledgement to HID
|
||||
core.
|
||||
Same as for GET_REPORT, only one SET_REPORT can be pending at a time. This
|
||||
restriction is enforced by HID core as some transport drivers do not support
|
||||
multiple synchronous SET_REPORT requests.
|
||||
|
||||
Other ctrl-channel requests are supported by USB-HID but are not available
|
||||
(or deprecated) in most other transport level specifications:
|
||||
|
||||
- GET/SET_IDLE: Only used by USB-HID and I2C-HID.
|
||||
- GET/SET_PROTOCOL: Not used by HID core.
|
||||
- RESET: Used by I2C-HID, not hooked up in HID core.
|
||||
- SET_POWER: Used by I2C-HID, not hooked up in HID core.
|
||||
|
||||
2) HID API
|
||||
==========
|
||||
|
||||
2.1) Initialization
|
||||
-------------------
|
||||
|
||||
Transport drivers normally use the following procedure to register a new device
|
||||
with HID core:
|
||||
|
||||
struct hid_device *hid;
|
||||
int ret;
|
||||
|
||||
hid = hid_allocate_device();
|
||||
if (IS_ERR(hid)) {
|
||||
ret = PTR_ERR(hid);
|
||||
goto err_<...>;
|
||||
}
|
||||
|
||||
strlcpy(hid->name, <device-name-src>, 127);
|
||||
strlcpy(hid->phys, <device-phys-src>, 63);
|
||||
strlcpy(hid->uniq, <device-uniq-src>, 63);
|
||||
|
||||
hid->ll_driver = &custom_ll_driver;
|
||||
hid->bus = <device-bus>;
|
||||
hid->vendor = <device-vendor>;
|
||||
hid->product = <device-product>;
|
||||
hid->version = <device-version>;
|
||||
hid->country = <device-country>;
|
||||
hid->dev.parent = <pointer-to-parent-device>;
|
||||
hid->driver_data = <transport-driver-data-field>;
|
||||
|
||||
ret = hid_add_device(hid);
|
||||
if (ret)
|
||||
goto err_<...>;
|
||||
|
||||
Once hid_add_device() is entered, HID core might use the callbacks provided in
|
||||
"custom_ll_driver". Note that fields like "country" can be ignored by underlying
|
||||
transport-drivers if not supported.
|
||||
|
||||
To unregister a device, use:
|
||||
|
||||
hid_destroy_device(hid);
|
||||
|
||||
Once hid_destroy_device() returns, HID core will no longer make use of any
|
||||
driver callbacks.
|
||||
|
||||
2.2) hid_ll_driver operations
|
||||
-----------------------------
|
||||
|
||||
The available HID callbacks are:
|
||||
- int (*start) (struct hid_device *hdev)
|
||||
Called from HID device drivers once they want to use the device. Transport
|
||||
drivers can choose to setup their device in this callback. However, normally
|
||||
devices are already set up before transport drivers register them to HID core
|
||||
so this is mostly only used by USB-HID.
|
||||
|
||||
- void (*stop) (struct hid_device *hdev)
|
||||
Called from HID device drivers once they are done with a device. Transport
|
||||
drivers can free any buffers and deinitialize the device. But note that
|
||||
->start() might be called again if another HID device driver is loaded on the
|
||||
device.
|
||||
Transport drivers are free to ignore it and deinitialize devices after they
|
||||
destroyed them via hid_destroy_device().
|
||||
|
||||
- int (*open) (struct hid_device *hdev)
|
||||
Called from HID device drivers once they are interested in data reports.
|
||||
Usually, while user-space didn't open any input API/etc., device drivers are
|
||||
not interested in device data and transport drivers can put devices asleep.
|
||||
However, once ->open() is called, transport drivers must be ready for I/O.
|
||||
->open() calls are nested for each client that opens the HID device.
|
||||
|
||||
- void (*close) (struct hid_device *hdev)
|
||||
Called from HID device drivers after ->open() was called but they are no
|
||||
longer interested in device reports. (Usually if user-space closed any input
|
||||
devices of the driver).
|
||||
Transport drivers can put devices asleep and terminate any I/O of all
|
||||
->open() calls have been followed by a ->close() call. However, ->start() may
|
||||
be called again if the device driver is interested in input reports again.
|
||||
|
||||
- int (*parse) (struct hid_device *hdev)
|
||||
Called once during device setup after ->start() has been called. Transport
|
||||
drivers must read the HID report-descriptor from the device and tell HID core
|
||||
about it via hid_parse_report().
|
||||
|
||||
- int (*power) (struct hid_device *hdev, int level)
|
||||
Called by HID core to give PM hints to transport drivers. Usually this is
|
||||
analogical to the ->open() and ->close() hints and redundant.
|
||||
|
||||
- void (*request) (struct hid_device *hdev, struct hid_report *report,
|
||||
int reqtype)
|
||||
Send an HID request on the ctrl channel. "report" contains the report that
|
||||
should be sent and "reqtype" the request type. Request-type can be
|
||||
HID_REQ_SET_REPORT or HID_REQ_GET_REPORT.
|
||||
This callback is optional. If not provided, HID core will assemble a raw
|
||||
report following the HID specs and send it via the ->raw_request() callback.
|
||||
The transport driver is free to implement this asynchronously.
|
||||
|
||||
- int (*wait) (struct hid_device *hdev)
|
||||
Used by HID core before calling ->request() again. A transport driver can use
|
||||
it to wait for any pending requests to complete if only one request is
|
||||
allowed at a time.
|
||||
|
||||
- int (*raw_request) (struct hid_device *hdev, unsigned char reportnum,
|
||||
__u8 *buf, size_t count, unsigned char rtype,
|
||||
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.
|
||||
|
||||
- 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
|
||||
which require high throughput for outgoing requests on the intr channel. This
|
||||
must not cause SET_REPORT calls! This must be implemented as asynchronous
|
||||
output report on the intr channel!
|
||||
|
||||
- int (*idle) (struct hid_device *hdev, int report, int idle, int reqtype)
|
||||
Perform SET/GET_IDLE request. Only used by USB-HID, do not implement!
|
||||
|
||||
2.3) Data Path
|
||||
--------------
|
||||
|
||||
Transport drivers are responsible of reading data from I/O devices. They must
|
||||
handle any I/O-related state-tracking themselves. HID core does not implement
|
||||
protocol handshakes or other management commands which can be required by the
|
||||
given HID transport specification.
|
||||
|
||||
Every raw data packet read from a device must be fed into HID core via
|
||||
hid_input_report(). You must specify the channel-type (intr or ctrl) and report
|
||||
type (input/output/feature). Under normal conditions, only input reports are
|
||||
provided via this API.
|
||||
|
||||
Responses to GET_REPORT requests via ->request() must also be provided via this
|
||||
API. Responses to ->raw_request() are synchronous and must be intercepted by the
|
||||
transport driver and not passed to hid_input_report().
|
||||
Acknowledgements to SET_REPORT requests are not of interest to HID core.
|
||||
|
||||
----------------------------------------------------
|
||||
Written 2013, David Herrmann <dh.herrmann@gmail.com>
|
@ -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;
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
@ -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_output_raw_report(hdev, buf, sizeof(buf),
|
||||
HID_FEATURE_REPORT);
|
||||
|
||||
if (ret >= 0) {
|
||||
/* insert a little delay of 10 jiffies ~ 40ms */
|
||||
@ -704,7 +705,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
buf[1] = 0xB2;
|
||||
get_random_bytes(&buf[2], 2);
|
||||
|
||||
ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
|
||||
ret = hid_output_raw_report(hdev, buf, sizeof(buf),
|
||||
HID_FEATURE_REPORT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,14 +44,6 @@ static const char kbd_descriptor[] = {
|
||||
0x19, 0xE0, /* USAGE_MINIMUM (Left Control) */
|
||||
0x29, 0xE7, /* USAGE_MAXIMUM (Right GUI) */
|
||||
0x81, 0x02, /* INPUT (Data,Var,Abs) */
|
||||
0x95, 0x05, /* REPORT COUNT (5) */
|
||||
0x05, 0x08, /* USAGE PAGE (LED page) */
|
||||
0x19, 0x01, /* USAGE MINIMUM (1) */
|
||||
0x29, 0x05, /* USAGE MAXIMUM (5) */
|
||||
0x91, 0x02, /* OUTPUT (Data, Variable, Absolute) */
|
||||
0x95, 0x01, /* REPORT COUNT (1) */
|
||||
0x75, 0x03, /* REPORT SIZE (3) */
|
||||
0x91, 0x01, /* OUTPUT (Constant) */
|
||||
0x95, 0x06, /* REPORT_COUNT (6) */
|
||||
0x75, 0x08, /* REPORT_SIZE (8) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
@ -60,6 +52,18 @@ static const char kbd_descriptor[] = {
|
||||
0x19, 0x00, /* USAGE_MINIMUM (no event) */
|
||||
0x2A, 0xFF, 0x00, /* USAGE_MAXIMUM (reserved) */
|
||||
0x81, 0x00, /* INPUT (Data,Ary,Abs) */
|
||||
0x85, 0x0e, /* REPORT_ID (14) */
|
||||
0x05, 0x08, /* USAGE PAGE (LED page) */
|
||||
0x95, 0x05, /* REPORT COUNT (5) */
|
||||
0x75, 0x01, /* REPORT SIZE (1) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
|
||||
0x19, 0x01, /* USAGE MINIMUM (1) */
|
||||
0x29, 0x05, /* USAGE MAXIMUM (5) */
|
||||
0x91, 0x02, /* OUTPUT (Data, Variable, Absolute) */
|
||||
0x95, 0x01, /* REPORT COUNT (1) */
|
||||
0x75, 0x03, /* REPORT SIZE (3) */
|
||||
0x91, 0x01, /* OUTPUT (Constant) */
|
||||
0xC0
|
||||
};
|
||||
|
||||
@ -544,10 +548,37 @@ static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
|
||||
size_t count,
|
||||
unsigned char report_type)
|
||||
{
|
||||
/* 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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
kfree(out_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rdcat(char *rdesc, unsigned int *rsize, const char *data, unsigned int size)
|
||||
@ -613,58 +644,6 @@ static int logi_dj_ll_parse(struct hid_device *hid)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
|
||||
unsigned int code, int value)
|
||||
{
|
||||
/* Sent by the input layer to handle leds and Force Feedback */
|
||||
struct hid_device *dj_hiddev = input_get_drvdata(dev);
|
||||
struct dj_device *dj_dev = dj_hiddev->driver_data;
|
||||
|
||||
struct dj_receiver_dev *djrcv_dev =
|
||||
dev_get_drvdata(dj_hiddev->dev.parent);
|
||||
struct hid_device *dj_rcv_hiddev = djrcv_dev->hdev;
|
||||
struct hid_report_enum *output_report_enum;
|
||||
|
||||
struct hid_field *field;
|
||||
struct hid_report *report;
|
||||
unsigned char *data;
|
||||
int offset;
|
||||
|
||||
dbg_hid("%s: %s, type:%d | code:%d | value:%d\n",
|
||||
__func__, dev->phys, type, code, value);
|
||||
|
||||
if (type != EV_LED)
|
||||
return -1;
|
||||
|
||||
offset = hidinput_find_field(dj_hiddev, type, code, &field);
|
||||
|
||||
if (offset == -1) {
|
||||
dev_warn(&dev->dev, "event field not found\n");
|
||||
return -1;
|
||||
}
|
||||
hid_set_field(field, offset, value);
|
||||
|
||||
data = hid_alloc_report_buf(field->report, GFP_ATOMIC);
|
||||
if (!data) {
|
||||
dev_warn(&dev->dev, "failed to allocate report buf memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hid_output_report(field->report, &data[0]);
|
||||
|
||||
output_report_enum = &dj_rcv_hiddev->report_enum[HID_OUTPUT_REPORT];
|
||||
report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT];
|
||||
hid_set_field(report->field[0], 0, dj_dev->device_index);
|
||||
hid_set_field(report->field[0], 1, REPORT_TYPE_LEDS);
|
||||
hid_set_field(report->field[0], 2, data[1]);
|
||||
|
||||
hid_hw_request(dj_rcv_hiddev, report, HID_REQ_SET_REPORT);
|
||||
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int logi_dj_ll_start(struct hid_device *hid)
|
||||
{
|
||||
dbg_hid("%s\n", __func__);
|
||||
@ -683,7 +662,6 @@ 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,
|
||||
};
|
||||
|
||||
|
||||
|
@ -538,7 +538,7 @@ 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),
|
||||
ret = hid_output_raw_report(hdev, feature, sizeof(feature),
|
||||
HID_FEATURE_REPORT);
|
||||
if (ret != -EIO && ret != sizeof(feature)) {
|
||||
hid_err(hdev, "unable to request touch data (%d)\n", ret);
|
||||
|
@ -810,7 +810,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");
|
||||
@ -823,7 +824,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_output_raw_report(hdev, buf, sizeof(buf),
|
||||
HID_FEATURE_REPORT);
|
||||
}
|
||||
|
||||
static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds)
|
||||
@ -1042,8 +1044,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)
|
||||
|
@ -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_output_raw_report(data->hdev, buf, BLINK1_CMD_SIZE,
|
||||
HID_FEATURE_REPORT);
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
@ -128,8 +128,7 @@ static void wacom_set_image(struct hid_device *hdev, const char *image,
|
||||
|
||||
rep_data[0] = WAC_CMD_ICON_START_STOP;
|
||||
rep_data[1] = 0;
|
||||
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
|
||||
HID_FEATURE_REPORT);
|
||||
ret = hid_output_raw_report(hdev, rep_data, 2, HID_FEATURE_REPORT);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
@ -143,15 +142,14 @@ static void wacom_set_image(struct hid_device *hdev, const char *image,
|
||||
rep_data[j + 3] = p[(i << 6) + j];
|
||||
|
||||
rep_data[2] = i;
|
||||
ret = hdev->hid_output_raw_report(hdev, rep_data, 67,
|
||||
ret = hid_output_raw_report(hdev, rep_data, 67,
|
||||
HID_FEATURE_REPORT);
|
||||
}
|
||||
|
||||
rep_data[0] = WAC_CMD_ICON_START_STOP;
|
||||
rep_data[1] = 0;
|
||||
|
||||
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
|
||||
HID_FEATURE_REPORT);
|
||||
ret = hid_output_raw_report(hdev, rep_data, 2, HID_FEATURE_REPORT);
|
||||
|
||||
err:
|
||||
return;
|
||||
@ -183,7 +181,7 @@ static void wacom_leds_set_brightness(struct led_classdev *led_dev,
|
||||
buf[3] = value;
|
||||
/* use fixed brightness for OLEDs */
|
||||
buf[4] = 0x08;
|
||||
hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT);
|
||||
hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
@ -339,7 +337,7 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
|
||||
rep_data[0] = 0x03 ; rep_data[1] = 0x00;
|
||||
limit = 3;
|
||||
do {
|
||||
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
|
||||
ret = hid_output_raw_report(hdev, rep_data, 2,
|
||||
HID_FEATURE_REPORT);
|
||||
} while (ret < 0 && limit-- > 0);
|
||||
|
||||
@ -352,7 +350,7 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
|
||||
rep_data[1] = 0x00;
|
||||
limit = 3;
|
||||
do {
|
||||
ret = hdev->hid_output_raw_report(hdev,
|
||||
ret = hid_output_raw_report(hdev,
|
||||
rep_data, 2, HID_FEATURE_REPORT);
|
||||
} while (ret < 0 && limit-- > 0);
|
||||
|
||||
@ -378,7 +376,7 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
|
||||
rep_data[0] = 0x03;
|
||||
rep_data[1] = wdata->features;
|
||||
|
||||
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
|
||||
ret = hid_output_raw_report(hdev, rep_data, 2,
|
||||
HID_FEATURE_REPORT);
|
||||
if (ret >= 0)
|
||||
wdata->high_speed = speed;
|
||||
|
@ -35,7 +35,7 @@ static int wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = hdev->hid_output_raw_report(hdev, buf, count, HID_OUTPUT_REPORT);
|
||||
ret = hid_output_raw_report(hdev, buf, count, HID_OUTPUT_REPORT);
|
||||
|
||||
kfree(buf);
|
||||
return ret;
|
||||
|
@ -153,7 +153,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
ret = dev->hid_output_raw_report(dev, buf, count, report_type);
|
||||
ret = hid_output_raw_report(dev, buf, count, report_type);
|
||||
out_free:
|
||||
kfree(buf);
|
||||
out:
|
||||
@ -189,7 +189,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
|
||||
|
||||
dev = hidraw_table[minor]->hid;
|
||||
|
||||
if (!dev->hid_get_raw_report) {
|
||||
if (!dev->ll_driver->raw_request) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
@ -216,14 +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,
|
||||
* which is passed to dev->hid_get_raw_report().
|
||||
* which is passed to hid_hw_raw_request().
|
||||
*/
|
||||
if (copy_from_user(&report_number, buffer, 1)) {
|
||||
ret = -EFAULT;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
ret = dev->hid_get_raw_report(dev, report_number, buf, count, report_type);
|
||||
ret = hid_hw_raw_request(dev, report_number, buf, count, report_type,
|
||||
HID_REQ_GET_REPORT);
|
||||
|
||||
if (ret < 0)
|
||||
goto out_free;
|
||||
|
@ -1005,7 +1005,6 @@ static int i2c_hid_probe(struct i2c_client *client,
|
||||
|
||||
hid->driver_data = client;
|
||||
hid->ll_driver = &i2c_hid_ll_driver;
|
||||
hid->hid_get_raw_report = i2c_hid_get_raw_report;
|
||||
hid->hid_output_raw_report = i2c_hid_output_raw_report;
|
||||
hid->dev.parent = &client->dev;
|
||||
ACPI_COMPANION_SET(&hid->dev, ACPI_COMPANION(&client->dev));
|
||||
|
@ -244,12 +244,39 @@ static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
|
||||
return count;
|
||||
}
|
||||
|
||||
static int uhid_hid_output_report(struct hid_device *hid, __u8 *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct uhid_device *uhid = hid->driver_data;
|
||||
unsigned long flags;
|
||||
struct uhid_event *ev;
|
||||
|
||||
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 struct hid_ll_driver uhid_hid_driver = {
|
||||
.start = uhid_hid_start,
|
||||
.stop = uhid_hid_stop,
|
||||
.open = uhid_hid_open,
|
||||
.close = uhid_hid_close,
|
||||
.parse = uhid_hid_parse,
|
||||
.output_report = uhid_hid_output_report,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
@ -377,7 +404,6 @@ static int uhid_dev_create(struct uhid_device *uhid,
|
||||
hid->uniq[63] = 0;
|
||||
|
||||
hid->ll_driver = &uhid_hid_driver;
|
||||
hid->hid_get_raw_report = uhid_hid_get_raw;
|
||||
hid->hid_output_raw_report = uhid_hid_output_raw;
|
||||
hid->bus = ev->u.create.bus;
|
||||
hid->vendor = ev->u.create.vendor;
|
||||
|
@ -884,58 +884,78 @@ static int usbhid_get_raw_report(struct hid_device *hid,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count,
|
||||
unsigned char report_type)
|
||||
static int usbhid_set_raw_report(struct hid_device *hid, unsigned int reportnum,
|
||||
__u8 *buf, size_t count, unsigned char rtype)
|
||||
{
|
||||
struct usbhid_device *usbhid = hid->driver_data;
|
||||
struct usb_device *dev = hid_to_usb_dev(hid);
|
||||
struct usb_interface *intf = usbhid->intf;
|
||||
struct usb_host_interface *interface = intf->cur_altsetting;
|
||||
int ret;
|
||||
int ret, skipped_report_id = 0;
|
||||
|
||||
if (usbhid->urbout && report_type != HID_FEATURE_REPORT) {
|
||||
int actual_length;
|
||||
int skipped_report_id = 0;
|
||||
/* Byte 0 is the report number. Report data starts at byte 1.*/
|
||||
buf[0] = reportnum;
|
||||
if (buf[0] == 0x0) {
|
||||
/* Don't send the Report ID */
|
||||
buf++;
|
||||
count--;
|
||||
skipped_report_id = 1;
|
||||
}
|
||||
|
||||
if (buf[0] == 0x0) {
|
||||
/* Don't send the Report ID */
|
||||
buf++;
|
||||
count--;
|
||||
skipped_report_id = 1;
|
||||
}
|
||||
ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
|
||||
buf, count, &actual_length,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
/* return the number of bytes transferred */
|
||||
if (ret == 0) {
|
||||
ret = actual_length;
|
||||
/* count also the report id */
|
||||
if (skipped_report_id)
|
||||
ret++;
|
||||
}
|
||||
} else {
|
||||
int skipped_report_id = 0;
|
||||
int report_id = buf[0];
|
||||
if (buf[0] == 0x0) {
|
||||
/* Don't send the Report ID */
|
||||
buf++;
|
||||
count--;
|
||||
skipped_report_id = 1;
|
||||
}
|
||||
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
|
||||
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
|
||||
HID_REQ_SET_REPORT,
|
||||
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
((report_type + 1) << 8) | report_id,
|
||||
((rtype + 1) << 8) | reportnum,
|
||||
interface->desc.bInterfaceNumber, buf, count,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
/* count also the report id, if this was a numbered report. */
|
||||
if (ret > 0 && skipped_report_id)
|
||||
/* count also the report id, if this was a numbered report. */
|
||||
if (ret > 0 && skipped_report_id)
|
||||
ret++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbhid_output_report(struct hid_device *hid, __u8 *buf, size_t count)
|
||||
{
|
||||
struct usbhid_device *usbhid = hid->driver_data;
|
||||
struct usb_device *dev = hid_to_usb_dev(hid);
|
||||
int actual_length, skipped_report_id = 0, ret;
|
||||
|
||||
if (!usbhid->urbout)
|
||||
return -EIO;
|
||||
|
||||
if (buf[0] == 0x0) {
|
||||
/* Don't send the Report ID */
|
||||
buf++;
|
||||
count--;
|
||||
skipped_report_id = 1;
|
||||
}
|
||||
|
||||
ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
|
||||
buf, count, &actual_length,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
/* return the number of bytes transferred */
|
||||
if (ret == 0) {
|
||||
ret = actual_length;
|
||||
/* count also the report id */
|
||||
if (skipped_report_id)
|
||||
ret++;
|
||||
}
|
||||
|
||||
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))
|
||||
@ -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,
|
||||
int reqtype)
|
||||
{
|
||||
@ -1223,6 +1257,8 @@ static struct hid_ll_driver usb_hid_driver = {
|
||||
.power = usbhid_power,
|
||||
.request = usbhid_request,
|
||||
.wait = usbhid_wait_io,
|
||||
.raw_request = usbhid_raw_request,
|
||||
.output_report = usbhid_output_report,
|
||||
.idle = usbhid_idle,
|
||||
};
|
||||
|
||||
@ -1253,7 +1289,6 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
|
||||
|
||||
usb_set_intfdata(intf, hid);
|
||||
hid->ll_driver = &usb_hid_driver;
|
||||
hid->hid_get_raw_report = usbhid_get_raw_report;
|
||||
hid->hid_output_raw_report = usbhid_output_raw_report;
|
||||
hid->ff_init = hid_pidff_init;
|
||||
#ifdef CONFIG_USB_HIDDEV
|
||||
|
@ -508,9 +508,6 @@ struct hid_device { /* device report descriptor */
|
||||
struct hid_usage *, __s32);
|
||||
void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
|
||||
|
||||
/* handler for raw input (Get_Report) data, used by hidraw */
|
||||
int (*hid_get_raw_report) (struct hid_device *, unsigned char, __u8 *, size_t, unsigned char);
|
||||
|
||||
/* handler for raw output data, used by hidraw */
|
||||
int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t, unsigned char);
|
||||
|
||||
@ -675,11 +672,12 @@ struct hid_driver {
|
||||
* @stop: called on remove
|
||||
* @open: called by input layer on open
|
||||
* @close: called by input layer on close
|
||||
* @hidinput_input_event: event input event (e.g. ff or leds)
|
||||
* @parse: this method is called only once to parse the device data,
|
||||
* shouldn't allocate anything to not leak memory
|
||||
* @request: send report request to device (e.g. feature report)
|
||||
* @wait: wait for buffered io to complete (send/recv reports)
|
||||
* @raw_request: send raw report request to device (e.g. feature report)
|
||||
* @output_report: send output report to device
|
||||
* @idle: send idle request to device
|
||||
*/
|
||||
struct hid_ll_driver {
|
||||
@ -691,17 +689,20 @@ struct hid_ll_driver {
|
||||
|
||||
int (*power)(struct hid_device *hdev, int level);
|
||||
|
||||
int (*hidinput_input_event) (struct input_dev *idev, unsigned int type,
|
||||
unsigned int code, int value);
|
||||
|
||||
int (*parse)(struct hid_device *hdev);
|
||||
|
||||
void (*request)(struct hid_device *hdev,
|
||||
struct hid_report *report, int reqtype);
|
||||
|
||||
int (*wait)(struct hid_device *hdev);
|
||||
int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype);
|
||||
|
||||
int (*raw_request) (struct hid_device *hdev, unsigned char reportnum,
|
||||
__u8 *buf, size_t len, unsigned char rtype,
|
||||
int reqtype);
|
||||
|
||||
int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len);
|
||||
|
||||
int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype);
|
||||
};
|
||||
|
||||
#define PM_HINT_FULLON 1<<5
|
||||
@ -967,6 +968,65 @@ static inline void hid_hw_request(struct hid_device *hdev,
|
||||
hdev->ll_driver->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 (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 (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
|
||||
*
|
||||
|
@ -223,51 +223,6 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
|
||||
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,
|
||||
unsigned char report_number,
|
||||
unsigned char *data, size_t count,
|
||||
@ -353,17 +308,24 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
|
||||
unsigned char report_type)
|
||||
static int hidp_set_raw_report(struct hid_device *hid, unsigned char reportnum,
|
||||
unsigned char *data, size_t count,
|
||||
unsigned char report_type)
|
||||
{
|
||||
struct hidp_session *session = hid->driver_data;
|
||||
int ret;
|
||||
|
||||
if (report_type == HID_OUTPUT_REPORT) {
|
||||
report_type = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
|
||||
return hidp_send_intr_message(session, report_type,
|
||||
data, count);
|
||||
} else if (report_type != HID_FEATURE_REPORT) {
|
||||
switch (report_type) {
|
||||
case HID_FEATURE_REPORT:
|
||||
report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -371,8 +333,8 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s
|
||||
return -ERESTARTSYS;
|
||||
|
||||
/* Set up our wait, and send the report request to the device. */
|
||||
data[0] = reportnum;
|
||||
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);
|
||||
if (ret)
|
||||
goto err;
|
||||
@ -411,6 +373,41 @@ err:
|
||||
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)
|
||||
{
|
||||
struct hidp_session *session = (struct hidp_session *) arg;
|
||||
@ -727,7 +724,8 @@ static struct hid_ll_driver hidp_hid_driver = {
|
||||
.stop = hidp_stop,
|
||||
.open = hidp_open,
|
||||
.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
|
||||
@ -775,7 +773,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_get_raw_report = hidp_get_raw_report;
|
||||
hid->hid_output_raw_report = hidp_output_raw_report;
|
||||
|
||||
/* True if device is blacklisted in drivers/hid/hid-core.c */
|
||||
|
Loading…
Reference in New Issue
Block a user