david/ipxe
david
/
ipxe
Archived
1
0
Fork 0
This repository has been archived on 2020-12-06. You can view files and clone it, but cannot push or open issues or pull requests.
ipxe/src/drivers/usb/uhci.h

351 lines
7.5 KiB
C

#ifndef _IPXE_UHCI_H
#define _IPXE_UHCI_H
/** @file
*
* USB Universal Host Controller Interface (UHCI) driver
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <assert.h>
#include <ipxe/pci.h>
#include <ipxe/usb.h>
/** Minimum alignment required for data structures
*
* With the exception of the frame list (which is page-aligned), data
* structures used by UHCI generally require 16-byte alignment.
*/
#define UHCI_ALIGN 16
/** Number of ports */
#define UHCI_PORTS 2
/** Maximum transfer size */
#define UHCI_MTU 1280
/** I/O BAR size */
#define UHCI_BAR_SIZE 0x14
/** USB command register */
#define UHCI_USBCMD 0x00
/** Max packet is 64 bytes */
#define UHCI_USBCMD_MAX64 0x0080
/** Host controller reset */
#define UHCI_USBCMD_HCRESET 0x0002
/** Run/stop */
#define UHCI_USBCMD_RUN 0x0001
/** USB status register */
#define UHCI_USBSTS 0x02
/** Host controller halted */
#define UHCI_USBSTS_HCHALTED 0x0020
/** USB interrupt */
#define UHCI_USBSTS_USBINT 0x0001
/** Frame list base address register */
#define UHCI_FLBASEADD 0x08
/** Port status and control register */
#define UHCI_PORTSC(port) ( 0x0e + ( (port) << 1 ) )
/** Port reset */
#define UHCI_PORTSC_PR 0x0200
/** Low-speed device attached */
#define UHCI_PORTSC_LS 0x0100
/** Port enabled/disabled change */
#define UHCI_PORTSC_PEC 0x0008
/** Port enabled */
#define UHCI_PORTSC_PED 0x0004
/** Connect status change */
#define UHCI_PORTSC_CSC 0x0002
/** Current connect status */
#define UHCI_PORTSC_CCS 0x0001
/** Port status change mask */
#define UHCI_PORTSC_CHANGE ( UHCI_PORTSC_CSC | UHCI_PORTSC_PEC )
/** Depth-first processing */
#define UHCI_LINK_DEPTH_FIRST 0x00000004UL
/** Queue head type */
#define UHCI_LINK_TYPE_QH 0x00000002UL
/** List terminator */
#define UHCI_LINK_TERMINATE 0x00000001UL
/** Number of frames in frame list */
#define UHCI_FRAMES 1024
/** A frame list */
struct uhci_frame_list {
/** Link pointer */
uint32_t link[UHCI_FRAMES];
} __attribute__ (( packed ));
/** A transfer descriptor */
struct uhci_transfer_descriptor {
/** Link pointer */
uint32_t link;
/** Actual length */
uint16_t actual;
/** Status */
uint8_t status;
/** Flags */
uint8_t flags;
/** Control */
uint32_t control;
/** Buffer pointer */
uint32_t data;
} __attribute__ (( packed ));
/** Length mask */
#define UHCI_LEN_MASK 0x7ff
/** Actual length */
#define UHCI_ACTUAL_LEN( actual ) ( ( (actual) + 1 ) & UHCI_LEN_MASK )
/** Active */
#define UHCI_STATUS_ACTIVE 0x80
/** Stalled */
#define UHCI_STATUS_STALLED 0x40
/** Data buffer error */
#define UHCI_STATUS_BUFFER 0x20
/** Babble detected */
#define UHCI_STATUS_BABBLE 0x10
/** NAK received */
#define UHCI_STATUS_NAK 0x08
/** CRC/timeout error */
#define UHCI_STATUS_CRC_TIMEOUT 0x04
/** Bitstuff error */
#define UHCI_STATUS_BITSTUFF 0x02
/** Short packet detect */
#define UHCI_FL_SPD 0x20
/** Error counter */
#define UHCI_FL_CERR( count ) ( (count) << 3 )
/** Error counter maximum value */
#define UHCI_FL_CERR_MAX UHCI_FL_CERR ( 3 )
/** Low speed device */
#define UHCI_FL_LS 0x04
/** Interrupt on completion */
#define UHCI_FL_IOC 0x01
/** Packet ID */
#define UHCI_CONTROL_PID( pid ) ( (pid) << 0 )
/** Packet ID mask */
#define UHCI_CONTROL_PID_MASK UHCI_CONTROL_PID ( 0xff )
/** Device address */
#define UHCI_CONTROL_DEVICE( address ) ( (address) << 8 )
/** Endpoint address */
#define UHCI_CONTROL_ENDPOINT( address ) ( (address) << 15 )
/** Data toggle */
#define UHCI_CONTROL_TOGGLE ( 1 << 19 )
/** Data length */
#define UHCI_CONTROL_LEN( len ) ( ( ( (len) - 1 ) & UHCI_LEN_MASK ) << 21 )
/** Check for data packet
*
* This check is based on the fact that only USB_PID_SETUP has bit 2
* set.
*/
#define UHCI_DATA_PACKET( control ) ( ! ( control & 0x04 ) )
/** Check for short packet */
#define UHCI_SHORT_PACKET( control, actual ) \
( ( ( (control) >> 21 ) ^ (actual) ) & UHCI_LEN_MASK )
/** USB legacy support register (in PCI configuration space) */
#define UHCI_USBLEGSUP 0xc0
/** USB legacy support default value */
#define UHCI_USBLEGSUP_DEFAULT 0x2000
/** A queue head */
struct uhci_queue_head {
/** Horizontal link pointer */
uint32_t link;
/** Current transfer descriptor */
uint32_t current;
} __attribute__ (( packed ));
/** A single UHCI transfer
*
* UHCI hardware is extremely simple, and requires software to build
* the entire packet schedule (including manually handling all of the
* data toggles). The hardware requires at least 16 bytes of transfer
* descriptors per 64 bytes of transmitted/received data. We allocate
* the transfer descriptors at the time that the transfer is enqueued,
* to avoid the need to allocate unreasonably large blocks when the
* endpoint is opened.
*/
struct uhci_transfer {
/** Producer counter */
unsigned int prod;
/** Consumer counter */
unsigned int cons;
/** Completed data length */
size_t len;
/** Transfer descriptors */
struct uhci_transfer_descriptor *desc;
/** I/O buffer */
struct io_buffer *iobuf;
};
/** Number of transfer descriptors in a ring
*
* This is a policy decision.
*/
#define UHCI_RING_COUNT 16
/** A transfer ring */
struct uhci_ring {
/** Producer counter */
unsigned int prod;
/** Consumer counter */
unsigned int cons;
/** Maximum packet length */
size_t mtu;
/** Base flags
*
* This incorporates the CERR and LS bits
*/
uint8_t flags;
/** Base control word
*
* This incorporates the device address, the endpoint address,
* and the data toggle for the next descriptor to be enqueued.
*/
uint32_t control;
/** Transfers */
struct uhci_transfer *xfer[UHCI_RING_COUNT];
/** End of transfer ring (if non-empty) */
struct uhci_transfer *end;
/** Queue head */
struct uhci_queue_head *head;
};
/**
* Calculate space used in transfer ring
*
* @v ring Transfer ring
* @ret fill Number of entries used
*/
static inline __attribute__ (( always_inline )) unsigned int
uhci_ring_fill ( struct uhci_ring *ring ) {
unsigned int fill;
fill = ( ring->prod - ring->cons );
assert ( fill <= UHCI_RING_COUNT );
return fill;
}
/**
* Calculate space remaining in transfer ring
*
* @v ring Transfer ring
* @ret remaining Number of entries remaining
*/
static inline __attribute__ (( always_inline )) unsigned int
uhci_ring_remaining ( struct uhci_ring *ring ) {
unsigned int fill = uhci_ring_fill ( ring );
return ( UHCI_RING_COUNT - fill );
}
/** Maximum time to wait for host controller to stop
*
* This is a policy decision.
*/
#define UHCI_STOP_MAX_WAIT_MS 100
/** Maximum time to wait for reset to complete
*
* This is a policy decision.
*/
#define UHCI_RESET_MAX_WAIT_MS 500
/** Maximum time to wait for a port to be enabled
*
* This is a policy decision.
*/
#define UHCI_PORT_ENABLE_MAX_WAIT_MS 500
/** A UHCI device */
struct uhci_device {
/** Registers */
unsigned long regs;
/** Name */
const char *name;
/** EHCI companion controller bus:dev.fn address (if any) */
unsigned int companion;
/** Asynchronous queue head */
struct uhci_queue_head *head;
/** Frame list */
struct uhci_frame_list *frame;
/** List of all endpoints */
struct list_head endpoints;
/** Asynchronous schedule */
struct list_head async;
/** Periodic schedule
*
* Listed in decreasing order of endpoint interval.
*/
struct list_head periodic;
/** USB bus */
struct usb_bus *bus;
};
/** A UHCI endpoint */
struct uhci_endpoint {
/** UHCI device */
struct uhci_device *uhci;
/** USB endpoint */
struct usb_endpoint *ep;
/** List of all endpoints */
struct list_head list;
/** Endpoint schedule */
struct list_head schedule;
/** Transfer ring */
struct uhci_ring ring;
};
#endif /* _IPXE_UHCI_H */