github.com/f-secure-foundry/tamago@v0.0.0-20220307101044-d73fcdd7f11b/soc/imx6/usb/setup.go (about) 1 // USB device mode support 2 // https://github.com/f-secure-foundry/tamago 3 // 4 // Copyright (c) F-Secure Corporation 5 // https://foundry.f-secure.com 6 // 7 // Use of this source code is governed by the license 8 // that can be found in the LICENSE file. 9 10 package usb 11 12 import ( 13 "encoding/binary" 14 "fmt" 15 16 "github.com/f-secure-foundry/tamago/internal/reg" 17 ) 18 19 // Standard request codes (p279, Table 9-4, USB2.0) 20 const ( 21 GET_STATUS = 0 22 CLEAR_FEATURE = 1 23 SET_FEATURE = 3 24 SET_ADDRESS = 5 25 GET_DESCRIPTOR = 6 26 SET_DESCRIPTOR = 7 27 GET_CONFIGURATION = 8 28 SET_CONFIGURATION = 9 29 GET_INTERFACE = 10 30 SET_INTERFACE = 11 31 SYNCH_FRAME = 12 32 ) 33 34 // Descriptor types (p279, Table 9-5, USB2.0) 35 const ( 36 DEVICE = 1 37 CONFIGURATION = 2 38 STRING = 3 39 INTERFACE = 4 40 ENDPOINT = 5 41 DEVICE_QUALIFIER = 6 42 OTHER_SPEED_CONFIGURATION = 7 43 INTERFACE_POWER = 8 44 45 // Engineering Change Notices (ECN) 46 OTG = 9 47 DEBUG = 10 48 INTERFACE_ASSOCIATION = 11 49 ) 50 51 // Standard feature selectors (p280, Table 9-6, USB2.0) 52 const ( 53 ENDPOINT_HALT = 0 54 DEVICE_REMOTE_WAKEUP = 1 55 TEST_MODE = 2 56 ) 57 58 // SetupData implements 59 // p276, Table 9-2. Format of Setup Data, USB2.0. 60 type SetupData struct { 61 RequestType uint8 62 Request uint8 63 Value uint16 64 Index uint16 65 Length uint16 66 } 67 68 // swap adjusts the endianness of values written in memory by the hardware, as 69 // they do not match the expected one by Go. 70 func (s *SetupData) swap() { 71 b := make([]byte, 2) 72 73 binary.BigEndian.PutUint16(b, s.Value) 74 s.Value = binary.LittleEndian.Uint16(b) 75 } 76 77 func (hw *USB) getSetup() (setup *SetupData) { 78 setup = &SetupData{} 79 80 // p3801, 56.4.6.4.2.1 Setup Phase, IMX6ULLRM 81 82 // clear setup status 83 reg.Set(hw.setup, 0) 84 // flush EP0 IN 85 reg.Set(hw.flush, ENDPTFLUSH_FETB+0) 86 // flush EP0 OUT 87 reg.Set(hw.flush, ENDPTFLUSH_FERB+0) 88 89 *setup = hw.qh(0, OUT).Setup 90 setup.swap() 91 92 return 93 } 94 95 func (hw *USB) getDescriptor(dev *Device, setup *SetupData) (err error) { 96 bDescriptorType := setup.Value & 0xff 97 index := setup.Value >> 8 98 99 switch bDescriptorType { 100 case DEVICE: 101 err = hw.tx(0, false, trim(dev.Descriptor.Bytes(), setup.Length)) 102 case CONFIGURATION: 103 var conf []byte 104 if conf, err = dev.Configuration(index); err == nil { 105 err = hw.tx(0, false, trim(conf, setup.Length)) 106 } 107 case STRING: 108 if int(index+1) > len(dev.Strings) { 109 hw.stall(0, IN) 110 err = fmt.Errorf("invalid string descriptor index %d", index) 111 } else { 112 err = hw.tx(0, false, trim(dev.Strings[index], setup.Length)) 113 } 114 case DEVICE_QUALIFIER: 115 err = hw.tx(0, false, dev.Qualifier.Bytes()) 116 default: 117 hw.stall(0, IN) 118 err = fmt.Errorf("unsupported descriptor type: %#x", bDescriptorType) 119 } 120 121 return 122 } 123 124 func (hw *USB) handleSetup(dev *Device, setup *SetupData) (err error) { 125 if setup == nil { 126 return 127 } 128 129 if dev.Setup != nil { 130 in, ack, done, err := dev.Setup(setup) 131 132 if err != nil { 133 hw.stall(0, IN) 134 return err 135 } else if len(in) != 0 { 136 err = hw.tx(0, false, in) 137 } else if ack { 138 err = hw.ack(0) 139 } 140 141 if done || err != nil { 142 return err 143 } 144 } 145 146 switch setup.Request { 147 case GET_STATUS: 148 // no meaningful status to report for now 149 err = hw.tx(0, false, []byte{0x00, 0x00}) 150 case CLEAR_FEATURE: 151 switch setup.Value { 152 case ENDPOINT_HALT: 153 n := int(setup.Index & 0b1111) 154 dir := int(setup.Index&0b10000000) / 0b10000000 155 156 hw.reset(n, dir) 157 err = hw.ack(0) 158 default: 159 hw.stall(0, IN) 160 } 161 case SET_ADDRESS: 162 addr := uint32((setup.Value<<8)&0xff00 | (setup.Value >> 8)) 163 164 reg.Set(hw.addr, DEVICEADDR_USBADRA) 165 reg.SetN(hw.addr, DEVICEADDR_USBADR, 0x7f, addr) 166 167 err = hw.ack(0) 168 case GET_DESCRIPTOR: 169 err = hw.getDescriptor(dev, setup) 170 case GET_CONFIGURATION: 171 err = hw.tx(0, false, []byte{dev.ConfigurationValue}) 172 case SET_CONFIGURATION: 173 dev.ConfigurationValue = uint8(setup.Value >> 8) 174 err = hw.ack(0) 175 case GET_INTERFACE: 176 err = hw.tx(0, false, []byte{dev.AlternateSetting}) 177 case SET_INTERFACE: 178 dev.AlternateSetting = uint8(setup.Value >> 8) 179 err = hw.ack(0) 180 case SET_ETHERNET_PACKET_FILTER: 181 // no meaningful action for now 182 err = hw.ack(0) 183 default: 184 hw.stall(0, IN) 185 err = fmt.Errorf("unsupported request code: %#x", setup.Request) 186 } 187 188 return 189 } 190 191 func trim(buf []byte, wLength uint16) []byte { 192 if int(wLength) < len(buf) { 193 buf = buf[0:wLength] 194 } 195 196 return buf 197 }