github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/usb.go (about) 1 //go:build sam || nrf52840 || rp2040 2 3 package machine 4 5 import ( 6 "machine/usb" 7 "machine/usb/descriptor" 8 9 "errors" 10 ) 11 12 type USBDevice struct { 13 initcomplete bool 14 InitEndpointComplete bool 15 } 16 17 var ( 18 USBDev = &USBDevice{} 19 USBCDC Serialer 20 ) 21 22 type Serialer interface { 23 WriteByte(c byte) error 24 Write(data []byte) (n int, err error) 25 Configure(config UARTConfig) error 26 Buffered() int 27 ReadByte() (byte, error) 28 DTR() bool 29 RTS() bool 30 } 31 32 var usbDescriptor descriptor.Descriptor 33 34 func usbVendorID() uint16 { 35 if usb.VendorID != 0 { 36 return usb.VendorID 37 } 38 39 return usb_VID 40 } 41 42 func usbProductID() uint16 { 43 if usb.ProductID != 0 { 44 return usb.ProductID 45 } 46 47 return usb_PID 48 } 49 50 func usbManufacturer() string { 51 if usb.Manufacturer != "" { 52 return usb.Manufacturer 53 } 54 55 return usb_STRING_MANUFACTURER 56 } 57 58 func usbProduct() string { 59 if usb.Product != "" { 60 return usb.Product 61 } 62 63 return usb_STRING_PRODUCT 64 } 65 66 func usbSerial() string { 67 if usb.Serial != "" { 68 return usb.Serial 69 } 70 return "" 71 } 72 73 // strToUTF16LEDescriptor converts a utf8 string into a string descriptor 74 // note: the following code only converts ascii characters to UTF16LE. In order 75 // to do a "proper" conversion, we would need to pull in the 'unicode/utf16' 76 // package, which at the time this was written added 512 bytes to the compiled 77 // binary. 78 func strToUTF16LEDescriptor(in string, out []byte) { 79 out[0] = byte(len(out)) 80 out[1] = descriptor.TypeString 81 for i, rune := range in { 82 out[(i<<1)+2] = byte(rune) 83 out[(i<<1)+3] = 0 84 } 85 return 86 } 87 88 const cdcLineInfoSize = 7 89 90 var ( 91 ErrUSBReadTimeout = errors.New("USB read timeout") 92 ErrUSBBytesRead = errors.New("USB invalid number of bytes read") 93 ErrUSBBytesWritten = errors.New("USB invalid number of bytes written") 94 ) 95 96 var ( 97 usbEndpointDescriptors [usb.NumberOfEndpoints]descriptor.Device 98 99 isEndpointHalt = false 100 isRemoteWakeUpEnabled = false 101 102 usbConfiguration uint8 103 usbSetInterface uint8 104 ) 105 106 //go:align 4 107 var udd_ep_control_cache_buffer [256]uint8 108 109 //go:align 4 110 var udd_ep_in_cache_buffer [usb.NumberOfEndpoints][64]uint8 111 112 //go:align 4 113 var udd_ep_out_cache_buffer [usb.NumberOfEndpoints][64]uint8 114 115 // usb_trans_buffer max size is 255 since that is max size 116 // for a descriptor (bLength is 1 byte), and the biggest use 117 // for this buffer is to transmit string descriptors. If 118 // this buffer is used for new purposes in future the length 119 // must be revisited. 120 var usb_trans_buffer [255]uint8 121 122 var ( 123 usbTxHandler [usb.NumberOfEndpoints]func() 124 usbRxHandler [usb.NumberOfEndpoints]func([]byte) 125 usbSetupHandler [usb.NumberOfInterfaces]func(usb.Setup) bool 126 127 endPoints = []uint32{ 128 usb.CONTROL_ENDPOINT: usb.ENDPOINT_TYPE_CONTROL, 129 usb.CDC_ENDPOINT_ACM: (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn), 130 usb.CDC_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut), 131 usb.CDC_ENDPOINT_IN: (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn), 132 usb.HID_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt In 133 usb.HID_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Interrupt Out 134 usb.MIDI_ENDPOINT_IN: (usb.ENDPOINT_TYPE_DISABLE), // Bulk In 135 usb.MIDI_ENDPOINT_OUT: (usb.ENDPOINT_TYPE_DISABLE), // Bulk Out 136 } 137 ) 138 139 // sendDescriptor creates and sends the various USB descriptor types that 140 // can be requested by the host. 141 func sendDescriptor(setup usb.Setup) { 142 switch setup.WValueH { 143 case descriptor.TypeConfiguration: 144 sendUSBPacket(0, usbDescriptor.Configuration, setup.WLength) 145 return 146 case descriptor.TypeDevice: 147 usbDescriptor.Configure(usbVendorID(), usbProductID()) 148 sendUSBPacket(0, usbDescriptor.Device, setup.WLength) 149 return 150 151 case descriptor.TypeString: 152 switch setup.WValueL { 153 case 0: 154 usb_trans_buffer[0] = 0x04 155 usb_trans_buffer[1] = 0x03 156 usb_trans_buffer[2] = 0x09 157 usb_trans_buffer[3] = 0x04 158 sendUSBPacket(0, usb_trans_buffer[:4], setup.WLength) 159 160 case usb.IPRODUCT: 161 b := usb_trans_buffer[:(len(usbProduct())<<1)+2] 162 strToUTF16LEDescriptor(usbProduct(), b) 163 sendUSBPacket(0, b, setup.WLength) 164 165 case usb.IMANUFACTURER: 166 b := usb_trans_buffer[:(len(usbManufacturer())<<1)+2] 167 strToUTF16LEDescriptor(usbManufacturer(), b) 168 sendUSBPacket(0, b, setup.WLength) 169 170 case usb.ISERIAL: 171 sz := len(usbSerial()) 172 if sz == 0 { 173 SendZlp() 174 } else { 175 b := usb_trans_buffer[:(sz<<1)+2] 176 strToUTF16LEDescriptor(usbSerial(), b) 177 sendUSBPacket(0, b, setup.WLength) 178 } 179 } 180 return 181 case descriptor.TypeHIDReport: 182 if h, ok := usbDescriptor.HID[setup.WIndex]; ok { 183 sendUSBPacket(0, h, setup.WLength) 184 return 185 } 186 case descriptor.TypeDeviceQualifier: 187 // skip 188 default: 189 } 190 191 // do not know how to handle this message, so return zero 192 SendZlp() 193 return 194 } 195 196 func handleStandardSetup(setup usb.Setup) bool { 197 switch setup.BRequest { 198 case usb.GET_STATUS: 199 usb_trans_buffer[0] = 0 200 usb_trans_buffer[1] = 0 201 202 if setup.BmRequestType != 0 { // endpoint 203 if isEndpointHalt { 204 usb_trans_buffer[0] = 1 205 } 206 } 207 208 sendUSBPacket(0, usb_trans_buffer[:2], setup.WLength) 209 return true 210 211 case usb.CLEAR_FEATURE: 212 if setup.WValueL == 1 { // DEVICEREMOTEWAKEUP 213 isRemoteWakeUpEnabled = false 214 } else if setup.WValueL == 0 { // ENDPOINTHALT 215 isEndpointHalt = false 216 } 217 SendZlp() 218 return true 219 220 case usb.SET_FEATURE: 221 if setup.WValueL == 1 { // DEVICEREMOTEWAKEUP 222 isRemoteWakeUpEnabled = true 223 } else if setup.WValueL == 0 { // ENDPOINTHALT 224 isEndpointHalt = true 225 } 226 SendZlp() 227 return true 228 229 case usb.SET_ADDRESS: 230 return handleUSBSetAddress(setup) 231 232 case usb.GET_DESCRIPTOR: 233 sendDescriptor(setup) 234 return true 235 236 case usb.SET_DESCRIPTOR: 237 return false 238 239 case usb.GET_CONFIGURATION: 240 usb_trans_buffer[0] = usbConfiguration 241 sendUSBPacket(0, usb_trans_buffer[:1], setup.WLength) 242 return true 243 244 case usb.SET_CONFIGURATION: 245 if setup.BmRequestType&usb.REQUEST_RECIPIENT == usb.REQUEST_DEVICE { 246 for i := 1; i < len(endPoints); i++ { 247 initEndpoint(uint32(i), endPoints[i]) 248 } 249 250 usbConfiguration = setup.WValueL 251 USBDev.InitEndpointComplete = true 252 253 SendZlp() 254 return true 255 } else { 256 return false 257 } 258 259 case usb.GET_INTERFACE: 260 usb_trans_buffer[0] = usbSetInterface 261 sendUSBPacket(0, usb_trans_buffer[:1], setup.WLength) 262 return true 263 264 case usb.SET_INTERFACE: 265 usbSetInterface = setup.WValueL 266 267 SendZlp() 268 return true 269 270 default: 271 return true 272 } 273 } 274 275 func EnableCDC(txHandler func(), rxHandler func([]byte), setupHandler func(usb.Setup) bool) { 276 if len(usbDescriptor.Device) == 0 { 277 usbDescriptor = descriptor.CDC 278 } 279 // Initialization of endpoints is required even for non-CDC 280 ConfigureUSBEndpoint(usbDescriptor, 281 []usb.EndpointConfig{ 282 { 283 Index: usb.CDC_ENDPOINT_ACM, 284 IsIn: true, 285 Type: usb.ENDPOINT_TYPE_INTERRUPT, 286 }, 287 { 288 Index: usb.CDC_ENDPOINT_OUT, 289 IsIn: false, 290 Type: usb.ENDPOINT_TYPE_BULK, 291 RxHandler: rxHandler, 292 }, 293 { 294 Index: usb.CDC_ENDPOINT_IN, 295 IsIn: true, 296 Type: usb.ENDPOINT_TYPE_BULK, 297 TxHandler: txHandler, 298 }, 299 }, 300 []usb.SetupConfig{ 301 { 302 Index: usb.CDC_ACM_INTERFACE, 303 Handler: setupHandler, 304 }, 305 }) 306 } 307 308 func ConfigureUSBEndpoint(desc descriptor.Descriptor, epSettings []usb.EndpointConfig, setup []usb.SetupConfig) { 309 usbDescriptor = desc 310 311 for _, ep := range epSettings { 312 if ep.IsIn { 313 endPoints[ep.Index] = uint32(ep.Type | usb.EndpointIn) 314 if ep.TxHandler != nil { 315 usbTxHandler[ep.Index] = ep.TxHandler 316 } 317 } else { 318 endPoints[ep.Index] = uint32(ep.Type | usb.EndpointOut) 319 if ep.RxHandler != nil { 320 usbRxHandler[ep.Index] = ep.RxHandler 321 } 322 } 323 } 324 325 for _, s := range setup { 326 usbSetupHandler[s.Index] = s.Handler 327 } 328 }