From 9d7c6d0400299c05c310efbab3f6909c69bf2a88 Mon Sep 17 00:00:00 2001 From: "reillyg@chromium.org" Date: Thu, 24 Jul 2014 13:43:37 +0000 Subject: [PATCH] This module provides a class to bind an instance of gadget.Gadget to the Linux gadgetfs user-space interface for implementing USB gadget devices. Some knowledge of the USB peripheral controller is required. Capabilities of the Beaglebone Black's MUSB OTG controller are provided in this patch. The Tornado library's I/O loop module is used by this class. Tornado will be used as the HTTP framework in the next patch in this series. BUG=396682 R=rockot@chromium.org,rpaquay@chromium.org,kalman@chromium.org Review URL: https://codereview.chromium.org/413853003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@285233 0039d316-1c4b-4281-b951-d872f2087c98 --- tools/usb_gadget/linux_gadgetfs.py | 302 +++++++++++++++++++++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 tools/usb_gadget/linux_gadgetfs.py diff --git a/tools/usb_gadget/linux_gadgetfs.py b/tools/usb_gadget/linux_gadgetfs.py new file mode 100644 index 000000000000..cc0c97c1def0 --- /dev/null +++ b/tools/usb_gadget/linux_gadgetfs.py @@ -0,0 +1,302 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""Linux gadgetfs glue. + +Exposes a USB gadget using a USB peripheral controller on Linux. The userspace +ABI is documented here: + +https://github.com/torvalds/linux/blob/master/drivers/usb/gadget/inode.c +""" + +import errno +import multiprocessing +import os +import struct + +from tornado import ioloop + +import usb_constants +import usb_descriptors + +GADGETFS_NOP = 0 +GADGETFS_CONNECT = 1 +GADGETFS_DISCONNECT = 2 +GADGETFS_SETUP = 3 +GADGETFS_SUSPEND = 4 + +BULK = 0x01 +INTERRUPT = 0x02 +ISOCHRONOUS = 0x04 + +USB_TRANSFER_TYPE_TO_MASK = { + usb_constants.TransferType.BULK: BULK, + usb_constants.TransferType.INTERRUPT: INTERRUPT, + usb_constants.TransferType.ISOCHRONOUS: ISOCHRONOUS +} + +IN = 0x01 +OUT = 0x02 + +HARDWARE = { + 'beaglebone-black': ( + 'musb-hdrc', # Gadget controller name, + { + 0x01: ('ep1out', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x81: ('ep1in', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x02: ('ep2out', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x82: ('ep2in', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x03: ('ep2out', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x83: ('ep2in', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x04: ('ep2out', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x84: ('ep2in', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x05: ('ep2out', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x85: ('ep2in', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x06: ('ep2out', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x86: ('ep2in', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x07: ('ep2out', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x87: ('ep2in', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x08: ('ep2out', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x88: ('ep2in', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x09: ('ep2out', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x89: ('ep2in', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x0A: ('ep2out', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x8A: ('ep2in', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x0B: ('ep2out', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x8B: ('ep2in', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x0C: ('ep2out', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x8C: ('ep2in', BULK | INTERRUPT | ISOCHRONOUS, 512), + 0x0D: ('ep13', BULK | INTERRUPT | ISOCHRONOUS, 4096), + 0x8D: ('ep13', BULK | INTERRUPT | ISOCHRONOUS, 4096), + 0x0E: ('ep14', BULK | INTERRUPT | ISOCHRONOUS, 1024), + 0x8E: ('ep14', BULK | INTERRUPT | ISOCHRONOUS, 1024), + 0x0F: ('ep15', BULK | INTERRUPT | ISOCHRONOUS, 1024), + 0x8F: ('ep15', BULK | INTERRUPT | ISOCHRONOUS, 1024), + } + ) +} + + +class LinuxGadgetfs(object): + """Linux gadgetfs-based gadget driver. + """ + + def __init__(self, hardware, mountpoint='/dev/gadget'): + """Initialize bindings to the Linux gadgetfs interface. + + Args: + hardware: Hardware type. + mountpoint: Gadget filesystem mount point. + """ + self._chip, self._hw_eps = HARDWARE[hardware] + self._ep_dir = mountpoint + self._gadget = None + self._fd = None + # map from bEndpointAddress to hardware ep name and open file descriptor + self._ep_fds = {} + self._io_loop = ioloop.IOLoop.current() + + def Create(self, gadget): + """Bind a gadget to the USB peripheral controller.""" + self._gadget = gadget + self._fd = os.open(os.path.join(self._ep_dir, self._chip), os.O_RDWR) + buf = ''.join([struct.pack('=I', 0), + gadget.GetFullSpeedConfigurationDescriptor().Encode(), + gadget.GetHighSpeedConfigurationDescriptor().Encode(), + gadget.GetDeviceDescriptor().Encode()]) + os.write(self._fd, buf) + self._io_loop.add_handler(self._fd, self.HandleEvent, self._io_loop.READ) + + def Destroy(self): + """Unbind the gadget from the USB peripheral controller.""" + self.Disconnected() + self._io_loop.remove_handler(self._fd) + os.close(self._fd) + self._gadget = None + self._fd = None + + def IsConfigured(self): + return self._gadget is not None + + def HandleEvent(self, unused_fd, unused_events): + buf = os.read(self._fd, 12) + event_type, = struct.unpack_from('=I', buf, 8) + + if event_type == GADGETFS_NOP: + print 'NOP' + elif event_type == GADGETFS_CONNECT: + speed, = struct.unpack('=Ixxxxxxxx', buf) + self.Connected(speed) + elif event_type == GADGETFS_DISCONNECT: + self.Disconnected() + elif event_type == GADGETFS_SETUP: + request_type, request, value, index, length = struct.unpack( + '