summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/drivers/usb/uhci.h
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/ipxe/src/drivers/usb/uhci.h')
-rw-r--r--qemu/roms/ipxe/src/drivers/usb/uhci.h350
1 files changed, 350 insertions, 0 deletions
diff --git a/qemu/roms/ipxe/src/drivers/usb/uhci.h b/qemu/roms/ipxe/src/drivers/usb/uhci.h
new file mode 100644
index 000000000..ba4c28f7e
--- /dev/null
+++ b/qemu/roms/ipxe/src/drivers/usb/uhci.h
@@ -0,0 +1,350 @@
+#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 */