memtest86plus/system/usbhcd.h
Martin Whitaker 644a13c730 Add usbdebug command line option and conditionally pause at end of USB scan.
If the usbdebug option is present, pause at the end of the USB scan until
a key is pressed. Otherwise, if the keyboard=usb option is present and no
USB keyboards were discovered, pause for 10 seconds. Otherwise don't pause.
2022-04-17 22:46:17 +01:00

282 lines
8.7 KiB
C

// SPDX-License-Identifier: GPL-2.0
#ifndef USBHCD_H
#define USBHCD_H
/**
* \file
*
* Provides the base USB host controller driver for USB keyboard support.
*
* This is an object-oriented design. The hcd_methods_t structure defines
* a set of virtual methods that will be implemented by the subclasses.
* The hcd_workspace_t structure defines the base class properties. The
* usb_hcd_t structure represents a driver object. The non-virtual and
* default base class methods are defined as separate functions, taking
* a usb_hcd_t pointer as their first parameter.
*
* The find_usb_keyboards function instantiates a driver object of the
* appropriate subclass for each USB controller it finds and stores it
* in the private usb_controllers table, where it can subsequently used
* to poll the keyboards for key presses.
*
*//*
* Copyright (C) 2021-2022 Martin Whitaker.
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "usb.h"
/**
* The size of the data transfer buffer in a host controller driver workspace.
* This aligns the start of the driver private data to a 1024 byte boundary.
*/
#define HCD_DATA_BUFFER_SIZE (1024 - sizeof(size_t))
/**
* A USB device speed (used internally by the various HCI drivers).
*/
typedef enum __attribute__ ((packed)) {
USB_SPEED_UNKNOWN = 0,
USB_SPEED_LOW = 1,
USB_SPEED_FULL = 2,
USB_SPEED_HIGH = 3
} usb_speed_t;
/**
* A USB endpoint descriptor (used internally by the various HCI drivers).
*/
typedef struct __attribute__ ((packed)) {
uintptr_t driver_data;
usb_speed_t device_speed;
uint8_t device_id;
uint8_t interface_num;
uint8_t endpoint_num;
uint16_t max_packet_size;
uint8_t interval;
uint8_t reserved;
} usb_ep_t;
/**
* A USB hub descriptor (used internally by the various HCI drivers).
*/
typedef struct __attribute__ ((packed)) {
const usb_ep_t *ep0;
uint32_t route;
uint8_t level;
uint8_t num_ports;
uint8_t tt_think_time;
uint8_t power_up_delay;
} usb_hub_t;
/**
* A USB host controller driver object reference.
*/
typedef const struct usb_hcd_s *usb_hcd_r;
/**
* A USB host controller driver method table.
*/
typedef struct {
bool (*reset_root_hub_port) (usb_hcd_r, int);
int (*allocate_slot) (usb_hcd_r);
bool (*release_slot) (usb_hcd_r, int);
bool (*assign_address) (usb_hcd_r, const usb_hub_t *, int, usb_speed_t, int, usb_ep_t *);
bool (*configure_hub_ep) (usb_hcd_r, const usb_ep_t *, const usb_hub_t *);
bool (*configure_kbd_ep) (usb_hcd_r, const usb_ep_t *, int);
bool (*setup_request) (usb_hcd_r, const usb_ep_t *, const usb_setup_pkt_t *);
bool (*get_data_request) (usb_hcd_r, const usb_ep_t *, const usb_setup_pkt_t *, const void *, size_t);
uint8_t (*get_keycode) (usb_hcd_r);
} hcd_methods_t;
/**
* A USB host controller driver workspace. This is extended by each HCI driver
* to append its private data.
*/
typedef struct __attribute__((packed)) {
uint8_t data_buffer[HCD_DATA_BUFFER_SIZE];
size_t data_length;
} hcd_workspace_t;
/**
* A USB host controller driver object.
*/
typedef struct usb_hcd_s {
const hcd_methods_t *methods;
hcd_workspace_t *ws;
} usb_hcd_t;
/**
* A set of USB device initialisation options.
*/
typedef enum {
USB_DEFAULT_INIT = 0,
USB_EXTRA_RESET = 1 << 0,
USB_IGNORE_EHCI = 1 << 1,
USB_DEBUG = 1 << 2
} usb_init_options_t;
/**
* The selected USB device initialisation options.
*
* Used internally by the various HCI drivers.
*/
extern usb_init_options_t usb_init_options;
/**
* Constructs a USB setup packet in buffer using the provided values.
*
* Used internally by the various HCI drivers.
*/
static inline void build_setup_packet(usb_setup_pkt_t *pkt, int type, int request, int value, int index, int length)
{
pkt->type = type;
pkt->request = request;
pkt->value = value;
pkt->index = index;
pkt->length = length;
}
/* Returns the default maximum packet size for a USB device running at the
* given speed.
*
* Used internally by the various HCI drivers.
*/
static inline int default_max_packet_size(usb_speed_t device_speed)
{
switch (device_speed) {
case USB_SPEED_LOW:
return 8;
case USB_SPEED_FULL:
return 64;
case USB_SPEED_HIGH:
return 64;
default:
return 0;
}
}
/**
* Returns true if size is a valid value for the maximum packet size for a
* USB device running at the given speed.
*
* Used internally by the various HCI drivers.
*/
static inline bool valid_usb_max_packet_size(int size, usb_speed_t speed)
{
return (size == 8) || ((speed != USB_SPEED_LOW) && (size == 16 || size == 32 || size == 64));
}
/**
* Returns true if buffer appears to contain a valid USB device descriptor.
*
* Used internally by the various HCI drivers.
*/
static inline bool valid_usb_device_descriptor(const uint8_t *buffer)
{
usb_desc_header_t *desc = (usb_desc_header_t *)buffer;
return desc->length == sizeof(usb_device_desc_t) && desc->type == USB_DESC_DEVICE;
}
/**
* Returns true if buffer appears to contain a valid USB configuration
* descriptor.
*
* Used internally by the various HCI drivers.
*/
static inline bool valid_usb_config_descriptor(const uint8_t *buffer)
{
usb_desc_header_t *desc = (usb_desc_header_t *)buffer;
return desc->length == sizeof(usb_config_desc_t) && desc->type == USB_DESC_CONFIGURATION;
}
/**
* Returns the USB route to the device attached to the hub port specified by
* hub and port_num. The top 8 bits of the returned value contain the root
* port number and the bottom 20 bits contain the USB3 route string.
*
* Used internally by the various HCI drivers.
*/
uint32_t usb_route(const usb_hub_t *hub, int port_num);
/**
* Waits for all the bits set in bit_mask to be cleared in the register pointed
* to by reg or for max_time microseconds to elapse.
*
* Used internally by the various HCI drivers.
*/
bool wait_until_clr(const volatile uint32_t *reg, uint32_t bit_mask, int max_time);
/**
* Waits for all the bits set in bit_mask to also be set in the register pointed
* to by reg or for max_time microseconds to elapse.
*
* Used internally by the various HCI drivers.
*/
bool wait_until_set(const volatile uint32_t *reg, uint32_t bit_mask, int max_time);
/**
* Displays an informational message, scrolling the screen if necessary.
* Takes the same arguments as the printf function.
*
* Used internally by the various HCI drivers.
*/
void print_usb_info(const char *fmt, ...);
/**
* Resets the specified USB hub port.
*
* Used internally by the various HCI drivers.
*/
bool reset_usb_hub_port(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_num);
/**
* Sets the device address for the device attached to the specified hub port
* (thus moving the device to Address state), fills in the descriptor for the
* device's default control endpoint (ep0), and leaves the device descriptor
* in the driver's data transfer buffer. Returns true if all actions are
* successfully completed.
*
* This is the default implementation of the HCD assign_address method.
*/
bool assign_usb_address(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_num,
usb_speed_t device_speed, int device_id, usb_ep_t *ep0);
/**
* Scans the specified USB device to detect whether it has any HID keyboards
* attached to it (directly or indirectly). If so, the keyboard device(s)
* are initialised and configured, as are any intermediate USB hubs, and the
* table defined by keyboards and max_keyboards is updated accordingly and
* num_keyboards is updated to match. Returns true if any keyboards were found
* and added to the table.
*
* Used internally by the various HCI drivers.
*/
bool find_attached_usb_keyboards(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_num,
usb_speed_t device_speed, int device_id, int *num_devices,
usb_ep_t keyboards[], int max_keyboards, int *num_keyboards);
/**
* Scans the attached USB devices and initialises all HID keyboard devices
* it finds (subject to implementation limits on the number of devices).
* Records the information needed to subsequently poll those devices for
* key presses.
*
* Used internally by keyboard.c.
*/
void find_usb_keyboards(bool pause_if_none);
/**
* Polls the keyboards discovered by find_usb_keyboards. Consumes and returns
* the HID key code for the first key press it detects. Returns zero if no key
* has been pressed.
*
* Used internally by keyboard.c.
*/
uint8_t get_usb_keycode(void);
#endif // USBHCD_H