├── LICENSE-2BSD.txt ├── README.md ├── doc ├── diagram.png └── menuconfig.png ├── examples └── blinker │ ├── config.py │ ├── core.py │ ├── test.c │ └── test.py ├── lambdausb ├── __init__.py ├── boards │ └── usbsniffer.py ├── io │ ├── __init__.py │ ├── ulpi.py │ └── usb_serial │ │ ├── __init__.py │ │ ├── phy.py │ │ ├── rx.py │ │ └── tx.py ├── lib │ ├── __init__.py │ └── stream.py ├── test │ ├── __init__.py │ ├── _util.py │ ├── test_usb_crc.py │ ├── test_usb_endpoint.py │ └── test_usb_mux.py └── usb │ ├── __init__.py │ ├── config.py │ ├── crc.py │ ├── defs.py │ ├── device.py │ ├── endpoint.py │ └── mux.py ├── setup.py └── tools └── genconfig ├── Makefile ├── createconfig.c ├── generate.sh ├── genpy.c └── usb.h /LICENSE-2BSD.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2019 LambdaConcept 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright notice, 9 | this list of conditions and the following disclaimer in the documentation 10 | and/or other materials provided with the distribution. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 16 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 19 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lambdaUSB 2 | 3 | ## A configurable USB 2.0 device core using [nMigen](https://github.com/m-labs/nmigen) 4 | 5 | **lambdaUSB is still in an experimental stage and is therefore incomplete. The user-facing API may change before reaching stability.** 6 | 7 | ![lambdaUSB Diagram Image](doc/diagram.png) 8 | 9 | ### Features 10 | 11 | * High Speed USB 12 | * up to 32 endpoints (16 inputs, 16 outputs) 13 | * double buffering, per endpoint 14 | 15 | ### Installation 16 | 17 | Download and install lambdaUSB: 18 | 19 | git clone https://github.com/lambdaconcept/lambdaUSB 20 | cd lambdaUSB 21 | python3 setup.py develop --user 22 | 23 | ### Usage 24 | 25 | 1. Instantiate the USB device: 26 | 27 | ```python 28 | m.submodules.ulpi_phy = ulpi_phy = ulpi.PHY(pins=platform.request("ulpi", 0)) 29 | m.submodules.usb_dev = usb_dev = usb.Device() 30 | m.d.comb += [ 31 | ulpi_phy.rx.connect(usb_dev.rx), 32 | usb_dev.tx.connect(ulpi_phy.tx), 33 | ] 34 | ``` 35 | 36 | For the moment, only ULPI transceivers such as the USB3300 are supported. 37 | 38 | 2. Instantiate endpoint interfaces: 39 | 40 | ```python 41 | ep1_in = usb.InputEndpoint(xfer=usb.Transfer.BULK, max_size=512) 42 | ep1_out = usb.OutputEndpoint(xfer=usb.Transfer.BULK, max_size=512) 43 | ``` 44 | 45 | 3. Add endpoint interfaces to the USB device: 46 | 47 | ```python 48 | usb_dev.add_endpoint(ep1_in, addr=1) 49 | usb_dev.add_endpoint(ep1_out, addr=1) 50 | ``` 51 | 52 | For a full example, have a look at `examples/blinker`. 53 | 54 | ### Device configuration 55 | 56 | For convenience, we provide a `ConfigurationFSM` to manage EP0 in `lambdausb.usb.config`. 57 | It stores the configuration descriptors in a ROM, and responds to host requests. 58 | 59 | To use it, you must first generate a config file: 60 | ``` 61 | cd tools/genconfig 62 | make 63 | ``` 64 | 65 | You will be presented a menuconfig interface from which you can setup your USB device: 66 | 67 | ![menuconfig interface](doc/menuconfig.png) 68 | 69 | The output `config.py` file can be imported and used like so: 70 | 71 | ```python 72 | from lambdausb.usb.config import ConfigurationFSM 73 | from config import descriptor_map, rom_init 74 | 75 | m.submodules.cfg_fsm = cfg_fsm = ConfigurationFSM(descriptor_map, rom_init) 76 | usb_dev.add_endpoint(cfg_fsm.ep_in, addr=0) 77 | usb_dev.add_endpoint(cfg_fsm.ep_out, addr=0) 78 | m.d.comb += usb_dev.addr.eq(cfg_fsm.dev_addr) 79 | ``` 80 | 81 | ### License 82 | 83 | lambdaUSB is released under the two-clause BSD license. 84 | -------------------------------------------------------------------------------- /doc/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdaconcept/lambdaUSB/2605a56c64b6fea17cd6528ee3ddbf0a8ff47d44/doc/diagram.png -------------------------------------------------------------------------------- /doc/menuconfig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdaconcept/lambdaUSB/2605a56c64b6fea17cd6528ee3ddbf0a8ff47d44/doc/menuconfig.png -------------------------------------------------------------------------------- /examples/blinker/config.py: -------------------------------------------------------------------------------- 1 | # Generated with genconfig (tools/genconfig) 2 | descriptor_map = { 3 | 0x01: {0: (0, 18)}, 4 | 0x02: {0: (18, 25)}, 5 | 0x03: { 6 | 0: (43, 4), 7 | 1: (47, 28), 8 | 2: (75, 26), 9 | 3: (101, 8), 10 | }, 11 | 0x06: {0: (109, 10)}, 12 | 0x0a: {0: (119, 2)}, 13 | } 14 | rom_init = [ 15 | 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 16 | 0xac, 0x05, 0x78, 0x56, 0x00, 0x01, 0x01, 0x02, 17 | 0x03, 0x01, 0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 18 | 0x00, 0xe0, 0x30, 0x09, 0x04, 0x00, 0x00, 0x01, 19 | 0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 20 | 0x00, 0x02, 0x00, 0x04, 0x03, 0x09, 0x04, 0x1c, 21 | 0x03, 0x4c, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x62, 22 | 0x00, 0x64, 0x00, 0x61, 0x00, 0x43, 0x00, 0x6f, 23 | 0x00, 0x6e, 0x00, 0x63, 0x00, 0x65, 0x00, 0x70, 24 | 0x00, 0x74, 0x00, 0x1a, 0x03, 0x62, 0x00, 0x6c, 25 | 0x00, 0x69, 0x00, 0x6e, 0x00, 0x6b, 0x00, 0x65, 26 | 0x00, 0x72, 0x00, 0x20, 0x00, 0x64, 0x00, 0x65, 27 | 0x00, 0x6d, 0x00, 0x6f, 0x00, 0x08, 0x03, 0x31, 28 | 0x00, 0x32, 0x00, 0x33, 0x00, 0x0a, 0x06, 0x00, 29 | 0x02, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x02, 30 | 0x0a, 31 | ] 32 | -------------------------------------------------------------------------------- /examples/blinker/core.py: -------------------------------------------------------------------------------- 1 | from nmigen import * 2 | 3 | from lambdausb import usb 4 | from lambdausb.usb.config import ConfigurationFSM 5 | from lambdausb.io import ulpi 6 | 7 | 8 | class RgbBlinker(Elaboratable): 9 | def __init__(self, pins): 10 | self.ep_out = usb.OutputEndpoint(xfer=usb.Transfer.BULK, max_size=512) 11 | self._pins = pins 12 | 13 | def elaborate(self, platform): 14 | m = Module() 15 | 16 | led = Signal() 17 | sel = Record([("r", 1), ("g", 1), ("b", 1)]) 18 | 19 | m.d.comb += self.ep_out.rdy.eq(1) 20 | with m.If(self.ep_out.stb): 21 | m.d.sync += sel.eq(self.ep_out.data[:3]) 22 | 23 | clk_freq = platform.default_clk_frequency 24 | ctr = Signal(range(int(clk_freq//2)), reset=int(clk_freq//2)-1) 25 | with m.If(ctr == 0): 26 | m.d.sync += ctr.eq(ctr.reset) 27 | m.d.sync += led.eq(~led) 28 | with m.Else(): 29 | m.d.sync += ctr.eq(ctr - 1) 30 | 31 | m.d.comb += [ 32 | self._pins.r.o.eq(sel.r & led), 33 | self._pins.g.o.eq(sel.g & led), 34 | self._pins.b.o.eq(sel.b & led) 35 | ] 36 | 37 | return m 38 | 39 | 40 | class USBBlinker(Elaboratable): 41 | def elaborate(self, platform): 42 | m = Module() 43 | 44 | m.domains += ClockDomain("sync") 45 | clk100 = platform.request("clk100", 0) 46 | eos = Signal() 47 | m.submodules += Instance("STARTUPE2", o_EOS=eos) 48 | m.submodules += Instance("BUFGCE", i_CE=eos, i_I=clk100.i, o_O=ClockSignal("sync")) 49 | 50 | # USB device 51 | m.submodules.ulpi_phy = ulpi_phy = ulpi.PHY(pins=platform.request("ulpi", 0)) 52 | m.submodules.usb_dev = usb_dev = usb.Device() 53 | m.d.comb += [ 54 | ResetSignal("sync").eq(ulpi_phy.dev_reset), 55 | ulpi_phy.rx.connect(usb_dev.rx), 56 | usb_dev.tx.connect(ulpi_phy.tx), 57 | ] 58 | 59 | # Configuration endpoint 60 | from config import descriptor_map, rom_init 61 | m.submodules.cfg_fsm = cfg_fsm = ConfigurationFSM(descriptor_map, rom_init) 62 | m.d.comb += usb_dev.addr.eq(cfg_fsm.dev_addr) 63 | usb_dev.add_endpoint(cfg_fsm.ep_in, addr=0) 64 | usb_dev.add_endpoint(cfg_fsm.ep_out, addr=0) 65 | 66 | # RGB blinker endpoint 67 | m.submodules.blinker = blinker = RgbBlinker(pins=platform.request("rgb_led", 0)) 68 | usb_dev.add_endpoint(blinker.ep_out, addr=1) 69 | 70 | return m 71 | 72 | 73 | if __name__ == "__main__": 74 | from lambdausb.boards.usbsniffer import USBSnifferPlatform 75 | platform = USBSnifferPlatform() 76 | platform.build(USBBlinker(), do_program=True) 77 | -------------------------------------------------------------------------------- /examples/blinker/test.c: -------------------------------------------------------------------------------- 1 | // gcc test.c -o test -lusb-1.0 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | int main(void) 9 | { 10 | libusb_context *ctx; 11 | libusb_init(&ctx); 12 | 13 | libusb_device_handle *devh = libusb_open_device_with_vid_pid(ctx, 0x05ac, 0x5678); 14 | if (!devh) { 15 | fprintf(stderr, "failed to open device 05ac:5678\n"); 16 | return -1; 17 | } 18 | libusb_claim_interface(devh, 0); 19 | 20 | uint8_t rgb = 4; 21 | for (size_t i = 0; i < 32; i++) { 22 | libusb_bulk_transfer(devh, 0x1, &rgb, 1, NULL, 0); 23 | printf("[OUT] data = %d\n", rgb); 24 | rgb = (rgb == 1) ? 4 : (rgb >> 1); 25 | sleep(1); // wait 1s to see the led change its color 26 | } 27 | 28 | libusb_close(devh); 29 | libusb_exit(ctx); 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /examples/blinker/test.py: -------------------------------------------------------------------------------- 1 | import time 2 | import usb.core 3 | 4 | 5 | def main(): 6 | dev = usb.core.find(idVendor=0x05ac, idProduct=0x5678) 7 | if dev is None: 8 | raise ValueError("Device 0x05ac:0x5678 was not found.") 9 | 10 | dev.set_configuration() 11 | 12 | rgb = 0b100 13 | for i in range(32): 14 | dev.write(1, rgb.to_bytes(1, byteorder='big'), 1) 15 | print(f"[OUT] data = {rgb}"); 16 | rgb = 0b100 if rgb == 0b001 else rgb >> 1 17 | time.sleep(1) # wait 1s to see the led change its color 18 | 19 | 20 | if __name__ == "__main__": 21 | main() 22 | -------------------------------------------------------------------------------- /lambdausb/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdaconcept/lambdaUSB/2605a56c64b6fea17cd6528ee3ddbf0a8ff47d44/lambdausb/__init__.py -------------------------------------------------------------------------------- /lambdausb/boards/usbsniffer.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | 4 | from nmigen.build import * 5 | from nmigen.vendor.xilinx_7series import * 6 | 7 | 8 | __all__ = ["USBSnifferPlatform"] 9 | 10 | 11 | class USBSnifferPlatform(Xilinx7SeriesPlatform): 12 | device = "xc7a35t" 13 | package = "fgg484" 14 | speed = "2" 15 | default_clk = "clk100" 16 | 17 | resources = [ 18 | Resource("clk100", 0, Pins("J19", dir="i"), Clock(100e6), Attrs(IOSTANDARD="LVCMOS33")), 19 | 20 | Resource("rgb_led", 0, 21 | Subsignal("r", PinsN("W2", dir="o")), 22 | Subsignal("g", PinsN("Y1", dir="o")), 23 | Subsignal("b", PinsN("W1", dir="o")), 24 | Attrs(IOSTANDARD="LVCMOS33") 25 | ), 26 | 27 | Resource("rgb_led", 1, 28 | Subsignal("r", PinsN("AA1", dir="o")), 29 | Subsignal("g", PinsN("AB1", dir="o")), 30 | Subsignal("b", PinsN("Y2" , dir="o")), 31 | Attrs(IOSTANDARD="LVCMOS33") 32 | ), 33 | 34 | Resource("serial", 0, 35 | Subsignal("tx", Pins("U21", dir="o")), # FPGA_GPIO0 36 | Subsignal("rx", Pins("T21", dir="i")), # FPGA_GPIO1 37 | Attrs(IOSTANDARD="LVCMOS33") 38 | ), 39 | 40 | Resource("ulpi_sw", 0, 41 | Subsignal("s", Pins("Y8", dir="o")), 42 | Subsignal("oe", PinsN("Y9", dir="o")), 43 | Attrs(IOSTANDARD="LVCMOS33") 44 | ), 45 | 46 | Resource("ulpi", 0, 47 | Subsignal("clk", Pins("W19", dir="i"), Clock(60e6)), 48 | Subsignal("data", Pins("AB18 AA18 AA19 AB20 AA20 AB21 AA21 AB22", dir="io")), 49 | Subsignal("dir", Pins("W21", dir="i")), 50 | Subsignal("stp", Pins("Y22", dir="o")), 51 | Subsignal("nxt", Pins("W22", dir="i")), 52 | Subsignal("rst", Pins("V20", dir="o")), 53 | Attrs(IOSTANDARD="LVCMOS33", SLEW="FAST") 54 | ), 55 | 56 | Resource("ulpi", 1, 57 | Subsignal("clk", Pins("V4", dir="i"), Clock(60e6)), 58 | Subsignal("data", Pins("AB2 AA3 AB3 Y4 AA4 AB5 AA5 AB6", dir="io")), 59 | Subsignal("dir", Pins("AB7", dir="i")), 60 | Subsignal("stp", Pins("AA6", dir="o")), 61 | Subsignal("nxt", Pins("AB8", dir="i")), 62 | Subsignal("rst", Pins("AA8", dir="o")), 63 | Attrs(IOSTANDARD="LVCMOS33", SLEW="FAST") 64 | ), 65 | 66 | Resource("ft601", 0, 67 | Subsignal("clk", Pins("D17", dir="i"), Clock(100e6)), 68 | Subsignal("rst", Pins("K22", dir="o")), 69 | Subsignal("data", Pins("A16 F14 A15 F13 A14 E14 A13 E13 B13 C15 C13 C14 B16 E17 B15 F16 " 70 | "A20 E18 B20 F18 D19 D21 E19 E21 A21 B21 A19 A18 F20 F19 B18 B17", dir="io")), 71 | Subsignal("be", Pins("K16 L16 G20 H20", dir="o")), 72 | Subsignal("rxf_n", Pins("M13", dir="i")), 73 | Subsignal("txe_n", Pins("L13", dir="i")), 74 | Subsignal("rd_n", Pins("K19", dir="o")), 75 | Subsignal("wr_n", Pins("M15", dir="o")), 76 | Subsignal("oe_n", Pins("L21", dir="o")), 77 | Subsignal("siwua", Pins("M16", dir="o")), 78 | Attrs(IOSTANDARD="LVCMOS33", SLEW="FAST") 79 | ) 80 | ] 81 | connectors = [] 82 | 83 | def toolchain_prepare(self, fragment, name, **kwargs): 84 | overrides = { 85 | "script_before_bitstream": 86 | "set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]", 87 | "script_after_bitstream": 88 | "write_cfgmem -force -format bin -interface spix4 -size 16 " 89 | "-loadbit \"up 0x0 {name}.bit\" -file {name}.bin".format(name=name), 90 | "add_constraints": 91 | "set_property INTERNAL_VREF 0.675 [get_iobanks 34]" 92 | } 93 | return super().toolchain_prepare(fragment, name, **overrides, **kwargs) 94 | 95 | def toolchain_program(self, products, name): 96 | xc3sprog = os.environ.get("XC3SPROG", "xc3sprog") 97 | with products.extract("{}.bit".format(name)) as bitstream_filename: 98 | subprocess.run([xc3sprog, "-c", "ft4232h", bitstream_filename], check=True) 99 | -------------------------------------------------------------------------------- /lambdausb/io/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdaconcept/lambdaUSB/2605a56c64b6fea17cd6528ee3ddbf0a8ff47d44/lambdausb/io/__init__.py -------------------------------------------------------------------------------- /lambdausb/io/ulpi.py: -------------------------------------------------------------------------------- 1 | from nmigen import * 2 | from nmigen.hdl.rec import * 3 | from nmigen.lib.cdc import AsyncFFSynchronizer 4 | 5 | from ..lib import stream 6 | 7 | 8 | __all__ = ["PHY", "Transceiver"] 9 | 10 | 11 | class PHY(Elaboratable): 12 | def __init__(self, *, pins, rx_depth=32, tx_depth=32): 13 | self.rx = Record([ 14 | ("stb", 1, DIR_FANOUT), 15 | ("lst", 1, DIR_FANOUT), 16 | ("data", 8, DIR_FANOUT), 17 | ("rdy", 1, DIR_FANIN), 18 | ]) 19 | self.tx = Record([ 20 | ("stb", 1, DIR_FANIN), 21 | ("lst", 1, DIR_FANIN), 22 | ("data", 8, DIR_FANIN), 23 | ("rdy", 1, DIR_FANOUT), 24 | ]) 25 | 26 | self.dev_reset = Signal() 27 | 28 | self.rx_depth = rx_depth 29 | self.tx_depth = tx_depth 30 | self._pins = pins 31 | 32 | def elaborate(self, platform): 33 | m = Module() 34 | 35 | m.domains += ClockDomain("ulpi", local=True) 36 | 37 | m.submodules.xcvr = xcvr = Transceiver(domain="ulpi", pins=self._pins) 38 | m.submodules.timer = timer = _Timer() 39 | m.submodules.splitter = splitter = _Splitter() 40 | m.submodules.sender = sender = _Sender() 41 | 42 | usb_reset = Signal() 43 | m.submodules.usb_reset_sync = AsyncFFSynchronizer(usb_reset, self.dev_reset, domain="sync") 44 | 45 | rx_fifo = stream.AsyncFIFO([("data", 8)], self.rx_depth, w_domain="ulpi", r_domain="sync") 46 | tx_fifo = stream.AsyncFIFO([("data", 8)], self.tx_depth, w_domain="sync", r_domain="ulpi") 47 | m.submodules.rx_fifo = rx_fifo 48 | m.submodules.tx_fifo = tx_fifo 49 | 50 | m.d.comb += [ 51 | self.rx.stb.eq(rx_fifo.source.valid), 52 | self.rx.lst.eq(rx_fifo.source.last), 53 | self.rx.data.eq(rx_fifo.source.data), 54 | rx_fifo.source.ready.eq(self.rx.rdy), 55 | 56 | tx_fifo.sink.valid.eq(self.tx.stb), 57 | tx_fifo.sink.last.eq(self.tx.lst), 58 | tx_fifo.sink.data.eq(self.tx.data), 59 | self.tx.rdy.eq(tx_fifo.sink.ready), 60 | 61 | splitter.source.connect(rx_fifo.sink), 62 | tx_fifo.source.connect(sender.sink), 63 | ] 64 | 65 | rx_cmd = Record([ 66 | ("line_state", 2), 67 | ("vbus_state", 2), 68 | ("event", 2), 69 | ("id", 1), 70 | ("alt_int", 1), 71 | ]) 72 | 73 | with m.If(xcvr.source.valid & xcvr.source.cmd): 74 | m.d.ulpi += rx_cmd.eq(xcvr.source.data) 75 | 76 | hs_mode = Signal() 77 | 78 | with m.FSM(domain="ulpi") as fsm: 79 | with m.State("RESET-0"): 80 | m.d.comb += xcvr.rst.eq(1) 81 | m.d.comb += timer.cnt25ns.eq(1) 82 | with m.If(timer.done): 83 | m.next = "RESET-1" 84 | 85 | with m.State("RESET-1"): 86 | m.d.comb += timer.cnt25ns.eq(1) 87 | with m.If(timer.done): 88 | m.next = "INIT-0" 89 | 90 | with m.State("INIT-0"): 91 | # Write Function Control register. 92 | m.d.comb += [ 93 | xcvr.sink.data.eq(0x80 | 0x4), 94 | xcvr.sink.valid.eq(1) 95 | ] 96 | with m.If(xcvr.sink.ready): 97 | m.next = "INIT-1" 98 | 99 | with m.State("INIT-1"): 100 | # XcvrSelect = 01 (Enable FS transceiver) 101 | # TermSelect = 1 (Peripheral FS) 102 | # OpMode = 00 (Normal operation) 103 | # Reset = 1 104 | # SuspendM = 1 (Powered) 105 | # Reserved = 0 106 | m.d.comb += [ 107 | xcvr.sink.data.eq(0b01100101), 108 | xcvr.sink.last.eq(1), 109 | xcvr.sink.valid.eq(1), 110 | ] 111 | m.d.comb += timer.cnt25ns.eq(1) 112 | with m.If(timer.done): 113 | m.next = "INIT-0" 114 | with m.If(xcvr.sink.ready): 115 | m.next = "INIT-2" 116 | 117 | with m.State("INIT-2"): 118 | with m.If(xcvr.source.valid & xcvr.source.cmd): 119 | m.next = "INIT-3" 120 | 121 | with m.State("INIT-3"): 122 | m.d.comb += timer.cnt2ns.eq(1) 123 | with m.If(timer.done): 124 | m.next = "INIT-4" 125 | 126 | with m.State("INIT-4"): 127 | # Write OTG Control register. 128 | m.d.comb += [ 129 | xcvr.sink.data.eq(0x80 | 0xa), 130 | xcvr.sink.valid.eq(1) 131 | ] 132 | with m.If(xcvr.sink.ready): 133 | m.next = "INIT-5" 134 | 135 | with m.State("INIT-5"): 136 | # DpPullDown = 0 (Disable D+ pull-down resistor) 137 | # DmPullDown = 0 (Disable D- pull-down resistor) 138 | m.d.comb += [ 139 | xcvr.sink.data.eq(0b00000000), 140 | xcvr.sink.last.eq(1), 141 | xcvr.sink.valid.eq(1) 142 | ] 143 | m.d.comb += timer.cnt25ns.eq(1) 144 | with m.If(timer.done): 145 | m.next = "INIT-4" 146 | with m.If(xcvr.sink.ready): 147 | m.next = "IDLE" 148 | 149 | with m.State("IDLE"): 150 | m.d.comb += [ 151 | xcvr.source.connect(splitter.sink), 152 | sender.source.connect(xcvr.sink), 153 | ] 154 | with m.If(rx_cmd.line_state == 0b00): 155 | m.d.comb += timer.cnt2ms.eq(1) 156 | with m.If(timer.done): 157 | # A reset condition was detected. 158 | m.d.comb += usb_reset.eq(1) 159 | # If the link is Full Speed, we attempt a chirp handshake to advertise 160 | # High Speed capability. 161 | with m.If(hs_mode): 162 | m.d.ulpi += hs_mode.eq(0) 163 | m.next = "INIT-0" 164 | with m.Else(): 165 | m.next = "CHIRP-0" 166 | 167 | with m.State("CHIRP-0"): 168 | # Write Function Control register. 169 | m.d.comb += [ 170 | xcvr.sink.data.eq(0x80 | 0x4), 171 | xcvr.sink.valid.eq(1) 172 | ] 173 | with m.If(xcvr.sink.ready): 174 | m.next = "CHIRP-1" 175 | 176 | with m.State("CHIRP-1"): 177 | # XcvrSelect = 00 (Enable HS transceiver) 178 | # TermSelect = 1 (Peripheral Chirp) 179 | # OpMode = 10 (Disable bit-stuff and NRZI encoding) 180 | # Reset = 0 181 | # SuspendM = 1 (Powered) 182 | # Reserved = 0 183 | m.d.comb += [ 184 | xcvr.sink.data.eq(0b01010100), 185 | xcvr.sink.last.eq(1), 186 | xcvr.sink.valid.eq(1) 187 | ] 188 | with m.If(xcvr.sink.ready): 189 | m.next = "CHIRP-2" 190 | 191 | with m.State("CHIRP-2"): 192 | # Send a NOPID TXCMD. 193 | m.d.comb += [ 194 | xcvr.sink.valid.eq(1), 195 | xcvr.sink.data.eq(0b01000000) 196 | ] 197 | with m.If(xcvr.sink.ready): 198 | m.next = "CHIRP-3" 199 | 200 | with m.State("CHIRP-3"): 201 | # Send a K chirp for 2ms. 202 | m.d.comb += [ 203 | xcvr.sink.valid.eq(1), 204 | xcvr.sink.data.eq(0x00), 205 | timer.cnt2ms.eq(1) 206 | ] 207 | with m.If(timer.done): 208 | m.next = "CHIRP-4" 209 | m.d.comb += xcvr.sink.last.eq(1) 210 | 211 | with m.State("CHIRP-4"): 212 | # Host responds by alternating K and J chirps. 213 | # FIXME: Detect a K-J-K-J-K-J pattern before going further. 214 | m.d.comb += timer.cnt2ms.eq(1) 215 | with m.If(timer.done): 216 | m.next = "CHIRP-5" 217 | 218 | with m.State("CHIRP-5"): 219 | # Write Function Control register. 220 | m.d.comb += [ 221 | xcvr.sink.data.eq(0x80 | 0x4), 222 | xcvr.sink.valid.eq(1) 223 | ] 224 | with m.If(xcvr.sink.ready): 225 | m.next = "CHIRP-6" 226 | 227 | with m.State("CHIRP-6"): 228 | # XcvrSelect = 00 (Enable HS transceiver) 229 | # TermSelect = 0 (Peripheral HS) 230 | # OpMode = 00 (Normal mode) 231 | # Reset = 0 232 | # SuspendM = 1 (Powered) 233 | # Reserved = 0 234 | m.d.comb += [ 235 | xcvr.sink.data.eq(0b01000000), 236 | xcvr.sink.last.eq(1), 237 | xcvr.sink.valid.eq(1) 238 | ] 239 | with m.If(xcvr.sink.ready): 240 | m.d.ulpi += hs_mode.eq(1) 241 | m.next = "IDLE" 242 | 243 | return m 244 | 245 | 246 | class Transceiver(Elaboratable): 247 | def __init__(self, domain="ulpi", pins=None): 248 | self.sink = stream.Endpoint([('data', 8)]) 249 | self.source = stream.Endpoint([('data', 8), ('cmd', 1)]) 250 | 251 | self.rst = Signal() 252 | self.dir = Signal() 253 | self.nxt = Signal() 254 | self.stp = Signal() 255 | self.data = Record([("i", 8), ("o", 8), ("oe", 1)]) 256 | 257 | self._domain = domain 258 | self._pins = pins 259 | 260 | def elaborate(self, platform): 261 | m = Module() 262 | 263 | if self._pins is not None: 264 | m.d.comb += [ 265 | ClockSignal(self._domain).eq(self._pins.clk.i), 266 | self.dir.eq(self._pins.dir.i), 267 | self.nxt.eq(self._pins.nxt.i), 268 | self.data.i.eq(self._pins.data.i), 269 | self._pins.data.o.eq(self.data.o), 270 | self._pins.data.oe.eq(self.data.oe), 271 | self._pins.rst.o.eq(self.rst), 272 | self._pins.stp.o.eq(self.stp), 273 | ] 274 | 275 | dir_r = Signal() 276 | m.d[self._domain] += dir_r.eq(self.dir) 277 | 278 | # Transmit 279 | with m.If(~dir_r & ~self.dir): 280 | m.d.comb += self.data.oe.eq(1) 281 | with m.If(~self.stp): 282 | with m.If(self.sink.valid): 283 | m.d.comb += self.data.o.eq(self.sink.data) 284 | with m.If(self.sink.last & self.nxt): 285 | m.d[self._domain] += self.stp.eq(1) 286 | m.d.comb += self.sink.ready.eq(self.nxt) 287 | 288 | with m.If(self.stp): 289 | m.d[self._domain] += self.stp.eq(0) 290 | 291 | # Receive 292 | with m.If(dir_r & self.dir): 293 | m.d[self._domain] += [ 294 | self.source.valid.eq(1), 295 | self.source.data.eq(self.data.i), 296 | self.source.cmd.eq(~self.nxt) 297 | ] 298 | with m.Else(): 299 | m.d[self._domain] += self.source.valid.eq(0) 300 | 301 | m.d.comb += self.source.last.eq(dir_r & ~self.dir) 302 | 303 | return m 304 | 305 | 306 | class _Timer(Elaboratable): 307 | def __init__(self): 308 | self.cnt2ns = Signal() 309 | self.cnt25ns = Signal() 310 | self.cnt2ms = Signal() 311 | self.done = Signal() 312 | 313 | def elaborate(self, platform): 314 | m = Module() 315 | 316 | counter = Signal(30) 317 | 318 | with m.If(self.cnt2ns | self.cnt25ns | self.cnt2ms): 319 | with m.If(self.done): 320 | m.d.ulpi += counter.eq(0) 321 | with m.Else(): 322 | m.d.ulpi += counter.eq(counter + 1) 323 | with m.Else(): 324 | m.d.ulpi += counter.eq(0) 325 | 326 | with m.If(self.cnt2ns & (counter == 10)): 327 | m.d.comb += self.done.eq(1) 328 | with m.If(self.cnt25ns & (counter == 120)): 329 | m.d.comb += self.done.eq(1) 330 | with m.If(self.cnt2ms & (counter == 120000)): 331 | m.d.comb += self.done.eq(1) 332 | 333 | return m 334 | 335 | 336 | class _Splitter(Elaboratable): 337 | def __init__(self): 338 | self.sink = stream.Endpoint([('data', 8), ('cmd', 1)]) 339 | self.source = stream.Endpoint([('data', 8)]) 340 | 341 | def elaborate(self, platform): 342 | m = Module() 343 | 344 | buf_data = Signal(8) 345 | buf_valid = Signal() 346 | 347 | m.d.ulpi += self.source.valid.eq(0) 348 | 349 | with m.If(self.sink.valid): 350 | with m.If(~self.sink.cmd): 351 | m.d.ulpi += [ 352 | buf_data.eq(self.sink.data), 353 | buf_valid.eq(1), 354 | ] 355 | with m.If(buf_valid): 356 | m.d.ulpi += [ 357 | self.source.valid.eq(1), 358 | self.source.data.eq(buf_data), 359 | self.source.last.eq(0), 360 | ] 361 | with m.Elif(self.sink.data & 0x38 == 0x08): 362 | with m.If(buf_valid): 363 | m.d.ulpi += [ 364 | self.source.valid.eq(1), 365 | self.source.last.eq(1), 366 | self.source.data.eq(buf_data), 367 | buf_valid.eq(0), 368 | ] 369 | 370 | return m 371 | 372 | 373 | class _Sender(Elaboratable): 374 | def __init__(self): 375 | self.sink = stream.Endpoint([("data", 8)]) 376 | self.source = stream.Endpoint([("data", 8)]) 377 | 378 | def elaborate(self, platform): 379 | m = Module() 380 | 381 | last_r = Signal(reset=1) 382 | 383 | # Detect first byte and replace it with 0100xxxx (with xxxx being the PID). 384 | with m.If(self.sink.valid & self.sink.ready): 385 | m.d.ulpi += last_r.eq(self.sink.last) 386 | 387 | with m.If(last_r): 388 | m.d.comb += [ 389 | self.source.data.eq(Cat(self.sink.data[0:4], 0b0100)), 390 | self.source.valid.eq(self.sink.valid), 391 | self.source.last.eq(self.sink.last), 392 | self.sink.ready.eq(self.source.ready) 393 | ] 394 | with m.Else(): 395 | m.d.comb += [ 396 | self.sink.connect(self.source) 397 | ] 398 | 399 | return m 400 | -------------------------------------------------------------------------------- /lambdausb/io/usb_serial/__init__.py: -------------------------------------------------------------------------------- 1 | from .phy import * 2 | -------------------------------------------------------------------------------- /lambdausb/io/usb_serial/phy.py: -------------------------------------------------------------------------------- 1 | from nmigen import * 2 | from nmigen.hdl.rec import * 3 | 4 | from ...lib import stream 5 | from .rx import PHY as PHYRX 6 | from .tx import PHY as PHYTX 7 | 8 | 9 | __all__ = ["PHY"] 10 | 11 | 12 | class PHY(Elaboratable): 13 | def __init__(self, pins, sync_freq): 14 | if sync_freq < 48e6: 15 | raise ValueError("sync_freq must be at least 48e6 Hz, not {!r}".format(sync_freq)) 16 | 17 | self.rx = Record([ 18 | ("stb", 1, DIR_FANOUT), 19 | ("lst", 1, DIR_FANOUT), 20 | ("data", 8, DIR_FANOUT), 21 | ("rdy", 1, DIR_FANIN), 22 | ]) 23 | self.tx = Record([ 24 | ("stb", 1, DIR_FANIN), 25 | ("lst", 1, DIR_FANIN), 26 | ("data", 8, DIR_FANIN), 27 | ("rdy", 1, DIR_FANOUT), 28 | ]) 29 | 30 | self.sync_freq = sync_freq 31 | self._pins = pins 32 | 33 | 34 | def elaborate(self, platform): 35 | m = Module() 36 | 37 | rx = m.submodules.rx = PHYRX(self.sync_freq) 38 | tx = m.submodules.tx = PHYTX(self.sync_freq) 39 | 40 | m.d.comb += [ 41 | rx.din[0].eq(self._pins.p.i), 42 | rx.din[1].eq(self._pins.n.i), 43 | self._pins.p.o.eq(tx.dout[0]), 44 | self._pins.n.o.eq(tx.dout[1]) 45 | ] 46 | 47 | period = int(self.sync_freq//12e6) 48 | 49 | with m.FSM() as fsm: 50 | with m.State("IDLE"): 51 | with m.If(~rx.idle): 52 | m.next = "RECEIVE" 53 | with m.Elif(self.tx.stb): 54 | m.next = "TRANSMIT" 55 | 56 | with m.State("RECEIVE"): 57 | m.d.comb += [ 58 | self.rx.stb.eq(rx.source.valid), 59 | self.rx.lst.eq(rx.source.last), 60 | self.rx.data.eq(rx.source.data), 61 | rx.source.ready.eq(self.rx.rdy), 62 | ] 63 | ctr_idle = Signal(range(2*period + 1), reset=2*period) 64 | with m.If(ctr_idle == 0): 65 | m.d.sync += ctr_idle.eq(ctr_idle.reset) 66 | m.next = "IDLE" 67 | with m.Elif(rx.idle): 68 | m.d.sync += ctr_idle.eq(ctr_idle - 1) 69 | 70 | with m.State("TRANSMIT"): 71 | m.d.comb += [ 72 | tx.sink.valid.eq(self.tx.stb), 73 | tx.sink.last.eq(self.tx.lst), 74 | tx.sink.data.eq(self.tx.data), 75 | self.tx.rdy.eq(tx.sink.ready), 76 | ] 77 | ctr_oen = Signal(range(2*period + 1), reset=2*period) 78 | with m.If(ctr_oen == 0): 79 | m.d.sync += ctr_oen.eq(ctr_oen.reset) 80 | m.next = "IDLE" 81 | with m.Elif(~tx.oe): 82 | m.d.sync += ctr_oen.eq(ctr_oen - 1) 83 | 84 | m.d.comb += [ 85 | rx.enable.eq(~fsm.ongoing("TRANSMIT")), 86 | self._pins.p.oe.eq(fsm.ongoing("TRANSMIT")), 87 | self._pins.n.oe.eq(fsm.ongoing("TRANSMIT")) 88 | ] 89 | 90 | return m 91 | -------------------------------------------------------------------------------- /lambdausb/io/usb_serial/rx.py: -------------------------------------------------------------------------------- 1 | from nmigen import * 2 | from nmigen.lib.coding import Encoder 3 | 4 | from ...lib import stream 5 | from ...usb.defs import LineState 6 | 7 | 8 | __all__ = ["NRZIDecoder", "PHY"] 9 | 10 | 11 | class NRZIDecoder(Elaboratable): 12 | def __init__(self, period): 13 | self.period = period 14 | self.din = Signal(2) 15 | self.source = stream.Endpoint([("data", 8)]) 16 | self.idle = Signal() 17 | self.enable = Signal() 18 | 19 | def elaborate(self, platform): 20 | m = Module() 21 | 22 | half_period = self.period // 2 23 | 24 | phase = Signal(range(8*self.period+1)) 25 | 26 | shreg = Signal(15) 27 | offset = Signal(3) 28 | width = Signal(3) 29 | bitstuff = Signal() 30 | 31 | valid = Signal() 32 | 33 | with m.If(self.enable): 34 | din_r = Signal.like(self.din) 35 | m.d.sync += din_r.eq(self.din) 36 | 37 | m.d.sync += self.source.valid.eq(0) 38 | 39 | with m.If(self.din == din_r): 40 | with m.If(phase < 8*self.period): 41 | m.d.sync += phase.eq(phase + 1) 42 | with m.Else(): 43 | m.d.comb += self.idle.eq(1) 44 | m.d.sync += offset.eq(0) 45 | 46 | with m.Elif(phase >= half_period): 47 | m.d.sync += bitstuff.eq(0) 48 | for i in range(7): 49 | with m.If((phase >= half_period + i*self.period) & (phase < half_period + (i+1)*self.period)): 50 | if i == 6: 51 | m.d.sync += bitstuff.eq(1) 52 | with m.If(bitstuff): 53 | m.d.sync += shreg.eq(Cat(Repl(0b1, i), shreg)) 54 | m.d.comb += width.eq(C(i)) 55 | with m.Else(): 56 | m.d.sync += shreg.eq(Cat(Repl(0b1, i), C(0b0), shreg)) 57 | m.d.comb += width.eq(C(i + 1)) 58 | m.d.sync += [ 59 | phase.eq(1), 60 | Cat(offset, valid).eq(offset + width), 61 | self.source.valid.eq(valid), 62 | self.source.data.eq(shreg.bit_select(offset, width=8)[::-1]), 63 | self.source.last.eq(Mux(bitstuff, self.din, din_r) == LineState.SE0), 64 | ] 65 | 66 | with m.If(self.source.valid & self.source.last): 67 | m.d.sync += phase.eq(8*self.period) 68 | 69 | return m 70 | 71 | 72 | class PHY(Elaboratable): 73 | def __init__(self, sync_freq): 74 | self.sync_freq = sync_freq 75 | self.din = Signal(2) 76 | self.source = stream.Endpoint([("data", 8)]) 77 | self.idle = Signal() 78 | self.enable = Signal() 79 | 80 | def elaborate(self, platform): 81 | m = Module() 82 | 83 | period = int(self.sync_freq//12e6) 84 | ctr_se0 = Signal(range(2*period)) 85 | 86 | nrzi_dec = m.submodules.nrzi_dec = NRZIDecoder(period) 87 | m.d.comb += [ 88 | nrzi_dec.din.eq(self.din), 89 | self.idle.eq(nrzi_dec.idle), 90 | nrzi_dec.enable.eq(self.enable) 91 | ] 92 | 93 | with m.FSM() as fsm: 94 | with m.State("IDLE"): 95 | with m.If(nrzi_dec.source.valid & (nrzi_dec.source.data == C(0b10000000))): 96 | # A SYNC pattern has been detected, which signals the start of a packet. 97 | m.next = "RECEIVE" 98 | 99 | with m.State("RECEIVE"): 100 | m.d.comb += nrzi_dec.source.connect(self.source) 101 | with m.If(nrzi_dec.source.valid & nrzi_dec.source.last & nrzi_dec.source.ready): 102 | m.next = "IDLE" 103 | 104 | return m 105 | -------------------------------------------------------------------------------- /lambdausb/io/usb_serial/tx.py: -------------------------------------------------------------------------------- 1 | from nmigen import * 2 | 3 | from ...lib import stream 4 | from ...usb.defs import LineState 5 | 6 | 7 | __all__ = ["NRZIEncoder", "PHY"] 8 | 9 | 10 | class NRZIEncoder(Elaboratable): 11 | def __init__(self, sync_freq): 12 | self.sync_freq = sync_freq 13 | self.sink = stream.Endpoint([("data", 8)]) 14 | self.idle = Signal() 15 | self.dout = Signal(2) 16 | 17 | def elaborate(self, platform): 18 | m = Module() 19 | 20 | phase_accumulator = Signal(32) 21 | tuning_word = Signal(32, reset=int((12e6/self.sync_freq)*2**32)) 22 | tick = Signal() 23 | 24 | m.d.sync += Cat(phase_accumulator, tick).eq(phase_accumulator + tuning_word) 25 | 26 | sink_last = Signal() 27 | shreg = Signal(9) 28 | ctr_bit = Signal(range(9), reset=8) 29 | ctr_one = Signal(range(7), reset=6) 30 | hold_line = Signal() 31 | 32 | with m.FSM() as fsm: 33 | with m.State("IDLE"): 34 | m.d.comb += self.sink.ready.eq(1) 35 | with m.If(self.sink.valid): 36 | m.d.sync += [ 37 | sink_last.eq(self.sink.last), 38 | shreg.eq(self.sink.data), 39 | ctr_bit.eq(ctr_bit.reset) 40 | ] 41 | m.next = "ENCODE" 42 | with m.If(~hold_line): 43 | m.d.sync += self.dout.eq(LineState.J) 44 | m.d.sync += hold_line.eq(1) 45 | 46 | with m.State("ENCODE"): 47 | with m.If(tick): 48 | with m.If((ctr_bit == 1) & ~sink_last): 49 | m.d.sync += hold_line.eq(1) 50 | m.next = "IDLE" 51 | with m.If(ctr_one == 0): 52 | # We must insert a 0 for every six consecutive 1s. 53 | m.d.sync += ctr_one.eq(ctr_one.reset) 54 | m.d.sync += self.dout.eq(~self.dout) 55 | with m.Elif(ctr_bit != 0): 56 | with m.If(shreg[0] == 1): 57 | m.d.sync += ctr_one.eq(ctr_one - 1) 58 | with m.Else(): 59 | m.d.sync += ctr_one.eq(ctr_one.reset) 60 | m.d.sync += self.dout.eq(~self.dout) 61 | m.d.sync += [ 62 | shreg.eq(Cat(shreg[1:], 0)), 63 | ctr_bit.eq(ctr_bit - 1), 64 | ] 65 | with m.Else(): 66 | m.d.sync += hold_line.eq(0) 67 | m.d.sync += ctr_one.eq(ctr_one.reset) 68 | m.next = "IDLE" 69 | 70 | m.d.comb += self.idle.eq(fsm.ongoing("IDLE")) 71 | 72 | return m 73 | 74 | 75 | class PHY(Elaboratable): 76 | def __init__(self, sync_freq): 77 | self.sync_freq = sync_freq 78 | self.sink = stream.Endpoint([("data", 8)]) 79 | self.oe = Signal() 80 | self.dout = Signal(2) 81 | 82 | def elaborate(self, platform): 83 | m = Module() 84 | 85 | nrzi_enc = m.submodules.nrzi_enc = NRZIEncoder(self.sync_freq) 86 | 87 | with m.FSM() as fsm: 88 | with m.State("SYNC"): 89 | # Encode and transmit the SYNC pattern. 90 | m.d.comb += [ 91 | nrzi_enc.sink.data.eq(0b10000000), 92 | nrzi_enc.sink.valid.eq(self.sink.valid), 93 | self.oe.eq(self.sink.valid), 94 | self.dout.eq(nrzi_enc.dout) 95 | ] 96 | with m.If(nrzi_enc.sink.valid & nrzi_enc.sink.ready): 97 | m.next = "TRANSMIT" 98 | 99 | with m.State("TRANSMIT"): 100 | # Encode and transmit the packet data. 101 | m.d.comb += [ 102 | self.sink.connect(nrzi_enc.sink), 103 | self.oe.eq(1), 104 | self.dout.eq(nrzi_enc.dout) 105 | ] 106 | with m.If(~self.sink.valid & nrzi_enc.idle): 107 | m.next = "EOP" 108 | 109 | with m.State("EOP"): 110 | period = int(self.sync_freq//12e6) 111 | ctr_eop = Signal(range(4*period), reset=4*period-1) 112 | # Hold SE0 for 2 cycles, which signals the end of packet. 113 | with m.If(ctr_eop == 0): 114 | m.d.sync += ctr_eop.eq(ctr_eop.reset) 115 | m.next = "SYNC" 116 | with m.Else(): 117 | m.d.sync += ctr_eop.eq(ctr_eop - 1) 118 | m.d.comb += [ 119 | self.oe.eq(1), 120 | self.dout.eq(LineState.SE0) 121 | ] 122 | 123 | return m 124 | -------------------------------------------------------------------------------- /lambdausb/lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdaconcept/lambdaUSB/2605a56c64b6fea17cd6528ee3ddbf0a8ff47d44/lambdausb/lib/__init__.py -------------------------------------------------------------------------------- /lambdausb/lib/stream.py: -------------------------------------------------------------------------------- 1 | from nmigen import * 2 | from nmigen.hdl.rec import * 3 | from nmigen.lib import fifo 4 | 5 | 6 | __all__ = ["Endpoint", "SyncFIFO", "AsyncFIFO"] 7 | 8 | 9 | def _make_fanout(layout): 10 | r = [] 11 | for f in layout: 12 | if isinstance(f[1], (int, tuple)): 13 | r.append((f[0], f[1], DIR_FANOUT)) 14 | else: 15 | r.append((f[0], _make_fanout(f[1]))) 16 | return r 17 | 18 | 19 | class EndpointDescription: 20 | def __init__(self, payload_layout): 21 | self.payload_layout = payload_layout 22 | 23 | def get_full_layout(self): 24 | reserved = {"valid", "ready", "first", "last", "payload"} 25 | attributed = set() 26 | for f in self.payload_layout: 27 | if f[0] in attributed: 28 | raise ValueError(f[0] + " already attributed in payload layout") 29 | if f[0] in reserved: 30 | raise ValueError(f[0] + " cannot be used in endpoint layout") 31 | attributed.add(f[0]) 32 | 33 | full_layout = [ 34 | ("valid", 1, DIR_FANOUT), 35 | ("ready", 1, DIR_FANIN), 36 | ("first", 1, DIR_FANOUT), 37 | ("last", 1, DIR_FANOUT), 38 | ("payload", _make_fanout(self.payload_layout)) 39 | ] 40 | return full_layout 41 | 42 | 43 | class Endpoint(Record): 44 | def __init__(self, layout_or_description, **kwargs): 45 | if isinstance(layout_or_description, EndpointDescription): 46 | self.description = layout_or_description 47 | else: 48 | self.description = EndpointDescription(layout_or_description) 49 | super().__init__(self.description.get_full_layout(), src_loc_at=1, **kwargs) 50 | 51 | def __getattr__(self, name): 52 | try: 53 | return super().__getattr__(name) 54 | except AttributeError: 55 | return self.fields["payload"][name] 56 | 57 | 58 | class _FIFOWrapper: 59 | def __init__(self, payload_layout): 60 | self.sink = Endpoint(payload_layout) 61 | self.source = Endpoint(payload_layout) 62 | 63 | self.layout = Layout([ 64 | ("payload", self.sink.description.payload_layout), 65 | ("first", 1, DIR_FANOUT), 66 | ("last", 1, DIR_FANOUT) 67 | ]) 68 | 69 | def elaborate(self, platform): 70 | m = Module() 71 | 72 | fifo = m.submodules.fifo = self.fifo 73 | fifo_din = Record(self.layout) 74 | fifo_dout = Record(self.layout) 75 | m.d.comb += [ 76 | fifo.w_data.eq(fifo_din), 77 | fifo_dout.eq(fifo.r_data), 78 | 79 | self.sink.ready.eq(fifo.w_rdy), 80 | fifo.w_en.eq(self.sink.valid), 81 | fifo_din.first.eq(self.sink.first), 82 | fifo_din.last.eq(self.sink.last), 83 | fifo_din.payload.eq(self.sink.payload), 84 | 85 | self.source.valid.eq(fifo.r_rdy), 86 | self.source.first.eq(fifo_dout.first), 87 | self.source.last.eq(fifo_dout.last), 88 | self.source.payload.eq(fifo_dout.payload), 89 | fifo.r_en.eq(self.source.ready) 90 | ] 91 | 92 | return m 93 | 94 | 95 | class SyncFIFO(Elaboratable, _FIFOWrapper): 96 | def __init__(self, layout, depth, fwft=True): 97 | super().__init__(layout) 98 | self.fifo = fifo.SyncFIFO(width=len(Record(self.layout)), depth=depth, fwft=fwft) 99 | self.depth = self.fifo.depth 100 | self.level = self.fifo.level 101 | 102 | 103 | class AsyncFIFO(Elaboratable, _FIFOWrapper): 104 | def __init__(self, layout, depth, r_domain="read", w_domain="write"): 105 | super().__init__(layout) 106 | self.fifo = fifo.AsyncFIFO(width=len(Record(self.layout)), depth=depth, 107 | r_domain=r_domain, w_domain=w_domain) 108 | self.depth = self.fifo.depth 109 | -------------------------------------------------------------------------------- /lambdausb/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdaconcept/lambdaUSB/2605a56c64b6fea17cd6528ee3ddbf0a8ff47d44/lambdausb/test/__init__.py -------------------------------------------------------------------------------- /lambdausb/test/_util.py: -------------------------------------------------------------------------------- 1 | from nmigen.back.pysim import * 2 | 3 | 4 | def simulation_test(dut, process, sync=True): 5 | sim = Simulator(dut) 6 | if sync: 7 | sim.add_clock(1e-6) 8 | sim.add_sync_process(process) 9 | else: 10 | sim.add_process(process) 11 | with sim.write_vcd("test.vcd"): 12 | sim.run() 13 | -------------------------------------------------------------------------------- /lambdausb/test/test_usb_crc.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from nmigen import * 4 | from nmigen.back.pysim import * 5 | 6 | from ..usb.crc import * 7 | from ._util import * 8 | 9 | 10 | class CRCTestCase(unittest.TestCase): 11 | def test_basic(self): 12 | dut = CRC(poly=0b11000000000000101, size=16, dw=8, init=0xffff) 13 | 14 | def process(): 15 | yield dut.clr.eq(1) 16 | yield 17 | 18 | yield dut.clr.eq(0) 19 | yield dut.en.eq(1) 20 | yield dut.val.eq(0x80) 21 | yield 22 | 23 | yield dut.val.eq(0x06) 24 | yield 25 | 26 | yield dut.val.eq(0x00) 27 | yield 28 | 29 | yield dut.val.eq(0x01) 30 | yield 31 | 32 | yield dut.val.eq(0x00) 33 | yield 34 | 35 | yield dut.val.eq(0x00) 36 | yield 37 | 38 | yield dut.val.eq(0x12) 39 | yield 40 | 41 | yield dut.val.eq(0x00) 42 | yield 43 | 44 | self.assertEqual((yield dut.res), 0xf4e0) 45 | 46 | simulation_test(dut, process, sync=True) 47 | -------------------------------------------------------------------------------- /lambdausb/test/test_usb_endpoint.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from ..usb.endpoint import * 4 | 5 | 6 | class InputEndpointTestCase(unittest.TestCase): 7 | def test_simple(self): 8 | ep = InputEndpoint(xfer=Transfer.CONTROL, max_size=64) 9 | self.assertEqual(ep.xfer, Transfer.CONTROL) 10 | self.assertEqual(ep.max_size, 64) 11 | 12 | def test_wrong_xfer(self): 13 | with self.assertRaisesRegex(TypeError, 14 | r"Transfer type must be an instance of Transfer, not 'foo'"): 15 | ep = InputEndpoint(xfer="foo", max_size=64) 16 | 17 | def test_wrong_size(self): 18 | with self.assertRaisesRegex(ValueError, 19 | r"Maximum packet size must be a positive integer, not 'foo'"): 20 | ep = InputEndpoint(xfer=Transfer.CONTROL, max_size="foo") 21 | with self.assertRaisesRegex(ValueError, 22 | r"Maximum packet size must be a positive integer, not -1"): 23 | ep = InputEndpoint(xfer=Transfer.CONTROL, max_size=-1) 24 | 25 | def test_wrong_size_isochronous(self): 26 | with self.assertRaisesRegex(ValueError, 27 | r"Invalid maximum packet size 1025; must be lesser than or equal to 1024 for an " 28 | r"isochronous endpoint"): 29 | ep = InputEndpoint(xfer=Transfer.ISOCHRONOUS, max_size=1025) 30 | 31 | def test_wrong_size_control(self): 32 | with self.assertRaisesRegex(ValueError, 33 | r"Invalid maximum packet size 65; must be lesser than or equal to 64 for a " 34 | r"control endpoint"): 35 | ep = InputEndpoint(xfer=Transfer.CONTROL, max_size=65) 36 | 37 | def test_wrong_size_bulk(self): 38 | with self.assertRaisesRegex(ValueError, 39 | r"Invalid maximum packet size 513; must be lesser than or equal to 512 for a " 40 | r"bulk endpoint"): 41 | ep = InputEndpoint(xfer=Transfer.BULK, max_size=513) 42 | 43 | def test_wrong_size_interrupt(self): 44 | with self.assertRaisesRegex(ValueError, 45 | r"Invalid maximum packet size 1025; must be lesser than or equal to 1024 for an " 46 | r"interrupt endpoint"): 47 | ep = InputEndpoint(xfer=Transfer.INTERRUPT, max_size=1025) 48 | 49 | 50 | class OutputEndpointTestCase(unittest.TestCase): 51 | def test_simple(self): 52 | ep = OutputEndpoint(xfer=Transfer.CONTROL, max_size=64) 53 | self.assertEqual(ep.xfer, Transfer.CONTROL) 54 | self.assertEqual(ep.max_size, 64) 55 | 56 | def test_wrong_xfer(self): 57 | with self.assertRaisesRegex(TypeError, 58 | r"Transfer type must be an instance of Transfer, not 'foo'"): 59 | ep = OutputEndpoint(xfer="foo", max_size=64) 60 | 61 | def test_wrong_size(self): 62 | with self.assertRaisesRegex(ValueError, 63 | r"Maximum packet size must be a positive integer, not 'foo'"): 64 | ep = OutputEndpoint(xfer=Transfer.CONTROL, max_size="foo") 65 | with self.assertRaisesRegex(ValueError, 66 | r"Maximum packet size must be a positive integer, not -1"): 67 | ep = OutputEndpoint(xfer=Transfer.CONTROL, max_size=-1) 68 | 69 | def test_wrong_size_isochronous(self): 70 | with self.assertRaisesRegex(ValueError, 71 | r"Invalid maximum packet size 1025; must be lesser than or equal to 1024 for an " 72 | r"isochronous endpoint"): 73 | ep = OutputEndpoint(xfer=Transfer.ISOCHRONOUS, max_size=1025) 74 | 75 | def test_wrong_size_control(self): 76 | with self.assertRaisesRegex(ValueError, 77 | r"Invalid maximum packet size 65; must be lesser than or equal to 64 for a " 78 | r"control endpoint"): 79 | ep = OutputEndpoint(xfer=Transfer.CONTROL, max_size=65) 80 | 81 | def test_wrong_size_bulk(self): 82 | with self.assertRaisesRegex(ValueError, 83 | r"Invalid maximum packet size 513; must be lesser than or equal to 512 for a " 84 | r"bulk endpoint"): 85 | ep = OutputEndpoint(xfer=Transfer.BULK, max_size=513) 86 | 87 | def test_wrong_size_interrupt(self): 88 | with self.assertRaisesRegex(ValueError, 89 | r"Invalid maximum packet size 1025; must be lesser than or equal to 1024 for an " 90 | r"interrupt endpoint"): 91 | ep = OutputEndpoint(xfer=Transfer.INTERRUPT, max_size=1025) 92 | 93 | def test_setup(self): 94 | ep_0 = OutputEndpoint(xfer=Transfer.CONTROL, max_size=64) 95 | ep_1 = OutputEndpoint(xfer=Transfer.BULK, max_size=64) 96 | self.assertEqual(ep_0.setup.width, 1) 97 | self.assertEqual(ep_1.setup.width, 0) 98 | -------------------------------------------------------------------------------- /lambdausb/test/test_usb_mux.py: -------------------------------------------------------------------------------- 1 | #nmigen: UnusedElaboratable=no 2 | 3 | import unittest 4 | 5 | from nmigen import * 6 | from nmigen.back.pysim import * 7 | 8 | from ._util import * 9 | from ..usb.mux import * 10 | from ..usb.endpoint import * 11 | 12 | 13 | class DoubleBufferTestCase(unittest.TestCase): 14 | def write(self, dut, data): 15 | yield dut.w_stb.eq(1) 16 | for i, byte in enumerate(data): 17 | self.assertTrue((yield dut.w_rdy)) 18 | yield dut.w_lst.eq(i == len(data) - 1) 19 | yield dut.w_data.eq(byte) 20 | yield 21 | yield dut.w_stb.eq(0) 22 | yield 23 | 24 | def read(self, dut): 25 | data = [] 26 | end = False 27 | yield dut.r_rdy.eq(1) 28 | while not end: 29 | yield 30 | self.assertTrue((yield dut.r_stb)) 31 | data.append((yield dut.r_data)) 32 | end = (yield dut.r_lst) 33 | yield dut.r_rdy.eq(0) 34 | yield 35 | return data 36 | 37 | def test_rw_simple(self): 38 | dut = DoubleBuffer(depth=64, width=8) 39 | 40 | def process(): 41 | data = [0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 0x40, 0x00] 42 | yield from self.write(dut, data) 43 | self.assertEqual((yield from self.read(dut)), data) 44 | 45 | simulation_test(dut, process) 46 | 47 | def test_r_ack(self): 48 | dut = DoubleBuffer(depth=64, width=8, read_ack=True) 49 | 50 | def process(): 51 | data = [0x12, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x40, 0xac, 52 | 0x05, 0x78, 0x56, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01] 53 | yield from self.write(dut, data) 54 | self.assertEqual((yield from self.read(dut)), data) 55 | self.assertTrue((yield dut.r_stb)) 56 | yield dut.r_rdy.eq(1) 57 | yield dut.r_ack.eq(1) 58 | yield 59 | yield dut.r_rdy.eq(0) 60 | yield 61 | self.assertFalse((yield dut.r_stb)) 62 | 63 | simulation_test(dut, process) 64 | 65 | def test_w_bank_overflow(self): 66 | dut = DoubleBuffer(depth=1, width=8) 67 | 68 | def process(): 69 | self.assertEqual((yield dut.w_rdy), 1) 70 | yield dut.w_stb.eq(1) 71 | yield dut.w_data.eq(0xaa) 72 | yield 73 | self.assertEqual((yield dut.w_rdy), 1) 74 | yield dut.w_stb.eq(1) 75 | yield dut.w_lst.eq(1) 76 | yield dut.w_data.eq(0xbb) 77 | yield 78 | yield; yield Delay() 79 | self.assertEqual((yield dut.r_stb), 0) 80 | 81 | simulation_test(dut, process) 82 | 83 | def test_w_full(self): 84 | dut = DoubleBuffer(depth=1, width=8) 85 | 86 | def process(): 87 | self.assertEqual((yield dut.w_rdy), 1) 88 | self.assertEqual((yield dut.r_stb), 0) 89 | yield dut.w_stb.eq(1) 90 | yield dut.w_lst.eq(1) 91 | yield dut.w_data.eq(0xaa) 92 | yield 93 | yield; yield Delay() 94 | self.assertEqual((yield dut.w_rdy), 1) 95 | self.assertEqual((yield dut.r_stb), 1) 96 | yield dut.w_stb.eq(1) 97 | yield dut.w_lst.eq(1) 98 | yield dut.w_data.eq(0xbb) 99 | yield 100 | yield; yield Delay() 101 | self.assertEqual((yield dut.w_rdy), 0) 102 | self.assertEqual((yield dut.r_stb), 1) 103 | 104 | simulation_test(dut, process) 105 | 106 | def test_w_drop(self): 107 | dut = DoubleBuffer(depth=2, width=8) 108 | 109 | def process(): 110 | self.assertEqual((yield dut.w_rdy), 1) 111 | yield dut.w_stb.eq(1) 112 | yield dut.w_data.eq(0xaa) 113 | yield 114 | self.assertEqual((yield dut.w_rdy), 1) 115 | yield dut.w_stb.eq(1) 116 | yield dut.w_lst.eq(1) 117 | yield dut.w_drop.eq(1) 118 | yield dut.w_data.eq(0xbb) 119 | yield 120 | yield; yield Delay() 121 | self.assertEqual((yield dut.r_stb), 0) 122 | 123 | simulation_test(dut, process) 124 | 125 | def test_rw_interleaved(self): 126 | dut = DoubleBuffer(depth=4, width=8) 127 | 128 | def process(): 129 | data_0 = [0xa0, 0xb0, 0xc0, 0xd0] 130 | data_1 = [0xa1, 0xb1, 0xc1, 0xd1] 131 | data_2 = [0xa2, 0xb2, 0xc2, 0xd2] 132 | yield from self.write(dut, data_0) 133 | yield 134 | yield from self.write(dut, data_1) 135 | self.assertEqual((yield from self.read(dut)), data_0) 136 | yield 137 | yield from self.write(dut, data_2) 138 | self.assertEqual((yield from self.read(dut)), data_1) 139 | self.assertEqual((yield from self.read(dut)), data_2) 140 | 141 | simulation_test(dut, process) 142 | 143 | 144 | class InputMultiplexerTestCase(unittest.TestCase): 145 | def test_add_endpoint_wrong(self): 146 | dut = InputMultiplexer() 147 | with self.assertRaisesRegex(TypeError, 148 | r"Endpoint must be an InputEndpoint, not 'foo'"): 149 | dut.add_endpoint("foo", addr=0) 150 | 151 | def test_add_endpoint_addr_wrong(self): 152 | dut = InputMultiplexer() 153 | ep = InputEndpoint(xfer=Transfer.CONTROL, max_size=64) 154 | with self.assertRaisesRegex(TypeError, 155 | r"Endpoint address must be an integer, not 'foo'"): 156 | dut.add_endpoint(ep, addr="foo") 157 | 158 | def test_add_endpoint_addr_range(self): 159 | dut = InputMultiplexer() 160 | ep = InputEndpoint(xfer=Transfer.CONTROL, max_size=64) 161 | with self.assertRaisesRegex(ValueError, 162 | r"Endpoint address must be between 0 and 15, not 16"): 163 | dut.add_endpoint(ep, addr=16) 164 | 165 | def test_add_endpoint_addr_twice(self): 166 | dut = InputMultiplexer() 167 | ep0 = InputEndpoint(xfer=Transfer.CONTROL, max_size=64) 168 | ep1 = InputEndpoint(xfer=Transfer.CONTROL, max_size=64) 169 | dut.add_endpoint(ep0, addr=0) 170 | with self.assertRaisesRegex(ValueError, 171 | r"Endpoint address 0 has already been assigned"): 172 | dut.add_endpoint(ep1, addr=0) 173 | 174 | def test_add_endpoint_twice(self): 175 | dut = InputMultiplexer() 176 | ep = InputEndpoint(xfer=Transfer.CONTROL, max_size=64) 177 | dut.add_endpoint(ep, addr=0) 178 | with self.assertRaisesRegex(ValueError, 179 | r"Endpoint \(rec ep stb lst data zlp rdy ack sof\) has already been added at " 180 | r"address 0"): 181 | dut.add_endpoint(ep, addr=1) 182 | 183 | def test_add_endpoint_0(self): 184 | dut = InputMultiplexer() 185 | ep = InputEndpoint(xfer=Transfer.BULK, max_size=64) 186 | with self.assertRaisesRegex(ValueError, 187 | r"Invalid transfer type BULK for endpoint 0; must be CONTROL"): 188 | dut.add_endpoint(ep, addr=0) 189 | 190 | def test_simple(self): 191 | dut = InputMultiplexer() 192 | ep0 = InputEndpoint(xfer=Transfer.CONTROL, max_size=64) 193 | ep1 = InputEndpoint(xfer=Transfer.BULK, max_size=512) 194 | dut.add_endpoint(ep0, addr=0) 195 | dut.add_endpoint(ep1, addr=1) 196 | 197 | def process(): 198 | self.assertEqual((yield dut.pkt.stb), 0) 199 | self.assertEqual((yield ep0.rdy), 0) 200 | self.assertEqual((yield ep1.rdy), 0) 201 | 202 | yield ep0.stb.eq(1) 203 | yield ep0.lst.eq(1) 204 | yield ep0.zlp.eq(1) 205 | yield ep0.data.eq(0xff) 206 | yield ep1.stb.eq(1) 207 | yield ep1.lst.eq(0) 208 | yield ep1.zlp.eq(0) 209 | yield ep1.data.eq(0xab) 210 | 211 | # Endpoint 0 212 | 213 | yield dut.sel.addr.eq(0) 214 | yield Delay() 215 | self.assertEqual((yield dut.sel.err), 0) 216 | self.assertEqual((yield dut.sel.xfer), Transfer.CONTROL) 217 | 218 | self.assertEqual((yield dut.pkt.stb), 1) 219 | self.assertEqual((yield dut.pkt.lst), 1) 220 | self.assertEqual((yield dut.pkt.zlp), 1) 221 | self.assertEqual((yield dut.pkt.data), 0xff) 222 | yield dut.pkt.rdy.eq(1) 223 | yield dut.pkt.ack.eq(1) 224 | yield Delay() 225 | self.assertEqual((yield ep0.rdy), 1) 226 | self.assertEqual((yield ep0.ack), 1) 227 | 228 | yield dut.pkt.rdy.eq(0) 229 | yield dut.pkt.ack.eq(0) 230 | 231 | # Endpoint 1 232 | 233 | yield dut.sel.addr.eq(1) 234 | yield Delay() 235 | self.assertEqual((yield dut.sel.err), 0) 236 | self.assertEqual((yield dut.sel.xfer), Transfer.BULK) 237 | 238 | self.assertEqual((yield dut.pkt.stb), 1) 239 | self.assertEqual((yield dut.pkt.lst), 0) 240 | self.assertEqual((yield dut.pkt.zlp), 0) 241 | self.assertEqual((yield dut.pkt.data), 0xab) 242 | yield dut.pkt.rdy.eq(1) 243 | yield dut.pkt.ack.eq(1) 244 | yield Delay() 245 | self.assertEqual((yield ep1.rdy), 1) 246 | self.assertEqual((yield ep1.ack), 1) 247 | 248 | yield dut.pkt.rdy.eq(0) 249 | yield dut.pkt.ack.eq(0) 250 | 251 | # Unknown endpoint 252 | 253 | yield dut.sel.addr.eq(2) 254 | yield Delay() 255 | self.assertEqual((yield dut.sel.err), 1) 256 | 257 | simulation_test(dut, process, sync=False) 258 | 259 | def test_buffered(self): 260 | dut = InputMultiplexer() 261 | ep = InputEndpoint(xfer=Transfer.CONTROL, max_size=2) 262 | dut.add_endpoint(ep, addr=0, buffered=True) 263 | 264 | def process(): 265 | self.assertEqual((yield dut.pkt.stb), 0) 266 | 267 | # Write first packet 268 | 269 | self.assertEqual((yield ep.rdy), 1) 270 | yield ep.stb.eq(1) 271 | yield ep.lst.eq(1) 272 | yield ep.zlp.eq(1) 273 | yield; yield Delay() 274 | 275 | self.assertEqual((yield ep.rdy), 0) 276 | yield; yield Delay() 277 | 278 | # Write second packet 279 | 280 | self.assertEqual((yield ep.rdy), 1) 281 | yield ep.lst.eq(0) 282 | yield ep.zlp.eq(0) 283 | yield ep.data.eq(0xaa) 284 | yield; yield Delay() 285 | self.assertEqual((yield ep.rdy), 1) 286 | yield ep.lst.eq(1) 287 | yield ep.data.eq(0xbb) 288 | yield; yield Delay() 289 | 290 | self.assertEqual((yield ep.rdy), 0) 291 | yield ep.stb.eq(0) 292 | yield 293 | 294 | # Read first packet 295 | 296 | yield dut.sel.addr.eq(0) 297 | yield Delay() 298 | self.assertEqual((yield dut.sel.err), 0) 299 | yield 300 | 301 | self.assertEqual((yield dut.pkt.stb), 1) 302 | self.assertEqual((yield dut.pkt.lst), 1) 303 | self.assertEqual((yield dut.pkt.zlp), 1) 304 | yield dut.pkt.rdy.eq(1) 305 | yield dut.pkt.ack.eq(1) 306 | yield 307 | yield dut.pkt.ack.eq(0) 308 | yield 309 | yield 310 | 311 | # Read second packet, without ack 312 | 313 | self.assertEqual((yield dut.pkt.stb), 1) 314 | self.assertEqual((yield dut.pkt.lst), 0) 315 | self.assertEqual((yield dut.pkt.zlp), 0) 316 | self.assertEqual((yield dut.pkt.data), 0xaa) 317 | yield 318 | self.assertEqual((yield dut.pkt.stb), 1) 319 | self.assertEqual((yield dut.pkt.lst), 1) 320 | self.assertEqual((yield dut.pkt.zlp), 0) 321 | self.assertEqual((yield dut.pkt.data), 0xbb) 322 | yield 323 | 324 | # Read second packet, with ack 325 | 326 | self.assertEqual((yield dut.pkt.stb), 1) 327 | self.assertEqual((yield dut.pkt.lst), 0) 328 | self.assertEqual((yield dut.pkt.zlp), 0) 329 | self.assertEqual((yield dut.pkt.data), 0xaa) 330 | yield 331 | self.assertEqual((yield dut.pkt.stb), 1) 332 | self.assertEqual((yield dut.pkt.lst), 1) 333 | self.assertEqual((yield dut.pkt.zlp), 0) 334 | self.assertEqual((yield dut.pkt.data), 0xbb) 335 | yield dut.pkt.ack.eq(1) 336 | yield 337 | yield 338 | 339 | self.assertEqual((yield dut.pkt.stb), 0) 340 | 341 | simulation_test(dut, process) 342 | 343 | def test_buffered_isochronous(self): 344 | dut = InputMultiplexer() 345 | ep = InputEndpoint(xfer=Transfer.ISOCHRONOUS, max_size=2) 346 | dut.add_endpoint(ep, addr=1, buffered=True) 347 | 348 | def process(): 349 | self.assertEqual((yield dut.pkt.stb), 0) 350 | 351 | # Write packet 352 | 353 | self.assertEqual((yield ep.rdy), 1) 354 | yield ep.stb.eq(1) 355 | yield ep.data.eq(0xaa) 356 | yield; yield Delay() 357 | self.assertEqual((yield ep.rdy), 1) 358 | yield ep.lst.eq(1) 359 | yield ep.data.eq(0xbb) 360 | yield; yield Delay() 361 | 362 | yield ep.stb.eq(0) 363 | yield 364 | 365 | # Read packet 366 | 367 | yield dut.sel.addr.eq(1) 368 | yield Delay() 369 | self.assertEqual((yield dut.sel.err), 0) 370 | yield 371 | 372 | yield dut.pkt.rdy.eq(1) 373 | yield 374 | 375 | self.assertEqual((yield dut.pkt.stb), 1) 376 | self.assertEqual((yield dut.pkt.lst), 0) 377 | self.assertEqual((yield dut.pkt.data), 0xaa) 378 | yield 379 | self.assertEqual((yield dut.pkt.stb), 1) 380 | self.assertEqual((yield dut.pkt.lst), 1) 381 | self.assertEqual((yield dut.pkt.data), 0xbb) 382 | yield 383 | yield 384 | 385 | self.assertEqual((yield dut.pkt.stb), 0) 386 | 387 | simulation_test(dut, process) 388 | 389 | def test_sof_broadcast(self): 390 | dut = InputMultiplexer() 391 | ep0 = InputEndpoint(xfer=Transfer.CONTROL, max_size=1) 392 | ep1 = InputEndpoint(xfer=Transfer.ISOCHRONOUS, max_size=1) 393 | dut.add_endpoint(ep0, addr=0) 394 | dut.add_endpoint(ep1, addr=1) 395 | 396 | def process(): 397 | self.assertEqual((yield ep0.sof), 0) 398 | self.assertEqual((yield ep1.sof), 0) 399 | yield dut.sof.eq(1) 400 | yield Delay() 401 | self.assertEqual((yield ep0.sof), 1) 402 | self.assertEqual((yield ep1.sof), 1) 403 | 404 | simulation_test(dut, process, sync=False) 405 | 406 | 407 | class OutputMultiplexerTestCase(unittest.TestCase): 408 | def test_add_endpoint_wrong(self): 409 | dut = OutputMultiplexer() 410 | with self.assertRaisesRegex(TypeError, 411 | r"Endpoint must be an OutputEndpoint, not 'foo'"): 412 | dut.add_endpoint("foo", addr=0) 413 | 414 | def test_add_endpoint_addr_wrong(self): 415 | dut = OutputMultiplexer() 416 | ep = OutputEndpoint(xfer=Transfer.CONTROL, max_size=64) 417 | with self.assertRaisesRegex(TypeError, 418 | r"Endpoint address must be an integer, not 'foo'"): 419 | dut.add_endpoint(ep, addr="foo") 420 | 421 | def test_add_endpoint_addr_range(self): 422 | dut = OutputMultiplexer() 423 | ep = OutputEndpoint(xfer=Transfer.CONTROL, max_size=64) 424 | with self.assertRaisesRegex(ValueError, 425 | r"Endpoint address must be between 0 and 15, not 16"): 426 | dut.add_endpoint(ep, addr=16) 427 | 428 | def test_add_endpoint_addr_twice(self): 429 | dut = OutputMultiplexer() 430 | ep0 = OutputEndpoint(xfer=Transfer.CONTROL, max_size=64) 431 | ep1 = OutputEndpoint(xfer=Transfer.CONTROL, max_size=64) 432 | dut.add_endpoint(ep0, addr=0) 433 | with self.assertRaisesRegex(ValueError, 434 | r"Endpoint address 0 has already been assigned"): 435 | dut.add_endpoint(ep1, addr=0) 436 | 437 | def test_add_endpoint_twice(self): 438 | dut = OutputMultiplexer() 439 | ep = OutputEndpoint(xfer=Transfer.CONTROL, max_size=64) 440 | dut.add_endpoint(ep, addr=0) 441 | with self.assertRaisesRegex(ValueError, 442 | r"Endpoint \(rec ep rdy stb lst data zlp setup drop sof\) has already been added at " 443 | r"address 0"): 444 | dut.add_endpoint(ep, addr=1) 445 | 446 | def test_add_endpoint_0(self): 447 | dut = OutputMultiplexer() 448 | ep = OutputEndpoint(xfer=Transfer.BULK, max_size=64) 449 | with self.assertRaisesRegex(ValueError, 450 | r"Invalid transfer type BULK for endpoint 0; must be CONTROL"): 451 | dut.add_endpoint(ep, addr=0) 452 | 453 | def test_simple(self): 454 | dut = OutputMultiplexer() 455 | ep0 = OutputEndpoint(xfer=Transfer.CONTROL, max_size=64) 456 | ep1 = OutputEndpoint(xfer=Transfer.BULK, max_size=512) 457 | dut.add_endpoint(ep0, addr=0) 458 | dut.add_endpoint(ep1, addr=1) 459 | 460 | def process(): 461 | self.assertEqual((yield ep0.stb), 0) 462 | self.assertEqual((yield ep1.stb), 0) 463 | 464 | yield dut.pkt.stb.eq(1) 465 | yield dut.pkt.lst.eq(1) 466 | yield dut.pkt.setup.eq(1) 467 | yield dut.pkt.zlp.eq(1) 468 | yield dut.pkt.data.eq(0xff) 469 | yield dut.pkt.drop.eq(1) 470 | yield ep0.rdy.eq(1) 471 | yield ep1.rdy.eq(1) 472 | 473 | # Endpoint 0 474 | 475 | yield dut.sel.addr.eq(0) 476 | yield Delay() 477 | self.assertEqual((yield dut.sel.err), 0) 478 | self.assertEqual((yield dut.sel.xfer), Transfer.CONTROL) 479 | 480 | self.assertEqual((yield ep0.stb), 1) 481 | self.assertEqual((yield ep0.lst), 1) 482 | self.assertEqual((yield ep0.setup), 1) 483 | self.assertEqual((yield ep0.zlp), 1) 484 | self.assertEqual((yield ep0.data), 0xff) 485 | self.assertEqual((yield ep0.drop), 1) 486 | self.assertEqual((yield ep1.stb), 0) 487 | self.assertEqual((yield dut.pkt.rdy), 1) 488 | 489 | # Endpoint 1 490 | 491 | yield dut.sel.addr.eq(1) 492 | yield Delay() 493 | self.assertEqual((yield dut.sel.err), 0) 494 | self.assertEqual((yield dut.sel.xfer), Transfer.BULK) 495 | 496 | self.assertEqual((yield ep1.stb), 1) 497 | self.assertEqual((yield ep1.lst), 1) 498 | self.assertEqual((yield ep1.setup), 0) 499 | self.assertEqual((yield ep1.zlp), 1) 500 | self.assertEqual((yield ep1.data), 0xff) 501 | self.assertEqual((yield ep1.drop), 1) 502 | self.assertEqual((yield ep0.stb), 0) 503 | self.assertEqual((yield dut.pkt.rdy), 1) 504 | 505 | # Unknown endpoint 506 | 507 | yield dut.sel.addr.eq(2) 508 | yield Delay() 509 | self.assertEqual((yield dut.sel.err), 1) 510 | 511 | simulation_test(dut, process, sync=False) 512 | 513 | def test_buffered(self): 514 | dut = OutputMultiplexer() 515 | ep = OutputEndpoint(xfer=Transfer.CONTROL, max_size=2) 516 | dut.add_endpoint(ep, addr=0, buffered=True) 517 | 518 | def process(): 519 | yield dut.sel.addr.eq(0) 520 | yield Delay() 521 | self.assertEqual((yield dut.sel.err), 0) 522 | yield 523 | 524 | # Write first packet 525 | 526 | self.assertEqual((yield dut.pkt.rdy), 1) 527 | yield dut.pkt.stb.eq(1) 528 | yield dut.pkt.lst.eq(1) 529 | yield dut.pkt.setup.eq(1) 530 | yield dut.pkt.zlp.eq(1) 531 | yield dut.pkt.data.eq(0xff) 532 | yield; yield Delay() 533 | 534 | self.assertEqual((yield dut.pkt.rdy), 0) 535 | yield; yield Delay() 536 | 537 | # Write second packet 538 | 539 | self.assertEqual((yield dut.pkt.rdy), 1) 540 | yield dut.pkt.lst.eq(0) 541 | yield dut.pkt.setup.eq(0) 542 | yield dut.pkt.zlp.eq(0) 543 | yield dut.pkt.data.eq(0xaa) 544 | yield; yield Delay() 545 | self.assertEqual((yield dut.pkt.rdy), 1) 546 | yield dut.pkt.lst.eq(1) 547 | yield dut.pkt.data.eq(0xbb) 548 | yield; yield Delay() 549 | 550 | self.assertEqual((yield dut.pkt.rdy), 0) 551 | yield dut.pkt.stb.eq(0) 552 | yield 553 | 554 | # Read first packet 555 | 556 | self.assertEqual((yield ep.stb), 1) 557 | self.assertEqual((yield ep.lst), 1) 558 | self.assertEqual((yield ep.setup), 1) 559 | self.assertEqual((yield ep.zlp), 1) 560 | self.assertEqual((yield ep.data), 0xff) 561 | yield ep.rdy.eq(1) 562 | yield 563 | yield 564 | yield 565 | 566 | # Read second packet 567 | 568 | self.assertEqual((yield ep.stb), 1) 569 | self.assertEqual((yield ep.lst), 0) 570 | self.assertEqual((yield ep.setup), 0) 571 | self.assertEqual((yield ep.zlp), 0) 572 | self.assertEqual((yield ep.data), 0xaa) 573 | yield 574 | self.assertEqual((yield ep.stb), 1) 575 | self.assertEqual((yield ep.lst), 1) 576 | self.assertEqual((yield ep.setup), 0) 577 | self.assertEqual((yield ep.zlp), 0) 578 | self.assertEqual((yield ep.data), 0xbb) 579 | yield 580 | self.assertEqual((yield ep.stb), 0) 581 | 582 | simulation_test(dut, process) 583 | 584 | def test_sof_broadcast(self): 585 | dut = OutputMultiplexer() 586 | ep0 = OutputEndpoint(xfer=Transfer.CONTROL, max_size=1) 587 | ep1 = OutputEndpoint(xfer=Transfer.ISOCHRONOUS, max_size=1) 588 | dut.add_endpoint(ep0, addr=0) 589 | dut.add_endpoint(ep1, addr=1) 590 | 591 | def process(): 592 | self.assertEqual((yield ep0.sof), 0) 593 | self.assertEqual((yield ep1.sof), 0) 594 | yield dut.sof.eq(1) 595 | yield Delay() 596 | self.assertEqual((yield ep0.sof), 1) 597 | self.assertEqual((yield ep1.sof), 1) 598 | 599 | simulation_test(dut, process, sync=False) 600 | -------------------------------------------------------------------------------- /lambdausb/usb/__init__.py: -------------------------------------------------------------------------------- 1 | from .config import * 2 | from .device import * 3 | from .endpoint import * 4 | -------------------------------------------------------------------------------- /lambdausb/usb/config.py: -------------------------------------------------------------------------------- 1 | import enum 2 | 3 | from nmigen import * 4 | 5 | from .endpoint import * 6 | 7 | 8 | __all__ = ["ConfigurationFSM"] 9 | 10 | 11 | class Request(enum.IntEnum): 12 | GET_DESCRIPTOR = 0x8006 13 | GET_DEV_STATUS = 0x8000 14 | SET_ADDRESS = 0x0005 15 | SET_CONFIG = 0x0009 16 | 17 | 18 | class ConfigurationFSM(Elaboratable): 19 | def __init__(self, descriptor_map, rom_init): 20 | self.ep_in = InputEndpoint(xfer=Transfer.CONTROL, max_size=64) 21 | self.ep_out = OutputEndpoint(xfer=Transfer.CONTROL, max_size=64) 22 | self.dev_addr = Signal(7) 23 | 24 | self.descriptor_map = descriptor_map 25 | self.rom_init = rom_init 26 | 27 | def elaborate(self, platform): 28 | m = Module() 29 | 30 | rom = Memory(width=8, depth=len(self.rom_init), init=self.rom_init) 31 | m.submodules.rom_rp = rom_rp = rom.read_port(transparent=False) 32 | rom_rp.en.reset = 0 33 | 34 | rom_offset = Signal(range(len(self.rom_init)), reset_less=True) 35 | desc_size = Signal(16, reset_less=True) 36 | 37 | setup = Record([ 38 | ("bmRequestType", [("rcpt", 5), ("type", 2), ("dir", 1)]), 39 | ("bRequest", 8), 40 | ("wValue", 16), 41 | ("wIndex", 16), 42 | ("wLength", 16), 43 | ]) 44 | 45 | dev_addr_next = Signal.like(self.dev_addr) 46 | 47 | with m.FSM() as fsm: 48 | with m.State("RECEIVE"): 49 | rx_ctr = Signal(range(8)) 50 | m.d.comb += self.ep_out.rdy.eq(1) 51 | with m.If(self.ep_out.stb): 52 | m.d.sync += setup.eq(Cat(setup[8:], self.ep_out.data)) 53 | with m.If(rx_ctr == 7): 54 | with m.If(self.ep_out.lst): 55 | with m.If(~self.ep_out.drop): 56 | m.next = "DECODE-REQUEST" 57 | with m.Else(): 58 | # Overflow. Flush remaining bytes. 59 | m.next = "FLUSH" 60 | m.d.sync += rx_ctr.eq(0) 61 | with m.Else(): 62 | m.d.sync += rx_ctr.eq(Mux(self.ep_out.lst, 0, rx_ctr + 1)) 63 | 64 | with m.State("DECODE-REQUEST"): 65 | with m.Switch(Cat(setup.bRequest, setup.bmRequestType)): 66 | with m.Case(Request.GET_DESCRIPTOR): 67 | m.next = "GET-DESCRIPTOR" 68 | with m.Case(Request.GET_DEV_STATUS): 69 | m.next = "SEND-DEV-STATUS-0" 70 | with m.Case(Request.SET_ADDRESS): 71 | m.d.sync += dev_addr_next.eq(setup.wValue[:7]) 72 | m.next = "SEND-ZLP" 73 | with m.Case(Request.SET_CONFIG): 74 | m.next = "SEND-ZLP" 75 | with m.Default(): 76 | # Unsupported request. Ignore. 77 | m.next = "RECEIVE" 78 | 79 | with m.State("GET-DESCRIPTOR"): 80 | with m.Switch(setup.wValue[8:]): 81 | for desc_type, index_map in self.descriptor_map.items(): 82 | with m.Case(desc_type): 83 | with m.Switch(setup.wValue[:8]): 84 | for desc_index, (offset, size) in index_map.items(): 85 | with m.Case(desc_index): 86 | m.d.sync += [ 87 | rom_offset.eq(offset), 88 | desc_size.eq(size) 89 | ] 90 | m.next = "SEND-DESCRIPTOR-0" 91 | with m.Default(): 92 | m.next = "RECEIVE" 93 | with m.Default(): 94 | m.next = "RECEIVE" 95 | 96 | with m.State("SEND-DESCRIPTOR-0"): 97 | m.d.comb += [ 98 | rom_rp.addr.eq(rom_offset), 99 | rom_rp.en.eq(1), 100 | ] 101 | m.next = "SEND-DESCRIPTOR-1" 102 | 103 | with m.State("SEND-DESCRIPTOR-1"): 104 | tx_ctr = Signal(16) 105 | m.d.comb += [ 106 | self.ep_in.stb.eq(1), 107 | self.ep_in.data.eq(rom_rp.data) 108 | ] 109 | with m.If(desc_size < setup.wLength): 110 | m.d.comb += self.ep_in.lst.eq(tx_ctr == (desc_size - 1)) 111 | with m.Else(): 112 | m.d.comb += self.ep_in.lst.eq(tx_ctr == (setup.wLength - 1)) 113 | m.d.comb += rom_rp.addr.eq(rom_offset + tx_ctr + 1) 114 | with m.If(self.ep_in.rdy): 115 | with m.If(self.ep_in.lst): 116 | m.d.sync += tx_ctr.eq(0) 117 | m.next = "SEND-DESCRIPTOR-2" 118 | with m.Else(): 119 | m.d.sync += tx_ctr.eq(tx_ctr + 1) 120 | m.d.comb += rom_rp.en.eq(1) 121 | 122 | with m.State("SEND-DESCRIPTOR-2"): 123 | with m.If(self.ep_in.rdy): 124 | with m.If(self.ep_in.ack): 125 | m.next = "RECEIVE" 126 | with m.Else(): 127 | m.next = "SEND-DESCRIPTOR-0" 128 | 129 | with m.State("SEND-DEV-STATUS-0"): 130 | tx_last = Signal() 131 | m.d.comb += [ 132 | self.ep_in.stb.eq(1), 133 | self.ep_in.data.eq(0x00), 134 | self.ep_in.lst.eq(tx_last), 135 | ] 136 | with m.If(self.ep_in.rdy): 137 | with m.If(tx_last): 138 | m.d.sync += tx_last.eq(0) 139 | m.next = "SEND-DEV-STATUS-1" 140 | with m.Else(): 141 | m.d.sync += tx_last.eq(1) 142 | 143 | with m.State("SEND-DEV-STATUS-1"): 144 | with m.If(self.ep_in.rdy): 145 | with m.If(self.ep_in.ack): 146 | m.next = "RECEIVE" 147 | with m.Else(): 148 | m.next = "SEND-DEV-STATUS-0" 149 | 150 | with m.State("SEND-ZLP"): 151 | m.d.comb += [ 152 | self.ep_in.stb.eq(1), 153 | self.ep_in.zlp.eq(1), 154 | self.ep_in.lst.eq(1), 155 | ] 156 | with m.If(self.ep_in.rdy & self.ep_in.ack): 157 | m.d.sync += self.dev_addr.eq(dev_addr_next) 158 | m.next = "RECEIVE" 159 | 160 | with m.State("FLUSH"): 161 | m.d.comb += self.ep_out.rdy.eq(1) 162 | with m.If(self.ep_out.stb & self.ep_out.lst): 163 | m.next = "RECEIVE" 164 | 165 | return m 166 | -------------------------------------------------------------------------------- /lambdausb/usb/crc.py: -------------------------------------------------------------------------------- 1 | from nmigen import * 2 | 3 | 4 | __all__ = ["CRC"] 5 | 6 | 7 | class CRC(Elaboratable): 8 | def __init__(self, poly, size, dw, init=0xffff): 9 | self.dw = dw 10 | self.size = size 11 | self.init = init 12 | self.poly = poly 13 | 14 | self.clr = Signal() 15 | self.en = Signal() 16 | self.val = Signal(dw) 17 | self.res = Signal(size) 18 | 19 | def elaborate(self, platform): 20 | m = Module() 21 | 22 | crcreg = [Signal(self.size, reset=self.init) for i in range(self.dw+1)] 23 | 24 | for i in range(self.dw): 25 | inv = self.val[i] ^ crcreg[i][self.size-1] 26 | tmp = [] 27 | tmp.append(inv) 28 | for j in range(self.size -1): 29 | if((self.poly >> (j + 1)) & 1): 30 | tmp.append(crcreg[i][j] ^ inv) 31 | else: 32 | tmp.append(crcreg[i][j]) 33 | m.d.comb += crcreg[i+1].eq(Cat(*tmp)) 34 | 35 | with m.If(self.clr): 36 | m.d.sync += crcreg[0].eq(self.init) 37 | with m.Elif(self.en): 38 | m.d.sync += crcreg[0].eq(crcreg[self.dw]) 39 | 40 | m.d.comb += self.res.eq(crcreg[self.dw][::-1] ^ self.init) 41 | 42 | return m 43 | -------------------------------------------------------------------------------- /lambdausb/usb/defs.py: -------------------------------------------------------------------------------- 1 | import enum 2 | 3 | from nmigen import * 4 | 5 | 6 | class PacketID(enum.IntEnum): 7 | OUT = 0b0001 8 | IN = 0b1001 9 | SOF = 0b0101 10 | SETUP = 0b1101 11 | 12 | DATA0 = 0b0011 13 | DATA1 = 0b1011 14 | DATA2 = 0b0111 15 | MDATA = 0b1111 16 | 17 | ACK = 0b0010 18 | NAK = 0b1010 19 | STALL = 0b1110 20 | NYET = 0b0110 21 | 22 | PRE = 0b1100 23 | ERR = 0b1100 24 | SPLIT = 0b1000 25 | PING = 0b0100 26 | 27 | RESERVED = 0 28 | 29 | @staticmethod 30 | def is_token(pid): 31 | assert isinstance(pid, Value) 32 | return pid.matches("--01") 33 | 34 | @staticmethod 35 | def is_data(pid): 36 | assert isinstance(pid, Value) 37 | return pid.matches("--11") 38 | 39 | @staticmethod 40 | def is_handshake(pid): 41 | assert isinstance(pid, Value) 42 | return pid.matches("--10") 43 | 44 | @staticmethod 45 | def is_special(pid): 46 | assert isinstance(pid, Value) 47 | return pid.matches("--00") 48 | 49 | 50 | class LineState(enum.IntEnum): 51 | SE0 = 0b00 52 | J = 0b01 53 | K = 0b10 54 | SE1 = 0b11 55 | -------------------------------------------------------------------------------- /lambdausb/usb/device.py: -------------------------------------------------------------------------------- 1 | from nmigen import * 2 | from nmigen.hdl.rec import * 3 | 4 | from .crc import CRC 5 | from .defs import * 6 | from .endpoint import * 7 | from .mux import * 8 | 9 | 10 | __all__ = ["Device"] 11 | 12 | 13 | class Device(Elaboratable): 14 | """USB 2.0 device controller. 15 | 16 | An USB 2.0 device controller, managing transactions between its endpoints and the host. 17 | 18 | Attributes 19 | ---------- 20 | rx.stb : Signal, in 21 | Receive strobe. Asserted by the underlying PHY when it has data to send. 22 | rx.lst : Signal, in 23 | Receive last. Asserted when `rx.data` holds the last byte of a packet. 24 | rx.data : Signal, in 25 | Receive data. 26 | rx.rdy : Signal, out 27 | Receive ready. Asserted when the device is able to receive data. 28 | tx.stb : Signal, out 29 | Transmit strobe. Asserted by the device when it has data to send. 30 | tx.lst : Signal, out 31 | Transmit last. Asserted when `tx.data` holds the last byte of a packet. 32 | tx.data : Signal, out 33 | Transmit data. 34 | tx.rdy : Signal, in 35 | Transmit ready. Asserted when the underlying PHY is able to receive data. 36 | addr : Signal, in 37 | Device address. Provided by the logic controlling endpoint 0. 38 | """ 39 | def __init__(self): 40 | self.rx = Record([ 41 | ("stb", 1, DIR_FANIN), 42 | ("lst", 1, DIR_FANIN), 43 | ("data", 8, DIR_FANIN), 44 | ("rdy", 1, DIR_FANOUT), 45 | ]) 46 | self.tx = Record([ 47 | ("stb", 1, DIR_FANOUT), 48 | ("lst", 1, DIR_FANOUT), 49 | ("data", 8, DIR_FANOUT), 50 | ("rdy", 1, DIR_FANIN), 51 | ]) 52 | 53 | self.addr = Signal(7) 54 | 55 | self._mux_in = InputMultiplexer() 56 | self._mux_out = OutputMultiplexer() 57 | 58 | def add_endpoint(self, ep, *, addr, buffered=False): 59 | """ 60 | Add an endpoint to the USB device. 61 | 62 | Parameters 63 | ---------- 64 | ep : :class:`endpoint.InputEndpoint` or :class:`endpoint.OutputEndpoint` 65 | Endpoint interface. 66 | addr : int 67 | Endpoint address. 68 | buffered : bool 69 | Endpoint buffering. Optional. If true, a double buffer is provided between the 70 | the endpoint and the device controller. 71 | """ 72 | if isinstance(ep, InputEndpoint): 73 | self._mux_in .add_endpoint(ep, addr=addr, buffered=buffered) 74 | elif isinstance(ep, OutputEndpoint): 75 | self._mux_out.add_endpoint(ep, addr=addr, buffered=buffered) 76 | else: 77 | raise TypeError("Endpoint must be an InputEndpoint or an OutputEndpoint, not {!r}" 78 | .format(ep)) 79 | 80 | def elaborate(self, platform): 81 | m = Module() 82 | 83 | m.submodules.mux_in = mux_in = self._mux_in 84 | m.submodules.mux_out = mux_out = self._mux_out 85 | 86 | m.submodules.token_sink = token_sink = _TokenSink() 87 | m.submodules.data_sink = data_sink = _DataSink() 88 | m.submodules.data_source = data_source = _DataSource() 89 | 90 | rx_pid = Signal(4) 91 | rx_pid_r = Signal.like(rx_pid) 92 | m.d.comb += rx_pid.eq(self.rx.data[:4]) 93 | 94 | # PIDs are followed by a 4-bit field equal to their one's complement. 95 | rx_pid_valid = Signal() 96 | m.d.comb += rx_pid_valid.eq((rx_pid ^ self.rx.data[4:]).all()) 97 | 98 | # DATA0 and DATA1 PIDs are alternated between non-isochronous transactions to let the 99 | # recipient know if it missed a data packet. 100 | # The `rx_seq[ep]` bit tracks the expected PID for host->device transactions, and 101 | # the `tx_seq[ep]` bit tracks the expected PID for device->host transactions. 102 | # See section 8.6 of the USB 2.0 specification for details. 103 | rx_seq = Array(Signal(16, name="rx_seq")) 104 | tx_seq = Array(Signal(16, name="tx_seq")) 105 | 106 | token_dev = Signal(7) 107 | token_ep = Signal(4) 108 | token_setup = Signal() 109 | 110 | expect_handshake = Signal() 111 | 112 | with m.FSM() as fsm: 113 | with m.State("IDLE"): 114 | m.d.comb += self.rx.rdy.eq(1) 115 | with m.If(self.rx.stb): 116 | with m.If(rx_pid_valid): 117 | m.d.sync += rx_pid_r.eq(rx_pid) 118 | with m.If(self.rx.lst): 119 | with m.If(PacketID.is_handshake(rx_pid) 120 | # Ignore handshake packets if we are not expecting one. 121 | & expect_handshake): 122 | m.next = "RECV-HANDSHAKE" 123 | with m.Else(): 124 | with m.If(PacketID.is_token(rx_pid) 125 | # PING packets use the same encoding as token packets. 126 | | (rx_pid == PacketID.PING)): 127 | m.next = "RECV-TOKEN-0" 128 | with m.Else(): 129 | m.next = "FLUSH-PACKET" 130 | with m.Elif(~self.rx.lst): 131 | m.next = "FLUSH-PACKET" 132 | 133 | with m.State("RECV-HANDSHAKE"): 134 | with m.If(rx_pid_r == PacketID.ACK): 135 | m.d.comb += [ 136 | mux_in.pkt.rdy.eq(1), 137 | mux_in.pkt.ack.eq(1), 138 | ] 139 | # Toggle the transmitter-side sequence bit upon receipt of an ACK. 140 | m.d.sync += tx_seq[token_ep].eq(~tx_seq[token_ep]) 141 | m.d.sync += expect_handshake.eq(0) 142 | m.next = "IDLE" 143 | 144 | with m.State("RECV-TOKEN-0"): 145 | m.d.comb += [ 146 | token_sink.rx.stb .eq(self.rx.stb), 147 | token_sink.rx.lst .eq(self.rx.lst), 148 | token_sink.rx.data.eq(self.rx.data), 149 | self.rx.rdy.eq(token_sink.rx.rdy), 150 | ] 151 | with m.If(token_sink.stb): 152 | with m.If(self.rx.lst): 153 | m.d.sync += [ 154 | token_dev.eq(token_sink.dev), 155 | token_ep .eq(token_sink.ep), 156 | ] 157 | m.next = "RECV-TOKEN-1" 158 | with m.Else(): 159 | m.next = "FLUSH-PACKET" 160 | with m.Elif(self.rx.stb & self.rx.lst): 161 | m.next = "IDLE" 162 | 163 | with m.State("RECV-TOKEN-1"): 164 | with m.If(rx_pid_r == PacketID.SOF): 165 | # When a new (micro)frame starts, assume any ongoing transaction has timed out. 166 | m.d.sync += expect_handshake.eq(0) 167 | m.d.comb += [ 168 | mux_out.sof.eq(1), 169 | mux_in .sof.eq(1), 170 | ] 171 | m.next = "IDLE" 172 | with m.Elif(token_dev == self.addr): 173 | with m.Switch(rx_pid_r): 174 | with m.Case(PacketID.PING): 175 | m.d.sync += mux_out.sel.addr.eq(token_ep) 176 | m.next = "SEND-PONG" 177 | with m.Case(PacketID.SETUP): 178 | m.d.sync += token_setup.eq(1) 179 | # Upon receipt of a SETUP token, we set the receiver-side sequence bit 180 | # to 0, and the transmitter-side sequence bit to 1. This guarantees 181 | # that at the end of the transaction (after receipt of a DATA0 packet), 182 | # both sequence bits will be equal to 1. 183 | m.d.sync += [ 184 | rx_seq[token_ep].eq(0), 185 | tx_seq[token_ep].eq(1), 186 | ] 187 | m.d.sync += mux_out.sel.addr.eq(token_ep) 188 | m.next = "RECV-DATA-0" 189 | with m.Case(PacketID.OUT): 190 | m.d.sync += mux_out.sel.addr.eq(token_ep) 191 | m.next = "RECV-DATA-0" 192 | with m.Case(PacketID.IN): 193 | m.d.sync += mux_in .sel.addr.eq(token_ep) 194 | m.next = "SEND-DATA-0" 195 | with m.Default(): 196 | # Unknown/unsupported token. 197 | m.next = "IDLE" 198 | with m.Else(): 199 | # We are not the recipient of this token. 200 | m.next = "IDLE" 201 | 202 | with m.State("SEND-PONG"): 203 | with m.If(mux_out.sel.err): 204 | # Invalid endpoint. Abort transaction. 205 | m.next = "IDLE" 206 | with m.Elif(mux_out.pkt.rdy): 207 | m.next = "SEND-ACK" 208 | with m.Else(): 209 | m.next = "SEND-NAK" 210 | 211 | with m.State("RECV-DATA-0"): 212 | expected_pid = Signal.like(rx_pid) 213 | m.d.comb += expected_pid.eq(Mux(rx_seq[token_ep], PacketID.DATA1, PacketID.DATA0)) 214 | with m.If(mux_out.sel.err): 215 | # Invalid endpoint. Abort transaction. 216 | m.next = "FLUSH-PACKET" 217 | with m.Else(): 218 | m.d.comb += self.rx.rdy.eq(1) 219 | with m.If(self.rx.stb): 220 | with m.If(self.rx.lst): 221 | m.next = "IDLE" 222 | with m.Elif(rx_pid_valid): 223 | with m.If(mux_out.sel.xfer != Transfer.ISOCHRONOUS): 224 | with m.If(rx_pid == expected_pid): 225 | m.next = "RECV-DATA-1" 226 | with m.Else(): 227 | m.next = "FLUSH-PACKET" 228 | with m.Else(): 229 | # FIXME: Data PID sequencing for isochronous transfers (section 230 | # 5.9.2 of the USB 2.0 specification) isn't implemented. 231 | # Be lenient and accept any data PID. 232 | with m.If(PacketID.is_data(rx_pid)): 233 | m.next = "RECV-DATA-1" 234 | with m.Else(): 235 | m.next = "FLUSH-PACKET" 236 | with m.Else(): 237 | m.next = "FLUSH-PACKET" 238 | 239 | with m.State("RECV-DATA-1"): 240 | ep_busy = Signal() 241 | m.d.comb += [ 242 | data_sink.rx.stb .eq(self.rx.stb), 243 | data_sink.rx.lst .eq(self.rx.lst), 244 | data_sink.rx.data.eq(self.rx.data), 245 | self.rx.rdy.eq(data_sink.rx.rdy), 246 | 247 | mux_out.pkt.stb .eq(data_sink.stb), 248 | mux_out.pkt.lst .eq(data_sink.lst), 249 | mux_out.pkt.data .eq(data_sink.data), 250 | mux_out.pkt.zlp .eq(data_sink.zlp), 251 | mux_out.pkt.drop .eq(data_sink.drop), 252 | mux_out.pkt.setup.eq(token_setup), 253 | ] 254 | with m.If(mux_out.pkt.stb): 255 | with m.If(~mux_out.pkt.rdy): 256 | m.d.sync += ep_busy.eq(1) 257 | with m.If(mux_out.pkt.lst): 258 | m.d.sync += ep_busy.eq(0) 259 | m.d.sync += token_setup.eq(0) 260 | with m.If(mux_out.pkt.drop): 261 | # CRC check failed. Ignore packet. 262 | m.next = "IDLE" 263 | with m.Elif(mux_out.sel.xfer == Transfer.ISOCHRONOUS): 264 | # Isochronous transactions do not include a handshake. 265 | m.next = "IDLE" 266 | with m.Elif(~mux_out.pkt.rdy | ep_busy): 267 | # Endpoint wasn't able to receive the whole payload. 268 | m.next = "SEND-NAK" 269 | with m.Else(): 270 | # Toggle the receiver-side sequence bit upon receipt of a valid data 271 | # packet. 272 | m.d.sync += rx_seq[token_ep].eq(~rx_seq[token_ep]) 273 | m.next = "SEND-ACK" 274 | 275 | with m.State("SEND-DATA-0"): 276 | with m.If(mux_in.sel.err): 277 | # Invalid endpoint. Abort transaction. 278 | m.next = "IDLE" 279 | with m.Elif(mux_in.pkt.stb): 280 | m.d.comb += [ 281 | self.tx.stb.eq(1), 282 | self.tx.lst.eq(0), 283 | ] 284 | with m.If(tx_seq[token_ep]): 285 | m.d.comb += [ 286 | self.tx.data[:4].eq( PacketID.DATA1), 287 | self.tx.data[4:].eq(~PacketID.DATA1), 288 | ] 289 | with m.Else(): 290 | m.d.comb += [ 291 | self.tx.data[:4].eq( PacketID.DATA0), 292 | self.tx.data[4:].eq(~PacketID.DATA0), 293 | ] 294 | with m.If(self.tx.rdy): 295 | m.next = "SEND-DATA-1" 296 | with m.Else(): 297 | # Endpoint is not ready to send a payload. 298 | with m.If(mux_in.sel.xfer == Transfer.ISOCHRONOUS): 299 | m.next = "IDLE" 300 | with m.Else(): 301 | m.next = "SEND-NAK" 302 | 303 | with m.State("SEND-DATA-1"): 304 | m.d.comb += [ 305 | data_source.tx.connect(self.tx), 306 | data_source.stb .eq(mux_in.pkt.stb), 307 | data_source.lst .eq(mux_in.pkt.lst), 308 | data_source.data.eq(mux_in.pkt.data), 309 | data_source.zlp .eq(mux_in.pkt.zlp), 310 | mux_in.pkt.rdy.eq(data_source.rdy), 311 | ] 312 | with m.If(self.tx.stb & self.tx.lst & self.tx.rdy): 313 | m.d.sync += expect_handshake.eq(1) 314 | m.next = "IDLE" 315 | 316 | with m.State("SEND-ACK"): 317 | m.d.comb += [ 318 | self.tx.stb.eq(1), 319 | self.tx.lst.eq(1), 320 | self.tx.data[:4].eq( PacketID.ACK), 321 | self.tx.data[4:].eq(~PacketID.ACK), 322 | ] 323 | with m.If(self.tx.rdy): 324 | m.next = "IDLE" 325 | 326 | with m.State("SEND-NAK"): 327 | m.d.comb += [ 328 | self.tx.stb.eq(1), 329 | self.tx.lst.eq(1), 330 | self.tx.data[:4].eq( PacketID.NAK), 331 | self.tx.data[4:].eq(~PacketID.NAK), 332 | ] 333 | with m.If(self.tx.rdy): 334 | m.next = "IDLE" 335 | 336 | with m.State("FLUSH-PACKET"): 337 | m.d.comb += self.rx.rdy.eq(1) 338 | with m.If(self.rx.stb & self.rx.lst): 339 | m.next = "IDLE" 340 | 341 | return m 342 | 343 | 344 | class _TokenSink(Elaboratable): 345 | def __init__(self): 346 | self.rx = Record([ 347 | ("stb", 1, DIR_FANIN), 348 | ("lst", 1, DIR_FANIN), 349 | ("data", 8, DIR_FANIN), 350 | ("rdy", 1, DIR_FANOUT), 351 | ]) 352 | self.stb = Signal() 353 | self.dev = Signal(7) 354 | self.ep = Signal(4) 355 | self.crc = Signal(5) 356 | 357 | def elaborate(self, platform): 358 | m = Module() 359 | 360 | m.submodules.crc = crc = CRC(poly=0b00101, size=5, dw=11, init=0x1f) 361 | 362 | ep_lsb = Signal() 363 | ep_msb = Signal(3) 364 | m.d.comb += self.ep.eq(Cat(ep_lsb, ep_msb)) 365 | 366 | m.d.comb += self.rx.rdy.eq(1) 367 | with m.If(self.rx.stb): 368 | token_msb = Signal() 369 | with m.If(~token_msb): 370 | m.d.sync += Cat(self.dev, ep_lsb).eq(self.rx.data) 371 | m.d.sync += token_msb.eq(1) 372 | with m.Else(): 373 | m.d.comb += Cat(ep_msb, self.crc).eq(self.rx.data) 374 | m.d.comb += [ 375 | crc.val.eq(Cat(self.dev, self.ep)), 376 | self.stb.eq(crc.res == self.crc), 377 | ] 378 | m.d.sync += token_msb.eq(0) 379 | 380 | return m 381 | 382 | 383 | class _DataSink(Elaboratable): 384 | def __init__(self): 385 | self.rx = Record([ 386 | ("stb", 1, DIR_FANIN), 387 | ("lst", 1, DIR_FANIN), 388 | ("data", 8, DIR_FANIN), 389 | ("rdy", 1, DIR_FANOUT), 390 | ]) 391 | self.stb = Signal() 392 | self.lst = Signal() 393 | self.data = Signal(8) 394 | self.zlp = Signal() 395 | self.drop = Signal() 396 | 397 | def elaborate(self, platform): 398 | m = Module() 399 | 400 | buf_0 = Record([("stb", 1), ("lst", 1), ("data", 8)]) 401 | buf_1 = Record.like(buf_0) 402 | 403 | m.submodules.crc = crc = CRC(poly=0b11000000000000101, size=16, dw=8, init=0xffff) 404 | 405 | with m.If(self.stb & self.lst): 406 | m.d.sync += [ 407 | buf_0.stb.eq(0), 408 | buf_1.stb.eq(0), 409 | ] 410 | with m.Else(): 411 | m.d.comb += self.rx.rdy.eq(1) 412 | with m.If(self.rx.stb): 413 | m.d.sync += [ 414 | buf_0.stb.eq(1), 415 | buf_0.lst.eq(self.rx.lst), 416 | buf_0.data.eq(self.rx.data), 417 | buf_1.eq(buf_0), 418 | ] 419 | 420 | m.d.comb += [ 421 | crc.en.eq(self.rx.stb & buf_1.stb), 422 | crc.val.eq(buf_1.data), 423 | crc.clr.eq(self.stb & self.lst), 424 | ] 425 | 426 | with m.If(buf_1.stb): 427 | with m.If(buf_0.lst): 428 | # We received a zero-length packet. (no data bytes, CRC field is 0) 429 | m.d.comb += [ 430 | self.stb.eq(1), 431 | self.lst.eq(1), 432 | self.zlp.eq(1), 433 | self.drop.eq(Cat(buf_1.data, buf_0.data).any()), 434 | ] 435 | with m.Else(): 436 | m.d.comb += [ 437 | self.stb.eq(self.rx.stb), 438 | self.lst.eq(self.rx.lst), 439 | self.data.eq(buf_1.data), 440 | self.drop.eq(crc.res != Cat(buf_0.data, self.rx.data)), 441 | ] 442 | 443 | return m 444 | 445 | 446 | class _DataSource(Elaboratable): 447 | def __init__(self): 448 | self.tx = Record([ 449 | ("stb", 1, DIR_FANOUT), 450 | ("lst", 1, DIR_FANOUT), 451 | ("data", 8, DIR_FANOUT), 452 | ("rdy", 1, DIR_FANIN), 453 | ]) 454 | self.stb = Signal() 455 | self.lst = Signal() 456 | self.data = Signal(8) 457 | self.zlp = Signal() 458 | self.rdy = Signal() 459 | 460 | def elaborate(self, platform): 461 | m = Module() 462 | 463 | m.submodules.crc = crc = CRC(poly=0b11000000000000101, size=16, dw=8, init=0xffff) 464 | crc_res_r = Signal.like(crc.res) 465 | 466 | with m.FSM(): 467 | with m.State("DATA"): 468 | m.d.comb += [ 469 | self.rdy.eq(self.tx.rdy), 470 | self.tx.stb.eq(self.stb), 471 | self.tx.data.eq(Mux(self.zlp, 0, self.data)), 472 | crc.en.eq(self.stb & self.rdy), 473 | crc.val.eq(self.data), 474 | ] 475 | with m.If(self.stb & self.rdy & self.lst): 476 | m.d.sync += crc_res_r.eq(crc.res) 477 | m.d.comb += crc.clr.eq(1) 478 | with m.If(self.zlp): 479 | m.next = "ZLP" 480 | with m.Else(): 481 | m.next = "CRC-0" 482 | 483 | with m.State("ZLP"): 484 | m.d.comb += [ 485 | self.tx.stb.eq(1), 486 | self.tx.lst.eq(1), 487 | self.tx.data.eq(0), 488 | ] 489 | with m.If(self.tx.rdy): 490 | m.next = "DATA" 491 | 492 | with m.State("CRC-0"): 493 | m.d.comb += [ 494 | self.tx.stb.eq(1), 495 | self.tx.data.eq(crc_res_r[:8]), 496 | ] 497 | with m.If(self.tx.rdy): 498 | m.next = "CRC-1" 499 | 500 | with m.State("CRC-1"): 501 | m.d.comb += [ 502 | self.tx.stb.eq(1), 503 | self.tx.lst.eq(1), 504 | self.tx.data.eq(crc_res_r[8:]), 505 | ] 506 | with m.If(self.tx.rdy): 507 | m.next = "DATA" 508 | 509 | return m 510 | -------------------------------------------------------------------------------- /lambdausb/usb/endpoint.py: -------------------------------------------------------------------------------- 1 | import enum 2 | 3 | from nmigen import * 4 | from nmigen.hdl.rec import * 5 | 6 | 7 | __all__ = ["Transfer", "InputEndpoint", "OutputEndpoint"] 8 | 9 | 10 | class Transfer(enum.IntEnum): 11 | """Transfer type. 12 | 13 | See USB 2.0 specification sections 4.7 and 5.4-5.8 for details. 14 | """ 15 | ISOCHRONOUS = 0 16 | CONTROL = 1 17 | BULK = 2 18 | INTERRUPT = 3 19 | 20 | 21 | class _Endpoint(Record): 22 | _doc_template = """ 23 | {description} 24 | 25 | Parameters 26 | ---------- 27 | xfer : :class:`Transfer` 28 | Transfer type. 29 | max_size : int 30 | Maximum packet size. We only check this value against upper bounds in High-Speed mode. 31 | It must also be greater than or equal to the wMaxPacketSize of the endpoint descriptor. 32 | {parameters} 33 | 34 | Attributes 35 | ---------- 36 | {attributes} 37 | """ 38 | def __init__(self, layout, xfer, max_size, name=None, src_loc_at=0): 39 | if not isinstance(xfer, Transfer): 40 | raise TypeError("Transfer type must be an instance of Transfer, not {!r}" 41 | .format(xfer)) 42 | 43 | if not isinstance(max_size, int) or max_size < 0: 44 | raise ValueError("Maximum packet size must be a positive integer, not {!r}" 45 | .format(max_size)) 46 | if xfer is Transfer.ISOCHRONOUS and max_size > 1024: 47 | raise ValueError("Invalid maximum packet size {}; must be lesser than or equal to " 48 | "1024 for an isochronous endpoint".format(max_size)) 49 | if xfer is Transfer.CONTROL and max_size > 64: 50 | raise ValueError("Invalid maximum packet size {}; must be lesser than or equal to " 51 | "64 for a control endpoint".format(max_size)) 52 | if xfer is Transfer.BULK and max_size > 512: 53 | raise ValueError("Invalid maximum packet size {}; must be lesser than or equal to " 54 | "512 for a bulk endpoint".format(max_size)) 55 | if xfer is Transfer.INTERRUPT and max_size > 1024: 56 | raise ValueError("Invalid maximum packet size {}; must be lesser than or equal to " 57 | "1024 for an interrupt endpoint".format(max_size)) 58 | 59 | self.xfer = xfer 60 | self.max_size = max_size 61 | 62 | super().__init__(layout, name=name, src_loc_at=1 + src_loc_at) 63 | 64 | __hash__ = object.__hash__ 65 | 66 | 67 | class InputEndpoint(_Endpoint): 68 | __doc__ = _Endpoint._doc_template.format( 69 | description=""" 70 | Input endpoint interface. 71 | 72 | This interface is an input from the host point of view, but an output from the device 73 | point of view. 74 | """.strip(), 75 | parameters="", 76 | attributes=""" 77 | stb : Signal, out 78 | Write strobe. 79 | lst : Signal, out 80 | Write last. Asserted when `data` holds the last byte of the payload. 81 | data : Signal, out 82 | Write data. 83 | zlp : Signal, out 84 | Write zero-length payload. To send an empty payload, the endpoint must assert `zlp` and 85 | `lst` at the beginning of the transfer. 86 | rdy : Signal, in 87 | Write ready. Asserted when the device is ready to accept data from the endpoint. 88 | ack : Signal, in 89 | Write acknowledge. Asserted when the device received an ACK for the previous payload. 90 | Unused if the endpoint was added to the device with a double buffer. This signal allows 91 | the endpoint to implement its own buffering mechanism. 92 | sof : Signal, in 93 | Start of (micro)frame. Asserted when the device received a SOF packet. 94 | """.strip()) 95 | def __init__(self, *, xfer, max_size, name=None, src_loc_at=0): 96 | layout = [ 97 | ("stb", 1, DIR_FANOUT), 98 | ("lst", 1, DIR_FANOUT), 99 | ("data", 8, DIR_FANOUT), 100 | ("zlp", 1, DIR_FANOUT), 101 | ("rdy", 1, DIR_FANIN), 102 | ("ack", 1, DIR_FANIN), 103 | ("sof", 1, DIR_FANIN), 104 | ] 105 | super().__init__(layout, xfer, max_size, name=name, src_loc_at=1 + src_loc_at) 106 | 107 | 108 | class OutputEndpoint(_Endpoint): 109 | __doc__ = _Endpoint._doc_template.format( 110 | description=""" 111 | Output endpoint interface. 112 | 113 | This interface is an output from the host point of view, but an input from the device 114 | point of view. 115 | """.strip(), 116 | parameters="", 117 | attributes=""" 118 | rdy : Signal, out 119 | Read ready. Asserted when the endpoint is ready to accept data from the device. 120 | stb : Signal, in 121 | Read strobe. 122 | lst : Signal, in 123 | Read last. Asserted when `data` holds the last byte of the payload. 124 | data : Signal, in 125 | Read data. 126 | zlp : Signal, in 127 | Read zero-length. Asserted when the payload is empty. Valid when `lst` is asserted. 128 | setup : Signal, in 129 | Read setup. Asserted when the payload comes from a SETUP packet. 130 | drop : Signal, in 131 | Drop payload. Asserted when the device invalidates the payload (e.g. because of a bad CRC). 132 | Unused if the endpoint was added to the device with a double buffer. This signal allows 133 | the endpoint to implement its own buffering mechanism. 134 | sof : Signal, in 135 | Start of frame. Asserted when the device received a SOF packet. 136 | """.strip()) 137 | def __init__(self, *, xfer, max_size, name=None, src_loc_at=0): 138 | layout = [ 139 | ("rdy", 1, DIR_FANOUT), 140 | ("stb", 1, DIR_FANIN), 141 | ("lst", 1, DIR_FANIN), 142 | ("data", 8, DIR_FANIN), 143 | ("zlp", 1, DIR_FANIN), 144 | ("setup", 1 if xfer is Transfer.CONTROL else 0, DIR_FANIN), 145 | ("drop", 1, DIR_FANIN), 146 | ("sof", 1, DIR_FANIN), 147 | ] 148 | super().__init__(layout, xfer, max_size, name=name, src_loc_at=1 + src_loc_at) 149 | -------------------------------------------------------------------------------- /lambdausb/usb/mux.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict 2 | 3 | from nmigen import * 4 | from nmigen.hdl.rec import * 5 | 6 | from .endpoint import * 7 | 8 | 9 | __all__ = ["DoubleBuffer", "InputMultiplexer", "OutputMultiplexer"] 10 | 11 | 12 | class DoubleBuffer(Elaboratable): 13 | def __init__(self, *, depth, width, read_ack=False): 14 | self.w_stb = Signal() 15 | self.w_lst = Signal() 16 | self.w_data = Signal(width) 17 | self.w_drop = Signal() 18 | self.w_rdy = Signal() 19 | 20 | self.r_stb = Signal() 21 | self.r_lst = Signal() 22 | self.r_data = Signal(width) 23 | self.r_rdy = Signal() 24 | self.r_ack = Signal(1 if read_ack else 0) 25 | 26 | self.depth = depth 27 | self.width = width 28 | self.read_ack = read_ack 29 | 30 | def elaborate(self, platform): 31 | m = Module() 32 | 33 | banks = [Record([("w_addr", range(self.depth)), ("w_data", self.width), ("w_en", 1), 34 | ("r_addr", range(self.depth)), ("r_data", self.width), ("r_en", 1), 35 | ("valid", 1), ("level", range(self.depth + 1))], 36 | name="bank_{}".format(i)) 37 | for i in range(2)] 38 | 39 | for i, bank in enumerate(banks): 40 | mem = Memory(depth=self.depth, width=self.width) 41 | m.submodules["mem{}_wp".format(i)] = mem_wp = mem.write_port() 42 | m.submodules["mem{}_rp".format(i)] = mem_rp = mem.read_port(transparent=False) 43 | m.d.comb += [ 44 | mem_wp.addr.eq(bank.w_addr), 45 | mem_wp.data.eq(bank.w_data), 46 | mem_wp.en.eq(bank.w_en), 47 | mem_rp.addr.eq(bank.r_addr), 48 | mem_rp.en.eq(bank.r_en), 49 | bank.r_data.eq(mem_rp.data), 50 | ] 51 | 52 | bank_lru = Signal() 53 | 54 | with m.FSM(reset="WRITE-0") as write_fsm: 55 | with m.State("WAIT"): 56 | with m.If(~banks[0].valid): 57 | m.next = "WRITE-0" 58 | with m.Elif(~banks[1].valid): 59 | m.next = "WRITE-1" 60 | 61 | for i, bank in enumerate(banks): 62 | with m.State("WRITE-{}".format(i)): 63 | w_addr_inc = Signal.like(bank.w_addr, name_suffix="_inc") 64 | m.d.comb += w_addr_inc.eq(bank.w_addr + 1) 65 | m.d.comb += [ 66 | self.w_rdy.eq(1), 67 | bank.w_en.eq(self.w_stb), 68 | bank.w_data.eq(self.w_data), 69 | ] 70 | with m.If(self.w_stb): 71 | with m.If(self.w_lst): 72 | m.d.sync += bank.w_addr.eq(0) 73 | m.next = "WAIT" 74 | with m.If(~self.w_drop): 75 | m.d.sync += [ 76 | bank.valid.eq(1), 77 | bank.level.eq(w_addr_inc), 78 | bank_lru.eq(1 - i), 79 | ] 80 | with m.Elif(w_addr_inc == self.depth): 81 | # Overflow. Flush remaining bytes. 82 | m.d.sync += bank.w_addr.eq(0) 83 | m.next = "FLUSH" 84 | with m.Else(): 85 | m.d.sync += bank.w_addr.eq(w_addr_inc) 86 | 87 | with m.State("FLUSH"): 88 | m.d.comb += self.w_rdy.eq(1) 89 | with m.If(self.w_stb & self.w_lst): 90 | m.next = "WAIT" 91 | 92 | with m.FSM() as read_fsm: 93 | with m.State("WAIT"): 94 | with m.If(banks[0].valid & ~(banks[1].valid & bank_lru)): 95 | m.d.comb += banks[0].r_en.eq(1) 96 | m.d.sync += banks[0].r_addr.eq(1) 97 | m.d.sync += self.r_lst.eq(banks[0].level == 1) 98 | m.next = "READ-0" 99 | with m.Elif(banks[1].valid): 100 | m.d.comb += banks[1].r_en.eq(1) 101 | m.d.sync += banks[1].r_addr.eq(1) 102 | m.d.sync += self.r_lst.eq(banks[1].level == 1) 103 | m.next = "READ-1" 104 | 105 | for i, bank in enumerate(banks): 106 | with m.State("READ-{}".format(i)): 107 | r_addr_inc = Signal.like(bank.r_addr, name_suffix="_inc") 108 | m.d.comb += r_addr_inc.eq(bank.r_addr + 1) 109 | m.d.comb += [ 110 | self.r_stb.eq(1), 111 | self.r_data.eq(bank.r_data), 112 | ] 113 | with m.If(self.r_rdy): 114 | r_done = self.r_ack if self.read_ack else self.r_lst 115 | with m.If(r_done): 116 | m.d.sync += bank.valid.eq(0) 117 | m.d.sync += bank.r_addr.eq(0) 118 | m.next = "WAIT" 119 | with m.Else(): 120 | m.d.comb += bank.r_en.eq(1) 121 | with m.If(r_addr_inc == bank.level): 122 | m.d.sync += bank.r_addr.eq(0) 123 | m.d.sync += self.r_lst.eq(1) 124 | with m.Else(): 125 | m.d.sync += bank.r_addr.eq(r_addr_inc) 126 | m.d.sync += self.r_lst.eq(0) 127 | 128 | return m 129 | 130 | 131 | class InputMultiplexer(Elaboratable): 132 | def __init__(self): 133 | self.sel = Record([ 134 | ("addr", 4, DIR_FANIN), 135 | ("xfer", 2, DIR_FANOUT), 136 | ("err", 1, DIR_FANOUT), 137 | ]) 138 | self.pkt = Record([ 139 | ("stb", 1, DIR_FANOUT), 140 | ("lst", 1, DIR_FANOUT), 141 | ("data", 8, DIR_FANOUT), 142 | ("zlp", 1, DIR_FANOUT), 143 | ("rdy", 1, DIR_FANIN), 144 | ("ack", 1, DIR_FANIN), 145 | ]) 146 | self.sof = Signal() 147 | 148 | self._ep_map = OrderedDict() 149 | self._addr_map = OrderedDict() 150 | 151 | def add_endpoint(self, ep, *, addr, buffered=False): 152 | if not isinstance(ep, InputEndpoint): 153 | raise TypeError("Endpoint must be an InputEndpoint, not {!r}" 154 | .format(ep)) 155 | if not isinstance(addr, int): 156 | raise TypeError("Endpoint address must be an integer, not {!r}" 157 | .format(addr)) 158 | if not addr in range(0, 16): 159 | raise ValueError("Endpoint address must be between 0 and 15, not {}" 160 | .format(addr)) 161 | if addr in self._ep_map: 162 | raise ValueError("Endpoint address {} has already been assigned" 163 | .format(addr)) 164 | if ep in self._addr_map: 165 | raise ValueError("Endpoint {!r} has already been added at address {}" 166 | .format(ep, self._addr_map[ep])) 167 | if addr == 0 and ep.xfer is not Transfer.CONTROL: 168 | raise ValueError("Invalid transfer type {} for endpoint 0; must be CONTROL" 169 | .format(Transfer(ep.xfer).name)) 170 | self._ep_map[addr] = ep, buffered 171 | self._addr_map[ep] = addr 172 | 173 | def elaborate(self, platform): 174 | m = Module() 175 | 176 | port_map = OrderedDict({addr: Record.like(self.pkt) for addr in self._ep_map}) 177 | 178 | for addr, (ep, buffered) in self._ep_map.items(): 179 | port = port_map[addr] 180 | if buffered: 181 | dbuf = DoubleBuffer(depth=ep.max_size, width=port.data.width + port.zlp.width, 182 | read_ack=ep.xfer is not Transfer.ISOCHRONOUS) 183 | m.submodules["dbuf_{}".format(addr)] = dbuf 184 | m.d.comb += [ 185 | dbuf.w_stb.eq(ep.stb), 186 | dbuf.w_lst.eq(ep.lst), 187 | dbuf.w_data.eq(Cat(ep.data, ep.zlp)), 188 | ep.rdy.eq(dbuf.w_rdy), 189 | 190 | port.stb.eq(dbuf.r_stb), 191 | port.lst.eq(dbuf.r_lst), 192 | Cat(port.data, port.zlp).eq(dbuf.r_data), 193 | dbuf.r_rdy.eq(port.rdy), 194 | dbuf.r_ack.eq(port.ack), 195 | ] 196 | else: 197 | m.d.comb += [ 198 | port.stb.eq(ep.stb), 199 | port.lst.eq(ep.lst), 200 | port.data.eq(ep.data), 201 | port.zlp.eq(ep.zlp), 202 | ep.rdy.eq(port.rdy), 203 | ep.ack.eq(port.ack), 204 | ] 205 | m.d.comb += ep.sof.eq(self.sof) 206 | 207 | with m.Switch(self.sel.addr): 208 | for addr, port in port_map.items(): 209 | ep, _ = self._ep_map[addr] 210 | with m.Case(addr): 211 | m.d.comb += [ 212 | self.sel.xfer.eq(ep.xfer), 213 | port.connect(self.pkt), 214 | ] 215 | with m.Default(): 216 | # Unknown endpoint. 217 | m.d.comb += self.sel.err.eq(1) 218 | 219 | return m 220 | 221 | 222 | class OutputMultiplexer(Elaboratable): 223 | def __init__(self): 224 | self.sel = Record([ 225 | ("addr", 4, DIR_FANIN), 226 | ("xfer", 2, DIR_FANOUT), 227 | ("err", 1, DIR_FANOUT), 228 | ]) 229 | self.pkt = Record([ 230 | ("stb", 1, DIR_FANIN), 231 | ("lst", 1, DIR_FANIN), 232 | ("data", 8, DIR_FANIN), 233 | ("zlp", 1, DIR_FANIN), 234 | ("setup", 1, DIR_FANIN), 235 | ("drop", 1, DIR_FANIN), 236 | ("rdy", 1, DIR_FANOUT), 237 | ]) 238 | self.sof = Signal() 239 | 240 | self._ep_map = OrderedDict() 241 | self._addr_map = OrderedDict() 242 | 243 | def add_endpoint(self, ep, *, addr, buffered=False): 244 | if not isinstance(ep, OutputEndpoint): 245 | raise TypeError("Endpoint must be an OutputEndpoint, not {!r}" 246 | .format(ep)) 247 | if not isinstance(addr, int): 248 | raise TypeError("Endpoint address must be an integer, not {!r}" 249 | .format(addr)) 250 | if not addr in range(0, 16): 251 | raise ValueError("Endpoint address must be between 0 and 15, not {}" 252 | .format(addr)) 253 | if addr in self._ep_map: 254 | raise ValueError("Endpoint address {} has already been assigned" 255 | .format(addr)) 256 | if ep in self._addr_map: 257 | raise ValueError("Endpoint {!r} has already been added at address {}" 258 | .format(ep, self._addr_map[ep])) 259 | if addr == 0 and ep.xfer is not Transfer.CONTROL: 260 | raise ValueError("Invalid transfer type {} for endpoint 0; must be CONTROL" 261 | .format(Transfer(ep.xfer).name)) 262 | self._ep_map[addr] = ep, buffered 263 | self._addr_map[ep] = addr 264 | 265 | def elaborate(self, platform): 266 | m = Module() 267 | 268 | port_map = OrderedDict({addr: Record.like(self.pkt) for addr in self._ep_map}) 269 | 270 | for addr, (ep, buffered) in self._ep_map.items(): 271 | port = port_map[addr] 272 | if buffered: 273 | dbuf_w_data = Cat(port.data, port.zlp, port.setup) 274 | dbuf = DoubleBuffer(depth=ep.max_size, width=len(dbuf_w_data)) 275 | m.submodules["dbuf_{}".format(addr)] = dbuf 276 | m.d.comb += [ 277 | dbuf.w_stb.eq(port.stb), 278 | dbuf.w_lst.eq(port.lst), 279 | dbuf.w_data.eq(dbuf_w_data), 280 | dbuf.w_drop.eq(port.drop), 281 | port.rdy.eq(dbuf.w_rdy), 282 | 283 | ep.stb.eq(dbuf.r_stb), 284 | ep.lst.eq(dbuf.r_lst), 285 | Cat(ep.data, ep.zlp, ep.setup).eq(dbuf.r_data), 286 | dbuf.r_rdy.eq(ep.rdy), 287 | ] 288 | else: 289 | m.d.comb += [ 290 | ep.stb.eq(port.stb), 291 | ep.lst.eq(port.lst), 292 | ep.data.eq(port.data), 293 | ep.zlp.eq(port.zlp), 294 | ep.setup.eq(port.setup), 295 | ep.drop.eq(port.drop), 296 | port.rdy.eq(ep.rdy), 297 | ] 298 | m.d.comb += ep.sof.eq(self.sof) 299 | 300 | with m.Switch(self.sel.addr): 301 | for addr, port in port_map.items(): 302 | ep, _ = self._ep_map[addr] 303 | with m.Case(addr): 304 | m.d.comb += [ 305 | self.sel.xfer.eq(ep.xfer), 306 | port.connect(self.pkt), 307 | ] 308 | with m.Default(): 309 | # Unknown endpoint. 310 | m.d.comb += self.sel.err.eq(1) 311 | 312 | return m 313 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | 4 | def scm_version(): 5 | def local_scheme(version): 6 | return version.format_choice("+{node}", "+{node}.dirty") 7 | return { 8 | "relative_to": __file__, 9 | "version_scheme": "guess-next-dev", 10 | "local_scheme": local_scheme 11 | } 12 | 13 | 14 | setup( 15 | name="lambdausb", 16 | use_scm_version=scm_version(), 17 | author="Jean-François Nguyen", 18 | author_email="jf@lambdaconcept.com", 19 | description="A configurable USB 2.0 device core", 20 | license="BSD", 21 | python_requires="~=3.6", 22 | setup_requires=["setuptools_scm"], 23 | install_requires=["setuptools", "nmigen"], 24 | packages=find_packages(), 25 | project_urls={ 26 | "Source Code": "https://github.com/lambdaconcept/lambdausb", 27 | "Bug Tracker": "https://github.com/lambdaconcept/lambdausb/issues", 28 | }, 29 | ) 30 | -------------------------------------------------------------------------------- /tools/genconfig/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all menuconfig clean 2 | 3 | all: config.py 4 | 5 | usbconf.h Kconfig: createconfig 6 | ./createconfig 7 | 8 | menuconfig .config: Kconfig 9 | kconfig-mconf Kconfig 10 | 11 | config.h: .config generate.sh 12 | sh generate.sh 13 | 14 | genpy: genpy.c config.h usbconf.h 15 | $(LINK.c) $< -o $@ 16 | 17 | config.py: genpy 18 | ./genpy 19 | 20 | clean: 21 | $(RM) createconfig usbconf.h Kconfig .config config.h genpy config.py 22 | -------------------------------------------------------------------------------- /tools/genconfig/createconfig.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | 7 | void generate_kconfig(int max_conf, int max_if, int max_ep, int max_string) 8 | { 9 | FILE *kconfig; 10 | kconfig = fopen("Kconfig", "w"); 11 | char filename[100]; 12 | 13 | 14 | fprintf(kconfig, "mainmenu \"USB Descriptors\"\n"); 15 | fprintf(kconfig, "\n"); 16 | fprintf(kconfig, "menu \"USB Device Descriptor\"\n"); 17 | fprintf(kconfig, "config USB_DEVICE_USB_VERSION\n"); 18 | fprintf(kconfig, "\thex \"USB Version\"\n"); 19 | fprintf(kconfig, "\tdefault 0x200\n"); 20 | fprintf(kconfig, "\t---help---\n"); 21 | fprintf(kconfig, "\t\tUSB Specification Release Number in\n"); 22 | fprintf(kconfig, "\t\tBinary-C oded Decimal (i.e., 2.10 is 210H).\n"); 23 | fprintf(kconfig, "\t\tThis field identifies the release of the USB\n"); 24 | fprintf(kconfig, "\t\tSpecification with which the device and its\n"); 25 | fprintf(kconfig, "\t\tdescriptors are compliant.\n"); 26 | fprintf(kconfig, "\n"); 27 | fprintf(kconfig, "\n"); 28 | fprintf(kconfig, "choice\n"); 29 | fprintf(kconfig, "prompt \"USB Device Class\"\n"); 30 | fprintf(kconfig, "config USB_DEVICE_CLASSID_DEVICE\n"); 31 | fprintf(kconfig, "\tbool \"Defined at Interface Level\"\n"); 32 | fprintf(kconfig, "\t---help---\n"); 33 | fprintf(kconfig, "\t\tThis base class is defined to be used in Device\n"); 34 | fprintf(kconfig, "\t\tDescriptors to indicate that class information\n"); 35 | fprintf(kconfig, "\t\tshould be determined from the Interface Descriptors\n"); 36 | fprintf(kconfig, "\t\tin the device. There is one class code definition\n"); 37 | fprintf(kconfig, "\t\tin this base class. All other values are reserved.\n"); 38 | fprintf(kconfig, "\n"); 39 | fprintf(kconfig, "\t\tThis value is also used in Interface Descriptors\n"); 40 | fprintf(kconfig, "\t\tto indicate a null class code triple.\n"); 41 | fprintf(kconfig, "\n"); 42 | fprintf(kconfig, "config USB_DEVICE_CLASS_CDC\n"); 43 | fprintf(kconfig, "\tbool \"Communications and CDC Control\"\n"); 44 | fprintf(kconfig, "\t---help---\n"); 45 | fprintf(kconfig, "\t\tThis base class is defined for devices that conform to\n"); 46 | fprintf(kconfig, "\t\tthe Communications Device Class Specification found on\n"); 47 | fprintf(kconfig, "\t\tthe USB-IF website. That specification defines the usable\n"); 48 | fprintf(kconfig, "\t\tset of SubClass and Protocol values. Values outside of\n"); 49 | fprintf(kconfig, "\t\tthat defined spec are reserved. Note that the Communication\n"); 50 | fprintf(kconfig, "\t\tDevice Class spec requires some class code values (triples)\n"); 51 | fprintf(kconfig, "\t\tto be used in Device Descriptors and some to be used in\n"); 52 | fprintf(kconfig, "\t\tInterface Descriptors.\n"); 53 | fprintf(kconfig, "\n"); 54 | fprintf(kconfig, "config USB_DEVICE_CLASS_HUB\n"); 55 | fprintf(kconfig, "\tbool \"USB HUB\"\n"); 56 | fprintf(kconfig, "\t---help---\n"); 57 | fprintf(kconfig, "\t\tThis base class is defined for devices that are USB\n"); 58 | fprintf(kconfig, "\t\thubs and conform to the definition in the USB specification.\n"); 59 | fprintf(kconfig, "\t\tThat specification defines the complete triples as shown below.\n"); 60 | fprintf(kconfig, "\t\tAll other values are reserved. These class codes can only be\n"); 61 | fprintf(kconfig, "\t\tused in Device Descriptors.\n"); 62 | fprintf(kconfig, "\n"); 63 | fprintf(kconfig, "config USB_DEVICE_CLASS_BILLBOARD\n"); 64 | fprintf(kconfig, "\tbool \"Billboard Device Class\"\n"); 65 | fprintf(kconfig, "\t---help---\n"); 66 | fprintf(kconfig, "\t\tBillBoard Device Class\n"); 67 | fprintf(kconfig, "\n"); 68 | fprintf(kconfig, "config USB_DEVICE_CLASS_DIAGNOSTIC\n"); 69 | fprintf(kconfig, "\tbool \"Diagnostic Device\"\n"); 70 | fprintf(kconfig, "\t---help---\n"); 71 | fprintf(kconfig, "\t\tThis base class is defined for devices that diagnostic\n"); 72 | fprintf(kconfig, "\t\tdevices. This class code can be used in Device or Interface\n"); 73 | fprintf(kconfig, "\t\tDescriptors. Trace is a form of debugging where processor\n"); 74 | fprintf(kconfig, "\t\tor system activity is made externally visible in real-time\n"); 75 | fprintf(kconfig, "\t\tor stored and later retrieved for viewing by an applications\n"); 76 | fprintf(kconfig, "\t\tdeveloper, applications program, or, external equipment\n"); 77 | fprintf(kconfig, "\t\tspecializing observing system activity. Design for Debug or\n"); 78 | fprintf(kconfig, "\t\tTest (Dfx). This refers to a logic block that provides debug\n"); 79 | fprintf(kconfig, "\t\tor test support (E.g. via Test Access Port (TAP)). DvC: Debug\n"); 80 | fprintf(kconfig, "\t\tCapability on the USB device (Device Capability)\n"); 81 | fprintf(kconfig, "\n"); 82 | fprintf(kconfig, "config USB_DEVICE_CLASS_MISCELLANEOUS\n"); 83 | fprintf(kconfig, "\tbool \"Miscellaneous\"\n"); 84 | fprintf(kconfig, "\t---help---\n"); 85 | fprintf(kconfig, "\t\tThis base class is defined for miscellaneous device definitions.\n"); 86 | fprintf(kconfig, "\t\tValues not shown in the table below are reserved. The use of\n"); 87 | fprintf(kconfig, "\t\tthese class codes (Device or Interface descriptor) are\n"); 88 | fprintf(kconfig, "\t\tspecifically annotated in each entry below.\n"); 89 | fprintf(kconfig, "\n"); 90 | fprintf(kconfig, "config USB_DEVICE_CLASS_VENDOR\n"); 91 | fprintf(kconfig, "\tbool \"Vendor Specific\"\n"); 92 | fprintf(kconfig, "\t---help---\n"); 93 | fprintf(kconfig, "\t\tThis base class is defined for vendors to use as they please.\n"); 94 | fprintf(kconfig, "\t\tThese class codes can be used in both Device and Interface Descriptors.\n"); 95 | fprintf(kconfig, "\n"); 96 | fprintf(kconfig, "\n"); 97 | fprintf(kconfig, "config USB_DEVICE_CLASS_CUSTOM\n"); 98 | fprintf(kconfig, "\tbool \"Select custom value\"\n"); 99 | fprintf(kconfig, "\t---help---\n"); 100 | fprintf(kconfig, "\t\tChoise the value yourself\n"); 101 | fprintf(kconfig, "endchoice\n"); 102 | fprintf(kconfig, "if USB_DEVICE_CLASS_CUSTOM\n"); 103 | fprintf(kconfig, "config USB_DEVICE_CLASS_CUSTOM_VAL\n"); 104 | fprintf(kconfig, "\thex \"Custom Device Class value\"\n"); 105 | fprintf(kconfig, "\trange 0 255\n"); 106 | fprintf(kconfig, "\tdefault 0x00\n"); 107 | fprintf(kconfig, "endif\n"); 108 | fprintf(kconfig, "\n"); 109 | fprintf(kconfig, "config USB_DEVICE_CLASS_VAL\n"); 110 | fprintf(kconfig, "\thex\n"); 111 | fprintf(kconfig, "\trange 0 255\n"); 112 | fprintf(kconfig, "\tdefault 0 if USB_DEVICE_CLASSID_DEVICE\n"); 113 | fprintf(kconfig, "\tdefault 2 if USB_DEVICE_CLASS_CDC\n"); 114 | fprintf(kconfig, "\tdefault 9 if USB_DEVICE_CLASS_HUB\n"); 115 | fprintf(kconfig, "\tdefault 0x11 if USB_DEVICE_CLASS_BILLBOARD\n"); 116 | fprintf(kconfig, "\tdefault 0xdc if USB_DEVICE_CLASS_DIAGNOSTIC\n"); 117 | fprintf(kconfig, "\tdefault 0xef if USB_DEVICE_CLASS_MISCELLANEOUS\n"); 118 | fprintf(kconfig, "\tdefault 0xff if USB_DEVICE_CLASS_VENDOR\n"); 119 | fprintf(kconfig, "\tdefault USB_DEVICE_CLASS_CUSTOM_VAL if USB_DEVICE_CLASS_CUSTOM\n"); 120 | fprintf(kconfig, "\n"); 121 | fprintf(kconfig, "config USB_DEVICE_SUBCLASS\n"); 122 | fprintf(kconfig, "\tint \"USB Subclass\"\n"); 123 | fprintf(kconfig, "\tdefault 0\n"); 124 | fprintf(kconfig, "\t---help---\n"); 125 | fprintf(kconfig, "\t\tSubclass code (assigned by the USB-IF).\n"); 126 | fprintf(kconfig, "\t\tThese codes are qualified by the value of\n"); 127 | fprintf(kconfig, "\t\tthe bDeviceClass field.\n"); 128 | fprintf(kconfig, "\t\tIf the bDeviceClass field is reset to zero,\n"); 129 | fprintf(kconfig, "\t\tthis field must also be reset to zero.\n"); 130 | fprintf(kconfig, "\t\tIf the bDeviceClass field is not set to FFH,\n"); 131 | fprintf(kconfig, "\t\tall values are reserved for assignment by\n"); 132 | fprintf(kconfig, "\t\tthe USB-IF.\n"); 133 | fprintf(kconfig, "\n"); 134 | fprintf(kconfig, "config USB_DEVICE_PROTOCOL\n"); 135 | fprintf(kconfig, "\tint \"USB Protocol\"\n"); 136 | fprintf(kconfig, "\tdefault 0\n"); 137 | fprintf(kconfig, "\t---help---\n"); 138 | fprintf(kconfig, "\t\tProtocol code (assigned by the USB-IF).\n"); 139 | fprintf(kconfig, "\t\tThese codes are qualified by the value of\n"); 140 | fprintf(kconfig, "\t\tthe bDeviceClass and the\n"); 141 | fprintf(kconfig, "\t\tbDeviceSubClass fields. If a device\n"); 142 | fprintf(kconfig, "\t\tsupports class-specific protocols on a\n"); 143 | fprintf(kconfig, "\t\tdevice basis as opposed to an interface\n"); 144 | fprintf(kconfig, "\t\tbasis, this code identifies the protocols\n"); 145 | fprintf(kconfig, "\t\tthat the device uses as defined by the\n"); 146 | fprintf(kconfig, "\t\tspecification of the device class.\n"); 147 | fprintf(kconfig, "\t\tIf this field is reset to zero, the device\n"); 148 | fprintf(kconfig, "\t\tdoes not use class-specific protocols on a\n"); 149 | fprintf(kconfig, "\t\tdevice basis. However, it may use classspecific protocols on an interface basis.\n"); 150 | fprintf(kconfig, "\t\tIf this field is set to FFH, the device uses a\n"); 151 | fprintf(kconfig, "\t\tvendor-specific protocol on a device basis.\n"); 152 | fprintf(kconfig, "\n"); 153 | fprintf(kconfig, "config USB_DEVICE_MXPACKETSIZE\n"); 154 | fprintf(kconfig, "\tint \"EP0 Max Packet Size\"\n"); 155 | fprintf(kconfig, "\tdefault 64\n"); 156 | fprintf(kconfig, "\trange 8 512\n"); 157 | fprintf(kconfig, "\t---help---\n"); 158 | fprintf(kconfig, "\t\tMaximum packet size for endpoint zero\n"); 159 | fprintf(kconfig, "\t\t(only 8, 16, 32, or 64 are valid)\n"); 160 | fprintf(kconfig, "\n"); 161 | fprintf(kconfig, "config USB_DEVICE_VENDORID\n"); 162 | fprintf(kconfig, "\thex \"Vendor ID\"\n"); 163 | fprintf(kconfig, "\tdefault 0x1234\n"); 164 | fprintf(kconfig, "\t---help---\n"); 165 | fprintf(kconfig, "\t\tVendor ID (assigned by the USB-IF)\n"); 166 | fprintf(kconfig, "config USB_DEVICE_PRODUCTID\n"); 167 | fprintf(kconfig, "\thex \"Product ID\"\n"); 168 | fprintf(kconfig, "\tdefault 0x5678\n"); 169 | fprintf(kconfig, "\t---help---\n"); 170 | fprintf(kconfig, "\t\tProduct ID (assigned by the manufacturer)\n"); 171 | fprintf(kconfig, "\n"); 172 | fprintf(kconfig, "config USB_DEVICE_DEVICEID\n"); 173 | fprintf(kconfig, "\thex \"Device ID\"\n"); 174 | fprintf(kconfig, "\tdefault 0x9ABC\n"); 175 | fprintf(kconfig, "\t---help---\n"); 176 | fprintf(kconfig, "\t\tDevice release number in binary-coded decimal\n"); 177 | fprintf(kconfig, "\n"); 178 | fprintf(kconfig, "config USB_DEVICE_IMFGR\n"); 179 | fprintf(kconfig, "\tint \"Manufacturer String Index\"\n"); 180 | fprintf(kconfig, "\tdefault 0\n"); 181 | fprintf(kconfig, "\t---help---\n"); 182 | fprintf(kconfig, "\t\tIndex of string descriptor describing manufacturer\n"); 183 | fprintf(kconfig, "\n"); 184 | fprintf(kconfig, "config USB_DEVICE_IPRODUCT\n"); 185 | fprintf(kconfig, "\tint \"Product String Index\"\n"); 186 | fprintf(kconfig, "\tdefault 0\n"); 187 | fprintf(kconfig, "\t---help---\n"); 188 | fprintf(kconfig, "\t\tIndex of string descriptor describing product\n"); 189 | fprintf(kconfig, "\n"); 190 | fprintf(kconfig, "config USB_DEVICE_ISERNO\n"); 191 | fprintf(kconfig, "\tint \"Serial Number String Index\"\n"); 192 | fprintf(kconfig, "\tdefault 0\n"); 193 | fprintf(kconfig, "\t---help---\n"); 194 | fprintf(kconfig, "\t\tIndex of string descriptor describing the device’s serial number\n"); 195 | fprintf(kconfig, "\n"); 196 | fprintf(kconfig, "config USB_DEVICE_NCONFIGS\n"); 197 | fprintf(kconfig, "\tint \"Number of Configuration\"\n"); 198 | fprintf(kconfig, "\trange 1 255\n"); 199 | fprintf(kconfig, "\t---help---\n"); 200 | fprintf(kconfig, "\t\tNumber of possible configurations\n"); 201 | fprintf(kconfig, "\n"); 202 | fprintf(kconfig, "endmenu\n"); 203 | fprintf(kconfig, "\n"); 204 | 205 | fprintf(kconfig, "choice\n"); 206 | fprintf(kconfig, "\tprompt \"USB Language ID\"\n"); 207 | fprintf(kconfig, "\tdefault USB_LANG_ENGLISH_UNITED_STATES\n"); 208 | 209 | fprintf(kconfig, "config USB_LANG_USER_SELECT\n"); 210 | fprintf(kconfig, "\tbool \"User Select\"\n"); 211 | fprintf(kconfig, "config USB_LANG_AFRIKAANS\n"); 212 | fprintf(kconfig, "\tbool \"Afrikaans\"\n"); 213 | fprintf(kconfig, "config USB_LANG_ALBANIAN\n"); 214 | fprintf(kconfig, "\tbool \"Albanian\"\n"); 215 | fprintf(kconfig, "config USB_LANG_ARABIC_SAUDI_ARABIA\n"); 216 | fprintf(kconfig, "\tbool \"Arabic (Saudi Arabia)\"\n"); 217 | fprintf(kconfig, "config USB_LANG_ARABIC_IRAQ\n"); 218 | fprintf(kconfig, "\tbool \"Arabic (Iraq)\"\n"); 219 | fprintf(kconfig, "config USB_LANG_ARABIC_EGYPT\n"); 220 | fprintf(kconfig, "\tbool \"Arabic (Egypt)\"\n"); 221 | fprintf(kconfig, "config USB_LANG_ARABIC_LIBYA\n"); 222 | fprintf(kconfig, "\tbool \"Arabic (Libya)\"\n"); 223 | fprintf(kconfig, "config USB_LANG_ARABIC_ALGERIA\n"); 224 | fprintf(kconfig, "\tbool \"Arabic (Algeria)\"\n"); 225 | fprintf(kconfig, "config USB_LANG_ARABIC_MOROCCO\n"); 226 | fprintf(kconfig, "\tbool \"Arabic (Morocco)\"\n"); 227 | fprintf(kconfig, "config USB_LANG_ARABIC_TUNISIA\n"); 228 | fprintf(kconfig, "\tbool \"Arabic (Tunisia)\"\n"); 229 | fprintf(kconfig, "config USB_LANG_ARABIC_OMAN\n"); 230 | fprintf(kconfig, "\tbool \"Arabic (Oman)\"\n"); 231 | fprintf(kconfig, "config USB_LANG_ARABIC_YEMEN\n"); 232 | fprintf(kconfig, "\tbool \"Arabic (Yemen)\"\n"); 233 | fprintf(kconfig, "config USB_LANG_ARABIC_SYRIA\n"); 234 | fprintf(kconfig, "\tbool \"Arabic (Syria)\"\n"); 235 | fprintf(kconfig, "config USB_LANG_ARABIC_JORDAN\n"); 236 | fprintf(kconfig, "\tbool \"Arabic (Jordan)\"\n"); 237 | fprintf(kconfig, "config USB_LANG_ARABIC_LEBANON\n"); 238 | fprintf(kconfig, "\tbool \"Arabic (Lebanon)\"\n"); 239 | fprintf(kconfig, "config USB_LANG_ARABIC_KUWAIT\n"); 240 | fprintf(kconfig, "\tbool \"Arabic (Kuwait)\"\n"); 241 | fprintf(kconfig, "config USB_LANG_ARABIC_UAE\n"); 242 | fprintf(kconfig, "\tbool \"Arabic (U.A.E.)\"\n"); 243 | fprintf(kconfig, "config USB_LANG_ARABIC_BAHRAIN\n"); 244 | fprintf(kconfig, "\tbool \"Arabic (Bahrain)\"\n"); 245 | fprintf(kconfig, "config USB_LANG_ARABIC_QATAR\n"); 246 | fprintf(kconfig, "\tbool \"Arabic (Qatar)\"\n"); 247 | fprintf(kconfig, "config USB_LANG_ARMENIAN\n"); 248 | fprintf(kconfig, "\tbool \"Armenian.\"\n"); 249 | fprintf(kconfig, "config USB_LANG_ASSAMESE\n"); 250 | fprintf(kconfig, "\tbool \"Assamese.\"\n"); 251 | fprintf(kconfig, "config USB_LANG_AZERI_LATIN\n"); 252 | fprintf(kconfig, "\tbool \"Azeri (Latin)\"\n"); 253 | fprintf(kconfig, "config USB_LANG_AZERI_CYRILLIC\n"); 254 | fprintf(kconfig, "\tbool \"Azeri (Cyrillic)\"\n"); 255 | fprintf(kconfig, "config USB_LANG_BASQUE\n"); 256 | fprintf(kconfig, "\tbool \"Basque\"\n"); 257 | fprintf(kconfig, "config USB_LANG_BELARUSSIAN\n"); 258 | fprintf(kconfig, "\tbool \"Belarussian\"\n"); 259 | fprintf(kconfig, "config USB_LANG_BENGALI\n"); 260 | fprintf(kconfig, "\tbool \"Bengali.\"\n"); 261 | fprintf(kconfig, "config USB_LANG_BULGARIAN\n"); 262 | fprintf(kconfig, "\tbool \"Bulgarian\"\n"); 263 | fprintf(kconfig, "config USB_LANG_BURMESE\n"); 264 | fprintf(kconfig, "\tbool \"Burmese\"\n"); 265 | fprintf(kconfig, "config USB_LANG_CATALAN\n"); 266 | fprintf(kconfig, "\tbool \"Catalan\"\n"); 267 | fprintf(kconfig, "config USB_LANG_CHINESE_TAIWAN\n"); 268 | fprintf(kconfig, "\tbool \"Chinese (Taiwan)\"\n"); 269 | fprintf(kconfig, "config USB_LANG_CHINESE_PRC\n"); 270 | fprintf(kconfig, "\tbool \"Chinese (PRC)\"\n"); 271 | fprintf(kconfig, "config USB_LANG_CHINESE_HONG_KONG_SAR_PRC\n"); 272 | fprintf(kconfig, "\tbool \"Chinese (Hong Kong SAR, PRC)\"\n"); 273 | fprintf(kconfig, "config USB_LANG_CHINESE_SINGAPORE\n"); 274 | fprintf(kconfig, "\tbool \"Chinese (Singapore)\"\n"); 275 | fprintf(kconfig, "config USB_LANG_CHINESE_MACAU_SAR\n"); 276 | fprintf(kconfig, "\tbool \"Chinese (Macau SAR)\"\n"); 277 | fprintf(kconfig, "config USB_LANG_CROATIAN\n"); 278 | fprintf(kconfig, "\tbool \"Croatian\"\n"); 279 | fprintf(kconfig, "config USB_LANG_CZECH\n"); 280 | fprintf(kconfig, "\tbool \"Czech\"\n"); 281 | fprintf(kconfig, "config USB_LANG_DANISH\n"); 282 | fprintf(kconfig, "\tbool \"Danish\"\n"); 283 | fprintf(kconfig, "config USB_LANG_DUTCH_NETHERLANDS\n"); 284 | fprintf(kconfig, "\tbool \"Dutch (Netherlands)\"\n"); 285 | fprintf(kconfig, "config USB_LANG_DUTCH_BELGIUM\n"); 286 | fprintf(kconfig, "\tbool \"Dutch (Belgium)\"\n"); 287 | fprintf(kconfig, "config USB_LANG_ENGLISH_UNITED_STATES\n"); 288 | fprintf(kconfig, "\tbool \"English (United States)\"\n"); 289 | fprintf(kconfig, "config USB_LANG_ENGLISH_UNITED_KINGDOM\n"); 290 | fprintf(kconfig, "\tbool \"English (United Kingdom)\"\n"); 291 | fprintf(kconfig, "config USB_LANG_ENGLISH_AUSTRALIAN\n"); 292 | fprintf(kconfig, "\tbool \"English (Australian)\"\n"); 293 | fprintf(kconfig, "config USB_LANG_ENGLISH_CANADIAN\n"); 294 | fprintf(kconfig, "\tbool \"English (Canadian)\"\n"); 295 | fprintf(kconfig, "config USB_LANG_ENGLISH_NEW_ZEALAND\n"); 296 | fprintf(kconfig, "\tbool \"English (New Zealand)\"\n"); 297 | fprintf(kconfig, "config USB_LANG_ENGLISH_IRELAND\n"); 298 | fprintf(kconfig, "\tbool \"English (Ireland)\"\n"); 299 | fprintf(kconfig, "config USB_LANG_ENGLISH_SOUTH_AFRICA\n"); 300 | fprintf(kconfig, "\tbool \"English (South Africa)\"\n"); 301 | fprintf(kconfig, "config USB_LANG_ENGLISH_JAMAICA\n"); 302 | fprintf(kconfig, "\tbool \"English (Jamaica)\"\n"); 303 | fprintf(kconfig, "config USB_LANG_ENGLISH_CARIBBEAN\n"); 304 | fprintf(kconfig, "\tbool \"English (Caribbean)\"\n"); 305 | fprintf(kconfig, "config USB_LANG_ENGLISH_BELIZE\n"); 306 | fprintf(kconfig, "\tbool \"English (Belize)\"\n"); 307 | fprintf(kconfig, "config USB_LANG_ENGLISH_TRINIDAD\n"); 308 | fprintf(kconfig, "\tbool \"English (Trinidad)\"\n"); 309 | fprintf(kconfig, "config USB_LANG_ENGLISH_ZIMBABWE\n"); 310 | fprintf(kconfig, "\tbool \"English (Zimbabwe)\"\n"); 311 | fprintf(kconfig, "config USB_LANG_ENGLISH_PHILIPPINES\n"); 312 | fprintf(kconfig, "\tbool \"English (Philippines)\"\n"); 313 | fprintf(kconfig, "config USB_LANG_ESTONIAN\n"); 314 | fprintf(kconfig, "\tbool \"Estonian\"\n"); 315 | fprintf(kconfig, "config USB_LANG_FAEROESE\n"); 316 | fprintf(kconfig, "\tbool \"Faeroese\"\n"); 317 | fprintf(kconfig, "config USB_LANG_FARSI\n"); 318 | fprintf(kconfig, "\tbool \"Farsi\"\n"); 319 | fprintf(kconfig, "config USB_LANG_FINNISH\n"); 320 | fprintf(kconfig, "\tbool \"Finnish\"\n"); 321 | fprintf(kconfig, "config USB_LANG_FRENCH_STANDARD\n"); 322 | fprintf(kconfig, "\tbool \"French (Standard)\"\n"); 323 | fprintf(kconfig, "config USB_LANG_FRENCH_BELGIAN\n"); 324 | fprintf(kconfig, "\tbool \"French (Belgian)\"\n"); 325 | fprintf(kconfig, "config USB_LANG_FRENCH_CANADIAN\n"); 326 | fprintf(kconfig, "\tbool \"French (Canadian)\"\n"); 327 | fprintf(kconfig, "config USB_LANG_FRENCH_SWITZERLAND\n"); 328 | fprintf(kconfig, "\tbool \"French (Switzerland)\"\n"); 329 | fprintf(kconfig, "config USB_LANG_FRENCH_LUXEMBOURG\n"); 330 | fprintf(kconfig, "\tbool \"French (Luxembourg)\"\n"); 331 | fprintf(kconfig, "config USB_LANG_FRENCH_MONACO\n"); 332 | fprintf(kconfig, "\tbool \"French (Monaco)\"\n"); 333 | fprintf(kconfig, "config USB_LANG_GEORGIAN\n"); 334 | fprintf(kconfig, "\tbool \"Georgian.\"\n"); 335 | fprintf(kconfig, "config USB_LANG_GERMAN_STANDARD\n"); 336 | fprintf(kconfig, "\tbool \"German (Standard)\"\n"); 337 | fprintf(kconfig, "config USB_LANG_GERMAN_SWITZERLAND\n"); 338 | fprintf(kconfig, "\tbool \"German (Switzerland)\"\n"); 339 | fprintf(kconfig, "config USB_LANG_GERMAN_AUSTRIA\n"); 340 | fprintf(kconfig, "\tbool \"German (Austria)\"\n"); 341 | fprintf(kconfig, "config USB_LANG_GERMAN_LUXEMBOURG\n"); 342 | fprintf(kconfig, "\tbool \"German (Luxembourg)\"\n"); 343 | fprintf(kconfig, "config USB_LANG_GERMAN_LIECHTENSTEIN\n"); 344 | fprintf(kconfig, "\tbool \"German (Liechtenstein)\"\n"); 345 | fprintf(kconfig, "config USB_LANG_GREEK\n"); 346 | fprintf(kconfig, "\tbool \"Greek\"\n"); 347 | fprintf(kconfig, "config USB_LANG_GUJARATI\n"); 348 | fprintf(kconfig, "\tbool \"Gujarati.\"\n"); 349 | fprintf(kconfig, "config USB_LANG_HEBREW\n"); 350 | fprintf(kconfig, "\tbool \"Hebrew\"\n"); 351 | fprintf(kconfig, "config USB_LANG_HINDI\n"); 352 | fprintf(kconfig, "\tbool \"Hindi.\"\n"); 353 | fprintf(kconfig, "config USB_LANG_HUNGARIAN\n"); 354 | fprintf(kconfig, "\tbool \"Hungarian\"\n"); 355 | fprintf(kconfig, "config USB_LANG_ICELANDIC\n"); 356 | fprintf(kconfig, "\tbool \"Icelandic\"\n"); 357 | fprintf(kconfig, "config USB_LANG_INDONESIAN\n"); 358 | fprintf(kconfig, "\tbool \"Indonesian\"\n"); 359 | fprintf(kconfig, "config USB_LANG_ITALIAN_STANDARD\n"); 360 | fprintf(kconfig, "\tbool \"Italian (Standard)\"\n"); 361 | fprintf(kconfig, "config USB_LANG_ITALIAN_SWITZERLAND\n"); 362 | fprintf(kconfig, "\tbool \"Italian (Switzerland)\"\n"); 363 | fprintf(kconfig, "config USB_LANG_JAPANESE\n"); 364 | fprintf(kconfig, "\tbool \"Japanese\"\n"); 365 | fprintf(kconfig, "config USB_LANG_KANNADA\n"); 366 | fprintf(kconfig, "\tbool \"Kannada.\"\n"); 367 | fprintf(kconfig, "config USB_LANG_KASHMIRI_INDIA\n"); 368 | fprintf(kconfig, "\tbool \"Kashmiri (India)\"\n"); 369 | fprintf(kconfig, "config USB_LANG_KAZAKH\n"); 370 | fprintf(kconfig, "\tbool \"Kazakh\"\n"); 371 | fprintf(kconfig, "config USB_LANG_KONKANI\n"); 372 | fprintf(kconfig, "\tbool \"Konkani.\"\n"); 373 | fprintf(kconfig, "config USB_LANG_KOREAN\n"); 374 | fprintf(kconfig, "\tbool \"Korean\"\n"); 375 | fprintf(kconfig, "config USB_LANG_KOREAN_JOHAB\n"); 376 | fprintf(kconfig, "\tbool \"Korean (Johab)\"\n"); 377 | fprintf(kconfig, "config USB_LANG_LATVIAN\n"); 378 | fprintf(kconfig, "\tbool \"Latvian\"\n"); 379 | fprintf(kconfig, "config USB_LANG_LITHUANIAN\n"); 380 | fprintf(kconfig, "\tbool \"Lithuanian\"\n"); 381 | fprintf(kconfig, "config USB_LANG_LITHUANIAN_CLASSIC\n"); 382 | fprintf(kconfig, "\tbool \"Lithuanian (Classic)\"\n"); 383 | fprintf(kconfig, "config USB_LANG_MACEDONIAN\n"); 384 | fprintf(kconfig, "\tbool \"Macedonian\"\n"); 385 | fprintf(kconfig, "config USB_LANG_MALAY_MALAYSIAN\n"); 386 | fprintf(kconfig, "\tbool \"Malay (Malaysian)\"\n"); 387 | fprintf(kconfig, "config USB_LANG_MALAY_BRUNEI_DARUSSALAM\n"); 388 | fprintf(kconfig, "\tbool \"Malay (Brunei Darussalam)\"\n"); 389 | fprintf(kconfig, "config USB_LANG_MALAYALAM\n"); 390 | fprintf(kconfig, "\tbool \"Malayalam.\"\n"); 391 | fprintf(kconfig, "config USB_LANG_MANIPURI\n"); 392 | fprintf(kconfig, "\tbool \"Manipuri\"\n"); 393 | fprintf(kconfig, "config USB_LANG_MARATHI\n"); 394 | fprintf(kconfig, "\tbool \"Marathi.\"\n"); 395 | fprintf(kconfig, "config USB_LANG_NEPALI_INDIA\n"); 396 | fprintf(kconfig, "\tbool \"Nepali (India).\"\n"); 397 | fprintf(kconfig, "config USB_LANG_NORWEGIAN_BOKMAL\n"); 398 | fprintf(kconfig, "\tbool \"Norwegian (Bokmal)\"\n"); 399 | fprintf(kconfig, "config USB_LANG_NORWEGIAN_NYNORSK\n"); 400 | fprintf(kconfig, "\tbool \"Norwegian (Nynorsk)\"\n"); 401 | fprintf(kconfig, "config USB_LANG_ORIYA\n"); 402 | fprintf(kconfig, "\tbool \"Oriya.\"\n"); 403 | fprintf(kconfig, "config USB_LANG_POLISH\n"); 404 | fprintf(kconfig, "\tbool \"Polish\"\n"); 405 | fprintf(kconfig, "config USB_LANG_PORTUGUESE_BRAZIL\n"); 406 | fprintf(kconfig, "\tbool \"Portuguese (Brazil)\"\n"); 407 | fprintf(kconfig, "config USB_LANG_PORTUGUESE_STANDARD\n"); 408 | fprintf(kconfig, "\tbool \"Portuguese (Standard)\"\n"); 409 | fprintf(kconfig, "config USB_LANG_PUNJABI\n"); 410 | fprintf(kconfig, "\tbool \"Punjabi.\"\n"); 411 | fprintf(kconfig, "config USB_LANG_ROMANIAN\n"); 412 | fprintf(kconfig, "\tbool \"Romanian\"\n"); 413 | fprintf(kconfig, "config USB_LANG_RUSSIAN\n"); 414 | fprintf(kconfig, "\tbool \"Russian\"\n"); 415 | fprintf(kconfig, "config USB_LANG_SANSKRIT\n"); 416 | fprintf(kconfig, "\tbool \"Sanskrit.\"\n"); 417 | fprintf(kconfig, "config USB_LANG_SERBIAN_CYRILLIC\n"); 418 | fprintf(kconfig, "\tbool \"Serbian (Cyrillic)\"\n"); 419 | fprintf(kconfig, "config USB_LANG_SERBIAN_LATIN\n"); 420 | fprintf(kconfig, "\tbool \"Serbian (Latin)\"\n"); 421 | fprintf(kconfig, "config USB_LANG_SINDHI\n"); 422 | fprintf(kconfig, "\tbool \"Sindhi\"\n"); 423 | fprintf(kconfig, "config USB_LANG_SLOVAK\n"); 424 | fprintf(kconfig, "\tbool \"Slovak\"\n"); 425 | fprintf(kconfig, "config USB_LANG_SLOVENIAN\n"); 426 | fprintf(kconfig, "\tbool \"Slovenian\"\n"); 427 | fprintf(kconfig, "config USB_LANG_SPANISH_TRADITIONAL_SORT\n"); 428 | fprintf(kconfig, "\tbool \"Spanish (Traditional Sort)\"\n"); 429 | fprintf(kconfig, "config USB_LANG_SPANISH_MEXICAN\n"); 430 | fprintf(kconfig, "\tbool \"Spanish (Mexican)\"\n"); 431 | fprintf(kconfig, "config USB_LANG_SPANISH_MODERN_SORT\n"); 432 | fprintf(kconfig, "\tbool \"Spanish (Modern Sort)\"\n"); 433 | fprintf(kconfig, "config USB_LANG_SPANISH_GUATEMALA\n"); 434 | fprintf(kconfig, "\tbool \"Spanish (Guatemala)\"\n"); 435 | fprintf(kconfig, "config USB_LANG_SPANISH_COSTA_RICA\n"); 436 | fprintf(kconfig, "\tbool \"Spanish (Costa Rica)\"\n"); 437 | fprintf(kconfig, "config USB_LANG_SPANISH_PANAMA\n"); 438 | fprintf(kconfig, "\tbool \"Spanish (Panama)\"\n"); 439 | fprintf(kconfig, "config USB_LANG_SPANISH_DOMINICAN_REPUBLIC\n"); 440 | fprintf(kconfig, "\tbool \"Spanish (Dominican Republic)\"\n"); 441 | fprintf(kconfig, "config USB_LANG_SPANISH_VENEZUELA\n"); 442 | fprintf(kconfig, "\tbool \"Spanish (Venezuela)\"\n"); 443 | fprintf(kconfig, "config USB_LANG_SPANISH_COLOMBIA\n"); 444 | fprintf(kconfig, "\tbool \"Spanish (Colombia)\"\n"); 445 | fprintf(kconfig, "config USB_LANG_SPANISH_PERU\n"); 446 | fprintf(kconfig, "\tbool \"Spanish (Peru)\"\n"); 447 | fprintf(kconfig, "config USB_LANG_SPANISH_ARGENTINA\n"); 448 | fprintf(kconfig, "\tbool \"Spanish (Argentina)\"\n"); 449 | fprintf(kconfig, "config USB_LANG_SPANISH_ECUADOR\n"); 450 | fprintf(kconfig, "\tbool \"Spanish (Ecuador)\"\n"); 451 | fprintf(kconfig, "config USB_LANG_SPANISH_CHILE\n"); 452 | fprintf(kconfig, "\tbool \"Spanish (Chile)\"\n"); 453 | fprintf(kconfig, "config USB_LANG_SPANISH_URUGUAY\n"); 454 | fprintf(kconfig, "\tbool \"Spanish (Uruguay)\"\n"); 455 | fprintf(kconfig, "config USB_LANG_SPANISH_PARAGUAY\n"); 456 | fprintf(kconfig, "\tbool \"Spanish (Paraguay)\"\n"); 457 | fprintf(kconfig, "config USB_LANG_SPANISH_BOLIVIA\n"); 458 | fprintf(kconfig, "\tbool \"Spanish (Bolivia)\"\n"); 459 | fprintf(kconfig, "config USB_LANG_SPANISH_EL_SALVADOR\n"); 460 | fprintf(kconfig, "\tbool \"Spanish (El Salvador)\"\n"); 461 | fprintf(kconfig, "config USB_LANG_SPANISH_HONDURAS\n"); 462 | fprintf(kconfig, "\tbool \"Spanish (Honduras)\"\n"); 463 | fprintf(kconfig, "config USB_LANG_SPANISH_NICARAGUA\n"); 464 | fprintf(kconfig, "\tbool \"Spanish (Nicaragua)\"\n"); 465 | fprintf(kconfig, "config USB_LANG_SPANISH_PUERTO_RICO\n"); 466 | fprintf(kconfig, "\tbool \"Spanish (Puerto Rico)\"\n"); 467 | fprintf(kconfig, "config USB_LANG_SUTU\n"); 468 | fprintf(kconfig, "\tbool \"Sutu\"\n"); 469 | fprintf(kconfig, "config USB_LANG_SWAHILI_KENYA\n"); 470 | fprintf(kconfig, "\tbool \"Swahili (Kenya)\"\n"); 471 | fprintf(kconfig, "config USB_LANG_SWEDISH\n"); 472 | fprintf(kconfig, "\tbool \"Swedish\"\n"); 473 | fprintf(kconfig, "config USB_LANG_SWEDISH_FINLAND\n"); 474 | fprintf(kconfig, "\tbool \"Swedish (Finland)\"\n"); 475 | fprintf(kconfig, "config USB_LANG_TAMIL\n"); 476 | fprintf(kconfig, "\tbool \"Tamil.\"\n"); 477 | fprintf(kconfig, "config USB_LANG_TATAR_TATARSTAN\n"); 478 | fprintf(kconfig, "\tbool \"Tatar (Tatarstan)\"\n"); 479 | fprintf(kconfig, "config USB_LANG_TELUGU\n"); 480 | fprintf(kconfig, "\tbool \"Telugu.\"\n"); 481 | fprintf(kconfig, "config USB_LANG_THAI\n"); 482 | fprintf(kconfig, "\tbool \"Thai\"\n"); 483 | fprintf(kconfig, "config USB_LANG_TURKISH\n"); 484 | fprintf(kconfig, "\tbool \"Turkish\"\n"); 485 | fprintf(kconfig, "config USB_LANG_UKRAINIAN\n"); 486 | fprintf(kconfig, "\tbool \"Ukrainian\"\n"); 487 | fprintf(kconfig, "config USB_LANG_URDU_PAKISTAN\n"); 488 | fprintf(kconfig, "\tbool \"Urdu (Pakistan)\"\n"); 489 | fprintf(kconfig, "config USB_LANG_URDU_INDIA\n"); 490 | fprintf(kconfig, "\tbool \"Urdu (India)\"\n"); 491 | fprintf(kconfig, "config USB_LANG_UZBEK_LATIN\n"); 492 | fprintf(kconfig, "\tbool \"Uzbek (Latin)\"\n"); 493 | fprintf(kconfig, "config USB_LANG_UZBEK_CYRILLIC\n"); 494 | fprintf(kconfig, "\tbool \"Uzbek (Cyrillic)\"\n"); 495 | fprintf(kconfig, "config USB_LANG_VIETNAMESE\n"); 496 | fprintf(kconfig, "\tbool \"Vietnamese\"\n"); 497 | fprintf(kconfig, "config USB_LANG_HID_USAGE_DATA_DESCRIPTOR\n"); 498 | fprintf(kconfig, "\tbool \"HID (Usage Data Descriptor)\"\n"); 499 | fprintf(kconfig, "config USB_LANG_HID_VENDOR_DEFINED_1\n"); 500 | fprintf(kconfig, "\tbool \"HID (Vendor Defined 1)\"\n"); 501 | fprintf(kconfig, "config USB_LANG_HID_VENDOR_DEFINED_2\n"); 502 | fprintf(kconfig, "\tbool \"HID (Vendor Defined 2)\"\n"); 503 | fprintf(kconfig, "config USB_LANG_HID_VENDOR_DEFINED_3\n"); 504 | fprintf(kconfig, "\tbool \"HID (Vendor Defined 3)\"\n"); 505 | fprintf(kconfig, "config USB_LANG_HID_VENDOR_DEFINED_4\n"); 506 | fprintf(kconfig, "\tbool \"HID (Vendor Defined 4)\"\n"); 507 | fprintf(kconfig, "endchoice\n"); 508 | 509 | fprintf(kconfig, "if USB_LANG_USER_SELECT\n"); 510 | fprintf(kconfig, "config USB_LANG_USER_VAL\n"); 511 | fprintf(kconfig, "\thex \"User Selected Lang ID\"\n"); 512 | fprintf(kconfig, "\tdefault 0x0000\n"); 513 | fprintf(kconfig, "\trange 0 65535\n"); 514 | fprintf(kconfig, "endif\n"); 515 | 516 | fprintf(kconfig, "config USB_LANG_VAL\n"); 517 | fprintf(kconfig, "\thex\n"); 518 | fprintf(kconfig, "\tdefault USB_LANG_USER_VAL if USB_LANG_USER_SELECT\n"); 519 | fprintf(kconfig, "\tdefault 0x0436 if USB_LANG_AFRIKAANS\n"); 520 | fprintf(kconfig, "\tdefault 0x041c if USB_LANG_ALBANIAN\n"); 521 | fprintf(kconfig, "\tdefault 0x0401 if USB_LANG_ARABIC_SAUDI_ARABIA\n"); 522 | fprintf(kconfig, "\tdefault 0x0801 if USB_LANG_ARABIC_IRAQ\n"); 523 | fprintf(kconfig, "\tdefault 0x0c01 if USB_LANG_ARABIC_EGYPT\n"); 524 | fprintf(kconfig, "\tdefault 0x1001 if USB_LANG_ARABIC_LIBYA\n"); 525 | fprintf(kconfig, "\tdefault 0x1401 if USB_LANG_ARABIC_ALGERIA\n"); 526 | fprintf(kconfig, "\tdefault 0x1801 if USB_LANG_ARABIC_MOROCCO\n"); 527 | fprintf(kconfig, "\tdefault 0x1c01 if USB_LANG_ARABIC_TUNISIA\n"); 528 | fprintf(kconfig, "\tdefault 0x2001 if USB_LANG_ARABIC_OMAN\n"); 529 | fprintf(kconfig, "\tdefault 0x2401 if USB_LANG_ARABIC_YEMEN\n"); 530 | fprintf(kconfig, "\tdefault 0x2801 if USB_LANG_ARABIC_SYRIA\n"); 531 | fprintf(kconfig, "\tdefault 0x2c01 if USB_LANG_ARABIC_JORDAN\n"); 532 | fprintf(kconfig, "\tdefault 0x3001 if USB_LANG_ARABIC_LEBANON\n"); 533 | fprintf(kconfig, "\tdefault 0x3401 if USB_LANG_ARABIC_KUWAIT\n"); 534 | fprintf(kconfig, "\tdefault 0x3801 if USB_LANG_ARABIC_UAE\n"); 535 | fprintf(kconfig, "\tdefault 0x3c01 if USB_LANG_ARABIC_BAHRAIN\n"); 536 | fprintf(kconfig, "\tdefault 0x4001 if USB_LANG_ARABIC_QATAR\n"); 537 | fprintf(kconfig, "\tdefault 0x042b if USB_LANG_ARMENIAN\n"); 538 | fprintf(kconfig, "\tdefault 0x044d if USB_LANG_ASSAMESE\n"); 539 | fprintf(kconfig, "\tdefault 0x042c if USB_LANG_AZERI_LATIN\n"); 540 | fprintf(kconfig, "\tdefault 0x082c if USB_LANG_AZERI_CYRILLIC\n"); 541 | fprintf(kconfig, "\tdefault 0x042d if USB_LANG_BASQUE\n"); 542 | fprintf(kconfig, "\tdefault 0x0423 if USB_LANG_BELARUSSIAN\n"); 543 | fprintf(kconfig, "\tdefault 0x0445 if USB_LANG_BENGALI\n"); 544 | fprintf(kconfig, "\tdefault 0x0402 if USB_LANG_BULGARIAN\n"); 545 | fprintf(kconfig, "\tdefault 0x0455 if USB_LANG_BURMESE\n"); 546 | fprintf(kconfig, "\tdefault 0x0403 if USB_LANG_CATALAN\n"); 547 | fprintf(kconfig, "\tdefault 0x0404 if USB_LANG_CHINESE_TAIWAN\n"); 548 | fprintf(kconfig, "\tdefault 0x0804 if USB_LANG_CHINESE_PRC\n"); 549 | fprintf(kconfig, "\tdefault 0x0c04 if USB_LANG_CHINESE_HONG_KONG_SAR_PRC\n"); 550 | fprintf(kconfig, "\tdefault 0x1004 if USB_LANG_CHINESE_SINGAPORE\n"); 551 | fprintf(kconfig, "\tdefault 0x1404 if USB_LANG_CHINESE_MACAU_SAR\n"); 552 | fprintf(kconfig, "\tdefault 0x041a if USB_LANG_CROATIAN\n"); 553 | fprintf(kconfig, "\tdefault 0x0405 if USB_LANG_CZECH\n"); 554 | fprintf(kconfig, "\tdefault 0x0406 if USB_LANG_DANISH\n"); 555 | fprintf(kconfig, "\tdefault 0x0413 if USB_LANG_DUTCH_NETHERLANDS\n"); 556 | fprintf(kconfig, "\tdefault 0x0813 if USB_LANG_DUTCH_BELGIUM\n"); 557 | fprintf(kconfig, "\tdefault 0x0409 if USB_LANG_ENGLISH_UNITED_STATES\n"); 558 | fprintf(kconfig, "\tdefault 0x0809 if USB_LANG_ENGLISH_UNITED_KINGDOM\n"); 559 | fprintf(kconfig, "\tdefault 0x0c09 if USB_LANG_ENGLISH_AUSTRALIAN\n"); 560 | fprintf(kconfig, "\tdefault 0x1009 if USB_LANG_ENGLISH_CANADIAN\n"); 561 | fprintf(kconfig, "\tdefault 0x1409 if USB_LANG_ENGLISH_NEW_ZEALAND\n"); 562 | fprintf(kconfig, "\tdefault 0x1809 if USB_LANG_ENGLISH_IRELAND\n"); 563 | fprintf(kconfig, "\tdefault 0x1c09 if USB_LANG_ENGLISH_SOUTH_AFRICA\n"); 564 | fprintf(kconfig, "\tdefault 0x2009 if USB_LANG_ENGLISH_JAMAICA\n"); 565 | fprintf(kconfig, "\tdefault 0x2409 if USB_LANG_ENGLISH_CARIBBEAN\n"); 566 | fprintf(kconfig, "\tdefault 0x2809 if USB_LANG_ENGLISH_BELIZE\n"); 567 | fprintf(kconfig, "\tdefault 0x2c09 if USB_LANG_ENGLISH_TRINIDAD\n"); 568 | fprintf(kconfig, "\tdefault 0x3009 if USB_LANG_ENGLISH_ZIMBABWE\n"); 569 | fprintf(kconfig, "\tdefault 0x3409 if USB_LANG_ENGLISH_PHILIPPINES\n"); 570 | fprintf(kconfig, "\tdefault 0x0425 if USB_LANG_ESTONIAN\n"); 571 | fprintf(kconfig, "\tdefault 0x0438 if USB_LANG_FAEROESE\n"); 572 | fprintf(kconfig, "\tdefault 0x0429 if USB_LANG_FARSI\n"); 573 | fprintf(kconfig, "\tdefault 0x040b if USB_LANG_FINNISH\n"); 574 | fprintf(kconfig, "\tdefault 0x040c if USB_LANG_FRENCH_STANDARD\n"); 575 | fprintf(kconfig, "\tdefault 0x080c if USB_LANG_FRENCH_BELGIAN\n"); 576 | fprintf(kconfig, "\tdefault 0x0c0c if USB_LANG_FRENCH_CANADIAN\n"); 577 | fprintf(kconfig, "\tdefault 0x100c if USB_LANG_FRENCH_SWITZERLAND\n"); 578 | fprintf(kconfig, "\tdefault 0x140c if USB_LANG_FRENCH_LUXEMBOURG\n"); 579 | fprintf(kconfig, "\tdefault 0x180c if USB_LANG_FRENCH_MONACO\n"); 580 | fprintf(kconfig, "\tdefault 0x0437 if USB_LANG_GEORGIAN\n"); 581 | fprintf(kconfig, "\tdefault 0x0407 if USB_LANG_GERMAN_STANDARD\n"); 582 | fprintf(kconfig, "\tdefault 0x0807 if USB_LANG_GERMAN_SWITZERLAND\n"); 583 | fprintf(kconfig, "\tdefault 0x0c07 if USB_LANG_GERMAN_AUSTRIA\n"); 584 | fprintf(kconfig, "\tdefault 0x1007 if USB_LANG_GERMAN_LUXEMBOURG\n"); 585 | fprintf(kconfig, "\tdefault 0x1407 if USB_LANG_GERMAN_LIECHTENSTEIN\n"); 586 | fprintf(kconfig, "\tdefault 0x0408 if USB_LANG_GREEK\n"); 587 | fprintf(kconfig, "\tdefault 0x0447 if USB_LANG_GUJARATI\n"); 588 | fprintf(kconfig, "\tdefault 0x040d if USB_LANG_HEBREW\n"); 589 | fprintf(kconfig, "\tdefault 0x0439 if USB_LANG_HINDI\n"); 590 | fprintf(kconfig, "\tdefault 0x040e if USB_LANG_HUNGARIAN\n"); 591 | fprintf(kconfig, "\tdefault 0x040f if USB_LANG_ICELANDIC\n"); 592 | fprintf(kconfig, "\tdefault 0x0421 if USB_LANG_INDONESIAN\n"); 593 | fprintf(kconfig, "\tdefault 0x0410 if USB_LANG_ITALIAN_STANDARD\n"); 594 | fprintf(kconfig, "\tdefault 0x0810 if USB_LANG_ITALIAN_SWITZERLAND\n"); 595 | fprintf(kconfig, "\tdefault 0x0411 if USB_LANG_JAPANESE\n"); 596 | fprintf(kconfig, "\tdefault 0x044b if USB_LANG_KANNADA\n"); 597 | fprintf(kconfig, "\tdefault 0x0860 if USB_LANG_KASHMIRI_INDIA\n"); 598 | fprintf(kconfig, "\tdefault 0x043f if USB_LANG_KAZAKH\n"); 599 | fprintf(kconfig, "\tdefault 0x0457 if USB_LANG_KONKANI\n"); 600 | fprintf(kconfig, "\tdefault 0x0412 if USB_LANG_KOREAN\n"); 601 | fprintf(kconfig, "\tdefault 0x0812 if USB_LANG_KOREAN_JOHAB\n"); 602 | fprintf(kconfig, "\tdefault 0x0426 if USB_LANG_LATVIAN\n"); 603 | fprintf(kconfig, "\tdefault 0x0427 if USB_LANG_LITHUANIAN\n"); 604 | fprintf(kconfig, "\tdefault 0x0827 if USB_LANG_LITHUANIAN_CLASSIC\n"); 605 | fprintf(kconfig, "\tdefault 0x042f if USB_LANG_MACEDONIAN\n"); 606 | fprintf(kconfig, "\tdefault 0x043e if USB_LANG_MALAY_MALAYSIAN\n"); 607 | fprintf(kconfig, "\tdefault 0x083e if USB_LANG_MALAY_BRUNEI_DARUSSALAM\n"); 608 | fprintf(kconfig, "\tdefault 0x044c if USB_LANG_MALAYALAM\n"); 609 | fprintf(kconfig, "\tdefault 0x0458 if USB_LANG_MANIPURI\n"); 610 | fprintf(kconfig, "\tdefault 0x044e if USB_LANG_MARATHI\n"); 611 | fprintf(kconfig, "\tdefault 0x0861 if USB_LANG_NEPALI_INDIA\n"); 612 | fprintf(kconfig, "\tdefault 0x0414 if USB_LANG_NORWEGIAN_BOKMAL\n"); 613 | fprintf(kconfig, "\tdefault 0x0814 if USB_LANG_NORWEGIAN_NYNORSK\n"); 614 | fprintf(kconfig, "\tdefault 0x0448 if USB_LANG_ORIYA\n"); 615 | fprintf(kconfig, "\tdefault 0x0415 if USB_LANG_POLISH\n"); 616 | fprintf(kconfig, "\tdefault 0x0416 if USB_LANG_PORTUGUESE_BRAZIL\n"); 617 | fprintf(kconfig, "\tdefault 0x0816 if USB_LANG_PORTUGUESE_STANDARD\n"); 618 | fprintf(kconfig, "\tdefault 0x0446 if USB_LANG_PUNJABI\n"); 619 | fprintf(kconfig, "\tdefault 0x0418 if USB_LANG_ROMANIAN\n"); 620 | fprintf(kconfig, "\tdefault 0x0419 if USB_LANG_RUSSIAN\n"); 621 | fprintf(kconfig, "\tdefault 0x044f if USB_LANG_SANSKRIT\n"); 622 | fprintf(kconfig, "\tdefault 0x0c1a if USB_LANG_SERBIAN_CYRILLIC\n"); 623 | fprintf(kconfig, "\tdefault 0x081a if USB_LANG_SERBIAN_LATIN\n"); 624 | fprintf(kconfig, "\tdefault 0x0459 if USB_LANG_SINDHI\n"); 625 | fprintf(kconfig, "\tdefault 0x041b if USB_LANG_SLOVAK\n"); 626 | fprintf(kconfig, "\tdefault 0x0424 if USB_LANG_SLOVENIAN\n"); 627 | fprintf(kconfig, "\tdefault 0x040a if USB_LANG_SPANISH_TRADITIONAL_SORT\n"); 628 | fprintf(kconfig, "\tdefault 0x080a if USB_LANG_SPANISH_MEXICAN\n"); 629 | fprintf(kconfig, "\tdefault 0x0c0a if USB_LANG_SPANISH_MODERN_SORT\n"); 630 | fprintf(kconfig, "\tdefault 0x100a if USB_LANG_SPANISH_GUATEMALA\n"); 631 | fprintf(kconfig, "\tdefault 0x140a if USB_LANG_SPANISH_COSTA_RICA\n"); 632 | fprintf(kconfig, "\tdefault 0x180a if USB_LANG_SPANISH_PANAMA\n"); 633 | fprintf(kconfig, "\tdefault 0x1c0a if USB_LANG_SPANISH_DOMINICAN_REPUBLIC\n"); 634 | fprintf(kconfig, "\tdefault 0x200a if USB_LANG_SPANISH_VENEZUELA\n"); 635 | fprintf(kconfig, "\tdefault 0x240a if USB_LANG_SPANISH_COLOMBIA\n"); 636 | fprintf(kconfig, "\tdefault 0x280a if USB_LANG_SPANISH_PERU\n"); 637 | fprintf(kconfig, "\tdefault 0x2c0a if USB_LANG_SPANISH_ARGENTINA\n"); 638 | fprintf(kconfig, "\tdefault 0x300a if USB_LANG_SPANISH_ECUADOR\n"); 639 | fprintf(kconfig, "\tdefault 0x340a if USB_LANG_SPANISH_CHILE\n"); 640 | fprintf(kconfig, "\tdefault 0x380a if USB_LANG_SPANISH_URUGUAY\n"); 641 | fprintf(kconfig, "\tdefault 0x3c0a if USB_LANG_SPANISH_PARAGUAY\n"); 642 | fprintf(kconfig, "\tdefault 0x400a if USB_LANG_SPANISH_BOLIVIA\n"); 643 | fprintf(kconfig, "\tdefault 0x440a if USB_LANG_SPANISH_EL_SALVADOR\n"); 644 | fprintf(kconfig, "\tdefault 0x480a if USB_LANG_SPANISH_HONDURAS\n"); 645 | fprintf(kconfig, "\tdefault 0x4c0a if USB_LANG_SPANISH_NICARAGUA\n"); 646 | fprintf(kconfig, "\tdefault 0x500a if USB_LANG_SPANISH_PUERTO_RICO\n"); 647 | fprintf(kconfig, "\tdefault 0x0430 if USB_LANG_SUTU\n"); 648 | fprintf(kconfig, "\tdefault 0x0441 if USB_LANG_SWAHILI_KENYA\n"); 649 | fprintf(kconfig, "\tdefault 0x041d if USB_LANG_SWEDISH\n"); 650 | fprintf(kconfig, "\tdefault 0x081d if USB_LANG_SWEDISH_FINLAND\n"); 651 | fprintf(kconfig, "\tdefault 0x0449 if USB_LANG_TAMIL\n"); 652 | fprintf(kconfig, "\tdefault 0x0444 if USB_LANG_TATAR_TATARSTAN\n"); 653 | fprintf(kconfig, "\tdefault 0x044a if USB_LANG_TELUGU\n"); 654 | fprintf(kconfig, "\tdefault 0x041e if USB_LANG_THAI\n"); 655 | fprintf(kconfig, "\tdefault 0x041f if USB_LANG_TURKISH\n"); 656 | fprintf(kconfig, "\tdefault 0x0422 if USB_LANG_UKRAINIAN\n"); 657 | fprintf(kconfig, "\tdefault 0x0420 if USB_LANG_URDU_PAKISTAN\n"); 658 | fprintf(kconfig, "\tdefault 0x0820 if USB_LANG_URDU_INDIA\n"); 659 | fprintf(kconfig, "\tdefault 0x0443 if USB_LANG_UZBEK_LATIN\n"); 660 | fprintf(kconfig, "\tdefault 0x0843 if USB_LANG_UZBEK_CYRILLIC\n"); 661 | fprintf(kconfig, "\tdefault 0x042a if USB_LANG_VIETNAMESE\n"); 662 | fprintf(kconfig, "\tdefault 0x04ff if USB_LANG_HID_USAGE_DATA_DESCRIPTOR\n"); 663 | fprintf(kconfig, "\tdefault 0xf0ff if USB_LANG_HID_VENDOR_DEFINED_1\n"); 664 | fprintf(kconfig, "\tdefault 0xf4ff if USB_LANG_HID_VENDOR_DEFINED_2\n"); 665 | fprintf(kconfig, "\tdefault 0xf8ff if USB_LANG_HID_VENDOR_DEFINED_3\n"); 666 | fprintf(kconfig, "\tdefault 0xfcff if USB_LANG_HID_VENDOR_DEFINED_4\n"); 667 | 668 | 669 | 670 | fprintf(kconfig, "menu \"USB Strings list\"\n"); 671 | fprintf(kconfig, "config USB_NSTRINGS\n"); 672 | fprintf(kconfig, "\tint \"Number of Strings\"\n"); 673 | fprintf(kconfig, "\tdefault 1\n"); 674 | 675 | for(int j=1; j= %d\n", j); 677 | fprintf(kconfig, "config USB_STRING_INDEX_%d\n", j); 678 | fprintf(kconfig, "\tstring \"string at index %d\"\n", j); 679 | fprintf(kconfig, "endif\n"); 680 | } 681 | fprintf(kconfig, "endmenu\n"); 682 | 683 | 684 | 685 | for(int i=0; i< max_conf; i++){ 686 | //fprintf(kconfig,"\tvisible if USB_DEVICE_NCONFIGS>%d\n", i); 687 | fprintf(kconfig, "if USB_DEVICE_NCONFIGS>%d\n", i); 688 | fprintf(kconfig, "menu \"USB Configuration No %d\"\n",i); 689 | fprintf(kconfig, "config USB_CONFIG%d_NINTERFACES\n", i); 690 | fprintf(kconfig, "\tint \"Number of Interfaces\"\n"); 691 | fprintf(kconfig, "\trange 1 255\n"); 692 | fprintf(kconfig, "\t---help---\n"); 693 | fprintf(kconfig, "\t\tNumber of interfaces supported by this configuration\n"); 694 | 695 | fprintf(kconfig, "config USB_CONFIG%d_CFGVALUE\n", i); 696 | fprintf(kconfig, "\tint \"Configuration Value\"\n"); 697 | fprintf(kconfig, "\tdefault %d\n", i+1); 698 | fprintf(kconfig, "\t---help---\n"); 699 | fprintf(kconfig, "\t\tValue to use as an argument to the SetConfiguration()\n\t\trequest to select this configuration\n"); 700 | 701 | fprintf(kconfig, "config USB_CONFIG%d_ICFG\n",i); 702 | fprintf(kconfig, "\tint \"Configuration String Index\"\n"); 703 | fprintf(kconfig, "\tdefault 0\n"); 704 | fprintf(kconfig, "\t---help---\n"); 705 | fprintf(kconfig, "\t\tIndex of string descriptor describing this configuration\n"); 706 | 707 | 708 | fprintf(kconfig, "menu \"USB Attribute\"\n"); 709 | fprintf(kconfig, "config USB_CONFIG%d_ATTR_D7\n", i); 710 | fprintf(kconfig, "\tbool \"Configuration Attribue D7\"\n"); 711 | fprintf(kconfig, "\tdefault y\n"); 712 | fprintf(kconfig, "\t---help---\n"); 713 | fprintf(kconfig, "\t\tD7 Reserved (set to one) for historical reason\n"); 714 | 715 | 716 | fprintf(kconfig, "config USB_CONFIG%d_ATTR_D6\n", i); 717 | fprintf(kconfig, "\tbool \"Self-Powered\"\n"); 718 | fprintf(kconfig, "\tdefault y\n"); 719 | fprintf(kconfig, "\t---help---\n"); 720 | fprintf(kconfig, "\t\tA device configuration that uses power from\n"); 721 | fprintf(kconfig, "\t\tthe bus and a local source reports a non-zero\n"); 722 | fprintf(kconfig, "\t\tvalue in bMaxPower to indicate the amount of\n"); 723 | fprintf(kconfig, "\t\tbus power required and sets D6. The actual\n"); 724 | fprintf(kconfig, "\t\tpower source at runtime may be determined\n"); 725 | fprintf(kconfig, "\t\tusing the GetStatus(DEVICE) request (see\n"); 726 | fprintf(kconfig, "\t\tSection 9.4.5).\n"); 727 | 728 | fprintf(kconfig, "config USB_CONFIG%d_ATTR_D5\n", i); 729 | fprintf(kconfig, "\tbool \"Remote Wakeup\"\n"); 730 | fprintf(kconfig, "\tdefault y\n"); 731 | fprintf(kconfig, "\t---help---\n"); 732 | fprintf(kconfig, "\t\tIf a device configuration supports remote Wakeup\n"); 733 | 734 | fprintf(kconfig, "config USB_CONFIG%d_ATTR_D4\n", i); 735 | fprintf(kconfig, "\tbool \"Configuration Attribue D4\"\n"); 736 | fprintf(kconfig, "\tdefault n\n"); 737 | fprintf(kconfig, "\t---help---\n"); 738 | fprintf(kconfig, "\t\tD4-0 Reserved (set to zero)\n"); 739 | 740 | fprintf(kconfig, "config USB_CONFIG%d_ATTR_D3\n", i); 741 | fprintf(kconfig, "\tbool \"Configuration Attribue D3\"\n"); 742 | fprintf(kconfig, "\tdefault n\n"); 743 | fprintf(kconfig, "\t---help---\n"); 744 | fprintf(kconfig, "\t\tD4-0 Reserved (set to zero)\n"); 745 | 746 | fprintf(kconfig, "config USB_CONFIG%d_ATTR_D2\n", i); 747 | fprintf(kconfig, "\tbool \"Configuration Attribue D2\"\n"); 748 | fprintf(kconfig, "\tdefault n\n"); 749 | fprintf(kconfig, "\t---help---\n"); 750 | fprintf(kconfig, "\t\tD4-0 Reserved (set to zero)\n"); 751 | 752 | fprintf(kconfig, "config USB_CONFIG%d_ATTR_D1\n", i); 753 | fprintf(kconfig, "\tbool \"Configuration Attribue D1\"\n"); 754 | fprintf(kconfig, "\tdefault n\n"); 755 | fprintf(kconfig, "\t---help---\n"); 756 | fprintf(kconfig, "\t\tD4-0 Reserved (set to zero)\n"); 757 | 758 | fprintf(kconfig, "config USB_CONFIG%d_ATTR_D0\n", i); 759 | fprintf(kconfig, "\tbool \"Configuration Attribue D0\"\n"); 760 | fprintf(kconfig, "\tdefault n\n"); 761 | fprintf(kconfig, "\t---help---\n"); 762 | fprintf(kconfig, "\t\tD4-0 Reserved (set to zero)\n"); 763 | 764 | fprintf(kconfig, "endmenu\n"); 765 | 766 | fprintf(kconfig, "config USB_CONFIG%d_MXPOWER\n",i); 767 | fprintf(kconfig, "\thex \"Maximum Power\"\n"); 768 | fprintf(kconfig, "\tdefault 0x30\n"); 769 | fprintf(kconfig, "\t---help---\n"); 770 | fprintf(kconfig, "\t\tMaximum power consumption of the USB\n"); 771 | fprintf(kconfig, "\t\tdevice from the bus in this specific\n"); 772 | fprintf(kconfig, "\t\tconfiguration when the device is fully\n"); 773 | fprintf(kconfig, "\t\toperational. Expressed in 2 mA units\n"); 774 | fprintf(kconfig, "\t\t(i.e., 50 = 100 mA).\n"); 775 | fprintf(kconfig, "\t\tNote: A device configuration reports whether\n"); 776 | fprintf(kconfig, "\t\tthe configuration is bus-powered or selfpowered.\n"); 777 | fprintf(kconfig, "\t\tDevice status reports whether the\n"); 778 | fprintf(kconfig, "\t\tdevice is currently self-powered. If a device is\n"); 779 | fprintf(kconfig, "\t\tdisconnected from its external power source, it\n"); 780 | fprintf(kconfig, "\t\tupdates device status to indicate that it is no\n"); 781 | fprintf(kconfig, "\t\tlonger self-powered.\n"); 782 | fprintf(kconfig, "\t\tA device may not increase its power draw\n"); 783 | fprintf(kconfig, "\t\tfrom the bus, when it loses its external power\n"); 784 | fprintf(kconfig, "\t\tsource, beyond the amount reported by its\n"); 785 | fprintf(kconfig, "\t\tconfiguration.\n"); 786 | fprintf(kconfig, "\t\tIf a device can continue to operate when\n"); 787 | fprintf(kconfig, "\t\tdisconnected from its external power source, it\n"); 788 | fprintf(kconfig, "\t\tcontinues to do so. If the device cannot\n"); 789 | fprintf(kconfig, "\t\tcontinue to operate, it fails operations it can\n"); 790 | fprintf(kconfig, "\t\tno longer support. The USB System Software\n"); 791 | fprintf(kconfig, "\t\tmay determine the cause of the failure by\n"); 792 | fprintf(kconfig, "\t\tchecking the status and noting the loss of the\n"); 793 | 794 | 795 | for(int j=0;j%d\n", i, j); 797 | fprintf(kconfig, "menu \"USB Interface No %d\"\n", j); 798 | 799 | 800 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_IFNO\n", i, j); 801 | fprintf(kconfig, "\tint \"Interface Number\"\n"); 802 | fprintf(kconfig, "\tdefault %d\n", j); 803 | fprintf(kconfig, "\t---help---\n"); 804 | fprintf(kconfig, "\t\tNumber of this interface. Zero-based\n"); 805 | fprintf(kconfig, "\t\tvalue identifying the index in the array of\n"); 806 | fprintf(kconfig, "\t\tconcurrent interfaces supported by this\n"); 807 | fprintf(kconfig, "\t\tconfiguration.\n"); 808 | 809 | 810 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_ALT\n", i, j); 811 | fprintf(kconfig, "\tint \"Alt Setting\"\n"); 812 | fprintf(kconfig, "\tdefault 0\n"); 813 | fprintf(kconfig, "\t---help---\n"); 814 | fprintf(kconfig, "\t\tValue used to select this alternate setting\n"); 815 | fprintf(kconfig, "\t\tfor the interface identified in the prior field\n"); 816 | 817 | 818 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_NEPS\n", i, j); 819 | fprintf(kconfig, "\tint \"Number of Endpoints\"\n"); 820 | fprintf(kconfig, "\tdefault 2\n"); 821 | fprintf(kconfig, "\t---help---\n"); 822 | fprintf(kconfig, "\t\tNumber of endpoints used by this\n"); 823 | fprintf(kconfig, "\t\tinterface (excluding endpoint zero). If this\n"); 824 | fprintf(kconfig, "\t\tvalue is zero, this interface only uses the\n"); 825 | fprintf(kconfig, "\t\tDefault Control Pipe.\n"); 826 | 827 | 828 | fprintf(kconfig, "choice\n"); 829 | fprintf(kconfig, "\tprompt \"USB Interface Class\"\n"); 830 | fprintf(kconfig, "\tdefault USB_CONFIG%d_INTERFACE%d_CLASS_VENDOR_SPECIFIC\n", i, j); 831 | 832 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_USER\n", i, j); 833 | fprintf(kconfig, "\tbool \"Set Manually\"\n"); 834 | fprintf(kconfig, "\t---help---\n"); 835 | fprintf(kconfig, "\t\tThis base class is defined for vendors to use as \n"); 836 | fprintf(kconfig, "\t\tthey please. These class codes can be used in both \n"); 837 | fprintf(kconfig, "\t\tDevice and Interface Descriptors.\n"); 838 | 839 | 840 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_AUDIO\n", i, j); 841 | fprintf(kconfig, "\tbool \"Audio Class\"\n"); 842 | fprintf(kconfig, "\t---help---\n"); 843 | fprintf(kconfig, "\t\tAudio class\n"); 844 | 845 | 846 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_HID\n", i, j); 847 | fprintf(kconfig, "\tbool \"HID\"\n"); 848 | fprintf(kconfig, "\t---help---\n"); 849 | fprintf(kconfig, "\t\tThis base class is defined for devices that conform\n"); 850 | fprintf(kconfig, "\t\tto the HID Device Class Specification found on the\n"); 851 | fprintf(kconfig, "\t\tUSB-IF website. That specification defines the usable\n"); 852 | fprintf(kconfig, "\t\tset of SubClass and Protocol values. Values outside\n"); 853 | fprintf(kconfig, "\t\tof that defined spec are reserved. These class codes\n"); 854 | fprintf(kconfig, "\t\tcan only be used in Interface Descriptors.\n"); 855 | 856 | 857 | 858 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_PHYSICAL\n", i, j); 859 | fprintf(kconfig, "\tbool \"Physical\"\n"); 860 | fprintf(kconfig, "\t---help---\n"); 861 | fprintf(kconfig, "\t\tThis base class is defined for devices that conform\n"); 862 | fprintf(kconfig, "\t\tto the Physical Device Class Specification found on\n"); 863 | fprintf(kconfig, "\t\tthe USB-IF website. That specification defines the\n"); 864 | fprintf(kconfig, "\t\tusable set of SubClass and Protocol values. Values\n"); 865 | fprintf(kconfig, "\t\toutside of that defined spec are reserved. These\n"); 866 | fprintf(kconfig, "\t\tclass codes can only be used in Interface Descriptors.\n"); 867 | 868 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_IMAGE\n", i, j); 869 | fprintf(kconfig, "\tbool \"Still Image\"\n"); 870 | fprintf(kconfig, "\t---help---\n"); 871 | fprintf(kconfig, "\t\tThis base class is defined for devices that conform\n"); 872 | fprintf(kconfig, "\t\tto the Imaging Device Class Specification found on\n"); 873 | fprintf(kconfig, "\t\tthe USB-IF website. That specification defines the\n"); 874 | fprintf(kconfig, "\t\tusable set of SubClass and Protocol values. Values\n"); 875 | fprintf(kconfig, "\t\toutside of that defined spec are reserved.\n"); 876 | 877 | 878 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_PRINTER\n", i, j); 879 | fprintf(kconfig, "\tbool \"Printer\"\n"); 880 | fprintf(kconfig, "\t---help---\n"); 881 | fprintf(kconfig, "\t\tThis base class is defined for devices that conform\n"); 882 | fprintf(kconfig, "\t\tto the Printer Device Class Specification found on\n"); 883 | fprintf(kconfig, "\t\tthe USB-IF website. That specification defines the\n"); 884 | fprintf(kconfig, "\t\tusable set of SubClass and Protocol values. Values\n"); 885 | fprintf(kconfig, "\t\toutside of that defined spec are reserved. These\n"); 886 | fprintf(kconfig, "\t\tclass codes can only be used in Interface Descriptors.\n"); 887 | 888 | 889 | 890 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_MSC\n", i, j); 891 | fprintf(kconfig, "\tbool \"Mass Storage\"\n"); 892 | fprintf(kconfig, "\t---help---\n"); 893 | fprintf(kconfig, "\t\tThis base class is defined for devices that conform\n"); 894 | fprintf(kconfig, "\t\tto the Mass Storage Device Class Specification found\n"); 895 | fprintf(kconfig, "\t\ton the USB-IF website. That specification defines the\n"); 896 | fprintf(kconfig, "\t\tusable set of SubClass and Protocol values. Values\n"); 897 | fprintf(kconfig, "\t\toutside of that defined spec are reserved. These\n"); 898 | fprintf(kconfig, "\t\tclass codes can only be used in Interface Descriptors.\n"); 899 | 900 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_CDC_DATA\n", i, j); 901 | fprintf(kconfig, "\tbool \"CDC DATA\"\n"); 902 | fprintf(kconfig, "\t---help---\n"); 903 | fprintf(kconfig, "\t\tThis base class is defined for devices that conform to the\n"); 904 | fprintf(kconfig, "\t\tCommunications Device Class Specification found on the\n"); 905 | fprintf(kconfig, "\t\tUSB-IF website. That specification defines the usable\n"); 906 | fprintf(kconfig, "\t\tset of SubClass and Protocol values.Values outside of\n"); 907 | fprintf(kconfig, "\t\tthat defined spec are reserved. These class codes can\n"); 908 | fprintf(kconfig, "\t\tonly be used in Interface Descriptors.\n"); 909 | 910 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_SMARTCARD\n", i, j); 911 | fprintf(kconfig, "\tbool \"Smart Card\"\n"); 912 | fprintf(kconfig, "\t---help---\n"); 913 | fprintf(kconfig, "\t\tThis base class is defined for devices that conform to\n"); 914 | fprintf(kconfig, "\t\tthe Smart Card Device Class Specification found on the\n"); 915 | fprintf(kconfig, "\t\tUSB-IF website. That specification defines the usable\n"); 916 | fprintf(kconfig, "\t\tset of SubClass and Protocol values.Values outside of\n"); 917 | fprintf(kconfig, "\t\tthat defined spec are reserved. These class codes can\n"); 918 | fprintf(kconfig, "\t\tonly be used in Interface Descriptors.\n"); 919 | 920 | 921 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_CONTENT_SECURITY\n", i, j); 922 | fprintf(kconfig, "\tbool \"Content Security\"\n"); 923 | fprintf(kconfig, "\t---help---\n"); 924 | fprintf(kconfig, "\t\tThis base class is defined for devices that conform to\n"); 925 | fprintf(kconfig, "\t\tthe Content Security Device Class Specification found\n"); 926 | fprintf(kconfig, "\t\ton the USB-IF website. That specification defines the\n"); 927 | fprintf(kconfig, "\t\tusable set of SubClass and Protocol values. Values\n"); 928 | fprintf(kconfig, "\t\toutside of that defined spec are reserved. These class\n"); 929 | fprintf(kconfig, "\t\tcodes can only be used in Interface Descriptors.\n"); 930 | fprintf(kconfig, "\t\t\n"); 931 | 932 | 933 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_VIDEO\n", i, j); 934 | fprintf(kconfig, "\tbool \"Video\"\n"); 935 | fprintf(kconfig, "\t---help---\n"); 936 | fprintf(kconfig, "\t\tThis base class is defined for devices that conform to\n"); 937 | fprintf(kconfig, "\t\tthe Video Device Class Specification found on the USB-IF\n"); 938 | fprintf(kconfig, "\t\twebsite. That specification defines the usable set of\n"); 939 | fprintf(kconfig, "\t\tSubClass and Protocol values. Values outside of that\n"); 940 | fprintf(kconfig, "\t\tdefined spec are reserved. These class codes can only\n"); 941 | fprintf(kconfig, "\t\tbe used in Interface Descriptors.\n"); 942 | 943 | 944 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_PERSONAL_HEALTHCARE\n", i, j); 945 | fprintf(kconfig, "\tbool \"Personal HealthCare\"\n"); 946 | fprintf(kconfig, "\t---help---\n"); 947 | fprintf(kconfig, "\t\tThis base class is defined for devices that conform to\n"); 948 | fprintf(kconfig, "\t\tthe Personal Healthcare Class Specification found on the USB-IF\n"); 949 | fprintf(kconfig, "\t\twebsite. That specification defines the usable set of\n"); 950 | fprintf(kconfig, "\t\tSubClass and Protocol values. Values outside of that\n"); 951 | fprintf(kconfig, "\t\tdefined spec are reserved. These class codes can only\n"); 952 | fprintf(kconfig, "\t\tbe used in Interface Descriptors.\n"); 953 | 954 | 955 | 956 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_AV\n", i, j); 957 | fprintf(kconfig, "\tbool \"Audio-Video\"\n"); 958 | fprintf(kconfig, "\t---help---\n"); 959 | fprintf(kconfig, "\t\tThe USB Audio/Video (AV) Device Class Definition describes\n"); 960 | fprintf(kconfig, "\t\tthe methods used to communicate with devices or functions\n"); 961 | fprintf(kconfig, "\t\tembedded in composite devices that are used to manipulate\n"); 962 | fprintf(kconfig, "\t\taudio, video, voice, and all image- and sound-related\n"); 963 | fprintf(kconfig, "\t\tfunctionality. That specification defines the usable set\n"); 964 | fprintf(kconfig, "\t\tof SubClass and Protocol values. Values outside of that\n"); 965 | fprintf(kconfig, "\t\tdefined spec are reserved. These class codes can only be\n"); 966 | fprintf(kconfig, "\t\tused in Interface Descriptors.\n"); 967 | 968 | 969 | 970 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_TYPEC_BRIDGE\n", i, j); 971 | fprintf(kconfig, "\tbool \"USB Type-C Bridge Class\"\n"); 972 | fprintf(kconfig, "\t---help---\n"); 973 | fprintf(kconfig, "\t\tTODO write help.\n"); 974 | 975 | 976 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_DIAG\n", i, j); 977 | fprintf(kconfig, "\tbool \"Diagnostic Device\"\n"); 978 | fprintf(kconfig, "\t---help---\n"); 979 | fprintf(kconfig, "\t\tThis base class is defined for devices that diagnostic devices.\n"); 980 | fprintf(kconfig, "\t\tThis class code can be used in Device or Interface Descriptors. \n"); 981 | fprintf(kconfig, "\t\tTrace is a form of debugging where processor or system activity\n"); 982 | fprintf(kconfig, "\t\tis made externally visible in real-time or stored and later\n"); 983 | fprintf(kconfig, "\t\tretrieved for viewing by an applications developer, applications\n"); 984 | fprintf(kconfig, "\t\tprogram, or, external equipment specializing observing system activity. \n"); 985 | fprintf(kconfig, "\t\tDesign for Debug or Test (Dfx). This refers to a logic block\n"); 986 | fprintf(kconfig, "\t\tthat provides debug or test support (E.g. via Test Access Port (TAP)). \n"); 987 | fprintf(kconfig, "\t\tDvC: Debug Capability on the USB device (Device Capability) \n"); 988 | 989 | 990 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_WIRELESS\n", i, j); 991 | fprintf(kconfig, "\tbool \"Wireless Controller\"\n"); 992 | fprintf(kconfig, "\t---help---\n"); 993 | fprintf(kconfig, "\t\tThis base class is defined for devices that are Wireless\n"); 994 | fprintf(kconfig, "\t\tcontrollers. Values not shown in the table below are reserved.\n"); 995 | fprintf(kconfig, "\t\tThese class codes are to be used in Interface Descriptors, with\n"); 996 | fprintf(kconfig, "\t\tthe exception of the Bluetooth class code which can also be\n"); 997 | fprintf(kconfig, "\t\tused in a Device Descriptor.\n"); 998 | 999 | 1000 | 1001 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_MISC\n", i, j); 1002 | fprintf(kconfig, "\tbool \"Miscellaneous\"\n"); 1003 | fprintf(kconfig, "\t---help---\n"); 1004 | fprintf(kconfig, "\t\tThis base class is defined for miscellaneous device definitions.\n"); 1005 | fprintf(kconfig, "\t\tValues not shown in the table below are reserved. The use of\n"); 1006 | fprintf(kconfig, "\t\tthese class codes (Device or Interface descriptor) are\n"); 1007 | fprintf(kconfig, "\t\tspecifically annotated in each entry below.\n"); 1008 | 1009 | 1010 | 1011 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_APP_SPECIFIC\n", i, j); 1012 | fprintf(kconfig, "\tbool \"Application Specific\"\n"); 1013 | fprintf(kconfig, "\t---help---\n"); 1014 | fprintf(kconfig, "\t\tThis base class is defined for devices that conform to\n"); 1015 | fprintf(kconfig, "\t\tseveral class specifications found on the USB-IF website.\n"); 1016 | fprintf(kconfig, "\t\tThat specification defines the usable set of SubClass and\n"); 1017 | fprintf(kconfig, "\t\tProtocol values. Values outside of that defined spec are\n"); 1018 | fprintf(kconfig, "\t\treserved. These class codes can only be used in\n"); 1019 | fprintf(kconfig, "\t\tInterface Descriptors.\n"); 1020 | 1021 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_VENDOR_SPECIFIC\n", i, j); 1022 | fprintf(kconfig, "\tbool \"Vendor Specific\"\n"); 1023 | fprintf(kconfig, "\t---help---\n"); 1024 | fprintf(kconfig, "\t\tThis base class is defined for vendors to use as \n"); 1025 | fprintf(kconfig, "\t\tthey please. These class codes can be used in both \n"); 1026 | fprintf(kconfig, "\t\tDevice and Interface Descriptors.\n"); 1027 | 1028 | 1029 | fprintf(kconfig, "endchoice\n"); 1030 | 1031 | fprintf(kconfig, "if USB_CONFIG%d_INTERFACE%d_CLASS_USER\n", i, j); 1032 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_CUSTOM_VAL\n",i,j); 1033 | fprintf(kconfig, "\thex \"Interface Class Value\"\n"); 1034 | fprintf(kconfig, "\trange 0 255\n"); 1035 | fprintf(kconfig, "\tdefault 0x00\n"); 1036 | fprintf(kconfig, "\tendif\n"); 1037 | 1038 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_CLASS_VAL\n", i, j); 1039 | fprintf(kconfig, "\thex\n"); 1040 | fprintf(kconfig, "\trange 0 255\n"); 1041 | 1042 | fprintf(kconfig, "\tdefault 0x00 if USB_CONFIG%d_INTERFACE%d_CLASS_USER\n", i, j); 1043 | fprintf(kconfig, "\tdefault 0x01 if USB_CONFIG%d_INTERFACE%d_CLASS_AUDIO\n", i, j); 1044 | fprintf(kconfig, "\tdefault 0x03 if USB_CONFIG%d_INTERFACE%d_CLASS_HID\n", i, j); 1045 | fprintf(kconfig, "\tdefault 0x05 if USB_CONFIG%d_INTERFACE%d_CLASS_PHYSICAL\n", i, j); 1046 | fprintf(kconfig, "\tdefault 0x06 if USB_CONFIG%d_INTERFACE%d_CLASS_IMAGE\n", i, j); 1047 | fprintf(kconfig, "\tdefault 0x07 if USB_CONFIG%d_INTERFACE%d_CLASS_PRINTER\n", i, j); 1048 | fprintf(kconfig, "\tdefault 0x08 if USB_CONFIG%d_INTERFACE%d_CLASS_MSC\n", i, j); 1049 | fprintf(kconfig, "\tdefault 0x0a if USB_CONFIG%d_INTERFACE%d_CLASS_CDC_DATA\n", i, j); 1050 | fprintf(kconfig, "\tdefault 0x0b if USB_CONFIG%d_INTERFACE%d_CLASS_SMARTCARD\n", i, j); 1051 | fprintf(kconfig, "\tdefault 0x0d if USB_CONFIG%d_INTERFACE%d_CLASS_CONTENT_SECURITY\n", i, j); 1052 | fprintf(kconfig, "\tdefault 0x0e if USB_CONFIG%d_INTERFACE%d_CLASS_VIDEO\n", i, j); 1053 | fprintf(kconfig, "\tdefault 0x0f if USB_CONFIG%d_INTERFACE%d_CLASS_PERSONAL_HEALTHCARE\n", i, j); 1054 | fprintf(kconfig, "\tdefault 0x10 if USB_CONFIG%d_INTERFACE%d_CLASS_AV\n", i, j); 1055 | fprintf(kconfig, "\tdefault 0x12 if USB_CONFIG%d_INTERFACE%d_CLASS_TYPEC_BRIDGE\n", i, j); 1056 | fprintf(kconfig, "\tdefault 0xdc if USB_CONFIG%d_INTERFACE%d_CLASS_DIAG\n", i, j); 1057 | fprintf(kconfig, "\tdefault 0xe0 if USB_CONFIG%d_INTERFACE%d_CLASS_WIRELESS\n", i, j); 1058 | fprintf(kconfig, "\tdefault 0xef if USB_CONFIG%d_INTERFACE%d_CLASS_MISC\n", i, j); 1059 | fprintf(kconfig, "\tdefault 0xfe if USB_CONFIG%d_INTERFACE%d_CLASS_APP_SPECIFIC\n", i, j); 1060 | fprintf(kconfig, "\tdefault 0xff if USB_CONFIG%d_INTERFACE%d_CLASS_VENDOR_SPECIFIC\n", i, j); 1061 | fprintf(kconfig, "\tdefault USB_CONFIG%d_INTERFACE%d_CLASS_CUSTOM_VAL if USB_CONFIG%d_INTERFACE%d_CLASS_USER\n",i,j, i, j); 1062 | 1063 | 1064 | 1065 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_SUBCLASS_VAL\n",i,j); 1066 | fprintf(kconfig, "\tint \"Interface SubClass Value\"\n"); 1067 | fprintf(kconfig, "\trange 0 255\n"); 1068 | fprintf(kconfig, "\tdefault 0\n"); 1069 | 1070 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_PROTOCOL_VAL\n",i,j); 1071 | fprintf(kconfig, "\tint \"Interface Protocol Value\"\n"); 1072 | fprintf(kconfig, "\trange 0 255\n"); 1073 | fprintf(kconfig, "\tdefault 0\n"); 1074 | 1075 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_IIF\n",i, j); 1076 | fprintf(kconfig, "\tint \"Interface String Index\"\n"); 1077 | fprintf(kconfig, "\tdefault 0\n"); 1078 | fprintf(kconfig, "\t---help---\n"); 1079 | fprintf(kconfig, "\t\tIndex of string descriptor describing this interface\n"); 1080 | 1081 | for(int k = 0; k < max_ep; k++){ 1082 | fprintf(kconfig, "if USB_CONFIG%d_INTERFACE%d_NEPS>%d\n", i, j, k); 1083 | fprintf(kconfig,"menu \"USB Endpoint %d\"\n", k); 1084 | 1085 | fprintf(kconfig,"config USB_CONFIG%d_INTERFACE%d_EP%d_ADDR\n",i,j,k); 1086 | fprintf(kconfig,"\thex \"Endpoint Address\"\n"); 1087 | if(k > 15) 1088 | fprintf(kconfig,"\tdefault 0x%02x\n", 0x80 | (k & 0xf)) ; 1089 | else 1090 | fprintf(kconfig,"\tdefault 0x%02x\n", (k & 0xf) + 1); 1091 | fprintf(kconfig, "\t---help---\n"); 1092 | fprintf(kconfig, "\t\tThe address of the endpoint on the USB device\n"); 1093 | fprintf(kconfig, "\t\tdescribed by this descriptor. The address is\n"); 1094 | fprintf(kconfig, "\t\tencoded as follows:\n"); 1095 | fprintf(kconfig, "\t\tBit 3...0: The endpoint number\n"); 1096 | fprintf(kconfig, "\t\tBit 6...4: Reserved, reset to zero\n"); 1097 | fprintf(kconfig, "\t\tBit 7: Direction, ignored for\n"); 1098 | fprintf(kconfig, "\t\tcontrol endpoints\n"); 1099 | fprintf(kconfig, "\t\t0 = OUT endpoint\n"); 1100 | fprintf(kconfig, "\t\t1 = IN endpoint\n"); 1101 | 1102 | 1103 | fprintf(kconfig, "choice\n"); 1104 | fprintf(kconfig, "prompt \"Transfer Type\" \n"); 1105 | fprintf(kconfig, "default USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_XFER_TYPE_BULK\n", i,j,k); 1106 | 1107 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_XFER_TYPE_CONTROL\n",i,j, k); 1108 | fprintf(kconfig, "\tbool \"Control\"\n"); 1109 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_XFER_TYPE_ISOCHRONOUS\n",i,j, k); 1110 | fprintf(kconfig, "\tbool \"Isochronous\"\n"); 1111 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_XFER_TYPE_BULK\n", i,j,k); 1112 | fprintf(kconfig, "\tbool \"Bulk\"\n"); 1113 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_XFER_TYPE_INTERRUPT\n",i,j, k); 1114 | fprintf(kconfig, "\tbool \"Interrupt\"\n"); 1115 | fprintf(kconfig, "endchoice\n"); 1116 | 1117 | 1118 | fprintf(kconfig, "choice\n"); 1119 | fprintf(kconfig, "prompt \"Synchronization Type\" \n"); 1120 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_SYNC_TYPE_NO_SYNC\n",i,j, k); 1121 | fprintf(kconfig, "\tbool \"No Synchronization\"\n"); 1122 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_SYNC_TYPE_ASYNCHRONOUS\n",i,j, k); 1123 | fprintf(kconfig, "\tbool \"Asynchronous\"\n"); 1124 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_SYNC_TYPE_ADAPTIVE\n", i,j,k); 1125 | fprintf(kconfig, "\tbool \"Adaptive\"\n"); 1126 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_SYNC_TYPE_SYNCHRONOUS\n",i,j, k); 1127 | fprintf(kconfig, "\tbool \"SYNCHRONOUS\"\n"); 1128 | fprintf(kconfig, "endchoice\n"); 1129 | 1130 | 1131 | fprintf(kconfig, "choice\n"); 1132 | fprintf(kconfig, "prompt \"USAGE Type\" \n"); 1133 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_USAGE_TYPE_DATA\n",i,j, k); 1134 | fprintf(kconfig, "\tbool \"Data\"\n"); 1135 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_USAGE_TYPE_FEEDBACK\n",i,j, k); 1136 | fprintf(kconfig, "\tbool \"Feedback\"\n"); 1137 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_USAGE_TYPE_IMPL_FEEDBACK\n", i,j,k); 1138 | fprintf(kconfig, "\tbool \"Implicit Feedback Data\"\n"); 1139 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_USAGE_TYPE_RESERVED\n",i,j, k); 1140 | fprintf(kconfig, "\tbool \"Reserved\"\n"); 1141 | fprintf(kconfig, "endchoice\n"); 1142 | 1143 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_NONE\n",i,j, k); 1144 | fprintf(kconfig, "\tint \"Reserved Endpoint Attribute D6 D7\"\n"); 1145 | fprintf(kconfig, "\tdefault 0\n"); 1146 | fprintf(kconfig, "\trange 0 3\n"); 1147 | 1148 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_USAGE_TYPE_VAL\n",i,j, k); 1149 | fprintf(kconfig, "\tint\n"); 1150 | fprintf(kconfig, "\tdefault 0 if USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_USAGE_TYPE_DATA\n",i,j, k); 1151 | fprintf(kconfig, "\tdefault 1 if USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_USAGE_TYPE_FEEDBACK\n",i,j, k); 1152 | fprintf(kconfig, "\tdefault 2 if USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_USAGE_TYPE_IMPL_FEEDBACK\n", i,j,k); 1153 | fprintf(kconfig, "\tdefault 3 if USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_USAGE_TYPE_RESERVED\n",i,j, k); 1154 | 1155 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_XFER_TYPE_VAL\n", i, j, k); 1156 | fprintf(kconfig, "\tint\n"); 1157 | fprintf(kconfig, "\tdefault 0 if USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_XFER_TYPE_CONTROL\n",i,j, k); 1158 | fprintf(kconfig, "\tdefault 1 if USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_XFER_TYPE_ISOCHRONOUS\n",i,j, k); 1159 | fprintf(kconfig, "\tdefault 2 if USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_XFER_TYPE_BULK\n", i,j,k); 1160 | fprintf(kconfig, "\tdefault 3 if USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_XFER_TYPE_INTERRUPT\n",i,j, k); 1161 | 1162 | 1163 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_SYNC_TYPE_VAL\n",i,j, k); 1164 | fprintf(kconfig, "\tint\n"); 1165 | fprintf(kconfig, "\tdefault 0 if USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_SYNC_TYPE_NO_SYNC\n",i,j, k); 1166 | fprintf(kconfig, "\tdefault 1 if USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_SYNC_TYPE_ASYNCHRONOUS\n",i,j, k); 1167 | fprintf(kconfig, "\tdefault 2 if USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_SYNC_TYPE_ADAPTIVE\n", i,j,k); 1168 | fprintf(kconfig, "\tdefault 3 if USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_SYNC_TYPE_SYNCHRONOUS\n",i,j, k); 1169 | 1170 | 1171 | 1172 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_MXPACKETSIZE\n",i,j, k); 1173 | fprintf(kconfig, "\thex \"Maximum Packet Size\"\n"); 1174 | fprintf(kconfig, "\tdefault 0x200\n"); 1175 | fprintf(kconfig, "\trange 0 65535\n"); 1176 | fprintf(kconfig, "\t---help---\n"); 1177 | fprintf(kconfig, "\t\tMaximum packet size this endpoint is capable of\n"); 1178 | fprintf(kconfig, "\t\tsending or receiving when this configuration is\n"); 1179 | fprintf(kconfig, "\t\tselected.\n"); 1180 | fprintf(kconfig, "\t\tFor isochronous endpoints, this value is used to\n"); 1181 | fprintf(kconfig, "\t\treserve the bus time in the schedule, required for the\n"); 1182 | fprintf(kconfig, "\t\tper-(micro)frame data payloads. The pipe may, on an\n"); 1183 | fprintf(kconfig, "\t\tongoing basis, actually use less bandwidth than that\n"); 1184 | fprintf(kconfig, "\t\treserved. The device reports, if necessary, the actual\n"); 1185 | fprintf(kconfig, "\t\tbandwidth used via its normal, non-USB defined\n"); 1186 | fprintf(kconfig, "\t\tmechanisms.\n"); 1187 | fprintf(kconfig, "\t\tFor all endpoints, bits 10..0 specify the maximum\n"); 1188 | fprintf(kconfig, "\t\tpacket size (in bytes).\n"); 1189 | fprintf(kconfig, "\t\tFor high-speed isochronous and interrupt endpoints:\n"); 1190 | fprintf(kconfig, "\t\tBits 12..11 specify the number of additional transaction\n"); 1191 | fprintf(kconfig, "\t\topportunities per microframe:\n"); 1192 | fprintf(kconfig, "\t\t00 = None (1 transaction per microframe)\n"); 1193 | fprintf(kconfig, "\t\t01 = 1 additional (2 per microframe)\n"); 1194 | fprintf(kconfig, "\t\t10 = 2 additional (3 per microframe)\n"); 1195 | fprintf(kconfig, "\t\t11 = Reserved\n"); 1196 | fprintf(kconfig, "\t\tBits 15..13 are reserved and must be set to zero.\n"); 1197 | fprintf(kconfig, "\t\tRefer to Chapter 5 for more information.\n"); 1198 | 1199 | 1200 | fprintf(kconfig, "config USB_CONFIG%d_INTERFACE%d_EP%d_INTERVAL\n",i,j, k); 1201 | fprintf(kconfig, "\tint \"Interval\"\n"); 1202 | fprintf(kconfig, "\tdefault 0\n"); 1203 | fprintf(kconfig, "\trange 0 255\n"); 1204 | fprintf(kconfig, "\t---help---\n"); 1205 | fprintf(kconfig, "\t\tInterval for polling endpoint for data transfers.\n"); 1206 | fprintf(kconfig, "\t\tExpressed in frames or microframes depending on the\n"); 1207 | fprintf(kconfig, "\t\tdevice operating speed (i.e., either 1 millisecond or\n"); 1208 | fprintf(kconfig, "\t\t125 µs units).\n"); 1209 | fprintf(kconfig, "\t\tFor full-/high-speed isochronous endpoints, this value\n"); 1210 | fprintf(kconfig, "\t\tmust be in the range from 1 to 16. The bInterval value\n"); 1211 | fprintf(kconfig, "\t\tis used as the exponent for a 2bInterval-1 value; e.g., a\n"); 1212 | fprintf(kconfig, "\t\tbInterval of 4 means a period of 8 (24-1).\n"); 1213 | fprintf(kconfig, "\t\tFor full-/low-speed interrupt endpoints, the value of\n"); 1214 | fprintf(kconfig, "\t\tthis field may be from 1 to 255.\n"); 1215 | fprintf(kconfig, "\t\tFor high-speed interrupt endpoints, the bInterval value\n"); 1216 | fprintf(kconfig, "\t\tis used as the exponent for a 2bInterval-1 value; e.g., a\n"); 1217 | fprintf(kconfig, "\t\tbInterval of 4 means a period of 8 (24-1). This value\n"); 1218 | fprintf(kconfig, "\t\tmust be from 1 to 16.\n"); 1219 | fprintf(kconfig, "\t\tFor high-speed bulk/control OUT endpoints, the\n"); 1220 | fprintf(kconfig, "\t\tbInterval must specify the maximum NAK rate of the\n"); 1221 | fprintf(kconfig, "\t\tendpoint. A value of 0 indicates the endpoint never\n"); 1222 | fprintf(kconfig, "\t\tNAKs. Other values indicate at most 1 NAK each\n"); 1223 | fprintf(kconfig, "\t\tbInterval number of microframes. This value must be\n"); 1224 | fprintf(kconfig, "\t\tin the range from 0 to 255.\n"); 1225 | fprintf(kconfig, "\t\tSee Chapter 5 description of periods for more detail.\n"); 1226 | 1227 | 1228 | fprintf(kconfig,"endmenu\n"); 1229 | fprintf(kconfig,"endif\n\n"); 1230 | } 1231 | 1232 | 1233 | 1234 | fprintf(kconfig,"endmenu\n"); 1235 | fprintf(kconfig,"endif\n\n"); 1236 | } 1237 | fprintf(kconfig,"endmenu\n\n"); 1238 | fprintf(kconfig,"endif\n\n"); 1239 | 1240 | } 1241 | fclose(kconfig); 1242 | } 1243 | 1244 | 1245 | 1246 | void generate_files(int max_conf, int max_if, int max_ep, int max_string) 1247 | { 1248 | 1249 | FILE *header; 1250 | header = fopen("usbconf.h", "w"); 1251 | 1252 | fprintf(header, "#include \"config.h\"\n#include \"usb.h\"\n\n"); 1253 | 1254 | for(int i =0; i < max_conf; i++){ 1255 | fprintf(header, "#if CONFIG_USB_DEVICE_NCONFIGS > %d\n", i); 1256 | fprintf(header, "struct usb_conf%d_s {\n", i); 1257 | fprintf(header, "\tstruct usb_configuration_descriptor config;\n"); 1258 | for(int j = 0; j < max_if;j++){ 1259 | fprintf(header, "#if CONFIG_USB_CONFIG%d_NINTERFACES > %d\n", i, j); 1260 | fprintf(header, "\tstruct usb_interface_descriptor interface%d;\n", j); 1261 | fprintf(header, "\tstruct usb_endpoint_descriptor interface%d_eps[CONFIG_USB_CONFIG%d_INTERFACE%d_NEPS];\n", j, i , j); 1262 | fprintf(header, "#endif\n"); 1263 | } 1264 | fprintf(header,"} __attribute__ ((packed));\n\n"); 1265 | fprintf(header, "#endif\n"); 1266 | } 1267 | fprintf(header, "\n\n\n"); 1268 | fprintf(header, "struct usb_config_table_s {\n"); 1269 | fprintf(header, "\tvoid *config;\n"); 1270 | fprintf(header, "\tunsigned int len;\n"); 1271 | fprintf(header, "};\n\n"); 1272 | 1273 | fprintf(header, "static char *usb_string_tab[] = {\n"); 1274 | for(int i=1; i < 32; i++){ 1275 | fprintf(header, "#if CONFIG_USB_NSTRINGS >= %d\n",i); 1276 | fprintf(header, "\tCONFIG_USB_STRING_INDEX_%d,\n",i); 1277 | fprintf(header, "#endif\n"); 1278 | } 1279 | fprintf(header, "};\n\n"); 1280 | 1281 | 1282 | // fprintf(header, "#include \n#include \"usbconf.h\"\n\n"); 1283 | 1284 | fprintf(header, "struct usb_device_descriptor device_desc = {\n"); 1285 | fprintf(header, "\t.bLength = sizeof(struct usb_device_descriptor),\n"); 1286 | fprintf(header, "\t.bDescriptorType=1,\n"); 1287 | fprintf(header, "\t.bcdUSB=CONFIG_USB_DEVICE_USB_VERSION,\n"); 1288 | fprintf(header, "\t.bDeviceClass=CONFIG_USB_DEVICE_CLASS_VAL,\n"); 1289 | fprintf(header, "\t.bDeviceSubClass=CONFIG_USB_DEVICE_SUBCLASS,\n"); 1290 | fprintf(header, "\t.bDeviceProtocol=CONFIG_USB_DEVICE_PROTOCOL,\n"); 1291 | fprintf(header, "\t.bMaxPacketSize0=CONFIG_USB_DEVICE_MXPACKETSIZE,\n"); 1292 | fprintf(header, "\t.idVendor=CONFIG_USB_DEVICE_VENDORID,\n"); 1293 | fprintf(header, "\t.idProduct=CONFIG_USB_DEVICE_PRODUCTID,\n"); 1294 | fprintf(header, "\t.bcdDevice=CONFIG_USB_DEVICE_DEVICEID,\n"); 1295 | fprintf(header, "\t.iManufacturer=CONFIG_USB_DEVICE_IMFGR,\n"); 1296 | fprintf(header, "\t.iProduct=CONFIG_USB_DEVICE_IPRODUCT,\n"); 1297 | fprintf(header, "\t.iSerialNumber=CONFIG_USB_DEVICE_ISERNO,\n"); 1298 | fprintf(header, "\t.bNumConfigurations=CONFIG_USB_DEVICE_NCONFIGS,\n"); 1299 | fprintf(header, "};\n\n"); 1300 | 1301 | 1302 | fprintf(header, "struct usb_qualifier_descriptor qualifier_desc = {\n"); 1303 | fprintf(header, "\t.bLength = sizeof(struct usb_qualifier_descriptor),\n"); 1304 | fprintf(header, "\t.bDescriptorType=6,\n"); 1305 | fprintf(header, "\t.bcdUSB=CONFIG_USB_DEVICE_USB_VERSION,\n"); 1306 | fprintf(header, "\t.bDeviceClass=CONFIG_USB_DEVICE_CLASS_VAL,\n"); 1307 | fprintf(header, "\t.bDeviceSubClass=CONFIG_USB_DEVICE_SUBCLASS,\n"); 1308 | fprintf(header, "\t.bDeviceProtocol=CONFIG_USB_DEVICE_PROTOCOL,\n"); 1309 | fprintf(header, "\t.bMaxPacketSize0=CONFIG_USB_DEVICE_MXPACKETSIZE,\n"); 1310 | fprintf(header, "\t.bNumConfigurations=CONFIG_USB_DEVICE_NCONFIGS,\n"); 1311 | fprintf(header, "\t.bReserved=0,\n"); 1312 | fprintf(header, "};\n\n"); 1313 | 1314 | 1315 | 1316 | fprintf(header, "unsigned char *string_tab[] = {\n"); 1317 | fprintf(header, "\tNULL,\n"); 1318 | for(int i=0; i< max_string; i++){ 1319 | fprintf(header, "#if CONFIG_USB_NSTRINGS > %d\n", i); 1320 | fprintf(header, "\tCONFIG_USB_STRING_INDEX_%d,\n",i+1); 1321 | fprintf(header, "#endif\n"); 1322 | } 1323 | fprintf(header, "};\n\n"); 1324 | 1325 | 1326 | 1327 | 1328 | for(int i =0; i < max_conf; i++){ 1329 | fprintf(header, "#if CONFIG_USB_DEVICE_NCONFIGS > %d\n", i); 1330 | fprintf(header, "static struct usb_conf%d_s conf%d = {\n", i, i); 1331 | fprintf(header, "\t.config = {\n"); 1332 | fprintf(header, "\t\t.bLength = sizeof(struct usb_configuration_descriptor),\n"); 1333 | fprintf(header, "\t\t.bDescriptorType = 2,\n"); 1334 | fprintf(header, "\t\t.wTotalLength = sizeof(struct usb_conf%d_s),\n", i); 1335 | fprintf(header, "\t\t.bNumInterfaces = CONFIG_USB_CONFIG%d_NINTERFACES,\n", i); 1336 | fprintf(header, "\t\t.bConfigurationValue=CONFIG_USB_CONFIG%d_CFGVALUE,\n", i); 1337 | fprintf(header, "\t\t.iConfiguration=CONFIG_USB_CONFIG0_ICFG,\n"); 1338 | fprintf(header, "\t\t.bmAttributes = 0\n"); 1339 | for(int tmp = 0; tmp < 8; tmp++){ 1340 | fprintf(header, "#ifdef CONFIG_USB_CONFIG%d_ATTR_D%d\n", i, tmp); 1341 | fprintf(header, "\t\t| %d\n", (1 << tmp)); 1342 | fprintf(header, "#endif\n"); 1343 | } 1344 | fprintf(header, "\t\t,\n"); 1345 | fprintf(header, "\t\t.bMaxPower=CONFIG_USB_CONFIG%d_MXPOWER\n", i); 1346 | fprintf(header, "\t},\n"); 1347 | 1348 | 1349 | for(int j=0; j %d\n", i, j); 1351 | fprintf(header, "\t.interface%d = {\n", j); 1352 | fprintf(header, "\t\t.bLength=sizeof(struct usb_interface_descriptor),\n"); 1353 | fprintf(header, "\t\t.bDescriptorType=4,\n"); 1354 | fprintf(header, "\t\t.bInterfaceNumber=CONFIG_USB_CONFIG%d_INTERFACE%d_IFNO,\n", i, j); 1355 | fprintf(header, "\t\t.bAlternateSetting=CONFIG_USB_CONFIG%d_INTERFACE%d_ALT,\n", i, j); 1356 | fprintf(header, "\t\t.bNumEndpoints=CONFIG_USB_CONFIG%d_INTERFACE%d_NEPS,\n", i, j); 1357 | fprintf(header, "\t\t.bInterfaceClass=CONFIG_USB_CONFIG%d_INTERFACE%d_CLASS_VAL,\n",i,j); 1358 | fprintf(header, "\t\t.bInterfaceSubClass=CONFIG_USB_CONFIG%d_INTERFACE%d_SUBCLASS_VAL,\n", i, j); 1359 | fprintf(header, "\t\t.bInterfaceProtocol=CONFIG_USB_CONFIG%d_INTERFACE%d_PROTOCOL_VAL,\n", i, j); 1360 | fprintf(header, "\t\t.iInterface=CONFIG_USB_CONFIG%d_INTERFACE%d_IIF,\n", i, j); 1361 | fprintf(header, "\t},\n"); 1362 | 1363 | for(int k=0; k < max_ep; k++){ 1364 | fprintf(header, "#if CONFIG_USB_CONFIG%d_INTERFACE%d_NEPS > %d\n", i, j, k); 1365 | 1366 | fprintf(header, "\t.interface%d_eps[%d] = {\n",j, k); 1367 | fprintf(header, "\t\t.bLength=sizeof(struct usb_endpoint_descriptor),\n"); 1368 | fprintf(header, "\t\t.bDescriptorType=5,\n"); 1369 | fprintf(header, "\t\t.bEndpointAddress=CONFIG_USB_CONFIG%d_INTERFACE%d_EP%d_ADDR,\n", i, j, k); 1370 | fprintf(header, "\t\t.bmAttributes=(CONFIG_USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_NONE << 6)\n\t\t | (CONFIG_USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_USAGE_TYPE_VAL << 4)\n\t\t | (CONFIG_USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_SYNC_TYPE_VAL << 2)\n\t\t | CONFIG_USB_CONFIG%d_INTERFACE%d_EP%d_ATTR_XFER_TYPE_VAL,\n", i,j,k,i,j,k,i,j,k,i,j,k); 1371 | fprintf(header, "\t\t.wMaxPacketSize=CONFIG_USB_CONFIG%d_INTERFACE%d_EP%d_MXPACKETSIZE,\n",i ,j , k); 1372 | fprintf(header, "\t\t.bInterval=CONFIG_USB_CONFIG%d_INTERFACE%d_EP%d_INTERVAL,\n", i,j,k); 1373 | fprintf(header, "\t},\n"); 1374 | 1375 | fprintf(header, "#endif\n"); 1376 | } 1377 | fprintf(header, "#endif\n"); 1378 | } 1379 | 1380 | 1381 | //fprintf(header, "\t.,\n"); 1382 | 1383 | 1384 | fprintf(header, "};\n"); 1385 | fprintf(header, "#endif\n\n"); 1386 | } 1387 | 1388 | fprintf(header, "\n\n\n"); 1389 | fprintf(header, "struct usb_config_table_s usb_config_table[] = {\n"); 1390 | for(int i=0; i< max_conf; i++){ 1391 | fprintf(header, "#if CONFIG_USB_DEVICE_NCONFIGS > %d\n", i); 1392 | fprintf(header, "\t{\n"); 1393 | fprintf(header, "\t\t.config = &conf%d,\n", i); 1394 | fprintf(header, "\t\t.len = sizeof(conf%d)\n", i); 1395 | fprintf(header, "\t},\n"); 1396 | fprintf(header, "#endif\n"); 1397 | } 1398 | fprintf(header, "\t{\n"); 1399 | fprintf(header, "\t\t.config = NULL,\n"); 1400 | fprintf(header, "\t\t.len = 0\n"); 1401 | fprintf(header, "\t}\n"); 1402 | 1403 | fprintf(header, "};\n"); 1404 | fclose(header); 1405 | } 1406 | 1407 | int main() 1408 | { 1409 | generate_kconfig(2, 32, 32, 32); 1410 | //generate_headers(2, 32, 32, 32); 1411 | generate_files(2, 32, 32, 32); 1412 | } 1413 | -------------------------------------------------------------------------------- /tools/genconfig/generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cat .config | grep -v "^#" |egrep -xv "[[:space:]]*" > tmpconf 3 | while read -r line; do echo "#define "$line | sed 's/=y//g' | sed 's/=/ /g';done < tmpconf > config.h 4 | rm -f tmpconf 5 | -------------------------------------------------------------------------------- /tools/genconfig/genpy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "usbconf.h" 6 | 7 | 8 | int main() 9 | { 10 | FILE *py; 11 | int offset=0; 12 | unsigned char *buf, *pnt; 13 | buf = malloc(4096); 14 | pnt = buf; 15 | 16 | py = fopen("config.py", "w"); 17 | fprintf(py, "# Generated with genconfig (tools/genconfig)\n"); 18 | fprintf(py, "descriptor_map = {\n"); 19 | 20 | fprintf(py, "\t0x01: {0: (%d, %ld)},\n",offset, sizeof(device_desc)); 21 | memcpy(buf + offset, &device_desc, sizeof(device_desc)); 22 | offset += sizeof(device_desc); 23 | 24 | fprintf(py, "\t0x02: {0: (%d, %d)},\n",offset, usb_config_table[0].len); 25 | memcpy(buf + offset, usb_config_table[0].config, usb_config_table[0].len); 26 | offset += usb_config_table[0].len; 27 | 28 | fprintf(py, "\t0x03: {\n"); 29 | fprintf(py, "\t\t 0: (%d, 4),\n", offset); 30 | 31 | buf[offset++] = 4; 32 | buf[offset++] = 3; 33 | buf[offset++] = CONFIG_USB_LANG_VAL & 0xff; 34 | buf[offset++] = (CONFIG_USB_LANG_VAL >> 8) & 0xff; 35 | 36 | for(int i =1; i < CONFIG_USB_NSTRINGS + 1; i++){ 37 | fprintf(py,"\t\t %d: (%d, %ld),\n" ,i, offset, sizeof(struct usb_string_descriptor) + strlen(string_tab[i])*2); 38 | 39 | buf[offset++] = sizeof(struct usb_string_descriptor) + strlen(string_tab[i])*2; 40 | buf[offset++] = 3; 41 | for(int j =0; j < strlen(string_tab[i]); j++){ 42 | buf[offset++] = string_tab[i][j]; 43 | buf[offset++]=0; 44 | } 45 | } 46 | fprintf(py, "\t},\n"); 47 | fprintf(py,"\t0x06: {0: (%d, %ld)},\n", offset, sizeof(qualifier_desc)); 48 | memcpy(buf + offset, &qualifier_desc, sizeof(qualifier_desc)); 49 | offset += sizeof(qualifier_desc); 50 | 51 | /*debug qualifier*/ 52 | fprintf(py, "\t0x0a: {0: (%d, %d)},\n", offset, 2); 53 | buf[offset++] = 2; 54 | buf[offset++] = USB_DESC_TYPE_DEBUG; 55 | 56 | fprintf(py, "}\n\n"); 57 | 58 | 59 | printf("total = %d\n", offset); 60 | 61 | fprintf(py, "rom_init = [ "); 62 | for(int i=0; i < offset; i++){ 63 | if(i%8 == 0) 64 | fprintf(py,"\n\t"); 65 | fprintf(py, "0x%02x, ", buf[i]); 66 | } 67 | fprintf(py, "\n]\n"); 68 | 69 | free(buf); 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /tools/genconfig/usb.h: -------------------------------------------------------------------------------- 1 | #ifndef __USB_DESC_H_ 2 | #define __USB_DESC_H_ 3 | 4 | 5 | typedef unsigned char u8; 6 | typedef unsigned short u16; 7 | 8 | 9 | #define USB_REQ_DIR_MASK (1 << 7) /* Bit 7=1: Direction bit */ 10 | #define USB_REQ_DIR_IN (1 << 7) /* Bit 7=1: Device-to-host */ 11 | #define USB_REQ_DIR_OUT (0 << 7) /* Bit 7=0: Host-to-device */ 12 | #define USB_REQ_ISIN(type) (((type) & USB_REQ_DIR_MASK) != 0) 13 | #define USB_REQ_ISOUT(type) (((type) & USB_REQ_DIR_MASK) == 0) 14 | 15 | /* Control Setup Packet. Byte 1 = Standard Request Codes */ 16 | 17 | #define USB_REQ_GETSTATUS (0x00) 18 | #define USB_REQ_CLEARFEATURE (0x01) 19 | #define USB_REQ_SETFEATURE (0x03) 20 | #define USB_REQ_SETADDRESS (0x05) 21 | #define USB_REQ_GETDESCRIPTOR (0x06) 22 | #define USB_REQ_SETDESCRIPTOR (0x07) 23 | #define USB_REQ_GETCONFIGURATION (0x08) 24 | #define USB_REQ_SETCONFIGURATION (0x09) 25 | #define USB_REQ_GETINTERFACE (0x0a) 26 | #define USB_REQ_SETINTERFACE (0x0b) 27 | #define USB_REQ_SYNCHFRAME (0x0c) 28 | 29 | #define USB_REQ_SETENCRYPTION (0x0d) /* Wireless USB */ 30 | #define USB_REQ_GETENCRYPTION (0x0e) 31 | #define USB_REQ_SETHANDSHAKE (0x0f) 32 | #define USB_REQ_GETHANDSHAKE (0x10) 33 | #define USB_REQ_SETCONNECTION (0x11) 34 | #define USB_REQ_SETSECURITYDATA (0x12) 35 | #define USB_REQ_GETSECURITYDATA (0x13) 36 | #define USB_REQ_SETWUSBDATA (0x14) 37 | #define USB_REQ_LOOPBACKDATAWRITE (0x15) 38 | #define USB_REQ_LOOPBACKDATAREAD (0x16) 39 | #define USB_REQ_SETINTERFACEDS (0x17) 40 | 41 | /* Descriptor types */ 42 | 43 | #define USB_DESC_TYPE_DEVICE (0x01) 44 | #define USB_DESC_TYPE_CONFIG (0x02) 45 | #define USB_DESC_TYPE_STRING (0x03) 46 | #define USB_DESC_TYPE_INTERFACE (0x04) 47 | #define USB_DESC_TYPE_ENDPOINT (0x05) 48 | #define USB_DESC_TYPE_DEVICEQUALIFIER (0x06) 49 | #define USB_DESC_TYPE_OTHERSPEEDCONFIG (0x07) 50 | #define USB_DESC_TYPE_INTERFACEPOWER (0x08) 51 | #define USB_DESC_TYPE_OTG (0x09) 52 | #define USB_DESC_TYPE_DEBUG (0x0a) 53 | #define USB_DESC_TYPE_INTERFACEASSOCIATION (0x0b) 54 | #define USB_DESC_TYPE_SECURITY (0x0c) 55 | #define USB_DESC_TYPE_KEY (0x0d) 56 | #define USB_DESC_TYPE_ENCRYPTION_TYPE (0x0e) 57 | #define USB_DESC_TYPE_BOS (0x0f) 58 | #define USB_DESC_TYPE_DEVICECAPABILITY (0x10) 59 | #define USB_DESC_TYPE_WIRELESS_ENDPOINTCOMP (0x11) 60 | #define USB_DESC_TYPE_CSDEVICE (0x21) 61 | #define USB_DESC_TYPE_CSCONFIG (0x22) 62 | #define USB_DESC_TYPE_CSSTRING (0x23) 63 | #define USB_DESC_TYPE_CSINTERFACE (0x24) 64 | #define USB_DESC_TYPE_CSENDPOINT (0x25) 65 | 66 | 67 | 68 | 69 | 70 | 71 | struct usb_endpoint_descriptor { 72 | u8 bLength; 73 | u8 bDescriptorType; /* 0x5 */ 74 | u8 bEndpointAddress; 75 | u8 bmAttributes; 76 | u16 wMaxPacketSize; 77 | u8 bInterval; 78 | } __attribute__ ((packed)); 79 | 80 | struct usb_interface_descriptor { 81 | u8 bLength; 82 | u8 bDescriptorType; /* 0x04 */ 83 | u8 bInterfaceNumber; 84 | u8 bAlternateSetting; 85 | u8 bNumEndpoints; 86 | u8 bInterfaceClass; 87 | u8 bInterfaceSubClass; 88 | u8 bInterfaceProtocol; 89 | u8 iInterface; 90 | } __attribute__ ((packed)); 91 | 92 | struct usb_configuration_descriptor { 93 | u8 bLength; 94 | u8 bDescriptorType; /* 0x2 */ 95 | u16 wTotalLength; 96 | u8 bNumInterfaces; 97 | u8 bConfigurationValue; 98 | u8 iConfiguration; 99 | u8 bmAttributes; 100 | u8 bMaxPower; 101 | } __attribute__ ((packed)); 102 | 103 | struct usb_device_descriptor { 104 | u8 bLength; 105 | u8 bDescriptorType; /* 0x01 */ 106 | u16 bcdUSB; 107 | u8 bDeviceClass; 108 | u8 bDeviceSubClass; 109 | u8 bDeviceProtocol; 110 | u8 bMaxPacketSize0; 111 | u16 idVendor; 112 | u16 idProduct; 113 | u16 bcdDevice; 114 | u8 iManufacturer; 115 | u8 iProduct; 116 | u8 iSerialNumber; 117 | u8 bNumConfigurations; 118 | } __attribute__ ((packed)); 119 | 120 | 121 | 122 | struct usb_string_descriptor { 123 | u8 bLength; 124 | u8 bDescriptorType; 125 | u16 wData[0]; 126 | } __attribute__ ((packed)); 127 | 128 | struct usb_generic_descriptor { 129 | u8 bLength; 130 | u8 bDescriptorType; 131 | u8 bDescriptorSubtype; 132 | } __attribute__ ((packed)); 133 | 134 | struct usb_qualifier_descriptor { 135 | u8 bLength; 136 | u8 bDescriptorType; /* 0x06 */ 137 | u16 bcdUSB; 138 | u8 bDeviceClass; 139 | u8 bDeviceSubClass; 140 | u8 bDeviceProtocol; 141 | u8 bMaxPacketSize0; 142 | u8 bNumConfigurations; 143 | u8 bReserved; 144 | } __attribute__ ((packed)); 145 | 146 | 147 | #endif 148 | --------------------------------------------------------------------------------