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