github.com/f-secure-foundry/tamago@v0.0.0-20220307101044-d73fcdd7f11b/soc/imx6/usb/setup.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  	"encoding/binary"
    14  	"fmt"
    15  
    16  	"github.com/f-secure-foundry/tamago/internal/reg"
    17  )
    18  
    19  // Standard request codes (p279, Table 9-4, USB2.0)
    20  const (
    21  	GET_STATUS        = 0
    22  	CLEAR_FEATURE     = 1
    23  	SET_FEATURE       = 3
    24  	SET_ADDRESS       = 5
    25  	GET_DESCRIPTOR    = 6
    26  	SET_DESCRIPTOR    = 7
    27  	GET_CONFIGURATION = 8
    28  	SET_CONFIGURATION = 9
    29  	GET_INTERFACE     = 10
    30  	SET_INTERFACE     = 11
    31  	SYNCH_FRAME       = 12
    32  )
    33  
    34  // Descriptor types (p279, Table 9-5, USB2.0)
    35  const (
    36  	DEVICE                    = 1
    37  	CONFIGURATION             = 2
    38  	STRING                    = 3
    39  	INTERFACE                 = 4
    40  	ENDPOINT                  = 5
    41  	DEVICE_QUALIFIER          = 6
    42  	OTHER_SPEED_CONFIGURATION = 7
    43  	INTERFACE_POWER           = 8
    44  
    45  	// Engineering Change Notices (ECN)
    46  	OTG                   = 9
    47  	DEBUG                 = 10
    48  	INTERFACE_ASSOCIATION = 11
    49  )
    50  
    51  // Standard feature selectors (p280, Table 9-6, USB2.0)
    52  const (
    53  	ENDPOINT_HALT        = 0
    54  	DEVICE_REMOTE_WAKEUP = 1
    55  	TEST_MODE            = 2
    56  )
    57  
    58  // SetupData implements
    59  // p276, Table 9-2. Format of Setup Data, USB2.0.
    60  type SetupData struct {
    61  	RequestType uint8
    62  	Request     uint8
    63  	Value       uint16
    64  	Index       uint16
    65  	Length      uint16
    66  }
    67  
    68  // swap adjusts the endianness of values written in memory by the hardware, as
    69  // they do not match the expected one by Go.
    70  func (s *SetupData) swap() {
    71  	b := make([]byte, 2)
    72  
    73  	binary.BigEndian.PutUint16(b, s.Value)
    74  	s.Value = binary.LittleEndian.Uint16(b)
    75  }
    76  
    77  func (hw *USB) getSetup() (setup *SetupData) {
    78  	setup = &SetupData{}
    79  
    80  	// p3801, 56.4.6.4.2.1 Setup Phase, IMX6ULLRM
    81  
    82  	// clear setup status
    83  	reg.Set(hw.setup, 0)
    84  	// flush EP0 IN
    85  	reg.Set(hw.flush, ENDPTFLUSH_FETB+0)
    86  	// flush EP0 OUT
    87  	reg.Set(hw.flush, ENDPTFLUSH_FERB+0)
    88  
    89  	*setup = hw.qh(0, OUT).Setup
    90  	setup.swap()
    91  
    92  	return
    93  }
    94  
    95  func (hw *USB) getDescriptor(dev *Device, setup *SetupData) (err error) {
    96  	bDescriptorType := setup.Value & 0xff
    97  	index := setup.Value >> 8
    98  
    99  	switch bDescriptorType {
   100  	case DEVICE:
   101  		err = hw.tx(0, false, trim(dev.Descriptor.Bytes(), setup.Length))
   102  	case CONFIGURATION:
   103  		var conf []byte
   104  		if conf, err = dev.Configuration(index); err == nil {
   105  			err = hw.tx(0, false, trim(conf, setup.Length))
   106  		}
   107  	case STRING:
   108  		if int(index+1) > len(dev.Strings) {
   109  			hw.stall(0, IN)
   110  			err = fmt.Errorf("invalid string descriptor index %d", index)
   111  		} else {
   112  			err = hw.tx(0, false, trim(dev.Strings[index], setup.Length))
   113  		}
   114  	case DEVICE_QUALIFIER:
   115  		err = hw.tx(0, false, dev.Qualifier.Bytes())
   116  	default:
   117  		hw.stall(0, IN)
   118  		err = fmt.Errorf("unsupported descriptor type: %#x", bDescriptorType)
   119  	}
   120  
   121  	return
   122  }
   123  
   124  func (hw *USB) handleSetup(dev *Device, setup *SetupData) (err error) {
   125  	if setup == nil {
   126  		return
   127  	}
   128  
   129  	if dev.Setup != nil {
   130  		in, ack, done, err := dev.Setup(setup)
   131  
   132  		if err != nil {
   133  			hw.stall(0, IN)
   134  			return err
   135  		} else if len(in) != 0 {
   136  			err = hw.tx(0, false, in)
   137  		} else if ack {
   138  			err = hw.ack(0)
   139  		}
   140  
   141  		if done || err != nil {
   142  			return err
   143  		}
   144  	}
   145  
   146  	switch setup.Request {
   147  	case GET_STATUS:
   148  		// no meaningful status to report for now
   149  		err = hw.tx(0, false, []byte{0x00, 0x00})
   150  	case CLEAR_FEATURE:
   151  		switch setup.Value {
   152  		case ENDPOINT_HALT:
   153  			n := int(setup.Index & 0b1111)
   154  			dir := int(setup.Index&0b10000000) / 0b10000000
   155  
   156  			hw.reset(n, dir)
   157  			err = hw.ack(0)
   158  		default:
   159  			hw.stall(0, IN)
   160  		}
   161  	case SET_ADDRESS:
   162  		addr := uint32((setup.Value<<8)&0xff00 | (setup.Value >> 8))
   163  
   164  		reg.Set(hw.addr, DEVICEADDR_USBADRA)
   165  		reg.SetN(hw.addr, DEVICEADDR_USBADR, 0x7f, addr)
   166  
   167  		err = hw.ack(0)
   168  	case GET_DESCRIPTOR:
   169  		err = hw.getDescriptor(dev, setup)
   170  	case GET_CONFIGURATION:
   171  		err = hw.tx(0, false, []byte{dev.ConfigurationValue})
   172  	case SET_CONFIGURATION:
   173  		dev.ConfigurationValue = uint8(setup.Value >> 8)
   174  		err = hw.ack(0)
   175  	case GET_INTERFACE:
   176  		err = hw.tx(0, false, []byte{dev.AlternateSetting})
   177  	case SET_INTERFACE:
   178  		dev.AlternateSetting = uint8(setup.Value >> 8)
   179  		err = hw.ack(0)
   180  	case SET_ETHERNET_PACKET_FILTER:
   181  		// no meaningful action for now
   182  		err = hw.ack(0)
   183  	default:
   184  		hw.stall(0, IN)
   185  		err = fmt.Errorf("unsupported request code: %#x", setup.Request)
   186  	}
   187  
   188  	return
   189  }
   190  
   191  func trim(buf []byte, wLength uint16) []byte {
   192  	if int(wLength) < len(buf) {
   193  		buf = buf[0:wLength]
   194  	}
   195  
   196  	return buf
   197  }