15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# Copyright 2014 The Chromium Authors. All rights reserved. 25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)# found in the LICENSE file. 45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)"""A HID-class echo device. 65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)This module provides a HID feature and HID device that can be used as an 85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)echo test for HID drivers. The device exposes vendor-specific input, output 95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)and feature usages that transmit 8 bytes of data. Data written sent as an 105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)output report is echoed as an input report. The value of the feature report 115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)can be written and read with control transfers. 125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)""" 135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import struct 155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import hid_constants 175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import hid_descriptors 185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import hid_gadget 195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import usb_constants 205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class EchoFeature(hid_gadget.HidFeature): 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) REPORT_DESC = hid_descriptors.ReportDescriptor( 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.UsagePage(0xFF00), # Vendor Defined 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.Usage(0), 275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.Collection( 285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_constants.CollectionType.APPLICATION, 295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.LogicalMinimum(0, force_length=1), 305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.LogicalMaximum(255, force_length=2), 315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.ReportSize(8), 325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.ReportCount(8), 335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.Usage(0), 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.Input(hid_descriptors.Data, 355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.Variable, 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.Absolute), 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.Usage(0), 385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.Output(hid_descriptors.Data, 395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.Variable, 405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.Absolute), 415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.Usage(0), 425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.Feature(hid_descriptors.Data, 435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.Variable, 445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hid_descriptors.Absolute) 455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ) 465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ) 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def __init__(self): 495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) super(EchoFeature, self).__init__() 505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._input_output_report = 0 515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._feature_report = 0 525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def SetInputReport(self, data): 545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._input_output_report, = struct.unpack('<Q', data) 555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.SendReport(struct.pack('<Q', self._input_output_report)) 565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return True 575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def SetOutputReport(self, data): 595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._input_output_report, = struct.unpack('<Q', data) 605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.SendReport(struct.pack('<Q', self._input_output_report)) 615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return True 625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def SetFeatureReport(self, data): 645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._feature_report, = struct.unpack('<Q', data) 655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return True 665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def GetInputReport(self): 685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return struct.pack('<Q', self._input_output_report) 695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def GetOutputReport(self): 715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return struct.pack('<Q', self._input_output_report) 725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def GetFeatureReport(self): 745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return struct.pack('<Q', self._feature_report) 755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class EchoGadget(hid_gadget.HidGadget): 785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def __init__(self): 805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._feature = EchoFeature() 815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) super(EchoGadget, self).__init__( 825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) report_desc=EchoFeature.REPORT_DESC, 835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) features={0: self._feature}, 845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) packet_size=8, 855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) interval_ms=1, 865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) out_endpoint=True, 875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) vendor_id=usb_constants.VendorID.GOOGLE, 885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) product_id=usb_constants.ProductID.GOOGLE_HID_ECHO_GADGET, 895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) device_version=0x0100) 905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.AddStringDescriptor(1, 'Google Inc.') 915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self.AddStringDescriptor(2, 'HID Echo Gadget') 925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)def RegisterHandlers(): 955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) from tornado import web 965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) class WebConfigureHandler(web.RequestHandler): 985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def post(self): 1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) server.SwitchGadget(EchoGadget()) 1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) import server 1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) server.app.add_handlers('.*$', [ 1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (r'/hid_echo/configure', WebConfigureHandler), 1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ]) 106