Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / tools / usb_gadget / hid_gadget.py
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
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.
11 """
12
13 import math
14 import struct
15 import uuid
16
17 import gadget
18 import hid_constants
19 import usb_constants
20 import usb_descriptors
21
22
23 class 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
291 class 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