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