1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Human Interface Device gadget module.
7 This gadget emulates a USB Human Interface Device. Multiple logical components
8 of a device can be composed together as separate "features" where each has its
9 own Report ID and will be called upon to answer get/set input/output/feature
10 report requests as necessary.
20 import usb_descriptors
23 class HidGadget(gadget
.Gadget
):
24 """Generic HID gadget.
27 def __init__(self
, report_desc
, features
, vendor_id
, product_id
,
28 packet_size
=64, interval_ms
=10, out_endpoint
=True,
29 device_version
=0x0100):
30 """Create a HID gadget.
33 report_desc: HID report descriptor.
34 features: Map between Report IDs and HidFeature objects to handle them.
35 vendor_id: Device Vendor ID.
36 product_id: Device Product ID.
37 packet_size: Maximum interrupt packet size.
38 interval_ms: Interrupt transfer interval in milliseconds.
39 out_endpoint: Should this device have an interrupt OUT endpoint?
40 device_version: Device version number.
43 ValueError: If any of the parameters are out of range.
45 device_desc
= usb_descriptors
.DeviceDescriptor(
52 bcdDevice
=device_version
)
54 fs_config_desc
= usb_descriptors
.ConfigurationDescriptor(
57 fs_interface_desc
= usb_descriptors
.InterfaceDescriptor(
59 bInterfaceClass
=usb_constants
.DeviceClass
.HID
,
60 bInterfaceSubClass
=0, # Non-bootable.
61 bInterfaceProtocol
=0, # None.
63 fs_config_desc
.AddInterface(fs_interface_desc
)
65 hs_config_desc
= usb_descriptors
.ConfigurationDescriptor(
68 hs_interface_desc
= usb_descriptors
.InterfaceDescriptor(
70 bInterfaceClass
=usb_constants
.DeviceClass
.HID
,
71 bInterfaceSubClass
=0, # Non-bootable.
72 bInterfaceProtocol
=0, # None.
74 hs_config_desc
.AddInterface(hs_interface_desc
)
76 hid_desc
= usb_descriptors
.HidDescriptor()
77 hid_desc
.AddDescriptor(hid_constants
.DescriptorType
.REPORT
,
79 fs_interface_desc
.Add(hid_desc
)
80 hs_interface_desc
.Add(hid_desc
)
82 fs_interval
= math
.ceil(math
.log(interval_ms
, 2)) + 1
83 if fs_interval
< 1 or fs_interval
> 16:
84 raise ValueError('Full speed interval out of range: {} ({} ms)'
85 .format(fs_interval
, interval_ms
))
87 fs_interface_desc
.AddEndpoint(usb_descriptors
.EndpointDescriptor(
88 bEndpointAddress
=0x81,
89 bmAttributes
=usb_constants
.TransferType
.INTERRUPT
,
90 wMaxPacketSize
=packet_size
,
94 hs_interval
= math
.ceil(math
.log(interval_ms
, 2)) + 4
95 if hs_interval
< 1 or hs_interval
> 16:
96 raise ValueError('High speed interval out of range: {} ({} ms)'
97 .format(hs_interval
, interval_ms
))
99 hs_interface_desc
.AddEndpoint(usb_descriptors
.EndpointDescriptor(
100 bEndpointAddress
=0x81,
101 bmAttributes
=usb_constants
.TransferType
.INTERRUPT
,
102 wMaxPacketSize
=packet_size
,
103 bInterval
=hs_interval
107 fs_interface_desc
.AddEndpoint(usb_descriptors
.EndpointDescriptor(
108 bEndpointAddress
=0x01,
109 bmAttributes
=usb_constants
.TransferType
.INTERRUPT
,
110 wMaxPacketSize
=packet_size
,
111 bInterval
=fs_interval
113 hs_interface_desc
.AddEndpoint(usb_descriptors
.EndpointDescriptor(
114 bEndpointAddress
=0x01,
115 bmAttributes
=usb_constants
.TransferType
.INTERRUPT
,
116 wMaxPacketSize
=packet_size
,
117 bInterval
=hs_interval
120 super(HidGadget
, self
).__init
__(device_desc
, fs_config_desc
, hs_config_desc
)
121 self
.AddStringDescriptor(3, '{:06X}'.format(uuid
.getnode()))
122 self
._report
_desc
= report_desc
123 self
._features
= features
125 def Connected(self
, chip
, speed
):
126 super(HidGadget
, self
).Connected(chip
, speed
)
127 for report_id
, feature
in self
._features
.iteritems():
128 feature
.Connected(self
, report_id
)
130 def Disconnected(self
):
131 super(HidGadget
, self
).Disconnected()
132 for feature
in self
._features
.itervalues():
133 feature
.Disconnected()
135 def GetDescriptor(self
, recipient
, typ
, index
, lang
, length
):
136 if recipient
== usb_constants
.Recipient
.INTERFACE
:
137 if typ
== hid_constants
.DescriptorType
.REPORT
:
139 return self
._report
_desc
[:length
]
141 return super(HidGadget
, self
).GetDescriptor(recipient
, typ
, index
, lang
,
144 def ClassControlRead(self
, recipient
, request
, value
, index
, length
):
145 """Handle class-specific control requests.
147 See Device Class Definition for Human Interface Devices (HID) Version 1.11
151 recipient: Request recipient (device, interface, endpoint, etc.)
152 request: bRequest field of the setup packet.
153 value: wValue field of the setup packet.
154 index: wIndex field of the setup packet.
155 length: Maximum amount of data the host expects the device to return.
158 A buffer to return to the USB host with len <= length on success or
159 None to stall the pipe.
161 if recipient
!= usb_constants
.Recipient
.INTERFACE
:
166 if request
== hid_constants
.Request
.GET_REPORT
:
167 report_type
, report_id
= value
>> 8, value
& 0xFF
168 print ('GetReport(type={}, id={}, length={})'
169 .format(report_type
, report_id
, length
))
170 return self
.GetReport(report_type
, report_id
, length
)
172 def ClassControlWrite(self
, recipient
, request
, value
, index
, data
):
173 """Handle class-specific control requests.
175 See Device Class Definition for Human Interface Devices (HID) Version 1.11
179 recipient: Request recipient (device, interface, endpoint, etc.)
180 request: bRequest field of the setup packet.
181 value: wValue field of the setup packet.
182 index: wIndex field of the setup packet.
183 data: Data stage of the request.
186 True on success, None to stall the pipe.
188 if recipient
!= usb_constants
.Recipient
.INTERFACE
:
193 if request
== hid_constants
.Request
.SET_REPORT
:
194 report_type
, report_id
= value
>> 8, value
& 0xFF
195 print('SetReport(type={}, id={}, length={})'
196 .format(report_type
, report_id
, len(data
)))
197 return self
.SetReport(report_type
, report_id
, data
)
198 elif request
== hid_constants
.Request
.SET_IDLE
:
199 duration
, report_id
= value
>> 8, value
& 0xFF
200 print('SetIdle(duration={}, report={})'
201 .format(duration
, report_id
))
204 def GetReport(self
, report_type
, report_id
, length
):
205 """Handle GET_REPORT requests.
207 See Device Class Definition for Human Interface Devices (HID) Version 1.11
211 report_type: Requested report type.
212 report_id: Requested report ID.
213 length: Maximum amount of data the host expects the device to return.
216 A buffer to return to the USB host with len <= length on success or
217 None to stall the pipe.
219 feature
= self
._features
.get(report_id
, None)
223 if report_type
== hid_constants
.ReportType
.INPUT
:
224 return feature
.GetInputReport()[:length
]
225 elif report_type
== hid_constants
.ReportType
.OUTPUT
:
226 return feature
.GetOutputReport()[:length
]
227 elif report_type
== hid_constants
.ReportType
.FEATURE
:
228 return feature
.GetFeatureReport()[:length
]
230 def SetReport(self
, report_type
, report_id
, data
):
231 """Handle SET_REPORT requests.
233 See Device Class Definition for Human Interface Devices (HID) Version 1.11
237 report_type: Report type.
238 report_id: Report ID.
242 True on success, None to stall the pipe.
244 feature
= self
._features
.get(report_id
, None)
248 if report_type
== hid_constants
.ReportType
.INPUT
:
249 return feature
.SetInputReport(data
)
250 elif report_type
== hid_constants
.ReportType
.OUTPUT
:
251 return feature
.SetOutputReport(data
)
252 elif report_type
== hid_constants
.ReportType
.FEATURE
:
253 return feature
.SetFeatureReport(data
)
255 def SendReport(self
, report_id
, data
):
256 """Send a HID report.
258 See Device Class Definition for Human Interface Devices (HID) Version 1.11
262 report_id: Report ID associated with the data.
263 data: Contents of the report.
266 self
.SendPacket(0x81, data
)
268 self
.SendPacket(0x81, struct
.pack('B', report_id
) + data
)
270 def ReceivePacket(self
, endpoint
, data
):
271 """Dispatch a report to the appropriate feature.
273 See Device Class Definition for Human Interface Devices (HID) Version 1.11
277 endpoint: Incoming endpoint (must be the Interrupt OUT pipe).
278 data: Interrupt packet data.
280 assert endpoint
== 0x01
282 if 0 in self
._features
:
283 self
._features
[0].SetOutputReport(data
)
285 report_id
, = struct
.unpack('B', data
[0])
286 feature
= self
._features
.get(report_id
, None)
287 if feature
is None or feature
.SetOutputReport(data
[1:]) is None:
288 self
.HaltEndpoint(endpoint
)
291 class HidFeature(object):
292 """Represents a component of a HID gadget.
294 A "feature" produces and consumes reports with a particular Report ID. For
295 example a keyboard, mouse or vendor specific functionality.
300 self
._report
_id
= None
302 def Connected(self
, my_gadget
, report_id
):
303 self
._gadget
= my_gadget
304 self
._report
_id
= report_id
306 def Disconnected(self
):
308 self
._report
_id
= None
310 def IsConnected(self
):
311 return self
._gadget
is not None
313 def SendReport(self
, data
):
314 """Send a report with this feature's Report ID.
317 data: Report to send. If necessary the Report ID will be added.
320 RuntimeError: If a report cannot be sent at this time.
322 if not self
.IsConnected():
323 raise RuntimeError('Device is not connected.')
324 self
._gadget
.SendReport(self
._report
_id
, data
)
326 def SetInputReport(self
, data
):
327 """Handle an input report sent from the host.
329 This function is called when a SET_REPORT(input) command for this class's
330 Report ID is received. It should be overridden by a subclass.
333 data: Contents of the input report.
335 pass # pragma: no cover
337 def SetOutputReport(self
, data
):
338 """Handle an feature report sent from the host.
340 This function is called when a SET_REPORT(output) command or interrupt OUT
341 transfer is received with this class's Report ID. It should be overridden
345 data: Contents of the output report.
347 pass # pragma: no cover
349 def SetFeatureReport(self
, data
):
350 """Handle an feature report sent from the host.
352 This function is called when a SET_REPORT(feature) command for this class's
353 Report ID is received. It should be overridden by a subclass.
356 data: Contents of the feature report.
358 pass # pragma: no cover
360 def GetInputReport(self
):
361 """Handle a input report request from the host.
363 This function is called when a GET_REPORT(input) command for this class's
364 Report ID is received. It should be overridden by a subclass.
367 The input report or None to stall the pipe.
369 pass # pragma: no cover
371 def GetOutputReport(self
):
372 """Handle a output report request from the host.
374 This function is called when a GET_REPORT(output) command for this class's
375 Report ID is received. It should be overridden by a subclass.
378 The output report or None to stall the pipe.
380 pass # pragma: no cover
382 def GetFeatureReport(self
):
383 """Handle a feature report request from the host.
385 This function is called when a GET_REPORT(feature) command for this class's
386 Report ID is received. It should be overridden by a subclass.
389 The feature report or None to stall the pipe.
391 pass # pragma: no cover