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.
4
5"""Human Interface Device gadget module.
6
7This gadget emulates a USB Human Interface Device. Multiple logical components
8of a device can be composed together as separate "features" where each has its
9own Report ID and will be called upon to answer get/set input/output/feature
10report requests as necessary.
11"""
12
13import math
14import struct
15import uuid
16
17import gadget
18import hid_constants
19import usb_constants
20import usb_descriptors
21
22
23class HidGadget(gadget.Gadget):
24  """Generic HID gadget.
25  """
26
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.
31
32    Args:
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.
41
42    Raises:
43      ValueError: If any of the parameters are out of range.
44    """
45    device_desc = usb_descriptors.DeviceDescriptor(
46        idVendor=vendor_id,
47        idProduct=product_id,
48        bcdUSB=0x0200,
49        iManufacturer=1,
50        iProduct=2,
51        iSerialNumber=3,
52        bcdDevice=device_version)
53
54    fs_config_desc = usb_descriptors.ConfigurationDescriptor(
55        bmAttributes=0x80,
56        MaxPower=50)
57    fs_interface_desc = usb_descriptors.InterfaceDescriptor(
58        bInterfaceNumber=0,
59        bInterfaceClass=usb_constants.DeviceClass.HID,
60        bInterfaceSubClass=0,  # Non-bootable.
61        bInterfaceProtocol=0,  # None.
62    )
63    fs_config_desc.AddInterface(fs_interface_desc)
64
65    hs_config_desc = usb_descriptors.ConfigurationDescriptor(
66        bmAttributes=0x80,
67        MaxPower=50)
68    hs_interface_desc = usb_descriptors.InterfaceDescriptor(
69        bInterfaceNumber=0,
70        bInterfaceClass=usb_constants.DeviceClass.HID,
71        bInterfaceSubClass=0,  # Non-bootable.
72        bInterfaceProtocol=0,  # None.
73    )
74    hs_config_desc.AddInterface(hs_interface_desc)
75
76    hid_desc = usb_descriptors.HidDescriptor()
77    hid_desc.AddDescriptor(hid_constants.DescriptorType.REPORT,
78                           len(report_desc))
79    fs_interface_desc.Add(hid_desc)
80    hs_interface_desc.Add(hid_desc)
81
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))
86
87    fs_interface_desc.AddEndpoint(usb_descriptors.EndpointDescriptor(
88        bEndpointAddress=0x81,
89        bmAttributes=usb_constants.TransferType.INTERRUPT,
90        wMaxPacketSize=packet_size,
91        bInterval=fs_interval
92    ))
93
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))
98
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
104    ))
105
106    if out_endpoint:
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
112      ))
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
118      ))
119
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
124
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)
129
130  def Disconnected(self):
131    super(HidGadget, self).Disconnected()
132    for feature in self._features.itervalues():
133      feature.Disconnected()
134
135  def GetDescriptor(self, recipient, typ, index, lang, length):
136    if recipient == usb_constants.Recipient.INTERFACE:
137      if typ == hid_constants.DescriptorType.REPORT:
138        if index == 0:
139          return self._report_desc[:length]
140
141    return super(HidGadget, self).GetDescriptor(recipient, typ, index, lang,
142                                                length)
143
144  def ClassControlRead(self, recipient, request, value, index, length):
145    """Handle class-specific control requests.
146
147    See Device Class Definition for Human Interface Devices (HID) Version 1.11
148    section 7.2.
149
150    Args:
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.
156
157    Returns:
158      A buffer to return to the USB host with len <= length on success or
159      None to stall the pipe.
160    """
161    if recipient != usb_constants.Recipient.INTERFACE:
162      return None
163    if index != 0:
164      return None
165
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)
171
172  def ClassControlWrite(self, recipient, request, value, index, data):
173    """Handle class-specific control requests.
174
175    See Device Class Definition for Human Interface Devices (HID) Version 1.11
176    section 7.2.
177
178    Args:
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.
184
185    Returns:
186      True on success, None to stall the pipe.
187    """
188    if recipient != usb_constants.Recipient.INTERFACE:
189      return None
190    if index != 0:
191      return None
192
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))
202      return True
203
204  def GetReport(self, report_type, report_id, length):
205    """Handle GET_REPORT requests.
206
207    See Device Class Definition for Human Interface Devices (HID) Version 1.11
208    section 7.2.1.
209
210    Args:
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.
214
215    Returns:
216      A buffer to return to the USB host with len <= length on success or
217      None to stall the pipe.
218    """
219    feature = self._features.get(report_id, None)
220    if feature is None:
221      return None
222
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]
229
230  def SetReport(self, report_type, report_id, data):
231    """Handle SET_REPORT requests.
232
233    See Device Class Definition for Human Interface Devices (HID) Version 1.11
234    section 7.2.2.
235
236    Args:
237      report_type: Report type.
238      report_id: Report ID.
239      data: Report data.
240
241    Returns:
242      True on success, None to stall the pipe.
243    """
244    feature = self._features.get(report_id, None)
245    if feature is None:
246      return None
247
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)
254
255  def SendReport(self, report_id, data):
256    """Send a HID report.
257
258    See Device Class Definition for Human Interface Devices (HID) Version 1.11
259    section 8.
260
261    Args:
262      report_id: Report ID associated with the data.
263      data: Contents of the report.
264    """
265    if report_id == 0:
266      self.SendPacket(0x81, data)
267    else:
268      self.SendPacket(0x81, struct.pack('B', report_id) + data)
269
270  def ReceivePacket(self, endpoint, data):
271    """Dispatch a report to the appropriate feature.
272
273    See Device Class Definition for Human Interface Devices (HID) Version 1.11
274    section 8.
275
276    Args:
277      endpoint: Incoming endpoint (must be the Interrupt OUT pipe).
278      data: Interrupt packet data.
279    """
280    assert endpoint == 0x01
281
282    if 0 in self._features:
283      self._features[0].SetOutputReport(data)
284    elif len(data) >= 1:
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)
289
290
291class HidFeature(object):
292  """Represents a component of a HID gadget.
293
294  A "feature" produces and consumes reports with a particular Report ID. For
295  example a keyboard, mouse or vendor specific functionality.
296  """
297
298  def __init__(self):
299    self._gadget = None
300    self._report_id = None
301
302  def Connected(self, my_gadget, report_id):
303    self._gadget = my_gadget
304    self._report_id = report_id
305
306  def Disconnected(self):
307    self._gadget = None
308    self._report_id = None
309
310  def IsConnected(self):
311    return self._gadget is not None
312
313  def SendReport(self, data):
314    """Send a report with this feature's Report ID.
315
316    Args:
317      data: Report to send. If necessary the Report ID will be added.
318
319    Raises:
320      RuntimeError: If a report cannot be sent at this time.
321    """
322    if not self.IsConnected():
323      raise RuntimeError('Device is not connected.')
324    self._gadget.SendReport(self._report_id, data)
325
326  def SetInputReport(self, data):
327    """Handle an input report sent from the host.
328
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.
331
332    Args:
333      data: Contents of the input report.
334    """
335    pass  # pragma: no cover
336
337  def SetOutputReport(self, data):
338    """Handle an feature report sent from the host.
339
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
342    by a subclass.
343
344    Args:
345      data: Contents of the output report.
346    """
347    pass  # pragma: no cover
348
349  def SetFeatureReport(self, data):
350    """Handle an feature report sent from the host.
351
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.
354
355    Args:
356      data: Contents of the feature report.
357    """
358    pass  # pragma: no cover
359
360  def GetInputReport(self):
361    """Handle a input report request from the host.
362
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.
365
366    Returns:
367      The input report or None to stall the pipe.
368    """
369    pass  # pragma: no cover
370
371  def GetOutputReport(self):
372    """Handle a output report request from the host.
373
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.
376
377    Returns:
378      The output report or None to stall the pipe.
379    """
380    pass  # pragma: no cover
381
382  def GetFeatureReport(self):
383    """Handle a feature report request from the host.
384
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.
387
388    Returns:
389      The feature report or None to stall the pipe.
390    """
391    pass  # pragma: no cover
392