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  }