Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
d6a611f5
K
Kernel
项目概览
openeuler
/
Kernel
1 年多 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
d6a611f5
编写于
2月 18, 2014
作者:
J
Jiri Kosina
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'for-3.15/hid-core-ll-transport-cleanup' into for-3.15/hid-cp2112
上级
5a673fce
53182517
变更
16
隐藏空白更改
内联
并排
Showing
16 changed file
with
714 addition
and
240 deletion
+714
-240
Documentation/hid/hid-transport.txt
Documentation/hid/hid-transport.txt
+316
-0
drivers/hid/hid-core.c
drivers/hid/hid-core.c
+44
-1
drivers/hid/hid-input.c
drivers/hid/hid-input.c
+5
-7
drivers/hid/hid-lg.c
drivers/hid/hid-lg.c
+4
-2
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-logitech-dj.c
+40
-71
drivers/hid/hid-magicmouse.c
drivers/hid/hid-magicmouse.c
+2
-2
drivers/hid/hid-sony.c
drivers/hid/hid-sony.c
+5
-4
drivers/hid/hid-thingm.c
drivers/hid/hid-thingm.c
+2
-2
drivers/hid/hid-wacom.c
drivers/hid/hid-wacom.c
+15
-13
drivers/hid/hid-wiimote-core.c
drivers/hid/hid-wiimote-core.c
+2
-2
drivers/hid/hidraw.c
drivers/hid/hidraw.c
+5
-4
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/i2c-hid/i2c-hid.c
+50
-31
drivers/hid/uhid.c
drivers/hid/uhid.c
+23
-1
drivers/hid/usbhid/hid-core.c
drivers/hid/usbhid/hid-core.c
+71
-36
include/linux/hid.h
include/linux/hid.h
+78
-9
net/bluetooth/hidp/core.c
net/bluetooth/hidp/core.c
+52
-55
未找到文件。
Documentation/hid/hid-transport.txt
0 → 100644
浏览文件 @
d6a611f5
HID I/O Transport Drivers
===========================
The HID subsystem is independent of the underlying transport driver. Initially,
only USB was supported, but other specifications adopted the HID design and
provided new transport drivers. The kernel includes at least support for USB,
Bluetooth, I2C and user-space I/O drivers.
1) HID Bus
==========
The HID subsystem is designed as a bus. Any I/O subsystem may provide HID
devices and register them with the HID bus. HID core then loads generic device
drivers on top of it. The transport drivers are responsible of raw data
transport and device setup/management. HID core is responsible of
report-parsing, report interpretation and the user-space API. Device specifics
and quirks are handled by all layers depending on the quirk.
+-----------+ +-----------+ +-----------+ +-----------+
| Device #1 | | Device #i | | Device #j | | Device #k |
+-----------+ +-----------+ +-----------+ +-----------+
\\ // \\ //
+------------+ +------------+
| I/O Driver | | I/O Driver |
+------------+ +------------+
|| ||
+------------------+ +------------------+
| Transport Driver | | Transport Driver |
+------------------+ +------------------+
\___ ___/
\ /
+----------------+
| HID Core |
+----------------+
/ | | \
/ | | \
____________/ | | \_________________
/ | | \
/ | | \
+----------------+ +-----------+ +------------------+ +------------------+
| Generic Driver | | MT Driver | | Custom Driver #1 | | Custom Driver #2 |
+----------------+ +-----------+ +------------------+ +------------------+
Example Drivers:
I/O: USB, I2C, Bluetooth-l2cap
Transport: USB-HID, I2C-HID, BT-HIDP
Everything below "HID Core" is simplified in this graph as it is only of
interest to HID device drivers. Transport drivers do not need to know the
specifics.
1.1) Device Setup
-----------------
I/O drivers normally provide hotplug detection or device enumeration APIs to the
transport drivers. Transport drivers use this to find any suitable HID device.
They allocate HID device objects and register them with HID core. Transport
drivers are not required to register themselves with HID core. HID core is never
aware of which transport drivers are available and is not interested in it. It
is only interested in devices.
Transport drivers attach a constant "struct hid_ll_driver" object with each
device. Once a device is registered with HID core, the callbacks provided via
this struct are used by HID core to communicate with the device.
Transport drivers are responsible of detecting device failures and unplugging.
HID core will operate a device as long as it is registered regardless of any
device failures. Once transport drivers detect unplug or failure events, they
must unregister the device from HID core and HID core will stop using the
provided callbacks.
1.2) Transport Driver Requirements
----------------------------------
The terms "asynchronous" and "synchronous" in this document describe the
transmission behavior regarding acknowledgements. An asynchronous channel must
not perform any synchronous operations like waiting for acknowledgements or
verifications. Generally, HID calls operating on asynchronous channels must be
running in atomic-context just fine.
On the other hand, synchronous channels can be implemented by the transport
driver in whatever way they like. They might just be the same as asynchronous
channels, but they can also provide acknowledgement reports, automatic
retransmission on failure, etc. in a blocking manner. If such functionality is
required on asynchronous channels, a transport-driver must implement that via
its own worker threads.
HID core requires transport drivers to follow a given design. A Transport
driver must provide two bi-directional I/O channels to each HID device. These
channels must not necessarily be bi-directional in the hardware itself. A
transport driver might just provide 4 uni-directional channels. Or it might
multiplex all four on a single physical channel. However, in this document we
will describe them as two bi-directional channels as they have several
properties in common.
- Interrupt Channel (intr): The intr channel is used for asynchronous data
reports. No management commands or data acknowledgements are sent on this
channel. Any unrequested incoming or outgoing data report must be sent on
this channel and is never acknowledged by the remote side. Devices usually
send their input events on this channel. Outgoing events are normally
not send via intr, except if high throughput is required.
- Control Channel (ctrl): The ctrl channel is used for synchronous requests and
device management. Unrequested data input events must not be sent on this
channel and are normally ignored. Instead, devices only send management
events or answers to host requests on this channel.
The control-channel is used for direct blocking queries to the device
independent of any events on the intr-channel.
Outgoing reports are usually sent on the ctrl channel via synchronous
SET_REPORT requests.
Communication between devices and HID core is mostly done via HID reports. A
report can be of one of three types:
- INPUT Report: Input reports provide data from device to host. This
data may include button events, axis events, battery status or more. This
data is generated by the device and sent to the host with or without
requiring explicit requests. Devices can choose to send data continuously or
only on change.
- OUTPUT Report: Output reports change device states. They are sent from host
to device and may include LED requests, rumble requests or more. Output
reports are never sent from device to host, but a host can retrieve their
current state.
Hosts may choose to send output reports either continuously or only on
change.
- FEATURE Report: Feature reports are used for specific static device features
and never reported spontaneously. A host can read and/or write them to access
data like battery-state or device-settings.
Feature reports are never sent without requests. A host must explicitly set
or retrieve a feature report. This also means, feature reports are never sent
on the intr channel as this channel is asynchronous.
INPUT and OUTPUT reports can be sent as pure data reports on the intr channel.
For INPUT reports this is the usual operational mode. But for OUTPUT reports,
this is rarely done as OUTPUT reports are normally quite scarce. But devices are
free to make excessive use of asynchronous OUTPUT reports (for instance, custom
HID audio speakers make great use of it).
Plain reports must not be sent on the ctrl channel, though. Instead, the ctrl
channel provides synchronous GET/SET_REPORT requests. Plain reports are only
allowed on the intr channel and are the only means of data there.
- GET_REPORT: A GET_REPORT request has a report ID as payload and is sent
from host to device. The device must answer with a data report for the
requested report ID on the ctrl channel as a synchronous acknowledgement.
Only one GET_REPORT request can be pending for each device. This restriction
is enforced by HID core as several transport drivers don't allow multiple
simultaneous GET_REPORT requests.
Note that data reports which are sent as answer to a GET_REPORT request are
not handled as generic device events. That is, if a device does not operate
in continuous data reporting mode, an answer to GET_REPORT does not replace
the raw data report on the intr channel on state change.
GET_REPORT is only used by custom HID device drivers to query device state.
Normally, HID core caches any device state so this request is not necessary
on devices that follow the HID specs except during device initialization to
retrieve the current state.
GET_REPORT requests can be sent for any of the 3 report types and shall
return the current report state of the device. However, OUTPUT reports as
payload may be blocked by the underlying transport driver if the
specification does not allow them.
- SET_REPORT: A SET_REPORT request has a report ID plus data as payload. It is
sent from host to device and a device must update it's current report state
according to the given data. Any of the 3 report types can be used. However,
INPUT reports as payload might be blocked by the underlying transport driver
if the specification does not allow them.
A device must answer with a synchronous acknowledgement. However, HID core
does not require transport drivers to forward this acknowledgement to HID
core.
Same as for GET_REPORT, only one SET_REPORT can be pending at a time. This
restriction is enforced by HID core as some transport drivers do not support
multiple synchronous SET_REPORT requests.
Other ctrl-channel requests are supported by USB-HID but are not available
(or deprecated) in most other transport level specifications:
- GET/SET_IDLE: Only used by USB-HID and I2C-HID.
- GET/SET_PROTOCOL: Not used by HID core.
- RESET: Used by I2C-HID, not hooked up in HID core.
- SET_POWER: Used by I2C-HID, not hooked up in HID core.
2) HID API
==========
2.1) Initialization
-------------------
Transport drivers normally use the following procedure to register a new device
with HID core:
struct hid_device *hid;
int ret;
hid = hid_allocate_device();
if (IS_ERR(hid)) {
ret = PTR_ERR(hid);
goto err_<...>;
}
strlcpy(hid->name, <device-name-src>, 127);
strlcpy(hid->phys, <device-phys-src>, 63);
strlcpy(hid->uniq, <device-uniq-src>, 63);
hid->ll_driver = &custom_ll_driver;
hid->bus = <device-bus>;
hid->vendor = <device-vendor>;
hid->product = <device-product>;
hid->version = <device-version>;
hid->country = <device-country>;
hid->dev.parent = <pointer-to-parent-device>;
hid->driver_data = <transport-driver-data-field>;
ret = hid_add_device(hid);
if (ret)
goto err_<...>;
Once hid_add_device() is entered, HID core might use the callbacks provided in
"custom_ll_driver". Note that fields like "country" can be ignored by underlying
transport-drivers if not supported.
To unregister a device, use:
hid_destroy_device(hid);
Once hid_destroy_device() returns, HID core will no longer make use of any
driver callbacks.
2.2) hid_ll_driver operations
-----------------------------
The available HID callbacks are:
- int (*start) (struct hid_device *hdev)
Called from HID device drivers once they want to use the device. Transport
drivers can choose to setup their device in this callback. However, normally
devices are already set up before transport drivers register them to HID core
so this is mostly only used by USB-HID.
- void (*stop) (struct hid_device *hdev)
Called from HID device drivers once they are done with a device. Transport
drivers can free any buffers and deinitialize the device. But note that
->start() might be called again if another HID device driver is loaded on the
device.
Transport drivers are free to ignore it and deinitialize devices after they
destroyed them via hid_destroy_device().
- int (*open) (struct hid_device *hdev)
Called from HID device drivers once they are interested in data reports.
Usually, while user-space didn't open any input API/etc., device drivers are
not interested in device data and transport drivers can put devices asleep.
However, once ->open() is called, transport drivers must be ready for I/O.
->open() calls are nested for each client that opens the HID device.
- void (*close) (struct hid_device *hdev)
Called from HID device drivers after ->open() was called but they are no
longer interested in device reports. (Usually if user-space closed any input
devices of the driver).
Transport drivers can put devices asleep and terminate any I/O of all
->open() calls have been followed by a ->close() call. However, ->start() may
be called again if the device driver is interested in input reports again.
- int (*parse) (struct hid_device *hdev)
Called once during device setup after ->start() has been called. Transport
drivers must read the HID report-descriptor from the device and tell HID core
about it via hid_parse_report().
- int (*power) (struct hid_device *hdev, int level)
Called by HID core to give PM hints to transport drivers. Usually this is
analogical to the ->open() and ->close() hints and redundant.
- void (*request) (struct hid_device *hdev, struct hid_report *report,
int reqtype)
Send an HID request on the ctrl channel. "report" contains the report that
should be sent and "reqtype" the request type. Request-type can be
HID_REQ_SET_REPORT or HID_REQ_GET_REPORT.
This callback is optional. If not provided, HID core will assemble a raw
report following the HID specs and send it via the ->raw_request() callback.
The transport driver is free to implement this asynchronously.
- int (*wait) (struct hid_device *hdev)
Used by HID core before calling ->request() again. A transport driver can use
it to wait for any pending requests to complete if only one request is
allowed at a time.
- int (*raw_request) (struct hid_device *hdev, unsigned char reportnum,
__u8 *buf, size_t count, unsigned char rtype,
int reqtype)
Same as ->request() but provides the report as raw buffer. This request shall
be synchronous. A transport driver must not use ->wait() to complete such
requests.
- int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len)
Send raw output report via intr channel. Used by some HID device drivers
which require high throughput for outgoing requests on the intr channel. This
must not cause SET_REPORT calls! This must be implemented as asynchronous
output report on the intr channel!
- int (*idle) (struct hid_device *hdev, int report, int idle, int reqtype)
Perform SET/GET_IDLE request. Only used by USB-HID, do not implement!
2.3) Data Path
--------------
Transport drivers are responsible of reading data from I/O devices. They must
handle any I/O-related state-tracking themselves. HID core does not implement
protocol handshakes or other management commands which can be required by the
given HID transport specification.
Every raw data packet read from a device must be fed into HID core via
hid_input_report(). You must specify the channel-type (intr or ctrl) and report
type (input/output/feature). Under normal conditions, only input reports are
provided via this API.
Responses to GET_REPORT requests via ->request() must also be provided via this
API. Responses to ->raw_request() are synchronous and must be intercepted by the
transport driver and not passed to hid_input_report().
Acknowledgements to SET_REPORT requests are not of interest to HID core.
----------------------------------------------------
Written 2013, David Herrmann <dh.herrmann@gmail.com>
drivers/hid/hid-core.c
浏览文件 @
d6a611f5
...
...
@@ -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,44 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
return
report
;
}
/*
* Implement a generic .request() callback, using .raw_request()
* DO NOT USE in hid drivers directly, but through hid_hw_request instead.
*/
void
__hid_request
(
struct
hid_device
*
hid
,
struct
hid_report
*
report
,
int
reqtype
)
{
char
*
buf
;
int
ret
;
int
len
;
if
(
!
hid
->
ll_driver
->
raw_request
)
return
;
buf
=
hid_alloc_report_buf
(
report
,
GFP_KERNEL
);
if
(
!
buf
)
return
;
len
=
hid_report_len
(
report
);
if
(
reqtype
==
HID_REQ_SET_REPORT
)
hid_output_report
(
report
,
buf
);
ret
=
hid
->
ll_driver
->
raw_request
(
hid
,
report
->
id
,
buf
,
len
,
report
->
type
,
reqtype
);
if
(
ret
<
0
)
{
dbg_hid
(
"unable to complete request: %d
\n
"
,
ret
);
goto
out
;
}
if
(
reqtype
==
HID_REQ_GET_REPORT
)
hid_input_report
(
hid
,
report
->
type
,
buf
,
ret
,
0
);
out:
kfree
(
buf
);
}
EXPORT_SYMBOL_GPL
(
__hid_request
);
int
hid_report_raw_event
(
struct
hid_device
*
hid
,
int
type
,
u8
*
data
,
int
size
,
int
interrupt
)
{
...
...
drivers/hid/hid-input.c
浏览文件 @
d6a611f5
...
...
@@ -350,9 +350,9 @@ static int hidinput_get_battery_property(struct power_supply *psy,
ret
=
-
ENOMEM
;
break
;
}
ret
=
dev
->
hid_get_raw_report
(
dev
,
dev
->
battery_report_id
,
buf
,
2
,
dev
->
battery_report_type
);
ret
=
hid_hw_raw_request
(
dev
,
dev
->
battery_report_id
,
buf
,
2
,
dev
->
battery_report_type
,
HID_REQ_GET_REPORT
);
if
(
ret
!=
2
)
{
ret
=
-
ENODATA
;
...
...
@@ -1184,7 +1184,7 @@ static void hidinput_led_worker(struct work_struct *work)
hid_output_report
(
report
,
buf
);
/* synchronous output report */
hid
->
hid
_output_raw_report
(
hid
,
buf
,
len
,
HID_OUTPUT_REPORT
);
hid_output_raw_report
(
hid
,
buf
,
len
,
HID_OUTPUT_REPORT
);
kfree
(
buf
);
}
...
...
@@ -1263,9 +1263,7 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
}
input_set_drvdata
(
input_dev
,
hid
);
if
(
hid
->
ll_driver
->
hidinput_input_event
)
input_dev
->
event
=
hid
->
ll_driver
->
hidinput_input_event
;
else
if
(
hid
->
ll_driver
->
request
||
hid
->
hid_output_raw_report
)
if
(
hid
->
ll_driver
->
request
||
hid
->
hid_output_raw_report
)
input_dev
->
event
=
hidinput_input_event
;
input_dev
->
open
=
hidinput_open
;
input_dev
->
close
=
hidinput_close
;
...
...
drivers/hid/hid-lg.c
浏览文件 @
d6a611f5
...
...
@@ -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
);
}
}
...
...
drivers/hid/hid-logitech-dj.c
浏览文件 @
d6a611f5
...
...
@@ -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_even
t
,
.
raw_request
=
logi_dj_ll_raw_reques
t
,
};
...
...
drivers/hid/hid-magicmouse.c
浏览文件 @
d6a611f5
...
...
@@ -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
=
h
dev
->
hid_output_raw_report
(
hdev
,
feature
,
sizeof
(
feature
),
HID_FEATURE
_REPORT
);
ret
=
h
id_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
;
...
...
drivers/hid/hid-sony.c
浏览文件 @
d6a611f5
...
...
@@ -706,7 +706,8 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev)
if
(
!
buf
)
return
-
ENOMEM
;
ret
=
hdev
->
hid_get_raw_report
(
hdev
,
0xf2
,
buf
,
17
,
HID_FEATURE_REPORT
);
ret
=
hid_hw_raw_request
(
hdev
,
0xf2
,
buf
,
17
,
HID_FEATURE_REPORT
,
HID_REQ_GET_REPORT
);
if
(
ret
<
0
)
hid_err
(
hdev
,
"can't set operational mode
\n
"
);
...
...
@@ -719,7 +720,8 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev)
static
int
sixaxis_set_operational_bt
(
struct
hid_device
*
hdev
)
{
unsigned
char
buf
[]
=
{
0xf4
,
0x42
,
0x03
,
0x00
,
0x00
};
return
hdev
->
hid_output_raw_report
(
hdev
,
buf
,
sizeof
(
buf
),
HID_FEATURE_REPORT
);
return
hid_hw_raw_request
(
hdev
,
buf
[
0
],
buf
,
sizeof
(
buf
),
HID_FEATURE_REPORT
,
HID_REQ_SET_REPORT
);
}
static
void
buzz_set_leds
(
struct
hid_device
*
hdev
,
const
__u8
*
leds
)
...
...
@@ -941,8 +943,7 @@ static void sixaxis_state_worker(struct work_struct *work)
buf
[
10
]
|=
sc
->
led_state
[
2
]
<<
3
;
buf
[
10
]
|=
sc
->
led_state
[
3
]
<<
4
;
sc
->
hdev
->
hid_output_raw_report
(
sc
->
hdev
,
buf
,
sizeof
(
buf
),
HID_OUTPUT_REPORT
);
hid_output_raw_report
(
sc
->
hdev
,
buf
,
sizeof
(
buf
),
HID_OUTPUT_REPORT
);
}
static
void
dualshock4_state_worker
(
struct
work_struct
*
work
)
...
...
drivers/hid/hid-thingm.c
浏览文件 @
d6a611f5
...
...
@@ -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
;
}
...
...
drivers/hid/hid-wacom.c
浏览文件 @
d6a611f5
...
...
@@ -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
=
h
dev
->
hid_output_raw_report
(
hdev
,
rep_data
,
2
,
HID_FEATURE
_REPORT
);
ret
=
h
id_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
=
h
dev
->
hid_output_raw_report
(
hdev
,
rep_data
,
67
,
HID_FEATURE_REPORT
);
ret
=
h
id_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
=
h
dev
->
hid_output_raw_report
(
hdev
,
rep_data
,
2
,
HID_FEATURE
_REPORT
);
ret
=
h
id_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
=
h
dev
->
hid_output_raw_report
(
hdev
,
rep_data
,
2
,
HID_FEATURE_REPORT
);
ret
=
h
id_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
=
h
dev
->
hid_output_raw_report
(
hdev
,
rep_data
,
2
,
HID_FEATURE
_REPORT
);
ret
=
h
id_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
;
...
...
drivers/hid/hid-wiimote-core.c
浏览文件 @
d6a611f5
...
...
@@ -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
=
h
dev
->
hid_output_raw_report
(
hdev
,
buf
,
count
,
HID_OUTPUT_REPORT
);
ret
=
h
id_hw_output_report
(
hdev
,
buf
,
count
);
kfree
(
buf
);
return
ret
;
...
...
drivers/hid/hidraw.c
浏览文件 @
d6a611f5
...
...
@@ -153,7 +153,7 @@ static ssize_t hidraw_send_report(struct file *file, const char __user *buffer,
goto
out_free
;
}
ret
=
dev
->
hid_output_raw_report
(
dev
,
buf
,
count
,
report_type
);
ret
=
hid_output_raw_report
(
dev
,
buf
,
count
,
report_type
);
out_free:
kfree
(
buf
);
out:
...
...
@@ -189,7 +189,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
dev
=
hidraw_table
[
minor
]
->
hid
;
if
(
!
dev
->
hid_get_raw_repor
t
)
{
if
(
!
dev
->
ll_driver
->
raw_reques
t
)
{
ret
=
-
ENODEV
;
goto
out
;
}
...
...
@@ -216,14 +216,15 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
/*
* Read the first byte from the user. This is the report number,
* which is passed to
dev->hid_get_raw_repor
t().
* which is passed to
hid_hw_raw_reques
t().
*/
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
;
...
...
drivers/hid/i2c-hid/i2c-hid.c
浏览文件 @
d6a611f5
...
...
@@ -256,18 +256,27 @@ static int i2c_hid_get_report(struct i2c_client *client, u8 reportType,
return
0
;
}
static
int
i2c_hid_set_report
(
struct
i2c_client
*
client
,
u8
reportType
,
u8
reportID
,
unsigned
char
*
buf
,
size_t
data_len
)
/**
* i2c_hid_set_or_send_report: forward an incoming report to the device
* @client: the i2c_client of the device
* @reportType: 0x03 for HID_FEATURE_REPORT ; 0x02 for HID_OUTPUT_REPORT
* @reportID: the report ID
* @buf: the actual data to transfer, without the report ID
* @len: size of buf
* @use_data: true: use SET_REPORT HID command, false: send plain OUTPUT report
*/
static
int
i2c_hid_set_or_send_report
(
struct
i2c_client
*
client
,
u8
reportType
,
u8
reportID
,
unsigned
char
*
buf
,
size_t
data_len
,
bool
use_data
)
{
struct
i2c_hid
*
ihid
=
i2c_get_clientdata
(
client
);
u8
*
args
=
ihid
->
argsbuf
;
const
struct
i2c_hid_cmd
*
hidcmd
=
&
hid_set_report_
cmd
;
const
struct
i2c_hid_cmd
*
hid
cmd
;
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
);
/* hid
raw
already checked that data_len < HID_MAX_BUFFER_SIZE */
/* hid
_hw_*
already checked that data_len < HID_MAX_BUFFER_SIZE */
u16
size
=
2
/* size */
+
(
reportID
?
1
:
0
)
/* reportID */
+
data_len
/* buf */
;
...
...
@@ -278,6 +287,9 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
i2c_hid_dbg
(
ihid
,
"%s
\n
"
,
__func__
);
if
(
!
use_data
&&
maxOutputLength
==
0
)
return
-
ENOSYS
;
if
(
reportID
>=
0x0F
)
{
args
[
index
++
]
=
reportID
;
reportID
=
0x0F
;
...
...
@@ -287,9 +299,10 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
* use the data register for feature reports or if the device does not
* support the output register
*/
if
(
reportType
==
0x03
||
maxOutputLength
==
0
)
{
if
(
use_data
)
{
args
[
index
++
]
=
dataRegister
&
0xFF
;
args
[
index
++
]
=
dataRegister
>>
8
;
hidcmd
=
&
hid_set_report_cmd
;
}
else
{
args
[
index
++
]
=
outputRegister
&
0xFF
;
args
[
index
++
]
=
outputRegister
>>
8
;
...
...
@@ -550,7 +563,7 @@ static int i2c_hid_get_raw_report(struct hid_device *hid,
}
static
int
i2c_hid_output_raw_report
(
struct
hid_device
*
hid
,
__u8
*
buf
,
size_t
count
,
unsigned
char
report_type
)
size_t
count
,
unsigned
char
report_type
,
bool
use_data
)
{
struct
i2c_client
*
client
=
hid
->
driver_data
;
int
report_id
=
buf
[
0
];
...
...
@@ -564,9 +577,9 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
count
--
;
}
ret
=
i2c_hid_set_report
(
client
,
ret
=
i2c_hid_set_
or_send_
report
(
client
,
report_type
==
HID_FEATURE_REPORT
?
0x03
:
0x02
,
report_id
,
buf
,
count
);
report_id
,
buf
,
count
,
use_data
);
if
(
report_id
&&
ret
>=
0
)
ret
++
;
/* add report_id to the number of transfered bytes */
...
...
@@ -574,34 +587,40 @@ 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
req
type
)
static
int
__i2c_hid_output_raw_report
(
struct
hid_device
*
hid
,
__u8
*
buf
,
size_t
count
,
unsigned
char
report_
type
)
{
struct
i2c_client
*
client
=
hid
->
driver_data
;
char
*
buf
;
int
ret
;
int
len
=
i2c_hid_get_report_length
(
rep
)
-
2
;
struct
i2c_hid
*
ihid
=
i2c_get_clientdata
(
client
);
bool
data
=
true
;
/* SET_REPORT */
buf
=
kzalloc
(
len
,
GFP_KERNEL
);
if
(
!
buf
)
return
;
if
(
report_type
==
HID_OUTPUT_REPORT
)
data
=
le16_to_cpu
(
ihid
->
hdesc
.
wMaxOutputLength
)
==
0
;
return
i2c_hid_output_raw_report
(
hid
,
buf
,
count
,
report_type
,
data
);
}
static
int
i2c_hid_output_report
(
struct
hid_device
*
hid
,
__u8
*
buf
,
size_t
count
)
{
return
i2c_hid_output_raw_report
(
hid
,
buf
,
count
,
HID_OUTPUT_REPORT
,
false
);
}
static
int
i2c_hid_raw_request
(
struct
hid_device
*
hid
,
unsigned
char
reportnum
,
__u8
*
buf
,
size_t
len
,
unsigned
char
rtype
,
int
reqtype
)
{
switch
(
reqtype
)
{
case
HID_REQ_GET_REPORT
:
ret
=
i2c_hid_get_raw_report
(
hid
,
rep
->
id
,
buf
,
len
,
rep
->
type
);
if
(
ret
<
0
)
dev_err
(
&
client
->
dev
,
"%s: unable to get report: %d
\n
"
,
__func__
,
ret
);
else
hid_input_report
(
hid
,
rep
->
type
,
buf
,
ret
,
0
);
break
;
return
i2c_hid_get_raw_report
(
hid
,
reportnum
,
buf
,
len
,
rtype
);
case
HID_REQ_SET_REPORT
:
hid_output_report
(
rep
,
buf
);
i2c_hid_output_raw_report
(
hid
,
buf
,
len
,
rep
->
type
);
break
;
if
(
buf
[
0
]
!=
reportnum
)
return
-
EINVAL
;
return
i2c_hid_output_raw_report
(
hid
,
buf
,
len
,
rtype
,
true
);
default:
return
-
EIO
;
}
kfree
(
buf
);
}
static
int
i2c_hid_parse
(
struct
hid_device
*
hid
)
...
...
@@ -760,7 +779,8 @@ static struct hid_ll_driver i2c_hid_ll_driver = {
.
open
=
i2c_hid_open
,
.
close
=
i2c_hid_close
,
.
power
=
i2c_hid_power
,
.
request
=
i2c_hid_request
,
.
output_report
=
i2c_hid_output_report
,
.
raw_request
=
i2c_hid_raw_request
,
};
static
int
i2c_hid_init_irq
(
struct
i2c_client
*
client
)
...
...
@@ -1005,8 +1025,7 @@ 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
->
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
;
...
...
drivers/hid/uhid.c
浏览文件 @
d6a611f5
...
...
@@ -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,7 +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
;
...
...
drivers/hid/usbhid/hid-core.c
浏览文件 @
d6a611f5
...
...
@@ -884,58 +884,78 @@ static int usbhid_get_raw_report(struct hid_device *hid,
return
ret
;
}
static
int
usbhid_
output_raw_report
(
struct
hid_device
*
hid
,
__u8
*
buf
,
size_t
count
,
unsigned
char
report_
type
)
static
int
usbhid_
set_raw_report
(
struct
hid_device
*
hid
,
unsigned
int
reportnum
,
__u8
*
buf
,
size_t
count
,
unsigned
char
r
type
)
{
struct
usbhid_device
*
usbhid
=
hid
->
driver_data
;
struct
usb_device
*
dev
=
hid_to_usb_dev
(
hid
);
struct
usb_interface
*
intf
=
usbhid
->
intf
;
struct
usb_host_interface
*
interface
=
intf
->
cur_altsetting
;
int
ret
;
int
ret
,
skipped_report_id
=
0
;
if
(
usbhid
->
urbout
&&
report_type
!=
HID_FEATURE_REPORT
)
{
int
actual_length
;
int
skipped_report_id
=
0
;
/* Byte 0 is the report number. Report data starts at byte 1.*/
buf
[
0
]
=
reportnum
;
if
(
buf
[
0
]
==
0x0
)
{
/* Don't send the Report ID */
buf
++
;
count
--
;
skipped_report_id
=
1
;
}
if
(
buf
[
0
]
==
0x0
)
{
/* Don't send the Report ID */
buf
++
;
count
--
;
skipped_report_id
=
1
;
}
ret
=
usb_interrupt_msg
(
dev
,
usbhid
->
urbout
->
pipe
,
buf
,
count
,
&
actual_length
,
USB_CTRL_SET_TIMEOUT
);
/* return the number of bytes transferred */
if
(
ret
==
0
)
{
ret
=
actual_length
;
/* count also the report id */
if
(
skipped_report_id
)
ret
++
;
}
}
else
{
int
skipped_report_id
=
0
;
int
report_id
=
buf
[
0
];
if
(
buf
[
0
]
==
0x0
)
{
/* Don't send the Report ID */
buf
++
;
count
--
;
skipped_report_id
=
1
;
}
ret
=
usb_control_msg
(
dev
,
usb_sndctrlpipe
(
dev
,
0
),
ret
=
usb_control_msg
(
dev
,
usb_sndctrlpipe
(
dev
,
0
),
HID_REQ_SET_REPORT
,
USB_DIR_OUT
|
USB_TYPE_CLASS
|
USB_RECIP_INTERFACE
,
((
r
eport_type
+
1
)
<<
8
)
|
report_id
,
((
r
type
+
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
++
;
}
return
ret
;
}
static
int
usbhid_output_raw_report
(
struct
hid_device
*
hid
,
__u8
*
buf
,
size_t
count
,
unsigned
char
report_type
)
{
struct
usbhid_device
*
usbhid
=
hid
->
driver_data
;
if
(
usbhid
->
urbout
&&
report_type
!=
HID_FEATURE_REPORT
)
return
usbhid_output_report
(
hid
,
buf
,
count
);
return
usbhid_set_raw_report
(
hid
,
buf
[
0
],
buf
,
count
,
report_type
);
}
static
void
usbhid_restart_queues
(
struct
usbhid_device
*
usbhid
)
{
if
(
usbhid
->
urbout
&&
!
test_bit
(
HID_OUT_RUNNING
,
&
usbhid
->
iofl
))
...
...
@@ -1200,6 +1220,20 @@ static void usbhid_request(struct hid_device *hid, struct hid_report *rep, int r
}
}
static
int
usbhid_raw_request
(
struct
hid_device
*
hid
,
unsigned
char
reportnum
,
__u8
*
buf
,
size_t
len
,
unsigned
char
rtype
,
int
reqtype
)
{
switch
(
reqtype
)
{
case
HID_REQ_GET_REPORT
:
return
usbhid_get_raw_report
(
hid
,
reportnum
,
buf
,
len
,
rtype
);
case
HID_REQ_SET_REPORT
:
return
usbhid_set_raw_report
(
hid
,
reportnum
,
buf
,
len
,
rtype
);
default:
return
-
EIO
;
}
}
static
int
usbhid_idle
(
struct
hid_device
*
hid
,
int
report
,
int
idle
,
int
reqtype
)
{
...
...
@@ -1223,6 +1257,8 @@ static struct hid_ll_driver usb_hid_driver = {
.
power
=
usbhid_power
,
.
request
=
usbhid_request
,
.
wait
=
usbhid_wait_io
,
.
raw_request
=
usbhid_raw_request
,
.
output_report
=
usbhid_output_report
,
.
idle
=
usbhid_idle
,
};
...
...
@@ -1253,7 +1289,6 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
usb_set_intfdata
(
intf
,
hid
);
hid
->
ll_driver
=
&
usb_hid_driver
;
hid
->
hid_get_raw_report
=
usbhid_get_raw_report
;
hid
->
hid_output_raw_report
=
usbhid_output_raw_report
;
hid
->
ff_init
=
hid_pidff_init
;
#ifdef CONFIG_USB_HIDDEV
...
...
include/linux/hid.h
浏览文件 @
d6a611f5
...
...
@@ -508,9 +508,6 @@ struct hid_device { /* device report descriptor */
struct
hid_usage
*
,
__s32
);
void
(
*
hiddev_report_event
)
(
struct
hid_device
*
,
struct
hid_report
*
);
/* handler for raw input (Get_Report) data, used by hidraw */
int
(
*
hid_get_raw_report
)
(
struct
hid_device
*
,
unsigned
char
,
__u8
*
,
size_t
,
unsigned
char
);
/* handler for raw output data, used by hidraw */
int
(
*
hid_output_raw_report
)
(
struct
hid_device
*
,
__u8
*
,
size_t
,
unsigned
char
);
...
...
@@ -675,11 +672,12 @@ struct hid_driver {
* @stop: called on remove
* @open: called by input layer on open
* @close: called by input layer on close
* @hidinput_input_event: event input event (e.g. ff or leds)
* @parse: this method is called only once to parse the device data,
* shouldn't allocate anything to not leak memory
* @request: send report request to device (e.g. feature report)
* @wait: wait for buffered io to complete (send/recv reports)
* @raw_request: send raw report request to device (e.g. feature report)
* @output_report: send output report to device
* @idle: send idle request to device
*/
struct
hid_ll_driver
{
...
...
@@ -691,17 +689,20 @@ struct hid_ll_driver {
int
(
*
power
)(
struct
hid_device
*
hdev
,
int
level
);
int
(
*
hidinput_input_event
)
(
struct
input_dev
*
idev
,
unsigned
int
type
,
unsigned
int
code
,
int
value
);
int
(
*
parse
)(
struct
hid_device
*
hdev
);
void
(
*
request
)(
struct
hid_device
*
hdev
,
struct
hid_report
*
report
,
int
reqtype
);
int
(
*
wait
)(
struct
hid_device
*
hdev
);
int
(
*
idle
)(
struct
hid_device
*
hdev
,
int
report
,
int
idle
,
int
reqtype
);
int
(
*
raw_request
)
(
struct
hid_device
*
hdev
,
unsigned
char
reportnum
,
__u8
*
buf
,
size_t
len
,
unsigned
char
rtype
,
int
reqtype
);
int
(
*
output_report
)
(
struct
hid_device
*
hdev
,
__u8
*
buf
,
size_t
len
);
int
(
*
idle
)(
struct
hid_device
*
hdev
,
int
report
,
int
idle
,
int
reqtype
);
};
#define PM_HINT_FULLON 1<<5
...
...
@@ -752,6 +753,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 +966,74 @@ 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
;
if
(
hdev
->
ll_driver
->
raw_request
)
return
hdev
->
ll_driver
->
raw_request
(
hdev
,
reportnum
,
buf
,
len
,
rtype
,
reqtype
);
return
-
ENOSYS
;
}
/**
* hid_hw_output_report - send output report to device
*
* @hdev: hid device
* @buf: raw data to transfer
* @len: length of buf
*
* @return: count of data transfered, negative if error
*/
static
inline
int
hid_hw_output_report
(
struct
hid_device
*
hdev
,
__u8
*
buf
,
size_t
len
)
{
if
(
len
<
1
||
len
>
HID_MAX_BUFFER_SIZE
||
!
buf
)
return
-
EINVAL
;
if
(
hdev
->
ll_driver
->
output_report
)
return
hdev
->
ll_driver
->
output_report
(
hdev
,
buf
,
len
);
return
-
ENOSYS
;
}
/**
* hid_output_raw_report - send an output or a feature report to the device
*
* @hdev: hid device
* @buf: raw data to transfer
* @len: length of buf
* @report_type: HID_FEATURE_REPORT or HID_OUTPUT_REPORT
*
* @return: count of data transfered, negative if error
*/
static
inline
int
hid_output_raw_report
(
struct
hid_device
*
hdev
,
__u8
*
buf
,
size_t
len
,
unsigned
char
report_type
)
{
return
hdev
->
hid_output_raw_report
(
hdev
,
buf
,
len
,
report_type
);
}
/**
...
...
net/bluetooth/hidp/core.c
浏览文件 @
d6a611f5
...
...
@@ -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 @@ static int hidp_get_raw_report(struct hid_device *hid,
return
ret
;
}
static
int
hidp_output_raw_report
(
struct
hid_device
*
hid
,
unsigned
char
*
data
,
size_t
count
,
unsigned
char
report_type
)
static
int
hidp_set_raw_report
(
struct
hid_device
*
hid
,
unsigned
char
reportnum
,
unsigned
char
*
data
,
size_t
count
,
unsigned
char
report_type
)
{
struct
hidp_session
*
session
=
hid
->
driver_data
;
int
ret
;
if
(
report_type
==
HID_OUTPUT_REPORT
)
{
report_type
=
HIDP_TRANS_DATA
|
HIDP_DATA_RTYPE_OUPUT
;
return
hidp_send_intr_message
(
session
,
report_type
,
data
,
count
);
}
else
if
(
report_type
!=
HID_FEATURE_REPORT
)
{
switch
(
report_type
)
{
case
HID_FEATURE_REPORT
:
report_type
=
HIDP_TRANS_SET_REPORT
|
HIDP_DATA_RTYPE_FEATURE
;
break
;
case
HID_INPUT_REPORT
:
report_type
=
HIDP_TRANS_SET_REPORT
|
HIDP_DATA_RTYPE_INPUT
;
break
;
case
HID_OUTPUT_REPORT
:
report_type
=
HIDP_TRANS_SET_REPORT
|
HIDP_DATA_RTYPE_OUPUT
;
break
;
default:
return
-
EINVAL
;
}
...
...
@@ -371,8 +333,8 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s
return
-
ERESTARTSYS
;
/* Set up our wait, and send the report request to the device. */
data
[
0
]
=
reportnum
;
set_bit
(
HIDP_WAITING_FOR_SEND_ACK
,
&
session
->
flags
);
report_type
=
HIDP_TRANS_SET_REPORT
|
HIDP_DATA_RTYPE_FEATURE
;
ret
=
hidp_send_ctrl_message
(
session
,
report_type
,
data
,
count
);
if
(
ret
)
goto
err
;
...
...
@@ -411,6 +373,41 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s
return
ret
;
}
static
int
hidp_output_report
(
struct
hid_device
*
hid
,
__u8
*
data
,
size_t
count
)
{
struct
hidp_session
*
session
=
hid
->
driver_data
;
return
hidp_send_intr_message
(
session
,
HIDP_TRANS_DATA
|
HIDP_DATA_RTYPE_OUPUT
,
data
,
count
);
}
static
int
hidp_output_raw_report
(
struct
hid_device
*
hid
,
unsigned
char
*
data
,
size_t
count
,
unsigned
char
report_type
)
{
if
(
report_type
==
HID_OUTPUT_REPORT
)
{
return
hidp_output_report
(
hid
,
data
,
count
);
}
else
if
(
report_type
!=
HID_FEATURE_REPORT
)
{
return
-
EINVAL
;
}
return
hidp_set_raw_report
(
hid
,
data
[
0
],
data
,
count
,
report_type
);
}
static
int
hidp_raw_request
(
struct
hid_device
*
hid
,
unsigned
char
reportnum
,
__u8
*
buf
,
size_t
len
,
unsigned
char
rtype
,
int
reqtype
)
{
switch
(
reqtype
)
{
case
HID_REQ_GET_REPORT
:
return
hidp_get_raw_report
(
hid
,
reportnum
,
buf
,
len
,
rtype
);
case
HID_REQ_SET_REPORT
:
return
hidp_set_raw_report
(
hid
,
reportnum
,
buf
,
len
,
rtype
);
default:
return
-
EIO
;
}
}
static
void
hidp_idle_timeout
(
unsigned
long
arg
)
{
struct
hidp_session
*
session
=
(
struct
hidp_session
*
)
arg
;
...
...
@@ -727,7 +724,8 @@ static struct hid_ll_driver hidp_hid_driver = {
.
stop
=
hidp_stop
,
.
open
=
hidp_open
,
.
close
=
hidp_close
,
.
hidinput_input_event
=
hidp_hidinput_event
,
.
raw_request
=
hidp_raw_request
,
.
output_report
=
hidp_output_report
,
};
/* This function sets up the hid device. It does not add it
...
...
@@ -775,7 +773,6 @@ static int hidp_setup_hid(struct hidp_session *session,
hid
->
dev
.
parent
=
&
session
->
conn
->
hcon
->
dev
;
hid
->
ll_driver
=
&
hidp_hid_driver
;
hid
->
hid_get_raw_report
=
hidp_get_raw_report
;
hid
->
hid_output_raw_report
=
hidp_output_raw_report
;
/* True if device is blacklisted in drivers/hid/hid-core.c */
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录