github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/soc/nxp/usb/endpoint_handler.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 "runtime" 14 "sync" 15 16 "github.com/usbarmory/tamago/internal/reg" 17 ) 18 19 // Endpoint represents a USB 2.0 endpoint. 20 type endpoint struct { 21 sync.Mutex 22 23 bus *USB 24 desc *EndpointDescriptor 25 26 n int 27 dir int 28 29 res []byte 30 err error 31 } 32 33 func (ep *endpoint) rx() { 34 var buf []byte 35 36 buf, ep.err = ep.bus.rx(ep.n, ep.res) 37 38 if ep.err == nil && len(buf) != 0 { 39 ep.res, ep.err = ep.desc.Function(buf, ep.err) 40 } 41 } 42 43 func (ep *endpoint) tx() { 44 ep.res, ep.err = ep.desc.Function(nil, ep.err) 45 46 if ep.err == nil && len(ep.res) != 0 { 47 ep.err = ep.bus.tx(ep.n, ep.res) 48 } 49 } 50 51 // Init initializes an endpoint. 52 func (ep *endpoint) Init() { 53 ep.n = ep.desc.Number() 54 ep.dir = ep.desc.Direction() 55 56 ep.bus.set(ep.n, ep.dir, int(ep.desc.MaxPacketSize), ep.desc.Zero, 0) 57 ep.bus.enable(ep.n, ep.dir, ep.desc.TransferType()) 58 } 59 60 // Flush clears the endpoint receive and transmit buffers. 61 func (ep *endpoint) Flush() { 62 reg.Set(ep.bus.flush, (ep.dir*16)+ep.n) 63 } 64 65 // Start initializes and runs an USB endpoint. 66 func (ep *endpoint) Start() { 67 if ep.desc.Function == nil { 68 return 69 } 70 71 ep.Lock() 72 73 defer func() { 74 ep.Flush() 75 ep.bus.wg.Done() 76 ep.Unlock() 77 }() 78 79 ep.Init() 80 81 for { 82 runtime.Gosched() 83 84 if ep.dir == OUT { 85 ep.rx() 86 } else { 87 ep.tx() 88 } 89 90 if ep.err != nil { 91 ep.bus.stall(ep.n, ep.dir) 92 } 93 94 select { 95 case <-ep.bus.exit: 96 return 97 default: 98 } 99 } 100 } 101 102 func (hw *USB) startEndpoints() { 103 if hw.Device.ConfigurationValue == 0 { 104 return 105 } 106 107 hw.exit = make(chan struct{}) 108 109 for _, conf := range hw.Device.Configurations { 110 if hw.Device.ConfigurationValue != conf.ConfigurationValue { 111 continue 112 } 113 114 for _, iface := range conf.Interfaces { 115 for _, desc := range iface.Endpoints { 116 ep := &endpoint{ 117 bus: hw, 118 desc: desc, 119 } 120 121 hw.wg.Add(1) 122 123 go func(ep *endpoint) { 124 ep.Start() 125 }(ep) 126 } 127 } 128 } 129 }