github.com/f-secure-foundry/tamago@v0.0.0-20220307101044-d73fcdd7f11b/soc/imx6/usb/device.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  	"sync"
    15  	"time"
    16  
    17  	"github.com/f-secure-foundry/tamago/internal/reg"
    18  	"github.com/f-secure-foundry/tamago/soc/imx6"
    19  )
    20  
    21  func init() {
    22  	if !imx6.Native {
    23  		return
    24  	}
    25  
    26  	// On i.MX6 the only way to detect if we are booting through Serial
    27  	// Download Mode over USB is to check whether the USB OTG1 controller
    28  	// was running in device mode prior to our own initialization.
    29  	if reg.Get(USB1_BASE+USB_UOGx_USBMODE, USBMODE_CM, 0b11) == USBMODE_CM_DEVICE &&
    30  		reg.Get(USB1_BASE+USB_UOGx_USBCMD, USBCMD_RS, 1) != 0 {
    31  		sdp = true
    32  	}
    33  }
    34  
    35  // DeviceMode sets the USB controller in device mode.
    36  func (hw *USB) DeviceMode() {
    37  	hw.Lock()
    38  	defer hw.Unlock()
    39  
    40  	reg.Set(hw.cmd, USBCMD_RST)
    41  	reg.Wait(hw.cmd, USBCMD_RST, 1, 0)
    42  
    43  	// p3872, 56.6.33 USB Device Mode (USB_nUSBMODE), IMX6ULLRM)
    44  	m := reg.Read(hw.mode)
    45  
    46  	// set device only controller
    47  	m = (m & ^uint32(0b11<<USBMODE_CM)) | (USBMODE_CM_DEVICE << USBMODE_CM)
    48  	// disable setup lockout
    49  	m |= (1 << USBMODE_SLOM)
    50  	// disable stream mode
    51  	m &^= (1 << USBMODE_SDIS)
    52  
    53  	reg.Write(hw.mode, m)
    54  	reg.Wait(hw.mode, USBMODE_CM, 0b11, USBMODE_CM_DEVICE)
    55  
    56  	// initialize endpoint queue head list
    57  	hw.initQH()
    58  	// set control endpoint
    59  	hw.set(0, IN, 64, true, 0)
    60  	hw.set(0, OUT, 64, true, 0)
    61  
    62  	// set OTG termination
    63  	reg.Set(hw.otg, OTGSC_OT)
    64  
    65  	// clear all pending interrupts
    66  	reg.Write(hw.sts, 0xffffffff)
    67  
    68  	// run
    69  	reg.Set(hw.cmd, USBCMD_RS)
    70  }
    71  
    72  // Start waits and handles configured USB endpoints in device mode, it should
    73  // never return. Note that isochronous endpoints are not supported.
    74  func (hw *USB) Start(dev *Device) {
    75  	var conf uint8
    76  	var wg sync.WaitGroup
    77  
    78  	for {
    79  		// check for bus reset
    80  		if reg.Get(hw.sts, USBSTS_URI, 1) == 1 {
    81  			// set inactive configuration
    82  			conf = 0
    83  			dev.ConfigurationValue = 0
    84  
    85  			// perform controller reset procedure
    86  			hw.Reset()
    87  		}
    88  
    89  		// wait for a setup packet
    90  		if !reg.WaitFor(10*time.Millisecond, hw.setup, 0, 1, 1) {
    91  			continue
    92  		}
    93  
    94  		// handle setup packet
    95  		if err := hw.handleSetup(dev, hw.getSetup()); err != nil {
    96  			log.Printf("imx6_usb: setup error, %v", err)
    97  		}
    98  
    99  		// check if configuration reload is required
   100  		if dev.ConfigurationValue == conf {
   101  			continue
   102  		} else {
   103  			conf = dev.ConfigurationValue
   104  		}
   105  
   106  		// stop configuration endpoints
   107  		if hw.done != nil {
   108  			close(hw.done)
   109  			wg.Wait()
   110  		}
   111  
   112  		// start configuration endpoints
   113  		hw.startEndpoints(&wg, dev, conf)
   114  	}
   115  }