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  }