usb

package
v0.0.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 28, 2024 License: BSD-3-Clause Imports: 15 Imported by: 0

Documentation

Overview

Package usb provides a high level access to the i.MX RT built-in USB controllers.

Logical vs hardware endpoint numbers.

This package uses two ways to describe an USB endpoint.

The Hardware Endpoint number (he) specifies an unidirectional communication channel available in the USB device. The supported direction is encoded in the least significant bit of the he (an even he means OUT endpoint, an odd he means IN endpoint).

The Logical Endpoint number (le) is what the USB documentation means when it uses the phrase endpoint or endpoint number. In this package it is used mainly in the context of control endpoints due to their obligatory bidirectional nature. In fact, a logical endpoint without specifying its direction is not a precise term because it may point to two unrelated communication channels.

This package uses uint8 for he and int8 for le. The connection between le and he is as follows: le = int8(he >> 1). The HE and LE functions can be used for readabble conversions.

Device Controller Driver (DCD)

DCD is primarily intended to be used by the higher-level drivers (e.g. CDC ACM serial driver) but can be also used directly as in the following example:

var usbd *usb.Device

func main() {
	usbd = usb.NewDevice(1)
	usbd.Init(rtos.IntPrioLow, descriptors, false)
	usbd.Enable()

	var done rtos.Note
	td := usb.NewDTD()
	td.SetNote(&done)
	buf := dma.MakeSlice[byte](512, 512)
	config := 1

usbNotReady:
	usbd.WaitConfig(config)

	for {
		bufp := unsafe.Pointer(&buf[0])
		rtos.CacheMaint(rtos.DCacheInval, bufp, len(buf))
		td.SetupTransfer(bufp, len(buf))
		done.Clear()

		if !usbd.Prime(rxhe, td, td, config) {
			goto usbNotReady
		}
		done.Sleep(-1)

		n, stat := td.Status()
		switch {
		case stat == 0:
			n = len(buf) - n
			handleRxData(buf[:n])

		case stat&usb.Active != 0:
			goto usbNotReady

		default:
			handleRxError(stat)
		}
	}
}

//go:interrupthandler
func USB_OTG1_Handler() {
	usbd.ISR()
}

Index

Constants

View Source
const (
	OUT uint8 = 0 // output endpoint (Rx for device, Tx for host)
	IN  uint8 = 1 // input endpoint (Tx for device, Rx for host)
)

Endpoint direction.

View Source
const (
	TransErr   = 1 << 3
	DataBufErr = 1 << 5
	Halted     = 1 << 6
	Active     = 1 << 7
)

DTD status

Variables

This section is empty.

Functions

func HE

func HE(le int8, dir uint8) uint8

HE returns the hardware endpiont number for the given logical endpoint and direction.

func LE

func LE(he uint8) (le int8, dir uint8)

LE returns the logical endpoint number and its direction for the given hardware endpoint.

Types

type ControlRequest

type ControlRequest struct {
	LE      int8   // logical endpoint number
	Request uint16 // bRequest<<8 | bmRequestType
	Value   uint16 // wValue
	Index   uint16 // wIndex
	Data    []byte // len(Data) = wLength
}

field serves two functions. In case of OUT direction it contains the data received from the host, otherwise (IN direction) it serves as the output buffer, for sending data to the host.

type DTD

type DTD struct {
	// contains filtered or unexported fields
}

A DTD is a Device Transfer Descriptor. It MUST BE allocated in the non-cacheable memory and 32 byte aligned. The NewDTD and MakeSliceDTD functions meet these requirements.

The DTD is used for priming the USB controller endpoints always in the form of DTD list. The next field of the last DTD on the list used for priming may by changed implicitly so you cannot use nil as an end-of-list mark.

func MakeSliceDTD

func MakeSliceDTD(len, cap int) []DTD

MakeSliceDTD returns new slice of DTD structs allocated in non-cacheable memory. Use carefully because currently there is no way to release memory allocated this way.

func NewDTD

func NewDTD() *DTD

NewDTD returns new DTD allocated in the non-cacheable memory. Use carefully because currently there is no way to release memory allocated this way.

func (*DTD) Next

func (td *DTD) Next() *DTD

Next returns the content of the td.next field.

func (*DTD) SetNext

func (td *DTD) SetNext(next *DTD)

SetNext sets the td.next field to the next.

func (*DTD) SetNote

func (td *DTD) SetNote(note *rtos.Note)

SetNote sets the Interrupt On Complete bit (IOC) in the td.token field and a note that will be used by an interrupt handler to communicate the completion of a transfer. As the Go GC may have no access to the td.note field you must keep a reference to the note somewhere. For the same reason the DTD type does not provide a method to obtain the note set.

Set note to nil to clear IOC.

After waking up from the note.Sleep the Status method should be used to check status of the transfer. Check all transfer descriptors in the list that may be signaled by this note.

func (*DTD) SetupTransfer

func (td *DTD) SetupTransfer(ptr unsafe.Pointer, size int) (n int)

SetupTransfer configures td to use the buffer specified by ptr and size for a data transfer. As the maximum transfer length that can be handled by single DTD is limited it returns how much of the buffer will be used. The limit depends on the buffer alignment in memory and can be any number from 16 KiB to 20 KiB. The remaining part of the buffer can be transfered using a next DTD in the list or assigned to the same DTD next time. In most cases the bufer requires a cache maintanance (see also dma.New, dma.MakeSlice, rtos.CacheMaint) and must be keep referenced until the end of transfer to avoid GC. The unsafe.Pointer type is there to remind you of both of these inconveniences.

func (*DTD) Status

func (td *DTD) Status() (n int, status uint8)

Status returns a transfer status. If td was used to prime an USB controller endpoint the returned value is only valid after waking up from the note.Sleep (see SetNote method) that signals the end of transfer to which this td belongs to.

N contains the number of bytes in the buffer that remain untransfered.

After a successful transaction, the status byte should be zero. If not zero, the Active bit means unfinished transfer due to the Bus Reset and the meanings of the remaining bits (Halted, DataBufErr, TransErr) can be found in the documentation of the Endpoint Transfer Descriptor (dTD).

type Device

type Device struct {
	// contains filtered or unexported fields
}

A Device represents an USB Device Controler Driver (DCD).

func NewDevice

func NewDevice(controller int) *Device

NewDevice returns a new device controler driver for USB controller 1 or 2.

func (*Device) Config

func (d *Device) Config() int

Config returns the configuration number selected during the USB enumeration process or zero if the device is not in the configured state.

func (*Device) Controller

func (d *Device) Controller() int

Controller returnt the controller number used this device driver.

func (*Device) Disable

func (d *Device) Disable()

Disable disables the device controller.

func (*Device) Enable

func (d *Device) Enable()

Enable enables the device controller.

func (*Device) Handle

func (d *Device) Handle(le int8, request uint16, handler func(cr *ControlRequest) int)

Handle registers the handler for the control requests adressed to the logical endpoint number le. All handlers must be registered before enabling the device.

func (*Device) ISR

func (d *Device) ISR()

ISR handles USB interrupts.

func (*Device) Init

func (d *Device) Init(intPrio int, descriptors map[uint32]string, forceFullSpeed bool)

Init initializes the USB device controler and the driver itself.

func (*Device) Prime

func (d *Device) Prime(he uint8, first, last *DTD) (primed bool)

Prime primes the he hardware endpoint with the list of transfer descriptors specified by the first and last pointers. It reports whether the endpoint was succesfully primed.

To successfully prime an endpoint the device must be in the configured state.

Prime can be used concurently by multiple goroutines also with the same endpoint.

The last descriptor in the tdl must have a note set to provide a way for the ISR to inform about the end of transfer (see DTD.SetNote). Setting notes for the preceding DTDs in the list is optional and depends on the logical structure of the transfer.

func (*Device) WaitConfig

func (d *Device) WaitConfig(cn int)

WaitConfig waits for the selection of the cn configuration number during the USB enumeration process. Use cn=0 to wait for the configured state (any configuration number).

type Error

type Error struct {
	Controller int    // controler number
	Function   string // function name
	HE         uint8  // hardware endpoint number
	Status     uint8  // DTD status field
}

An Error may be used by a higher-level driver to inform about unsuccessfull transfer with the additional information provided by the device driver or the hardware controller.

func (*Error) Error

func (e *Error) Error() string

func (*Error) NotReady

func (e *Error) NotReady() bool

NotReady reports whether the error was returned because the USB device was in the unconfigured state or the selected configuration number does not match the required one.

Directories

Path Synopsis
Package usbserial provides a simple USB CDC ACM serial driver.
Package usbserial provides a simple USB CDC ACM serial driver.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL