forked from Minki/linux
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID updates from Jiri Kosina: - substantial cleanup of the generic and transport layers, in the direction of an ultimate goal of making struct hid_device completely transport independent, by Benjamin Tissoires - cp2112 driver from David Barksdale - a lot of fixes and new hardware support (Dualshock 4) to hid-sony driver, by Frank Praznik - support for Win 8.1 multitouch protocol by Andrew Duggan - other smaller fixes / device ID additions * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (75 commits) HID: sony: fix force feedback mismerge HID: sony: Set the quriks flag for Bluetooth controllers HID: sony: Fix Sixaxis cable state detection HID: uhid: Add UHID_CREATE2 + UHID_INPUT2 HID: hyperv: fix _raw_request() prototype HID: hyperv: Implement a stub raw_request() entry point HID: hid-sensor-hub: fix sleeping function called from invalid context HID: multitouch: add support for Win 8.1 multitouch touchpads HID: remove hid_output_raw_report transport implementations HID: sony: do not rely on hid_output_raw_report HID: cp2112: remove the last hid_output_raw_report() call HID: cp2112: remove various hid_out_raw_report calls HID: multitouch: add support of other generic collections in hid-mt HID: multitouch: remove pen special handling HID: multitouch: remove registered devices with default behavior HID: hidp: Add a comment that some devices depend on the current behavior of uniq HID: sony: Prevent duplicate controller connections. HID: sony: Perform a boundry check on the sixaxis battery level index. HID: sony: Fix work queue issues HID: sony: Fix multi-line comment styling ...
This commit is contained in:
commit
0f1b1e6d73
317
Documentation/hid/hid-transport.txt
Normal file
317
Documentation/hid/hid-transport.txt
Normal file
@ -0,0 +1,317 @@
|
||||
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. 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
|
||||
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>
|
@ -93,6 +93,11 @@ the request was handled successfully.
|
||||
event to the kernel. The payload is of type struct uhid_create_req and
|
||||
contains information about your device. You can start I/O now.
|
||||
|
||||
UHID_CREATE2:
|
||||
Same as UHID_CREATE, but the HID report descriptor data (rd_data) is an array
|
||||
inside struct uhid_create2_req, instead of a pointer to a separate array.
|
||||
Enables use from languages that don't support pointers, e.g. Python.
|
||||
|
||||
UHID_DESTROY:
|
||||
This destroys the internal HID device. No further I/O will be accepted. There
|
||||
may still be pending messages that you can receive with read() but no further
|
||||
@ -105,6 +110,12 @@ the request was handled successfully.
|
||||
contains a data-payload. This is the raw data that you read from your device.
|
||||
The kernel will parse the HID reports and react on it.
|
||||
|
||||
UHID_INPUT2:
|
||||
Same as UHID_INPUT, but the data array is the last field of uhid_input2_req.
|
||||
Enables userspace to write only the required bytes to kernel (ev.type +
|
||||
ev.u.input2.size + the part of the data array that matters), instead of
|
||||
the entire struct uhid_input2_req.
|
||||
|
||||
UHID_FEATURE_ANSWER:
|
||||
If you receive a UHID_FEATURE request you must answer with this request. You
|
||||
must copy the "id" field from the request into the answer. Set the "err" field
|
||||
|
@ -175,6 +175,15 @@ config HID_PRODIKEYS
|
||||
multimedia keyboard, but will lack support for the musical keyboard
|
||||
and some additional multimedia keys.
|
||||
|
||||
config HID_CP2112
|
||||
tristate "Silicon Labs CP2112 HID USB-to-SMBus Bridge support"
|
||||
depends on USB_HID && I2C && GPIOLIB
|
||||
---help---
|
||||
Support for Silicon Labs CP2112 HID USB to SMBus Master Bridge.
|
||||
This is a HID device driver which registers as an i2c adapter
|
||||
and gpiochip to expose these functions of the CP2112. The
|
||||
customizable USB descriptor fields are exposed as sysfs attributes.
|
||||
|
||||
config HID_CYPRESS
|
||||
tristate "Cypress mouse and barcode readers" if EXPERT
|
||||
depends on HID
|
||||
@ -608,25 +617,27 @@ config HID_SAMSUNG
|
||||
Support for Samsung InfraRed remote control or keyboards.
|
||||
|
||||
config HID_SONY
|
||||
tristate "Sony PS2/3 accessories"
|
||||
tristate "Sony PS2/3/4 accessories"
|
||||
depends on USB_HID
|
||||
depends on NEW_LEDS
|
||||
depends on LEDS_CLASS
|
||||
select POWER_SUPPLY
|
||||
---help---
|
||||
Support for
|
||||
|
||||
* Sony PS3 6-axis controllers
|
||||
* Sony PS4 DualShock 4 controllers
|
||||
* Buzz controllers
|
||||
* Sony PS3 Blue-ray Disk Remote Control (Bluetooth)
|
||||
* Logitech Harmony adapter for Sony Playstation 3 (Bluetooth)
|
||||
|
||||
config SONY_FF
|
||||
bool "Sony PS2/3 accessories force feedback support"
|
||||
bool "Sony PS2/3/4 accessories force feedback support"
|
||||
depends on HID_SONY
|
||||
select INPUT_FF_MEMLESS
|
||||
---help---
|
||||
Say Y here if you have a Sony PS2/3 accessory and want to enable force
|
||||
feedback support for it.
|
||||
Say Y here if you have a Sony PS2/3/4 accessory and want to enable
|
||||
force feedback support for it.
|
||||
|
||||
config HID_SPEEDLINK
|
||||
tristate "Speedlink VAD Cezanne mouse support"
|
||||
|
@ -41,6 +41,7 @@ obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
|
||||
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
|
||||
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
|
||||
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
|
||||
obj-$(CONFIG_HID_CP2112) += hid-cp2112.o
|
||||
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
|
||||
obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o
|
||||
obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o
|
||||
|
@ -1248,6 +1248,11 @@ void hid_output_report(struct hid_report *report, __u8 *data)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hid_output_report);
|
||||
|
||||
static int hid_report_len(struct hid_report *report)
|
||||
{
|
||||
return ((report->size - 1) >> 3) + 1 + (report->id > 0) + 7;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocator for buffer that is going to be passed to hid_output_report()
|
||||
*/
|
||||
@ -1258,7 +1263,7 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags)
|
||||
* of implement() working on 8 byte chunks
|
||||
*/
|
||||
|
||||
int len = ((report->size - 1) >> 3) + 1 + (report->id > 0) + 7;
|
||||
int len = hid_report_len(report);
|
||||
|
||||
return kmalloc(len, flags);
|
||||
}
|
||||
@ -1314,6 +1319,41 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
|
||||
return report;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement a generic .request() callback, using .raw_request()
|
||||
* DO NOT USE in hid drivers directly, but through hid_hw_request instead.
|
||||
*/
|
||||
void __hid_request(struct hid_device *hid, struct hid_report *report,
|
||||
int reqtype)
|
||||
{
|
||||
char *buf;
|
||||
int ret;
|
||||
int len;
|
||||
|
||||
buf = hid_alloc_report_buf(report, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
len = hid_report_len(report);
|
||||
|
||||
if (reqtype == HID_REQ_SET_REPORT)
|
||||
hid_output_report(report, buf);
|
||||
|
||||
ret = hid->ll_driver->raw_request(hid, report->id, buf, len,
|
||||
report->type, reqtype);
|
||||
if (ret < 0) {
|
||||
dbg_hid("unable to complete request: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (reqtype == HID_REQ_GET_REPORT)
|
||||
hid_input_report(hid, report->type, buf, ret, 0);
|
||||
|
||||
out:
|
||||
kfree(buf);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__hid_request);
|
||||
|
||||
int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
|
||||
int interrupt)
|
||||
{
|
||||
@ -1693,6 +1733,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
|
||||
@ -1782,6 +1823,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) },
|
||||
@ -2433,6 +2475,14 @@ int hid_add_device(struct hid_device *hdev)
|
||||
if (hid_ignore(hdev))
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* Check for the mandatory transport channel.
|
||||
*/
|
||||
if (!hdev->ll_driver->raw_request) {
|
||||
hid_err(hdev, "transport driver missing .raw_request()\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the device report descriptor once and use as template
|
||||
* for the driver-specific modifications.
|
||||
|
1073
drivers/hid/hid-cp2112.c
Normal file
1073
drivers/hid/hid-cp2112.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -460,12 +460,22 @@ static void mousevsc_hid_stop(struct hid_device *hid)
|
||||
{
|
||||
}
|
||||
|
||||
static int mousevsc_hid_raw_request(struct hid_device *hid,
|
||||
unsigned char report_num,
|
||||
__u8 *buf, size_t len,
|
||||
unsigned char rtype,
|
||||
int reqtype)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hid_ll_driver mousevsc_ll_driver = {
|
||||
.parse = mousevsc_hid_parse,
|
||||
.open = mousevsc_hid_open,
|
||||
.close = mousevsc_hid_close,
|
||||
.start = mousevsc_hid_start,
|
||||
.stop = mousevsc_hid_stop,
|
||||
.raw_request = mousevsc_hid_raw_request,
|
||||
};
|
||||
|
||||
static struct hid_driver mousevsc_hid_driver;
|
||||
|
@ -67,6 +67,9 @@
|
||||
#define USB_VENDOR_ID_ALPS 0x0433
|
||||
#define USB_DEVICE_ID_IBM_GAMEPAD 0x1101
|
||||
|
||||
#define USB_VENDOR_ID_ANTON 0x1130
|
||||
#define USB_DEVICE_ID_ANTON_TOUCH_PAD 0x3101
|
||||
|
||||
#define USB_VENDOR_ID_APPLE 0x05ac
|
||||
#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
|
||||
#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d
|
||||
@ -242,6 +245,7 @@
|
||||
#define USB_VENDOR_ID_CYGNAL 0x10c4
|
||||
#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a
|
||||
#define USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH 0x81b9
|
||||
#define USB_DEVICE_ID_CYGNAL_CP2112 0xea90
|
||||
|
||||
#define USB_DEVICE_ID_CYGNAL_RADIO_SI4713 0x8244
|
||||
|
||||
@ -616,6 +620,7 @@
|
||||
|
||||
#define USB_VENDOR_ID_MICROSOFT 0x045e
|
||||
#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
|
||||
#define USB_DEVICE_ID_MS_OFFICE_KB 0x0048
|
||||
#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
|
||||
#define USB_DEVICE_ID_MS_NE4K 0x00db
|
||||
#define USB_DEVICE_ID_MS_NE4K_JP 0x00dc
|
||||
|
@ -350,9 +350,9 @@ static int hidinput_get_battery_property(struct power_supply *psy,
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
ret = dev->hid_get_raw_report(dev, dev->battery_report_id,
|
||||
buf, 2,
|
||||
dev->battery_report_type);
|
||||
ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 2,
|
||||
dev->battery_report_type,
|
||||
HID_REQ_GET_REPORT);
|
||||
|
||||
if (ret != 2) {
|
||||
ret = -ENODATA;
|
||||
@ -789,10 +789,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
|
||||
case 0x199: map_key_clear(KEY_CHAT); break;
|
||||
case 0x19c: map_key_clear(KEY_LOGOFF); break;
|
||||
case 0x19e: map_key_clear(KEY_COFFEE); break;
|
||||
case 0x1a3: map_key_clear(KEY_NEXT); break;
|
||||
case 0x1a4: map_key_clear(KEY_PREVIOUS); break;
|
||||
case 0x1a6: map_key_clear(KEY_HELP); break;
|
||||
case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
|
||||
case 0x1ab: map_key_clear(KEY_SPELLCHECK); break;
|
||||
case 0x1ae: map_key_clear(KEY_KEYBOARD); break;
|
||||
case 0x1b4: map_key_clear(KEY_FILE); break;
|
||||
case 0x1b6: map_key_clear(KEY_IMAGES); break;
|
||||
case 0x1b7: map_key_clear(KEY_AUDIO); break;
|
||||
case 0x1b8: map_key_clear(KEY_VIDEO); break;
|
||||
@ -1150,7 +1153,7 @@ static void hidinput_led_worker(struct work_struct *work)
|
||||
led_work);
|
||||
struct hid_field *field;
|
||||
struct hid_report *report;
|
||||
int len;
|
||||
int len, ret;
|
||||
__u8 *buf;
|
||||
|
||||
field = hidinput_get_led_field(hid);
|
||||
@ -1184,7 +1187,10 @@ static void hidinput_led_worker(struct work_struct *work)
|
||||
|
||||
hid_output_report(report, buf);
|
||||
/* synchronous output report */
|
||||
hid->hid_output_raw_report(hid, buf, len, HID_OUTPUT_REPORT);
|
||||
ret = hid_hw_output_report(hid, buf, len);
|
||||
if (ret == -ENOSYS)
|
||||
hid_hw_raw_request(hid, report->id, buf, len, HID_OUTPUT_REPORT,
|
||||
HID_REQ_SET_REPORT);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
@ -1263,10 +1269,7 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
|
||||
}
|
||||
|
||||
input_set_drvdata(input_dev, hid);
|
||||
if (hid->ll_driver->hidinput_input_event)
|
||||
input_dev->event = hid->ll_driver->hidinput_input_event;
|
||||
else if (hid->ll_driver->request || hid->hid_output_raw_report)
|
||||
input_dev->event = hidinput_input_event;
|
||||
input_dev->event = hidinput_input_event;
|
||||
input_dev->open = hidinput_open;
|
||||
input_dev->close = hidinput_close;
|
||||
input_dev->setkeycode = hidinput_setkeycode;
|
||||
|
@ -692,7 +692,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) {
|
||||
unsigned char buf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
|
||||
ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
|
||||
if (ret >= 0) {
|
||||
/* insert a little delay of 10 jiffies ~ 40ms */
|
||||
@ -704,7 +705,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
buf[1] = 0xB2;
|
||||
get_random_bytes(&buf[2], 2);
|
||||
|
||||
ret = hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
|
||||
ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(buf),
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,14 +44,6 @@ static const char kbd_descriptor[] = {
|
||||
0x19, 0xE0, /* USAGE_MINIMUM (Left Control) */
|
||||
0x29, 0xE7, /* USAGE_MAXIMUM (Right GUI) */
|
||||
0x81, 0x02, /* INPUT (Data,Var,Abs) */
|
||||
0x95, 0x05, /* REPORT COUNT (5) */
|
||||
0x05, 0x08, /* USAGE PAGE (LED page) */
|
||||
0x19, 0x01, /* USAGE MINIMUM (1) */
|
||||
0x29, 0x05, /* USAGE MAXIMUM (5) */
|
||||
0x91, 0x02, /* OUTPUT (Data, Variable, Absolute) */
|
||||
0x95, 0x01, /* REPORT COUNT (1) */
|
||||
0x75, 0x03, /* REPORT SIZE (3) */
|
||||
0x91, 0x01, /* OUTPUT (Constant) */
|
||||
0x95, 0x06, /* REPORT_COUNT (6) */
|
||||
0x75, 0x08, /* REPORT_SIZE (8) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
@ -60,6 +52,18 @@ static const char kbd_descriptor[] = {
|
||||
0x19, 0x00, /* USAGE_MINIMUM (no event) */
|
||||
0x2A, 0xFF, 0x00, /* USAGE_MAXIMUM (reserved) */
|
||||
0x81, 0x00, /* INPUT (Data,Ary,Abs) */
|
||||
0x85, 0x0e, /* REPORT_ID (14) */
|
||||
0x05, 0x08, /* USAGE PAGE (LED page) */
|
||||
0x95, 0x05, /* REPORT COUNT (5) */
|
||||
0x75, 0x01, /* REPORT SIZE (1) */
|
||||
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
|
||||
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
|
||||
0x19, 0x01, /* USAGE MINIMUM (1) */
|
||||
0x29, 0x05, /* USAGE MAXIMUM (5) */
|
||||
0x91, 0x02, /* OUTPUT (Data, Variable, Absolute) */
|
||||
0x95, 0x01, /* REPORT COUNT (1) */
|
||||
0x75, 0x03, /* REPORT SIZE (3) */
|
||||
0x91, 0x01, /* OUTPUT (Constant) */
|
||||
0xC0
|
||||
};
|
||||
|
||||
@ -189,9 +193,6 @@ static const u8 hid_reportid_size_map[NUMBER_OF_HID_REPORTS] = {
|
||||
|
||||
static struct hid_ll_driver logi_dj_ll_driver;
|
||||
|
||||
static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
|
||||
size_t count,
|
||||
unsigned char report_type);
|
||||
static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
|
||||
|
||||
static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
|
||||
@ -258,7 +259,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
|
||||
}
|
||||
|
||||
dj_hiddev->ll_driver = &logi_dj_ll_driver;
|
||||
dj_hiddev->hid_output_raw_report = logi_dj_output_hidraw_report;
|
||||
|
||||
dj_hiddev->dev.parent = &djrcv_hdev->dev;
|
||||
dj_hiddev->bus = BUS_USB;
|
||||
@ -540,14 +540,35 @@ static void logi_dj_ll_close(struct hid_device *hid)
|
||||
dbg_hid("%s:%s\n", __func__, hid->phys);
|
||||
}
|
||||
|
||||
static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
|
||||
size_t count,
|
||||
unsigned char report_type)
|
||||
static int logi_dj_ll_raw_request(struct hid_device *hid,
|
||||
unsigned char reportnum, __u8 *buf,
|
||||
size_t count, unsigned char report_type,
|
||||
int reqtype)
|
||||
{
|
||||
/* Called by hid raw to send data */
|
||||
dbg_hid("%s\n", __func__);
|
||||
struct dj_device *djdev = hid->driver_data;
|
||||
struct dj_receiver_dev *djrcv_dev = djdev->dj_receiver_dev;
|
||||
u8 *out_buf;
|
||||
int ret;
|
||||
|
||||
return 0;
|
||||
if (buf[0] != REPORT_TYPE_LEDS)
|
||||
return -EINVAL;
|
||||
|
||||
out_buf = kzalloc(DJREPORT_SHORT_LENGTH, GFP_ATOMIC);
|
||||
if (!out_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (count < DJREPORT_SHORT_LENGTH - 2)
|
||||
count = DJREPORT_SHORT_LENGTH - 2;
|
||||
|
||||
out_buf[0] = REPORT_ID_DJ_SHORT;
|
||||
out_buf[1] = djdev->device_index;
|
||||
memcpy(out_buf + 2, buf, count);
|
||||
|
||||
ret = hid_hw_raw_request(djrcv_dev->hdev, out_buf[0], out_buf,
|
||||
DJREPORT_SHORT_LENGTH, report_type, reqtype);
|
||||
|
||||
kfree(out_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rdcat(char *rdesc, unsigned int *rsize, const char *data, unsigned int size)
|
||||
@ -613,58 +634,6 @@ static int logi_dj_ll_parse(struct hid_device *hid)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
|
||||
unsigned int code, int value)
|
||||
{
|
||||
/* Sent by the input layer to handle leds and Force Feedback */
|
||||
struct hid_device *dj_hiddev = input_get_drvdata(dev);
|
||||
struct dj_device *dj_dev = dj_hiddev->driver_data;
|
||||
|
||||
struct dj_receiver_dev *djrcv_dev =
|
||||
dev_get_drvdata(dj_hiddev->dev.parent);
|
||||
struct hid_device *dj_rcv_hiddev = djrcv_dev->hdev;
|
||||
struct hid_report_enum *output_report_enum;
|
||||
|
||||
struct hid_field *field;
|
||||
struct hid_report *report;
|
||||
unsigned char *data;
|
||||
int offset;
|
||||
|
||||
dbg_hid("%s: %s, type:%d | code:%d | value:%d\n",
|
||||
__func__, dev->phys, type, code, value);
|
||||
|
||||
if (type != EV_LED)
|
||||
return -1;
|
||||
|
||||
offset = hidinput_find_field(dj_hiddev, type, code, &field);
|
||||
|
||||
if (offset == -1) {
|
||||
dev_warn(&dev->dev, "event field not found\n");
|
||||
return -1;
|
||||
}
|
||||
hid_set_field(field, offset, value);
|
||||
|
||||
data = hid_alloc_report_buf(field->report, GFP_ATOMIC);
|
||||
if (!data) {
|
||||
dev_warn(&dev->dev, "failed to allocate report buf memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hid_output_report(field->report, &data[0]);
|
||||
|
||||
output_report_enum = &dj_rcv_hiddev->report_enum[HID_OUTPUT_REPORT];
|
||||
report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT];
|
||||
hid_set_field(report->field[0], 0, dj_dev->device_index);
|
||||
hid_set_field(report->field[0], 1, REPORT_TYPE_LEDS);
|
||||
hid_set_field(report->field[0], 2, data[1]);
|
||||
|
||||
hid_hw_request(dj_rcv_hiddev, report, HID_REQ_SET_REPORT);
|
||||
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int logi_dj_ll_start(struct hid_device *hid)
|
||||
{
|
||||
dbg_hid("%s\n", __func__);
|
||||
@ -683,7 +652,7 @@ static struct hid_ll_driver logi_dj_ll_driver = {
|
||||
.stop = logi_dj_ll_stop,
|
||||
.open = logi_dj_ll_open,
|
||||
.close = logi_dj_ll_close,
|
||||
.hidinput_input_event = logi_dj_ll_input_event,
|
||||
.raw_request = logi_dj_ll_raw_request,
|
||||
};
|
||||
|
||||
|
||||
|
@ -538,8 +538,8 @@ static int magicmouse_probe(struct hid_device *hdev,
|
||||
* but there seems to be no other way of switching the mode.
|
||||
* Thus the super-ugly hacky success check below.
|
||||
*/
|
||||
ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature),
|
||||
HID_FEATURE_REPORT);
|
||||
ret = hid_hw_raw_request(hdev, feature[0], feature, sizeof(feature),
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
if (ret != -EIO && ret != sizeof(feature)) {
|
||||
hid_err(hdev, "unable to request touch data (%d)\n", ret);
|
||||
goto err_stop_hw;
|
||||
|
@ -62,9 +62,48 @@ static int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage,
|
||||
{
|
||||
struct input_dev *input = hi->input;
|
||||
|
||||
if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) {
|
||||
switch (usage->hid & HID_USAGE) {
|
||||
/*
|
||||
* Microsoft uses these 2 reserved usage ids for 2 keys on
|
||||
* the MS office kb labelled "Office Home" and "Task Pane".
|
||||
*/
|
||||
case 0x29d:
|
||||
ms_map_key_clear(KEY_PROG1);
|
||||
return 1;
|
||||
case 0x29e:
|
||||
ms_map_key_clear(KEY_PROG2);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
|
||||
return 0;
|
||||
|
||||
switch (usage->hid & HID_USAGE) {
|
||||
case 0xfd06: ms_map_key_clear(KEY_CHAT); break;
|
||||
case 0xfd07: ms_map_key_clear(KEY_PHONE); break;
|
||||
case 0xff00:
|
||||
/* Special keypad keys */
|
||||
ms_map_key_clear(KEY_KPEQUAL);
|
||||
set_bit(KEY_KPLEFTPAREN, input->keybit);
|
||||
set_bit(KEY_KPRIGHTPAREN, input->keybit);
|
||||
break;
|
||||
case 0xff01:
|
||||
/* Scroll wheel */
|
||||
hid_map_usage_clear(hi, usage, bit, max, EV_REL, REL_WHEEL);
|
||||
break;
|
||||
case 0xff02:
|
||||
/*
|
||||
* This byte contains a copy of the modifier keys byte of a
|
||||
* standard hid keyboard report, as send by interface 0
|
||||
* (this usage is found on interface 1).
|
||||
*
|
||||
* This byte only gets send when another key in the same report
|
||||
* changes state, and as such is useless, ignore it.
|
||||
*/
|
||||
return -1;
|
||||
case 0xff05:
|
||||
set_bit(EV_REP, input->evbit);
|
||||
ms_map_key_clear(KEY_F13);
|
||||
@ -83,6 +122,9 @@ static int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage,
|
||||
static int ms_presenter_8k_quirk(struct hid_input *hi, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
|
||||
return 0;
|
||||
|
||||
set_bit(EV_REP, hi->input->evbit);
|
||||
switch (usage->hid & HID_USAGE) {
|
||||
case 0xfd08: ms_map_key_clear(KEY_FORWARD); break;
|
||||
@ -102,9 +144,6 @@ static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
{
|
||||
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
|
||||
|
||||
if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
|
||||
return 0;
|
||||
|
||||
if (quirks & MS_ERGONOMY) {
|
||||
int ret = ms_ergonomy_kb_quirk(hi, usage, bit, max);
|
||||
if (ret)
|
||||
@ -134,14 +173,39 @@ static int ms_event(struct hid_device *hdev, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
|
||||
struct input_dev *input;
|
||||
|
||||
if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
|
||||
!usage->type)
|
||||
return 0;
|
||||
|
||||
input = field->hidinput->input;
|
||||
|
||||
/* Handling MS keyboards special buttons */
|
||||
if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff00)) {
|
||||
/* Special keypad keys */
|
||||
input_report_key(input, KEY_KPEQUAL, value & 0x01);
|
||||
input_report_key(input, KEY_KPLEFTPAREN, value & 0x02);
|
||||
input_report_key(input, KEY_KPRIGHTPAREN, value & 0x04);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff01)) {
|
||||
/* Scroll wheel */
|
||||
int step = ((value & 0x60) >> 5) + 1;
|
||||
|
||||
switch (value & 0x1f) {
|
||||
case 0x01:
|
||||
input_report_rel(input, REL_WHEEL, step);
|
||||
break;
|
||||
case 0x1f:
|
||||
input_report_rel(input, REL_WHEEL, -step);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff05)) {
|
||||
struct input_dev *input = field->hidinput->input;
|
||||
static unsigned int last_key = 0;
|
||||
unsigned int key = 0;
|
||||
switch (value) {
|
||||
@ -194,6 +258,8 @@ err_free:
|
||||
static const struct hid_device_id ms_devices[] = {
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV),
|
||||
.driver_data = MS_HIDINPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB),
|
||||
.driver_data = MS_ERGONOMY },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K),
|
||||
.driver_data = MS_ERGONOMY },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP),
|
||||
|
@ -68,6 +68,9 @@ MODULE_LICENSE("GPL");
|
||||
#define MT_QUIRK_HOVERING (1 << 11)
|
||||
#define MT_QUIRK_CONTACT_CNT_ACCURATE (1 << 12)
|
||||
|
||||
#define MT_INPUTMODE_TOUCHSCREEN 0x02
|
||||
#define MT_INPUTMODE_TOUCHPAD 0x03
|
||||
|
||||
struct mt_slot {
|
||||
__s32 x, y, cx, cy, p, w, h;
|
||||
__s32 contactid; /* the device ContactID assigned to this slot */
|
||||
@ -84,6 +87,7 @@ struct mt_class {
|
||||
__s32 sn_pressure; /* Signal/noise ratio for pressure events */
|
||||
__u8 maxcontacts;
|
||||
bool is_indirect; /* true for touchpads */
|
||||
bool export_all_inputs; /* do not ignore mouse, keyboards, etc... */
|
||||
};
|
||||
|
||||
struct mt_fields {
|
||||
@ -100,11 +104,11 @@ struct mt_device {
|
||||
int cc_value_index; /* contact count value index in the field */
|
||||
unsigned last_slot_field; /* the last field of a slot */
|
||||
unsigned mt_report_id; /* the report ID of the multitouch device */
|
||||
unsigned pen_report_id; /* the report ID of the pen device */
|
||||
__s16 inputmode; /* InputMode HID feature, -1 if non-existent */
|
||||
__s16 inputmode_index; /* InputMode HID feature index in the report */
|
||||
__s16 maxcontact_report_id; /* Maximum Contact Number HID feature,
|
||||
-1 if non-existent */
|
||||
__u8 inputmode_value; /* InputMode HID feature value */
|
||||
__u8 num_received; /* how many contacts we received */
|
||||
__u8 num_expected; /* expected last contact index */
|
||||
__u8 maxcontacts;
|
||||
@ -128,16 +132,17 @@ static void mt_post_parse(struct mt_device *td);
|
||||
#define MT_CLS_CONFIDENCE_MINUS_ONE 0x0005
|
||||
#define MT_CLS_DUAL_INRANGE_CONTACTID 0x0006
|
||||
#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0007
|
||||
#define MT_CLS_DUAL_NSMU_CONTACTID 0x0008
|
||||
/* reserved 0x0008 */
|
||||
#define MT_CLS_INRANGE_CONTACTNUMBER 0x0009
|
||||
#define MT_CLS_NSMU 0x000a
|
||||
#define MT_CLS_DUAL_CONTACT_NUMBER 0x0010
|
||||
#define MT_CLS_DUAL_CONTACT_ID 0x0011
|
||||
/* reserved 0x0010 */
|
||||
/* reserved 0x0011 */
|
||||
#define MT_CLS_WIN_8 0x0012
|
||||
#define MT_CLS_EXPORT_ALL_INPUTS 0x0013
|
||||
|
||||
/* vendor specific classes */
|
||||
#define MT_CLS_3M 0x0101
|
||||
#define MT_CLS_CYPRESS 0x0102
|
||||
/* reserved 0x0102 */
|
||||
#define MT_CLS_EGALAX 0x0103
|
||||
#define MT_CLS_EGALAX_SERIAL 0x0104
|
||||
#define MT_CLS_TOPSEED 0x0105
|
||||
@ -189,28 +194,18 @@ static struct mt_class mt_classes[] = {
|
||||
.quirks = MT_QUIRK_VALID_IS_INRANGE |
|
||||
MT_QUIRK_SLOT_IS_CONTACTNUMBER,
|
||||
.maxcontacts = 2 },
|
||||
{ .name = MT_CLS_DUAL_NSMU_CONTACTID,
|
||||
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
|
||||
MT_QUIRK_SLOT_IS_CONTACTID,
|
||||
.maxcontacts = 2 },
|
||||
{ .name = MT_CLS_INRANGE_CONTACTNUMBER,
|
||||
.quirks = MT_QUIRK_VALID_IS_INRANGE |
|
||||
MT_QUIRK_SLOT_IS_CONTACTNUMBER },
|
||||
{ .name = MT_CLS_DUAL_CONTACT_NUMBER,
|
||||
.quirks = MT_QUIRK_ALWAYS_VALID |
|
||||
MT_QUIRK_CONTACT_CNT_ACCURATE |
|
||||
MT_QUIRK_SLOT_IS_CONTACTNUMBER,
|
||||
.maxcontacts = 2 },
|
||||
{ .name = MT_CLS_DUAL_CONTACT_ID,
|
||||
.quirks = MT_QUIRK_ALWAYS_VALID |
|
||||
MT_QUIRK_CONTACT_CNT_ACCURATE |
|
||||
MT_QUIRK_SLOT_IS_CONTACTID,
|
||||
.maxcontacts = 2 },
|
||||
{ .name = MT_CLS_WIN_8,
|
||||
.quirks = MT_QUIRK_ALWAYS_VALID |
|
||||
MT_QUIRK_IGNORE_DUPLICATES |
|
||||
MT_QUIRK_HOVERING |
|
||||
MT_QUIRK_CONTACT_CNT_ACCURATE },
|
||||
{ .name = MT_CLS_EXPORT_ALL_INPUTS,
|
||||
.quirks = MT_QUIRK_ALWAYS_VALID |
|
||||
MT_QUIRK_CONTACT_CNT_ACCURATE,
|
||||
.export_all_inputs = true },
|
||||
|
||||
/*
|
||||
* vendor specific classes
|
||||
@ -223,10 +218,6 @@ static struct mt_class mt_classes[] = {
|
||||
.sn_height = 128,
|
||||
.maxcontacts = 60,
|
||||
},
|
||||
{ .name = MT_CLS_CYPRESS,
|
||||
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
|
||||
MT_QUIRK_CYPRESS,
|
||||
.maxcontacts = 10 },
|
||||
{ .name = MT_CLS_EGALAX,
|
||||
.quirks = MT_QUIRK_SLOT_IS_CONTACTID |
|
||||
MT_QUIRK_VALID_IS_INRANGE,
|
||||
@ -360,45 +351,6 @@ static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
|
||||
f->usages[f->length++] = usage->hid;
|
||||
}
|
||||
|
||||
static int mt_pen_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
struct hid_field *field, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
struct mt_device *td = hid_get_drvdata(hdev);
|
||||
|
||||
td->pen_report_id = field->report->id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt_pen_input_mapped(struct hid_device *hdev, struct hid_input *hi,
|
||||
struct hid_field *field, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt_pen_event(struct hid_device *hid, struct hid_field *field,
|
||||
struct hid_usage *usage, __s32 value)
|
||||
{
|
||||
/* let hid-input handle it */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mt_pen_report(struct hid_device *hid, struct hid_report *report)
|
||||
{
|
||||
struct hid_field *field = report->field[0];
|
||||
|
||||
input_sync(field->hidinput->input);
|
||||
}
|
||||
|
||||
static void mt_pen_input_configured(struct hid_device *hdev,
|
||||
struct hid_input *hi)
|
||||
{
|
||||
/* force BTN_STYLUS to allow tablet matching in udev */
|
||||
__set_bit(BTN_STYLUS, hi->input->keybit);
|
||||
}
|
||||
|
||||
static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
struct hid_field *field, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
@ -415,8 +367,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
* Model touchscreens providing buttons as touchpads.
|
||||
*/
|
||||
if (field->application == HID_DG_TOUCHPAD ||
|
||||
(usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
|
||||
(usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
|
||||
td->mt_flags |= INPUT_MT_POINTER;
|
||||
td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
|
||||
}
|
||||
|
||||
if (usage->usage_index)
|
||||
prev_usage = &field->usage[usage->usage_index - 1];
|
||||
@ -776,28 +730,52 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
||||
struct hid_field *field, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
/* Only map fields from TouchScreen or TouchPad collections.
|
||||
* We need to ignore fields that belong to other collections
|
||||
* such as Mouse that might have the same GenericDesktop usages. */
|
||||
if (field->application != HID_DG_TOUCHSCREEN &&
|
||||
struct mt_device *td = hid_get_drvdata(hdev);
|
||||
|
||||
/*
|
||||
* If mtclass.export_all_inputs is not set, only map fields from
|
||||
* TouchScreen or TouchPad collections. We need to ignore fields
|
||||
* that belong to other collections such as Mouse that might have
|
||||
* the same GenericDesktop usages.
|
||||
*/
|
||||
if (!td->mtclass.export_all_inputs &&
|
||||
field->application != HID_DG_TOUCHSCREEN &&
|
||||
field->application != HID_DG_PEN &&
|
||||
field->application != HID_DG_TOUCHPAD)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
|
||||
* for the stylus.
|
||||
*/
|
||||
if (field->physical == HID_DG_STYLUS)
|
||||
return mt_pen_input_mapping(hdev, hi, field, usage, bit, max);
|
||||
return 0;
|
||||
|
||||
return mt_touch_input_mapping(hdev, hi, field, usage, bit, max);
|
||||
if (field->application == HID_DG_TOUCHSCREEN ||
|
||||
field->application == HID_DG_TOUCHPAD)
|
||||
return mt_touch_input_mapping(hdev, hi, field, usage, bit, max);
|
||||
|
||||
/* let hid-core decide for the others */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
|
||||
struct hid_field *field, struct hid_usage *usage,
|
||||
unsigned long **bit, int *max)
|
||||
{
|
||||
/*
|
||||
* some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
|
||||
* for the stylus.
|
||||
*/
|
||||
if (field->physical == HID_DG_STYLUS)
|
||||
return mt_pen_input_mapped(hdev, hi, field, usage, bit, max);
|
||||
return 0;
|
||||
|
||||
return mt_touch_input_mapped(hdev, hi, field, usage, bit, max);
|
||||
if (field->application == HID_DG_TOUCHSCREEN ||
|
||||
field->application == HID_DG_TOUCHPAD)
|
||||
return mt_touch_input_mapped(hdev, hi, field, usage, bit, max);
|
||||
|
||||
/* let hid-core decide for the others */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt_event(struct hid_device *hid, struct hid_field *field,
|
||||
@ -808,25 +786,22 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
|
||||
if (field->report->id == td->mt_report_id)
|
||||
return mt_touch_event(hid, field, usage, value);
|
||||
|
||||
if (field->report->id == td->pen_report_id)
|
||||
return mt_pen_event(hid, field, usage, value);
|
||||
|
||||
/* ignore other reports */
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mt_report(struct hid_device *hid, struct hid_report *report)
|
||||
{
|
||||
struct mt_device *td = hid_get_drvdata(hid);
|
||||
struct hid_field *field = report->field[0];
|
||||
|
||||
if (!(hid->claimed & HID_CLAIMED_INPUT))
|
||||
return;
|
||||
|
||||
if (report->id == td->mt_report_id)
|
||||
mt_touch_report(hid, report);
|
||||
return mt_touch_report(hid, report);
|
||||
|
||||
if (report->id == td->pen_report_id)
|
||||
mt_pen_report(hid, report);
|
||||
if (field && field->hidinput && field->hidinput->input)
|
||||
input_sync(field->hidinput->input);
|
||||
}
|
||||
|
||||
static void mt_set_input_mode(struct hid_device *hdev)
|
||||
@ -841,7 +816,7 @@ static void mt_set_input_mode(struct hid_device *hdev)
|
||||
re = &(hdev->report_enum[HID_FEATURE_REPORT]);
|
||||
r = re->report_id_hash[td->inputmode];
|
||||
if (r) {
|
||||
r->field[0]->value[td->inputmode_index] = 0x02;
|
||||
r->field[0]->value[td->inputmode_index] = td->inputmode_value;
|
||||
hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
|
||||
}
|
||||
}
|
||||
@ -907,13 +882,49 @@ static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
||||
struct mt_device *td = hid_get_drvdata(hdev);
|
||||
char *name;
|
||||
const char *suffix = NULL;
|
||||
struct hid_field *field = hi->report->field[0];
|
||||
|
||||
if (hi->report->id == td->mt_report_id)
|
||||
mt_touch_input_configured(hdev, hi);
|
||||
|
||||
/*
|
||||
* some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
|
||||
* for the stylus. Check this first, and then rely on the application
|
||||
* field.
|
||||
*/
|
||||
if (hi->report->field[0]->physical == HID_DG_STYLUS) {
|
||||
suffix = "Pen";
|
||||
mt_pen_input_configured(hdev, hi);
|
||||
/* force BTN_STYLUS to allow tablet matching in udev */
|
||||
__set_bit(BTN_STYLUS, hi->input->keybit);
|
||||
} else {
|
||||
switch (field->application) {
|
||||
case HID_GD_KEYBOARD:
|
||||
suffix = "Keyboard";
|
||||
break;
|
||||
case HID_GD_KEYPAD:
|
||||
suffix = "Keypad";
|
||||
break;
|
||||
case HID_GD_MOUSE:
|
||||
suffix = "Mouse";
|
||||
break;
|
||||
case HID_DG_STYLUS:
|
||||
suffix = "Pen";
|
||||
/* force BTN_STYLUS to allow tablet matching in udev */
|
||||
__set_bit(BTN_STYLUS, hi->input->keybit);
|
||||
break;
|
||||
case HID_DG_TOUCHSCREEN:
|
||||
/* we do not set suffix = "Touchscreen" */
|
||||
break;
|
||||
case HID_GD_SYSTEM_CONTROL:
|
||||
suffix = "System Control";
|
||||
break;
|
||||
case HID_CP_CONSUMER_CONTROL:
|
||||
suffix = "Consumer Control";
|
||||
break;
|
||||
default:
|
||||
suffix = "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (suffix) {
|
||||
@ -973,9 +984,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
||||
td->mtclass = *mtclass;
|
||||
td->inputmode = -1;
|
||||
td->maxcontact_report_id = -1;
|
||||
td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
|
||||
td->cc_index = -1;
|
||||
td->mt_report_id = -1;
|
||||
td->pen_report_id = -1;
|
||||
hid_set_drvdata(hdev, td);
|
||||
|
||||
td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields),
|
||||
@ -1034,6 +1045,12 @@ static void mt_remove(struct hid_device *hdev)
|
||||
hid_hw_stop(hdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* This list contains only:
|
||||
* - VID/PID of products not working with the default multitouch handling
|
||||
* - 2 generic rules.
|
||||
* So there is no point in adding here any device with MT_CLS_DEFAULT.
|
||||
*/
|
||||
static const struct hid_device_id mt_devices[] = {
|
||||
|
||||
/* 3M panels */
|
||||
@ -1047,15 +1064,12 @@ static const struct hid_device_id mt_devices[] = {
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_3M,
|
||||
USB_DEVICE_ID_3M3266) },
|
||||
|
||||
/* ActionStar panels */
|
||||
{ .driver_data = MT_CLS_NSMU,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR,
|
||||
USB_DEVICE_ID_ACTIONSTAR_1011) },
|
||||
/* Anton devices */
|
||||
{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_ANTON,
|
||||
USB_DEVICE_ID_ANTON_TOUCH_PAD) },
|
||||
|
||||
/* Atmel panels */
|
||||
{ .driver_data = MT_CLS_SERIAL,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_ATMEL,
|
||||
USB_DEVICE_ID_ATMEL_MULTITOUCH) },
|
||||
{ .driver_data = MT_CLS_SERIAL,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_ATMEL,
|
||||
USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) },
|
||||
@ -1064,16 +1078,11 @@ static const struct hid_device_id mt_devices[] = {
|
||||
{ .driver_data = MT_CLS_NSMU,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_BAANTO,
|
||||
USB_DEVICE_ID_BAANTO_MT_190W2) },
|
||||
|
||||
/* Cando panels */
|
||||
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
|
||||
USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
|
||||
{ .driver_data = MT_CLS_DUAL_CONTACT_NUMBER,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
|
||||
USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
|
||||
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
|
||||
USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
|
||||
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
|
||||
USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
|
||||
@ -1088,16 +1097,6 @@ static const struct hid_device_id mt_devices[] = {
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
|
||||
USB_DEVICE_ID_CVTOUCH_SCREEN) },
|
||||
|
||||
/* Cypress panel */
|
||||
{ .driver_data = MT_CLS_CYPRESS,
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS,
|
||||
USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
|
||||
|
||||
/* Data Modul easyMaxTouch */
|
||||
{ .driver_data = MT_CLS_DEFAULT,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_DATA_MODUL,
|
||||
USB_VENDOR_ID_DATA_MODUL_EASYMAXTOUCH) },
|
||||
|
||||
/* eGalax devices (resistive) */
|
||||
{ .driver_data = MT_CLS_EGALAX,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
|
||||
@ -1156,11 +1155,6 @@ static const struct hid_device_id mt_devices[] = {
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
|
||||
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
|
||||
|
||||
/* Elo TouchSystems IntelliTouch Plus panel */
|
||||
{ .driver_data = MT_CLS_DUAL_CONTACT_ID,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_ELO,
|
||||
USB_DEVICE_ID_ELO_TS2515) },
|
||||
|
||||
/* Flatfrog Panels */
|
||||
{ .driver_data = MT_CLS_FLATFROG,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG,
|
||||
@ -1209,37 +1203,11 @@ static const struct hid_device_id mt_devices[] = {
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT,
|
||||
USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) },
|
||||
|
||||
/* Ideacom panel */
|
||||
{ .driver_data = MT_CLS_SERIAL,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
|
||||
USB_DEVICE_ID_IDEACOM_IDC6650) },
|
||||
{ .driver_data = MT_CLS_SERIAL,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
|
||||
USB_DEVICE_ID_IDEACOM_IDC6651) },
|
||||
|
||||
/* Ilitek dual touch panel */
|
||||
{ .driver_data = MT_CLS_NSMU,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_ILITEK,
|
||||
USB_DEVICE_ID_ILITEK_MULTITOUCH) },
|
||||
|
||||
/* IRTOUCH panels */
|
||||
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
|
||||
USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
|
||||
|
||||
/* LG Display panels */
|
||||
{ .driver_data = MT_CLS_DEFAULT,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_LG,
|
||||
USB_DEVICE_ID_LG_MULTITOUCH) },
|
||||
|
||||
/* Lumio panels */
|
||||
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_LUMIO,
|
||||
USB_DEVICE_ID_CRYSTALTOUCH) },
|
||||
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_LUMIO,
|
||||
USB_DEVICE_ID_CRYSTALTOUCH_DUAL) },
|
||||
|
||||
/* MosArt panels */
|
||||
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_ASUS,
|
||||
@ -1251,11 +1219,6 @@ static const struct hid_device_id mt_devices[] = {
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_TURBOX,
|
||||
USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
|
||||
|
||||
/* Nexio panels */
|
||||
{ .driver_data = MT_CLS_DEFAULT,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_NEXIO,
|
||||
USB_DEVICE_ID_NEXIO_MULTITOUCH_420)},
|
||||
|
||||
/* Panasonic panels */
|
||||
{ .driver_data = MT_CLS_PANASONIC,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
|
||||
@ -1269,11 +1232,6 @@ static const struct hid_device_id mt_devices[] = {
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK,
|
||||
USB_DEVICE_ID_NOVATEK_PCT) },
|
||||
|
||||
/* PenMount panels */
|
||||
{ .driver_data = MT_CLS_CONFIDENCE,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_PENMOUNT,
|
||||
USB_DEVICE_ID_PENMOUNT_PCI) },
|
||||
|
||||
/* PixArt optical touch screen */
|
||||
{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
|
||||
@ -1286,45 +1244,19 @@ static const struct hid_device_id mt_devices[] = {
|
||||
USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) },
|
||||
|
||||
/* PixCir-based panels */
|
||||
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_HANVON,
|
||||
USB_DEVICE_ID_HANVON_MULTITOUCH) },
|
||||
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
|
||||
USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
|
||||
|
||||
/* Quanta-based panels */
|
||||
{ .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
|
||||
USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
|
||||
{ .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
|
||||
USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) },
|
||||
{ .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
|
||||
USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008) },
|
||||
|
||||
/* SiS panels */
|
||||
{ .driver_data = MT_CLS_DEFAULT,
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH,
|
||||
USB_DEVICE_ID_SIS9200_TOUCH) },
|
||||
{ .driver_data = MT_CLS_DEFAULT,
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH,
|
||||
USB_DEVICE_ID_SIS817_TOUCH) },
|
||||
{ .driver_data = MT_CLS_DEFAULT,
|
||||
HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH,
|
||||
USB_DEVICE_ID_SIS1030_TOUCH) },
|
||||
|
||||
/* Stantum panels */
|
||||
{ .driver_data = MT_CLS_CONFIDENCE,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_STANTUM,
|
||||
USB_DEVICE_ID_MTP)},
|
||||
{ .driver_data = MT_CLS_CONFIDENCE,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
|
||||
USB_DEVICE_ID_MTP_STM)},
|
||||
{ .driver_data = MT_CLS_DEFAULT,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX,
|
||||
USB_DEVICE_ID_MTP_SITRONIX)},
|
||||
|
||||
/* TopSeed panels */
|
||||
{ .driver_data = MT_CLS_TOPSEED,
|
||||
@ -1383,11 +1315,6 @@ static const struct hid_device_id mt_devices[] = {
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
|
||||
USB_DEVICE_ID_XIROKU_CSR2) },
|
||||
|
||||
/* Zytronic panels */
|
||||
{ .driver_data = MT_CLS_SERIAL,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_ZYTRONIC,
|
||||
USB_DEVICE_ID_ZYTRONIC_ZXY100) },
|
||||
|
||||
/* Generic MT device */
|
||||
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },
|
||||
|
||||
|
@ -56,9 +56,9 @@ struct sensor_hub_pending {
|
||||
* @dyn_callback_lock: spin lock to protect callback list
|
||||
* @hid_sensor_hub_client_devs: Stores all MFD cells for a hub instance.
|
||||
* @hid_sensor_client_cnt: Number of MFD cells, (no of sensors attached).
|
||||
* @ref_cnt: Number of MFD clients have opened this device
|
||||
*/
|
||||
struct sensor_hub_data {
|
||||
struct hid_sensor_hub_device *hsdev;
|
||||
struct mutex mutex;
|
||||
spinlock_t lock;
|
||||
struct sensor_hub_pending pending;
|
||||
@ -67,6 +67,7 @@ struct sensor_hub_data {
|
||||
struct mfd_cell *hid_sensor_hub_client_devs;
|
||||
int hid_sensor_client_cnt;
|
||||
unsigned long quirks;
|
||||
int ref_cnt;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -79,6 +80,7 @@ struct sensor_hub_data {
|
||||
struct hid_sensor_hub_callbacks_list {
|
||||
struct list_head list;
|
||||
u32 usage_id;
|
||||
struct hid_sensor_hub_device *hsdev;
|
||||
struct hid_sensor_hub_callbacks *usage_callback;
|
||||
void *priv;
|
||||
};
|
||||
@ -97,20 +99,18 @@ static struct hid_report *sensor_hub_report(int id, struct hid_device *hdev,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int sensor_hub_get_physical_device_count(
|
||||
struct hid_report_enum *report_enum)
|
||||
static int sensor_hub_get_physical_device_count(struct hid_device *hdev)
|
||||
{
|
||||
struct hid_report *report;
|
||||
struct hid_field *field;
|
||||
int cnt = 0;
|
||||
int i;
|
||||
int count = 0;
|
||||
|
||||
list_for_each_entry(report, &report_enum->report_list, list) {
|
||||
field = report->field[0];
|
||||
if (report->maxfield && field && field->physical)
|
||||
cnt++;
|
||||
for (i = 0; i < hdev->maxcollection; ++i) {
|
||||
struct hid_collection *collection = &hdev->collection[i];
|
||||
if (collection->type == HID_COLLECTION_PHYSICAL)
|
||||
++count;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
return count;
|
||||
}
|
||||
|
||||
static void sensor_hub_fill_attr_info(
|
||||
@ -128,15 +128,23 @@ static void sensor_hub_fill_attr_info(
|
||||
|
||||
static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
|
||||
struct hid_device *hdev,
|
||||
u32 usage_id, void **priv)
|
||||
u32 usage_id,
|
||||
int collection_index,
|
||||
struct hid_sensor_hub_device **hsdev,
|
||||
void **priv)
|
||||
{
|
||||
struct hid_sensor_hub_callbacks_list *callback;
|
||||
struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
|
||||
|
||||
spin_lock(&pdata->dyn_callback_lock);
|
||||
list_for_each_entry(callback, &pdata->dyn_callback_list, list)
|
||||
if (callback->usage_id == usage_id) {
|
||||
if (callback->usage_id == usage_id &&
|
||||
(collection_index >=
|
||||
callback->hsdev->start_collection_index) &&
|
||||
(collection_index <
|
||||
callback->hsdev->end_collection_index)) {
|
||||
*priv = callback->priv;
|
||||
*hsdev = callback->hsdev;
|
||||
spin_unlock(&pdata->dyn_callback_lock);
|
||||
return callback->usage_callback;
|
||||
}
|
||||
@ -154,7 +162,8 @@ int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
|
||||
|
||||
spin_lock(&pdata->dyn_callback_lock);
|
||||
list_for_each_entry(callback, &pdata->dyn_callback_list, list)
|
||||
if (callback->usage_id == usage_id) {
|
||||
if (callback->usage_id == usage_id &&
|
||||
callback->hsdev == hsdev) {
|
||||
spin_unlock(&pdata->dyn_callback_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -163,6 +172,7 @@ int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
|
||||
spin_unlock(&pdata->dyn_callback_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
callback->hsdev = hsdev;
|
||||
callback->usage_callback = usage_callback;
|
||||
callback->usage_id = usage_id;
|
||||
callback->priv = NULL;
|
||||
@ -181,7 +191,8 @@ int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
|
||||
|
||||
spin_lock(&pdata->dyn_callback_lock);
|
||||
list_for_each_entry(callback, &pdata->dyn_callback_list, list)
|
||||
if (callback->usage_id == usage_id) {
|
||||
if (callback->usage_id == usage_id &&
|
||||
callback->hsdev == hsdev) {
|
||||
list_del(&callback->list);
|
||||
kfree(callback);
|
||||
break;
|
||||
@ -260,13 +271,12 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
|
||||
|
||||
spin_lock_irqsave(&data->lock, flags);
|
||||
data->pending.status = true;
|
||||
report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT);
|
||||
if (!report) {
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
goto err_free;
|
||||
}
|
||||
hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT);
|
||||
if (!report)
|
||||
goto err_free;
|
||||
|
||||
hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
|
||||
wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5);
|
||||
switch (data->pending.raw_size) {
|
||||
case 1:
|
||||
@ -291,6 +301,28 @@ err_free:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sensor_hub_input_attr_get_raw_value);
|
||||
|
||||
int hid_sensor_get_usage_index(struct hid_sensor_hub_device *hsdev,
|
||||
u32 report_id, int field_index, u32 usage_id)
|
||||
{
|
||||
struct hid_report *report;
|
||||
struct hid_field *field;
|
||||
int i;
|
||||
|
||||
report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT);
|
||||
if (!report || (field_index >= report->maxfield))
|
||||
goto done_proc;
|
||||
|
||||
field = report->field[field_index];
|
||||
for (i = 0; i < field->maxusage; ++i) {
|
||||
if (field->usage[i].hid == usage_id)
|
||||
return field->usage[i].usage_index;
|
||||
}
|
||||
|
||||
done_proc:
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hid_sensor_get_usage_index);
|
||||
|
||||
int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
|
||||
u8 type,
|
||||
u32 usage_id,
|
||||
@ -298,8 +330,7 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
|
||||
struct hid_sensor_hub_attribute_info *info)
|
||||
{
|
||||
int ret = -1;
|
||||
int i, j;
|
||||
int collection_index = -1;
|
||||
int i;
|
||||
struct hid_report *report;
|
||||
struct hid_field *field;
|
||||
struct hid_report_enum *report_enum;
|
||||
@ -313,44 +344,31 @@ int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
|
||||
info->units = -1;
|
||||
info->unit_expo = -1;
|
||||
|
||||
for (i = 0; i < hdev->maxcollection; ++i) {
|
||||
struct hid_collection *collection = &hdev->collection[i];
|
||||
if (usage_id == collection->usage) {
|
||||
collection_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (collection_index == -1)
|
||||
goto err_ret;
|
||||
|
||||
report_enum = &hdev->report_enum[type];
|
||||
list_for_each_entry(report, &report_enum->report_list, list) {
|
||||
for (i = 0; i < report->maxfield; ++i) {
|
||||
field = report->field[i];
|
||||
if (field->physical == usage_id &&
|
||||
field->logical == attr_usage_id) {
|
||||
sensor_hub_fill_attr_info(info, i, report->id,
|
||||
field);
|
||||
ret = 0;
|
||||
} else {
|
||||
for (j = 0; j < field->maxusage; ++j) {
|
||||
if (field->usage[j].hid ==
|
||||
attr_usage_id &&
|
||||
field->usage[j].collection_index ==
|
||||
collection_index) {
|
||||
sensor_hub_fill_attr_info(info,
|
||||
i, report->id, field);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
if (field->maxusage) {
|
||||
if (field->physical == usage_id &&
|
||||
(field->logical == attr_usage_id ||
|
||||
field->usage[0].hid ==
|
||||
attr_usage_id) &&
|
||||
(field->usage[0].collection_index >=
|
||||
hsdev->start_collection_index) &&
|
||||
(field->usage[0].collection_index <
|
||||
hsdev->end_collection_index)) {
|
||||
|
||||
sensor_hub_fill_attr_info(info, i,
|
||||
report->id,
|
||||
field);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
err_ret:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sensor_hub_input_get_attribute_info);
|
||||
@ -366,7 +384,7 @@ static int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message)
|
||||
list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
|
||||
if (callback->usage_callback->suspend)
|
||||
callback->usage_callback->suspend(
|
||||
pdata->hsdev, callback->priv);
|
||||
callback->hsdev, callback->priv);
|
||||
}
|
||||
spin_unlock(&pdata->dyn_callback_lock);
|
||||
|
||||
@ -383,7 +401,7 @@ static int sensor_hub_resume(struct hid_device *hdev)
|
||||
list_for_each_entry(callback, &pdata->dyn_callback_list, list) {
|
||||
if (callback->usage_callback->resume)
|
||||
callback->usage_callback->resume(
|
||||
pdata->hsdev, callback->priv);
|
||||
callback->hsdev, callback->priv);
|
||||
}
|
||||
spin_unlock(&pdata->dyn_callback_lock);
|
||||
|
||||
@ -410,6 +428,7 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
|
||||
struct hid_sensor_hub_callbacks *callback = NULL;
|
||||
struct hid_collection *collection = NULL;
|
||||
void *priv = NULL;
|
||||
struct hid_sensor_hub_device *hsdev = NULL;
|
||||
|
||||
hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n",
|
||||
report->id, size, report->type);
|
||||
@ -444,23 +463,26 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
|
||||
report->field[i]->usage->collection_index];
|
||||
hid_dbg(hdev, "collection->usage %x\n",
|
||||
collection->usage);
|
||||
callback = sensor_hub_get_callback(pdata->hsdev->hdev,
|
||||
report->field[i]->physical,
|
||||
&priv);
|
||||
|
||||
callback = sensor_hub_get_callback(hdev,
|
||||
report->field[i]->physical,
|
||||
report->field[i]->usage[0].collection_index,
|
||||
&hsdev, &priv);
|
||||
|
||||
if (callback && callback->capture_sample) {
|
||||
if (report->field[i]->logical)
|
||||
callback->capture_sample(pdata->hsdev,
|
||||
callback->capture_sample(hsdev,
|
||||
report->field[i]->logical, sz, ptr,
|
||||
callback->pdev);
|
||||
else
|
||||
callback->capture_sample(pdata->hsdev,
|
||||
callback->capture_sample(hsdev,
|
||||
report->field[i]->usage->hid, sz, ptr,
|
||||
callback->pdev);
|
||||
}
|
||||
ptr += sz;
|
||||
}
|
||||
if (callback && collection && callback->send_event)
|
||||
callback->send_event(pdata->hsdev, collection->usage,
|
||||
callback->send_event(hsdev, collection->usage,
|
||||
callback->pdev);
|
||||
spin_unlock_irqrestore(&pdata->lock, flags);
|
||||
|
||||
@ -473,7 +495,7 @@ int sensor_hub_device_open(struct hid_sensor_hub_device *hsdev)
|
||||
struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
if (!hsdev->ref_cnt) {
|
||||
if (!data->ref_cnt) {
|
||||
ret = hid_hw_open(hsdev->hdev);
|
||||
if (ret) {
|
||||
hid_err(hsdev->hdev, "failed to open hid device\n");
|
||||
@ -481,7 +503,7 @@ int sensor_hub_device_open(struct hid_sensor_hub_device *hsdev)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
hsdev->ref_cnt++;
|
||||
data->ref_cnt++;
|
||||
mutex_unlock(&data->mutex);
|
||||
|
||||
return ret;
|
||||
@ -493,8 +515,8 @@ void sensor_hub_device_close(struct hid_sensor_hub_device *hsdev)
|
||||
struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
|
||||
|
||||
mutex_lock(&data->mutex);
|
||||
hsdev->ref_cnt--;
|
||||
if (!hsdev->ref_cnt)
|
||||
data->ref_cnt--;
|
||||
if (!data->ref_cnt)
|
||||
hid_hw_close(hsdev->hdev);
|
||||
mutex_unlock(&data->mutex);
|
||||
}
|
||||
@ -541,26 +563,19 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
||||
struct sensor_hub_data *sd;
|
||||
int i;
|
||||
char *name;
|
||||
struct hid_report *report;
|
||||
struct hid_report_enum *report_enum;
|
||||
struct hid_field *field;
|
||||
int dev_cnt;
|
||||
struct hid_sensor_hub_device *hsdev;
|
||||
struct hid_sensor_hub_device *last_hsdev = NULL;
|
||||
|
||||
sd = devm_kzalloc(&hdev->dev, sizeof(*sd), GFP_KERNEL);
|
||||
if (!sd) {
|
||||
hid_err(hdev, "cannot allocate Sensor data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
sd->hsdev = devm_kzalloc(&hdev->dev, sizeof(*sd->hsdev), GFP_KERNEL);
|
||||
if (!sd->hsdev) {
|
||||
hid_err(hdev, "cannot allocate hid_sensor_hub_device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hid_set_drvdata(hdev, sd);
|
||||
sd->quirks = id->driver_data;
|
||||
sd->hsdev->hdev = hdev;
|
||||
sd->hsdev->vendor_id = hdev->vendor;
|
||||
sd->hsdev->product_id = hdev->product;
|
||||
|
||||
spin_lock_init(&sd->lock);
|
||||
spin_lock_init(&sd->dyn_callback_lock);
|
||||
mutex_init(&sd->mutex);
|
||||
@ -578,9 +593,8 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
||||
}
|
||||
INIT_LIST_HEAD(&sd->dyn_callback_list);
|
||||
sd->hid_sensor_client_cnt = 0;
|
||||
report_enum = &hdev->report_enum[HID_INPUT_REPORT];
|
||||
|
||||
dev_cnt = sensor_hub_get_physical_device_count(report_enum);
|
||||
dev_cnt = sensor_hub_get_physical_device_count(hdev);
|
||||
if (dev_cnt > HID_MAX_PHY_DEVICES) {
|
||||
hid_err(hdev, "Invalid Physical device count\n");
|
||||
ret = -EINVAL;
|
||||
@ -594,42 +608,63 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
||||
ret = -ENOMEM;
|
||||
goto err_stop_hw;
|
||||
}
|
||||
list_for_each_entry(report, &report_enum->report_list, list) {
|
||||
hid_dbg(hdev, "Report id:%x\n", report->id);
|
||||
field = report->field[0];
|
||||
if (report->maxfield && field &&
|
||||
field->physical) {
|
||||
|
||||
for (i = 0; i < hdev->maxcollection; ++i) {
|
||||
struct hid_collection *collection = &hdev->collection[i];
|
||||
|
||||
if (collection->type == HID_COLLECTION_PHYSICAL) {
|
||||
|
||||
hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL);
|
||||
if (!hsdev) {
|
||||
hid_err(hdev, "cannot allocate hid_sensor_hub_device\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_no_mem;
|
||||
}
|
||||
hsdev->hdev = hdev;
|
||||
hsdev->vendor_id = hdev->vendor;
|
||||
hsdev->product_id = hdev->product;
|
||||
hsdev->start_collection_index = i;
|
||||
if (last_hsdev)
|
||||
last_hsdev->end_collection_index = i;
|
||||
last_hsdev = hsdev;
|
||||
name = kasprintf(GFP_KERNEL, "HID-SENSOR-%x",
|
||||
field->physical);
|
||||
collection->usage);
|
||||
if (name == NULL) {
|
||||
hid_err(hdev, "Failed MFD device name\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_free_names;
|
||||
goto err_no_mem;
|
||||
}
|
||||
sd->hid_sensor_hub_client_devs[
|
||||
sd->hid_sensor_client_cnt].id = PLATFORM_DEVID_AUTO;
|
||||
sd->hid_sensor_client_cnt].id =
|
||||
PLATFORM_DEVID_AUTO;
|
||||
sd->hid_sensor_hub_client_devs[
|
||||
sd->hid_sensor_client_cnt].name = name;
|
||||
sd->hid_sensor_hub_client_devs[
|
||||
sd->hid_sensor_client_cnt].platform_data =
|
||||
sd->hsdev;
|
||||
hsdev;
|
||||
sd->hid_sensor_hub_client_devs[
|
||||
sd->hid_sensor_client_cnt].pdata_size =
|
||||
sizeof(*sd->hsdev);
|
||||
hid_dbg(hdev, "Adding %s:%p\n", name, sd);
|
||||
sizeof(*hsdev);
|
||||
hid_dbg(hdev, "Adding %s:%d\n", name,
|
||||
hsdev->start_collection_index);
|
||||
sd->hid_sensor_client_cnt++;
|
||||
}
|
||||
}
|
||||
if (last_hsdev)
|
||||
last_hsdev->end_collection_index = i;
|
||||
|
||||
ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs,
|
||||
sd->hid_sensor_client_cnt, NULL, 0, NULL);
|
||||
if (ret < 0)
|
||||
goto err_free_names;
|
||||
goto err_no_mem;
|
||||
|
||||
return ret;
|
||||
|
||||
err_free_names:
|
||||
for (i = 0; i < sd->hid_sensor_client_cnt ; ++i)
|
||||
err_no_mem:
|
||||
for (i = 0; i < sd->hid_sensor_client_cnt; ++i) {
|
||||
kfree(sd->hid_sensor_hub_client_devs[i].name);
|
||||
kfree(sd->hid_sensor_hub_client_devs[i].platform_data);
|
||||
}
|
||||
kfree(sd->hid_sensor_hub_client_devs);
|
||||
err_stop_hw:
|
||||
hid_hw_stop(hdev);
|
||||
@ -651,8 +686,10 @@ static void sensor_hub_remove(struct hid_device *hdev)
|
||||
complete(&data->pending.ready);
|
||||
spin_unlock_irqrestore(&data->lock, flags);
|
||||
mfd_remove_devices(&hdev->dev);
|
||||
for (i = 0; i < data->hid_sensor_client_cnt ; ++i)
|
||||
for (i = 0; i < data->hid_sensor_client_cnt; ++i) {
|
||||
kfree(data->hid_sensor_hub_client_devs[i].name);
|
||||
kfree(data->hid_sensor_hub_client_devs[i].platform_data);
|
||||
}
|
||||
kfree(data->hid_sensor_hub_client_devs);
|
||||
hid_set_drvdata(hdev, NULL);
|
||||
mutex_destroy(&data->mutex);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -48,8 +48,8 @@ static int blink1_send_command(struct blink1_data *data,
|
||||
buf[0], buf[1], buf[2], buf[3], buf[4],
|
||||
buf[5], buf[6], buf[7], buf[8]);
|
||||
|
||||
ret = data->hdev->hid_output_raw_report(data->hdev, buf,
|
||||
BLINK1_CMD_SIZE, HID_FEATURE_REPORT);
|
||||
ret = hid_hw_raw_request(data->hdev, buf[0], buf, BLINK1_CMD_SIZE,
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
@ -128,8 +128,8 @@ static void wacom_set_image(struct hid_device *hdev, const char *image,
|
||||
|
||||
rep_data[0] = WAC_CMD_ICON_START_STOP;
|
||||
rep_data[1] = 0;
|
||||
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
|
||||
HID_FEATURE_REPORT);
|
||||
ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
@ -143,15 +143,15 @@ static void wacom_set_image(struct hid_device *hdev, const char *image,
|
||||
rep_data[j + 3] = p[(i << 6) + j];
|
||||
|
||||
rep_data[2] = i;
|
||||
ret = hdev->hid_output_raw_report(hdev, rep_data, 67,
|
||||
HID_FEATURE_REPORT);
|
||||
ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 67,
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
}
|
||||
|
||||
rep_data[0] = WAC_CMD_ICON_START_STOP;
|
||||
rep_data[1] = 0;
|
||||
|
||||
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
|
||||
HID_FEATURE_REPORT);
|
||||
ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
|
||||
err:
|
||||
return;
|
||||
@ -183,7 +183,8 @@ static void wacom_leds_set_brightness(struct led_classdev *led_dev,
|
||||
buf[3] = value;
|
||||
/* use fixed brightness for OLEDs */
|
||||
buf[4] = 0x08;
|
||||
hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT);
|
||||
hid_hw_raw_request(hdev, buf[0], buf, 9, HID_FEATURE_REPORT,
|
||||
HID_REQ_SET_REPORT);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
@ -339,8 +340,8 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
|
||||
rep_data[0] = 0x03 ; rep_data[1] = 0x00;
|
||||
limit = 3;
|
||||
do {
|
||||
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
|
||||
HID_FEATURE_REPORT);
|
||||
ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
} while (ret < 0 && limit-- > 0);
|
||||
|
||||
if (ret >= 0) {
|
||||
@ -352,8 +353,9 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
|
||||
rep_data[1] = 0x00;
|
||||
limit = 3;
|
||||
do {
|
||||
ret = hdev->hid_output_raw_report(hdev,
|
||||
rep_data, 2, HID_FEATURE_REPORT);
|
||||
ret = hid_hw_raw_request(hdev, rep_data[0],
|
||||
rep_data, 2, HID_FEATURE_REPORT,
|
||||
HID_REQ_SET_REPORT);
|
||||
} while (ret < 0 && limit-- > 0);
|
||||
|
||||
if (ret >= 0) {
|
||||
@ -378,8 +380,8 @@ static void wacom_set_features(struct hid_device *hdev, u8 speed)
|
||||
rep_data[0] = 0x03;
|
||||
rep_data[1] = wdata->features;
|
||||
|
||||
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
|
||||
HID_FEATURE_REPORT);
|
||||
ret = hid_hw_raw_request(hdev, rep_data[0], rep_data, 2,
|
||||
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
|
||||
if (ret >= 0)
|
||||
wdata->high_speed = speed;
|
||||
break;
|
||||
|
@ -28,14 +28,14 @@ static int wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
|
||||
__u8 *buf;
|
||||
int ret;
|
||||
|
||||
if (!hdev->hid_output_raw_report)
|
||||
if (!hdev->ll_driver->output_report)
|
||||
return -ENODEV;
|
||||
|
||||
buf = kmemdup(buffer, count, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = hdev->hid_output_raw_report(hdev, buf, count, HID_OUTPUT_REPORT);
|
||||
ret = hid_hw_output_report(hdev, buf, count);
|
||||
|
||||
kfree(buf);
|
||||
return ret;
|
||||
|
@ -123,10 +123,6 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
|
||||
|
||||
dev = hidraw_table[minor]->hid;
|
||||
|
||||
if (!dev->hid_output_raw_report) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (count > HID_MAX_BUFFER_SIZE) {
|
||||
hid_warn(dev, "pid %d passed too large report\n",
|
||||
@ -153,7 +149,21 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
ret = dev->hid_output_raw_report(dev, buf, count, report_type);
|
||||
if ((report_type == HID_OUTPUT_REPORT) &&
|
||||
!(dev->quirks & HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP)) {
|
||||
ret = hid_hw_output_report(dev, buf, count);
|
||||
/*
|
||||
* compatibility with old implementation of USB-HID and I2C-HID:
|
||||
* if the device does not support receiving output reports,
|
||||
* on an interrupt endpoint, fallback to SET_REPORT HID command.
|
||||
*/
|
||||
if (ret != -ENOSYS)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
ret = hid_hw_raw_request(dev, buf[0], buf, count, report_type,
|
||||
HID_REQ_SET_REPORT);
|
||||
|
||||
out_free:
|
||||
kfree(buf);
|
||||
out:
|
||||
@ -189,7 +199,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
|
||||
|
||||
dev = hidraw_table[minor]->hid;
|
||||
|
||||
if (!dev->hid_get_raw_report) {
|
||||
if (!dev->ll_driver->raw_request) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
@ -216,14 +226,15 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
|
||||
|
||||
/*
|
||||
* Read the first byte from the user. This is the report number,
|
||||
* which is passed to dev->hid_get_raw_report().
|
||||
* which is passed to hid_hw_raw_request().
|
||||
*/
|
||||
if (copy_from_user(&report_number, buffer, 1)) {
|
||||
ret = -EFAULT;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
ret = dev->hid_get_raw_report(dev, report_number, buf, count, report_type);
|
||||
ret = hid_hw_raw_request(dev, report_number, buf, count, report_type,
|
||||
HID_REQ_GET_REPORT);
|
||||
|
||||
if (ret < 0)
|
||||
goto out_free;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/err.h>
|
||||
@ -256,18 +257,27 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
|
||||
u8 reportID, unsigned char *buf, size_t data_len)
|
||||
/**
|
||||
* i2c_hid_set_or_send_report: forward an incoming report to the device
|
||||
* @client: the i2c_client of the device
|
||||
* @reportType: 0x03 for HID_FEATURE_REPORT ; 0x02 for HID_OUTPUT_REPORT
|
||||
* @reportID: the report ID
|
||||
* @buf: the actual data to transfer, without the report ID
|
||||
* @len: size of buf
|
||||
* @use_data: true: use SET_REPORT HID command, false: send plain OUTPUT report
|
||||
*/
|
||||
static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType,
|
||||
u8 reportID, unsigned char *buf, size_t data_len, bool use_data)
|
||||
{
|
||||
struct i2c_hid *ihid = i2c_get_clientdata(client);
|
||||
u8 *args = ihid->argsbuf;
|
||||
const struct i2c_hid_cmd * hidcmd = &hid_set_report_cmd;
|
||||
const struct i2c_hid_cmd *hidcmd;
|
||||
int ret;
|
||||
u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
|
||||
u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister);
|
||||
u16 maxOutputLength = le16_to_cpu(ihid->hdesc.wMaxOutputLength);
|
||||
|
||||
/* hidraw already checked that data_len < HID_MAX_BUFFER_SIZE */
|
||||
/* hid_hw_* already checked that data_len < HID_MAX_BUFFER_SIZE */
|
||||
u16 size = 2 /* size */ +
|
||||
(reportID ? 1 : 0) /* reportID */ +
|
||||
data_len /* buf */;
|
||||
@ -278,6 +288,9 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
|
||||
|
||||
i2c_hid_dbg(ihid, "%s\n", __func__);
|
||||
|
||||
if (!use_data && maxOutputLength == 0)
|
||||
return -ENOSYS;
|
||||
|
||||
if (reportID >= 0x0F) {
|
||||
args[index++] = reportID;
|
||||
reportID = 0x0F;
|
||||
@ -287,9 +300,10 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
|
||||
* use the data register for feature reports or if the device does not
|
||||
* support the output register
|
||||
*/
|
||||
if (reportType == 0x03 || maxOutputLength == 0) {
|
||||
if (use_data) {
|
||||
args[index++] = dataRegister & 0xFF;
|
||||
args[index++] = dataRegister >> 8;
|
||||
hidcmd = &hid_set_report_cmd;
|
||||
} else {
|
||||
args[index++] = outputRegister & 0xFF;
|
||||
args[index++] = outputRegister >> 8;
|
||||
@ -454,10 +468,18 @@ static void i2c_hid_init_reports(struct hid_device *hid)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The device must be powered on while we fetch initial reports
|
||||
* from it.
|
||||
*/
|
||||
pm_runtime_get_sync(&client->dev);
|
||||
|
||||
list_for_each_entry(report,
|
||||
&hid->report_enum[HID_FEATURE_REPORT].report_list, list)
|
||||
i2c_hid_init_report(report, inbuf, ihid->bufsize);
|
||||
|
||||
pm_runtime_put(&client->dev);
|
||||
|
||||
kfree(inbuf);
|
||||
}
|
||||
|
||||
@ -550,7 +572,7 @@ static int i2c_hid_get_raw_report(struct hid_device *hid,
|
||||
}
|
||||
|
||||
static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
|
||||
size_t count, unsigned char report_type)
|
||||
size_t count, unsigned char report_type, bool use_data)
|
||||
{
|
||||
struct i2c_client *client = hid->driver_data;
|
||||
int report_id = buf[0];
|
||||
@ -564,9 +586,9 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
|
||||
count--;
|
||||
}
|
||||
|
||||
ret = i2c_hid_set_report(client,
|
||||
ret = i2c_hid_set_or_send_report(client,
|
||||
report_type == HID_FEATURE_REPORT ? 0x03 : 0x02,
|
||||
report_id, buf, count);
|
||||
report_id, buf, count, use_data);
|
||||
|
||||
if (report_id && ret >= 0)
|
||||
ret++; /* add report_id to the number of transfered bytes */
|
||||
@ -574,34 +596,27 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep,
|
||||
int reqtype)
|
||||
static int i2c_hid_output_report(struct hid_device *hid, __u8 *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct i2c_client *client = hid->driver_data;
|
||||
char *buf;
|
||||
int ret;
|
||||
int len = i2c_hid_get_report_length(rep) - 2;
|
||||
|
||||
buf = hid_alloc_report_buf(rep, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return;
|
||||
return i2c_hid_output_raw_report(hid, buf, count, HID_OUTPUT_REPORT,
|
||||
false);
|
||||
}
|
||||
|
||||
static int i2c_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
|
||||
__u8 *buf, size_t len, unsigned char rtype,
|
||||
int reqtype)
|
||||
{
|
||||
switch (reqtype) {
|
||||
case HID_REQ_GET_REPORT:
|
||||
ret = i2c_hid_get_raw_report(hid, rep->id, buf, len, rep->type);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: unable to get report: %d\n",
|
||||
__func__, ret);
|
||||
else
|
||||
hid_input_report(hid, rep->type, buf, ret, 0);
|
||||
break;
|
||||
return i2c_hid_get_raw_report(hid, reportnum, buf, len, rtype);
|
||||
case HID_REQ_SET_REPORT:
|
||||
hid_output_report(rep, buf);
|
||||
i2c_hid_output_raw_report(hid, buf, len, rep->type);
|
||||
break;
|
||||
if (buf[0] != reportnum)
|
||||
return -EINVAL;
|
||||
return i2c_hid_output_raw_report(hid, buf, len, rtype, true);
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
static int i2c_hid_parse(struct hid_device *hid)
|
||||
@ -703,8 +718,8 @@ static int i2c_hid_open(struct hid_device *hid)
|
||||
|
||||
mutex_lock(&i2c_hid_open_mut);
|
||||
if (!hid->open++) {
|
||||
ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
|
||||
if (ret) {
|
||||
ret = pm_runtime_get_sync(&client->dev);
|
||||
if (ret < 0) {
|
||||
hid->open--;
|
||||
goto done;
|
||||
}
|
||||
@ -712,7 +727,7 @@ static int i2c_hid_open(struct hid_device *hid)
|
||||
}
|
||||
done:
|
||||
mutex_unlock(&i2c_hid_open_mut);
|
||||
return ret;
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
static void i2c_hid_close(struct hid_device *hid)
|
||||
@ -729,7 +744,7 @@ static void i2c_hid_close(struct hid_device *hid)
|
||||
clear_bit(I2C_HID_STARTED, &ihid->flags);
|
||||
|
||||
/* Save some power */
|
||||
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
|
||||
pm_runtime_put(&client->dev);
|
||||
}
|
||||
mutex_unlock(&i2c_hid_open_mut);
|
||||
}
|
||||
@ -738,19 +753,18 @@ static int i2c_hid_power(struct hid_device *hid, int lvl)
|
||||
{
|
||||
struct i2c_client *client = hid->driver_data;
|
||||
struct i2c_hid *ihid = i2c_get_clientdata(client);
|
||||
int ret = 0;
|
||||
|
||||
i2c_hid_dbg(ihid, "%s lvl:%d\n", __func__, lvl);
|
||||
|
||||
switch (lvl) {
|
||||
case PM_HINT_FULLON:
|
||||
ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
|
||||
pm_runtime_get_sync(&client->dev);
|
||||
break;
|
||||
case PM_HINT_NORMAL:
|
||||
ret = i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
|
||||
pm_runtime_put(&client->dev);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hid_ll_driver i2c_hid_ll_driver = {
|
||||
@ -760,7 +774,8 @@ static struct hid_ll_driver i2c_hid_ll_driver = {
|
||||
.open = i2c_hid_open,
|
||||
.close = i2c_hid_close,
|
||||
.power = i2c_hid_power,
|
||||
.request = i2c_hid_request,
|
||||
.output_report = i2c_hid_output_report,
|
||||
.raw_request = i2c_hid_raw_request,
|
||||
};
|
||||
|
||||
static int i2c_hid_init_irq(struct i2c_client *client)
|
||||
@ -973,13 +988,17 @@ static int i2c_hid_probe(struct i2c_client *client,
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
pm_runtime_get_noresume(&client->dev);
|
||||
pm_runtime_set_active(&client->dev);
|
||||
pm_runtime_enable(&client->dev);
|
||||
|
||||
ret = i2c_hid_fetch_hid_descriptor(ihid);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
goto err_pm;
|
||||
|
||||
ret = i2c_hid_init_irq(client);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
goto err_pm;
|
||||
|
||||
hid = hid_allocate_device();
|
||||
if (IS_ERR(hid)) {
|
||||
@ -991,8 +1010,6 @@ static int i2c_hid_probe(struct i2c_client *client,
|
||||
|
||||
hid->driver_data = client;
|
||||
hid->ll_driver = &i2c_hid_ll_driver;
|
||||
hid->hid_get_raw_report = i2c_hid_get_raw_report;
|
||||
hid->hid_output_raw_report = i2c_hid_output_raw_report;
|
||||
hid->dev.parent = &client->dev;
|
||||
ACPI_COMPANION_SET(&hid->dev, ACPI_COMPANION(&client->dev));
|
||||
hid->bus = BUS_I2C;
|
||||
@ -1010,6 +1027,7 @@ static int i2c_hid_probe(struct i2c_client *client,
|
||||
goto err_mem_free;
|
||||
}
|
||||
|
||||
pm_runtime_put(&client->dev);
|
||||
return 0;
|
||||
|
||||
err_mem_free:
|
||||
@ -1018,6 +1036,10 @@ err_mem_free:
|
||||
err_irq:
|
||||
free_irq(client->irq, ihid);
|
||||
|
||||
err_pm:
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
pm_runtime_disable(&client->dev);
|
||||
|
||||
err:
|
||||
i2c_hid_free_buffers(ihid);
|
||||
kfree(ihid);
|
||||
@ -1029,6 +1051,11 @@ static int i2c_hid_remove(struct i2c_client *client)
|
||||
struct i2c_hid *ihid = i2c_get_clientdata(client);
|
||||
struct hid_device *hid;
|
||||
|
||||
pm_runtime_get_sync(&client->dev);
|
||||
pm_runtime_disable(&client->dev);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
|
||||
hid = ihid->hid;
|
||||
hid_destroy_device(hid);
|
||||
|
||||
@ -1074,7 +1101,31 @@ static int i2c_hid_resume(struct device *dev)
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(i2c_hid_pm, i2c_hid_suspend, i2c_hid_resume);
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
static int i2c_hid_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
|
||||
disable_irq(client->irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_hid_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
enable_irq(client->irq);
|
||||
i2c_hid_set_power(client, I2C_HID_PWR_ON);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops i2c_hid_pm = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(i2c_hid_suspend, i2c_hid_resume)
|
||||
SET_RUNTIME_PM_OPS(i2c_hid_runtime_suspend, i2c_hid_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
||||
static const struct i2c_device_id i2c_hid_id_table[] = {
|
||||
{ "hid", 0 },
|
||||
|
@ -244,12 +244,35 @@ static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
|
||||
return count;
|
||||
}
|
||||
|
||||
static int uhid_hid_output_report(struct hid_device *hid, __u8 *buf,
|
||||
size_t count)
|
||||
{
|
||||
return uhid_hid_output_raw(hid, buf, count, HID_OUTPUT_REPORT);
|
||||
}
|
||||
|
||||
static int uhid_raw_request(struct hid_device *hid, unsigned char reportnum,
|
||||
__u8 *buf, size_t len, unsigned char rtype,
|
||||
int reqtype)
|
||||
{
|
||||
switch (reqtype) {
|
||||
case HID_REQ_GET_REPORT:
|
||||
return uhid_hid_get_raw(hid, reportnum, buf, len, rtype);
|
||||
case HID_REQ_SET_REPORT:
|
||||
/* TODO: implement proper SET_REPORT functionality */
|
||||
return -ENOSYS;
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
static struct hid_ll_driver uhid_hid_driver = {
|
||||
.start = uhid_hid_start,
|
||||
.stop = uhid_hid_stop,
|
||||
.open = uhid_hid_open,
|
||||
.close = uhid_hid_close,
|
||||
.parse = uhid_hid_parse,
|
||||
.output_report = uhid_hid_output_report,
|
||||
.raw_request = uhid_raw_request,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
@ -377,8 +400,6 @@ static int uhid_dev_create(struct uhid_device *uhid,
|
||||
hid->uniq[63] = 0;
|
||||
|
||||
hid->ll_driver = &uhid_hid_driver;
|
||||
hid->hid_get_raw_report = uhid_hid_get_raw;
|
||||
hid->hid_output_raw_report = uhid_hid_output_raw;
|
||||
hid->bus = ev->u.create.bus;
|
||||
hid->vendor = ev->u.create.vendor;
|
||||
hid->product = ev->u.create.product;
|
||||
@ -407,6 +428,67 @@ err_free:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int uhid_dev_create2(struct uhid_device *uhid,
|
||||
const struct uhid_event *ev)
|
||||
{
|
||||
struct hid_device *hid;
|
||||
int ret;
|
||||
|
||||
if (uhid->running)
|
||||
return -EALREADY;
|
||||
|
||||
uhid->rd_size = ev->u.create2.rd_size;
|
||||
if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL);
|
||||
if (!uhid->rd_data)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(uhid->rd_data, ev->u.create2.rd_data, uhid->rd_size);
|
||||
|
||||
hid = hid_allocate_device();
|
||||
if (IS_ERR(hid)) {
|
||||
ret = PTR_ERR(hid);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
strncpy(hid->name, ev->u.create2.name, 127);
|
||||
hid->name[127] = 0;
|
||||
strncpy(hid->phys, ev->u.create2.phys, 63);
|
||||
hid->phys[63] = 0;
|
||||
strncpy(hid->uniq, ev->u.create2.uniq, 63);
|
||||
hid->uniq[63] = 0;
|
||||
|
||||
hid->ll_driver = &uhid_hid_driver;
|
||||
hid->bus = ev->u.create2.bus;
|
||||
hid->vendor = ev->u.create2.vendor;
|
||||
hid->product = ev->u.create2.product;
|
||||
hid->version = ev->u.create2.version;
|
||||
hid->country = ev->u.create2.country;
|
||||
hid->driver_data = uhid;
|
||||
hid->dev.parent = uhid_misc.this_device;
|
||||
|
||||
uhid->hid = hid;
|
||||
uhid->running = true;
|
||||
|
||||
ret = hid_add_device(hid);
|
||||
if (ret) {
|
||||
hid_err(hid, "Cannot register HID device\n");
|
||||
goto err_hid;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_hid:
|
||||
hid_destroy_device(hid);
|
||||
uhid->hid = NULL;
|
||||
uhid->running = false;
|
||||
err_free:
|
||||
kfree(uhid->rd_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int uhid_dev_destroy(struct uhid_device *uhid)
|
||||
{
|
||||
if (!uhid->running)
|
||||
@ -435,6 +517,17 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev)
|
||||
{
|
||||
if (!uhid->running)
|
||||
return -EINVAL;
|
||||
|
||||
hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data,
|
||||
min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uhid_dev_feature_answer(struct uhid_device *uhid,
|
||||
struct uhid_event *ev)
|
||||
{
|
||||
@ -571,12 +664,18 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
|
||||
case UHID_CREATE:
|
||||
ret = uhid_dev_create(uhid, &uhid->input_buf);
|
||||
break;
|
||||
case UHID_CREATE2:
|
||||
ret = uhid_dev_create2(uhid, &uhid->input_buf);
|
||||
break;
|
||||
case UHID_DESTROY:
|
||||
ret = uhid_dev_destroy(uhid);
|
||||
break;
|
||||
case UHID_INPUT:
|
||||
ret = uhid_dev_input(uhid, &uhid->input_buf);
|
||||
break;
|
||||
case UHID_INPUT2:
|
||||
ret = uhid_dev_input2(uhid, &uhid->input_buf);
|
||||
break;
|
||||
case UHID_FEATURE_ANSWER:
|
||||
ret = uhid_dev_feature_answer(uhid, &uhid->input_buf);
|
||||
break;
|
||||
|
@ -884,52 +884,66 @@ static int usbhid_get_raw_report(struct hid_device *hid,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count,
|
||||
unsigned char report_type)
|
||||
static int usbhid_set_raw_report(struct hid_device *hid, unsigned int reportnum,
|
||||
__u8 *buf, size_t count, unsigned char rtype)
|
||||
{
|
||||
struct usbhid_device *usbhid = hid->driver_data;
|
||||
struct usb_device *dev = hid_to_usb_dev(hid);
|
||||
struct usb_interface *intf = usbhid->intf;
|
||||
struct usb_host_interface *interface = intf->cur_altsetting;
|
||||
int ret;
|
||||
int ret, skipped_report_id = 0;
|
||||
|
||||
if (usbhid->urbout && report_type != HID_FEATURE_REPORT) {
|
||||
int actual_length;
|
||||
int skipped_report_id = 0;
|
||||
/* Byte 0 is the report number. Report data starts at byte 1.*/
|
||||
if ((rtype == HID_OUTPUT_REPORT) &&
|
||||
(hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORT_ID))
|
||||
buf[0] = 0;
|
||||
else
|
||||
buf[0] = reportnum;
|
||||
|
||||
if (buf[0] == 0x0) {
|
||||
/* Don't send the Report ID */
|
||||
buf++;
|
||||
count--;
|
||||
skipped_report_id = 1;
|
||||
}
|
||||
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),
|
||||
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),
|
||||
HID_REQ_SET_REPORT,
|
||||
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
((report_type + 1) << 8) | report_id,
|
||||
((rtype + 1) << 8) | reportnum,
|
||||
interface->desc.bInterfaceNumber, buf, count,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
/* count also the report id, if this was a numbered report. */
|
||||
if (ret > 0 && skipped_report_id)
|
||||
/* count also the report id, if this was a numbered report. */
|
||||
if (ret > 0 && skipped_report_id)
|
||||
ret++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int usbhid_output_report(struct hid_device *hid, __u8 *buf, size_t count)
|
||||
{
|
||||
struct usbhid_device *usbhid = hid->driver_data;
|
||||
struct usb_device *dev = hid_to_usb_dev(hid);
|
||||
int actual_length, skipped_report_id = 0, ret;
|
||||
|
||||
if (!usbhid->urbout)
|
||||
return -ENOSYS;
|
||||
|
||||
if (buf[0] == 0x0) {
|
||||
/* Don't send the Report ID */
|
||||
buf++;
|
||||
count--;
|
||||
skipped_report_id = 1;
|
||||
}
|
||||
|
||||
ret = usb_interrupt_msg(dev, usbhid->urbout->pipe,
|
||||
buf, count, &actual_length,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
/* return the number of bytes transferred */
|
||||
if (ret == 0) {
|
||||
ret = actual_length;
|
||||
/* count also the report id */
|
||||
if (skipped_report_id)
|
||||
ret++;
|
||||
}
|
||||
|
||||
@ -1200,6 +1214,20 @@ static void usbhid_request(struct hid_device *hid, struct hid_report *rep, int r
|
||||
}
|
||||
}
|
||||
|
||||
static int usbhid_raw_request(struct hid_device *hid, unsigned char reportnum,
|
||||
__u8 *buf, size_t len, unsigned char rtype,
|
||||
int reqtype)
|
||||
{
|
||||
switch (reqtype) {
|
||||
case HID_REQ_GET_REPORT:
|
||||
return usbhid_get_raw_report(hid, reportnum, buf, len, rtype);
|
||||
case HID_REQ_SET_REPORT:
|
||||
return usbhid_set_raw_report(hid, reportnum, buf, len, rtype);
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
static int usbhid_idle(struct hid_device *hid, int report, int idle,
|
||||
int reqtype)
|
||||
{
|
||||
@ -1223,6 +1251,8 @@ static struct hid_ll_driver usb_hid_driver = {
|
||||
.power = usbhid_power,
|
||||
.request = usbhid_request,
|
||||
.wait = usbhid_wait_io,
|
||||
.raw_request = usbhid_raw_request,
|
||||
.output_report = usbhid_output_report,
|
||||
.idle = usbhid_idle,
|
||||
};
|
||||
|
||||
@ -1253,8 +1283,6 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
|
||||
|
||||
usb_set_intfdata(intf, hid);
|
||||
hid->ll_driver = &usb_hid_driver;
|
||||
hid->hid_get_raw_report = usbhid_get_raw_report;
|
||||
hid->hid_output_raw_report = usbhid_output_raw_report;
|
||||
hid->ff_init = hid_pidff_init;
|
||||
#ifdef CONFIG_USB_HIDDEV
|
||||
hid->hiddev_connect = hiddev_connect;
|
||||
|
@ -38,29 +38,40 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
|
||||
if (state) {
|
||||
if (sensor_hub_device_open(st->hsdev))
|
||||
return -EIO;
|
||||
state_val =
|
||||
HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM;
|
||||
report_val =
|
||||
HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM;
|
||||
|
||||
state_val = hid_sensor_get_usage_index(st->hsdev,
|
||||
st->power_state.report_id,
|
||||
st->power_state.index,
|
||||
HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM);
|
||||
report_val = hid_sensor_get_usage_index(st->hsdev,
|
||||
st->report_state.report_id,
|
||||
st->report_state.index,
|
||||
HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM);
|
||||
} else {
|
||||
sensor_hub_device_close(st->hsdev);
|
||||
state_val =
|
||||
HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM;
|
||||
report_val =
|
||||
HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM;
|
||||
state_val = hid_sensor_get_usage_index(st->hsdev,
|
||||
st->power_state.report_id,
|
||||
st->power_state.index,
|
||||
HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM);
|
||||
report_val = hid_sensor_get_usage_index(st->hsdev,
|
||||
st->report_state.report_id,
|
||||
st->report_state.index,
|
||||
HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM);
|
||||
}
|
||||
|
||||
st->data_ready = state;
|
||||
state_val += st->power_state.logical_minimum;
|
||||
report_val += st->report_state.logical_minimum;
|
||||
sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
|
||||
|
||||
if (state_val >= 0) {
|
||||
state_val += st->power_state.logical_minimum;
|
||||
sensor_hub_set_feature(st->hsdev, st->power_state.report_id,
|
||||
st->power_state.index,
|
||||
(s32)state_val);
|
||||
}
|
||||
|
||||
sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
|
||||
if (report_val >= 0) {
|
||||
report_val += st->report_state.logical_minimum;
|
||||
sensor_hub_set_feature(st->hsdev, st->report_state.report_id,
|
||||
st->report_state.index,
|
||||
(s32)report_val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -51,13 +51,15 @@ struct hid_sensor_hub_attribute_info {
|
||||
* @hdev: Stores the hid instance.
|
||||
* @vendor_id: Vendor id of hub device.
|
||||
* @product_id: Product id of hub device.
|
||||
* @ref_cnt: Number of MFD clients have opened this device
|
||||
* @start_collection_index: Starting index for a phy type collection
|
||||
* @end_collection_index: Last index for a phy type collection
|
||||
*/
|
||||
struct hid_sensor_hub_device {
|
||||
struct hid_device *hdev;
|
||||
u32 vendor_id;
|
||||
u32 product_id;
|
||||
int ref_cnt;
|
||||
int start_collection_index;
|
||||
int end_collection_index;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -218,4 +220,7 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st,
|
||||
int hid_sensor_read_samp_freq_value(struct hid_sensor_common *st,
|
||||
int *val1, int *val2);
|
||||
|
||||
int hid_sensor_get_usage_index(struct hid_sensor_hub_device *hsdev,
|
||||
u32 report_id, int field_index, u32 usage_id);
|
||||
|
||||
#endif
|
||||
|
@ -140,15 +140,15 @@
|
||||
#define HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS 0x1000
|
||||
|
||||
/* Power state enumerations */
|
||||
#define HID_USAGE_SENSOR_PROP_POWER_STATE_UNDEFINED_ENUM 0x00
|
||||
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM 0x01
|
||||
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D1_LOW_POWER_ENUM 0x02
|
||||
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D2_STANDBY_WITH_WAKE_ENUM 0x03
|
||||
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D3_SLEEP_WITH_WAKE_ENUM 0x04
|
||||
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM 0x05
|
||||
#define HID_USAGE_SENSOR_PROP_POWER_STATE_UNDEFINED_ENUM 0x200850
|
||||
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM 0x200851
|
||||
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D1_LOW_POWER_ENUM 0x200852
|
||||
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D2_STANDBY_WITH_WAKE_ENUM 0x200853
|
||||
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D3_SLEEP_WITH_WAKE_ENUM 0x200854
|
||||
#define HID_USAGE_SENSOR_PROP_POWER_STATE_D4_POWER_OFF_ENUM 0x200855
|
||||
|
||||
/* Report State enumerations */
|
||||
#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM 0x00
|
||||
#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x01
|
||||
#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_NO_EVENTS_ENUM 0x200840
|
||||
#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x200841
|
||||
|
||||
#endif
|
||||
|
@ -201,6 +201,7 @@ struct hid_item {
|
||||
#define HID_GD_VBRZ 0x00010045
|
||||
#define HID_GD_VNO 0x00010046
|
||||
#define HID_GD_FEATURE 0x00010047
|
||||
#define HID_GD_SYSTEM_CONTROL 0x00010080
|
||||
#define HID_GD_UP 0x00010090
|
||||
#define HID_GD_DOWN 0x00010091
|
||||
#define HID_GD_RIGHT 0x00010092
|
||||
@ -208,6 +209,8 @@ struct hid_item {
|
||||
|
||||
#define HID_DC_BATTERYSTRENGTH 0x00060020
|
||||
|
||||
#define HID_CP_CONSUMER_CONTROL 0x000c0001
|
||||
|
||||
#define HID_DG_DIGITIZER 0x000d0001
|
||||
#define HID_DG_PEN 0x000d0002
|
||||
#define HID_DG_LIGHTPEN 0x000d0003
|
||||
@ -287,6 +290,8 @@ struct hid_item {
|
||||
#define HID_QUIRK_NO_EMPTY_INPUT 0x00000100
|
||||
#define HID_QUIRK_NO_INIT_INPUT_REPORTS 0x00000200
|
||||
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
|
||||
#define HID_QUIRK_SKIP_OUTPUT_REPORT_ID 0x00020000
|
||||
#define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP 0x00040000
|
||||
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
|
||||
#define HID_QUIRK_NO_INIT_REPORTS 0x20000000
|
||||
#define HID_QUIRK_NO_IGNORE 0x40000000
|
||||
@ -508,12 +513,6 @@ struct hid_device { /* device report descriptor */
|
||||
struct hid_usage *, __s32);
|
||||
void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
|
||||
|
||||
/* handler for raw input (Get_Report) data, used by hidraw */
|
||||
int (*hid_get_raw_report) (struct hid_device *, unsigned char, __u8 *, size_t, unsigned char);
|
||||
|
||||
/* handler for raw output data, used by hidraw */
|
||||
int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t, unsigned char);
|
||||
|
||||
/* debugging support via debugfs */
|
||||
unsigned short debug;
|
||||
struct dentry *debug_dir;
|
||||
@ -675,11 +674,12 @@ struct hid_driver {
|
||||
* @stop: called on remove
|
||||
* @open: called by input layer on open
|
||||
* @close: called by input layer on close
|
||||
* @hidinput_input_event: event input event (e.g. ff or leds)
|
||||
* @parse: this method is called only once to parse the device data,
|
||||
* shouldn't allocate anything to not leak memory
|
||||
* @request: send report request to device (e.g. feature report)
|
||||
* @wait: wait for buffered io to complete (send/recv reports)
|
||||
* @raw_request: send raw report request to device (e.g. feature report)
|
||||
* @output_report: send output report to device
|
||||
* @idle: send idle request to device
|
||||
*/
|
||||
struct hid_ll_driver {
|
||||
@ -691,17 +691,20 @@ struct hid_ll_driver {
|
||||
|
||||
int (*power)(struct hid_device *hdev, int level);
|
||||
|
||||
int (*hidinput_input_event) (struct input_dev *idev, unsigned int type,
|
||||
unsigned int code, int value);
|
||||
|
||||
int (*parse)(struct hid_device *hdev);
|
||||
|
||||
void (*request)(struct hid_device *hdev,
|
||||
struct hid_report *report, int reqtype);
|
||||
|
||||
int (*wait)(struct hid_device *hdev);
|
||||
int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype);
|
||||
|
||||
int (*raw_request) (struct hid_device *hdev, unsigned char reportnum,
|
||||
__u8 *buf, size_t len, unsigned char rtype,
|
||||
int reqtype);
|
||||
|
||||
int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len);
|
||||
|
||||
int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype);
|
||||
};
|
||||
|
||||
#define PM_HINT_FULLON 1<<5
|
||||
@ -752,6 +755,7 @@ struct hid_field *hidinput_get_led_field(struct hid_device *hid);
|
||||
unsigned int hidinput_count_leds(struct hid_device *hid);
|
||||
__s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code);
|
||||
void hid_output_report(struct hid_report *report, __u8 *data);
|
||||
void __hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype);
|
||||
u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags);
|
||||
struct hid_device *hid_allocate_device(void);
|
||||
struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
|
||||
@ -964,7 +968,55 @@ static inline void hid_hw_request(struct hid_device *hdev,
|
||||
struct hid_report *report, int reqtype)
|
||||
{
|
||||
if (hdev->ll_driver->request)
|
||||
hdev->ll_driver->request(hdev, report, reqtype);
|
||||
return hdev->ll_driver->request(hdev, report, reqtype);
|
||||
|
||||
__hid_request(hdev, report, reqtype);
|
||||
}
|
||||
|
||||
/**
|
||||
* hid_hw_raw_request - send report request to device
|
||||
*
|
||||
* @hdev: hid device
|
||||
* @reportnum: report ID
|
||||
* @buf: in/out data to transfer
|
||||
* @len: length of buf
|
||||
* @rtype: HID report type
|
||||
* @reqtype: HID_REQ_GET_REPORT or HID_REQ_SET_REPORT
|
||||
*
|
||||
* @return: count of data transfered, negative if error
|
||||
*
|
||||
* Same behavior as hid_hw_request, but with raw buffers instead.
|
||||
*/
|
||||
static inline int hid_hw_raw_request(struct hid_device *hdev,
|
||||
unsigned char reportnum, __u8 *buf,
|
||||
size_t len, unsigned char rtype, int reqtype)
|
||||
{
|
||||
if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
return hdev->ll_driver->raw_request(hdev, reportnum, buf, len,
|
||||
rtype, reqtype);
|
||||
}
|
||||
|
||||
/**
|
||||
* hid_hw_output_report - send output report to device
|
||||
*
|
||||
* @hdev: hid device
|
||||
* @buf: raw data to transfer
|
||||
* @len: length of buf
|
||||
*
|
||||
* @return: count of data transfered, negative if error
|
||||
*/
|
||||
static inline int hid_hw_output_report(struct hid_device *hdev, __u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf)
|
||||
return -EINVAL;
|
||||
|
||||
if (hdev->ll_driver->output_report)
|
||||
return hdev->ll_driver->output_report(hdev, buf, len);
|
||||
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/hid.h>
|
||||
|
||||
enum uhid_event_type {
|
||||
UHID_CREATE,
|
||||
@ -34,6 +35,8 @@ enum uhid_event_type {
|
||||
UHID_INPUT,
|
||||
UHID_FEATURE,
|
||||
UHID_FEATURE_ANSWER,
|
||||
UHID_CREATE2,
|
||||
UHID_INPUT2,
|
||||
};
|
||||
|
||||
struct uhid_create_req {
|
||||
@ -50,6 +53,19 @@ struct uhid_create_req {
|
||||
__u32 country;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct uhid_create2_req {
|
||||
__u8 name[128];
|
||||
__u8 phys[64];
|
||||
__u8 uniq[64];
|
||||
__u16 rd_size;
|
||||
__u16 bus;
|
||||
__u32 vendor;
|
||||
__u32 product;
|
||||
__u32 version;
|
||||
__u32 country;
|
||||
__u8 rd_data[HID_MAX_DESCRIPTOR_SIZE];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define UHID_DATA_MAX 4096
|
||||
|
||||
enum uhid_report_type {
|
||||
@ -63,6 +79,11 @@ struct uhid_input_req {
|
||||
__u16 size;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct uhid_input2_req {
|
||||
__u16 size;
|
||||
__u8 data[UHID_DATA_MAX];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
struct uhid_output_req {
|
||||
__u8 data[UHID_DATA_MAX];
|
||||
__u16 size;
|
||||
@ -100,6 +121,8 @@ struct uhid_event {
|
||||
struct uhid_output_ev_req output_ev;
|
||||
struct uhid_feature_req feature;
|
||||
struct uhid_feature_answer_req feature_answer;
|
||||
struct uhid_create2_req create2;
|
||||
struct uhid_input2_req input2;
|
||||
} u;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
@ -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,29 @@ 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_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;
|
||||
@ -739,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
|
||||
@ -781,15 +767,15 @@ static int hidp_setup_hid(struct hidp_session *session,
|
||||
snprintf(hid->phys, sizeof(hid->phys), "%pMR",
|
||||
&l2cap_pi(session->ctrl_sock->sk)->chan->src);
|
||||
|
||||
/* NOTE: Some device modules depend on the dst address being stored in
|
||||
* uniq. Please be aware of this before making changes to this behavior.
|
||||
*/
|
||||
snprintf(hid->uniq, sizeof(hid->uniq), "%pMR",
|
||||
&l2cap_pi(session->ctrl_sock->sk)->chan->dst);
|
||||
|
||||
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 */
|
||||
if (hid_ignore(hid)) {
|
||||
hid_destroy_device(session->hid);
|
||||
|
Loading…
Reference in New Issue
Block a user