blob: 0589bc52e23eddc5edb9d6d186f782b2acde5e0c [file] [log] [blame]
/*
* Copyright (C) 2008 coresystems GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef __USB_H
#define __USB_H
#include <pci.h>
#include <stddef.h>
#include <stdint.h>
typedef enum {
UsbHostToDevice = 0,
UsbDeviceToHost = 1
} UsbDevReqDir;
typedef enum {
UsbStandardType = 0,
UsbClassType = 1,
UsbVendorType = 2,
UsbReservedType = 3
} UsbDevReqType;
typedef enum {
UsbDevRecp = 0,
UsbIfaceRecp = 1,
UsbEndpRecp = 2,
UsbOtherRecp = 3
} UsbDevReqRecp;
enum {
UsbDescTypeDev = 1,
UsbDescTypeCfg = 2,
UsbDescTypeStr = 3,
UsbDescTypeIntf = 4,
UsbDescTypeEndp = 5,
};
typedef enum {
UsbReqGetStatus = 0,
UsbReqClearFeature = 1,
UsbReqSetFeature = 3,
UsbReqSetAddress = 5,
UsbReqGetDescriptor = 6,
UsbReqSetDescriptor = 7,
UsbReqGetConfiguration = 8,
UsbReqSetConfiguration = 9,
UsbReqGetInterface = 10,
UsbReqSetInterface = 11,
UsbReqSynchFrame = 12
} bRequestCodes;
// Feature selectors.
enum {
UsbEndpointHalt = 0,
UsbDeviceRemoteWakeup = 1,
UsbTestMode = 2
};
// SetAddress() recovery interval (USB 2.0 specification 9.2.6.3).
#define SET_ADDRESS_MDELAY 2
typedef struct {
uint8_t bDescLength;
uint8_t bDescriptorType;
uint8_t bNbrPorts;
union {
struct {
uint32_t logicalPowerSwitchingMode:2;
uint32_t isCompoundDevice:1;
uint32_t overcurrentProtectionMode:2;
uint32_t ttThinkTime:2;
uint32_t arePortIndicatorsSupported:1;
uint32_t:8;
} __attribute__ ((packed));
uint16_t wHubCharacteristics;
} __attribute__ ((packed));
uint8_t bPowerOn2PwrGood;
uint8_t bHubContrCurrent;
} __attribute__ ((packed)) UsbHubDescriptor;
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
} __attribute__ ((packed)) UsbDeviceDescriptor;
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength;
uint8_t bNumInterfaces;
uint8_t bConfigurationValue;
uint8_t iConfiguration;
uint8_t bmAttributes;
uint8_t bMaxPower;
} __attribute__ ((packed)) UsbConfigurationDescriptor;
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
} __attribute__ ((packed)) UsbInterfaceDescriptor;
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
} __attribute__ ((packed)) UsbEndpointDescriptor;
typedef struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdHID;
uint8_t bCountryCode;
uint8_t bNumDescriptors;
uint8_t bReportDescriptorType;
uint16_t wReportDescriptorLength;
} __attribute__ ((packed)) UsbHidDescriptor;
typedef struct {
union {
struct {
UsbDevReqRecp req_recp:5;
UsbDevReqType req_type:2;
UsbDevReqDir data_dir:1;
} __attribute__ ((packed));
uint8_t bmRequestType;
} __attribute__ ((packed));
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
} __attribute__ ((packed)) UsbDevReq;
struct UsbDevHc;
typedef struct UsbDevHc UsbDevHc;
struct UsbDev;
typedef struct UsbDev UsbDev;
typedef enum {
UsbDirSetup,
UsbDirIn,
UsbDirOut
} UsbDirection;
typedef enum {
UsbEndpTypeControl = 0,
UsbEndpTypeIsochronous = 1,
UsbEndpTypeBulk = 2,
UsbEndpTypeInterrupt = 3
} UsbEndpointType;
typedef struct {
UsbDev *dev;
int endpoint;
UsbDirection direction;
int toggle;
int maxpacketsize;
UsbEndpointType type;
int interval; // Expressed as binary logarithm of the number
// of microframes (i.e. t = 125us * 2 ^ interval).
} UsbEndpoint;
typedef enum {
UsbFullSpeed = 0,
UsbLowSpeed = 1,
UsbHighSpeed = 2,
UsbSuperSpeed = 3,
} UsbSpeed;
struct UsbDev {
UsbDevHc *controller;
UsbEndpoint endpoints[32];
int num_endp;
int address; // usb address
int hub; // hub, device is attached to
int port; // port where device is attached
UsbSpeed speed;
uint32_t quirks; // quirks field. got to love usb
void *data;
UsbDeviceDescriptor *descriptor;
UsbConfigurationDescriptor *configuration;
void (*init)(UsbDev *dev);
void (*destroy)(UsbDev *dev);
void (*poll)(UsbDev *dev);
};
typedef enum {
UsbOhci = 0,
UsbUhci = 1,
UsbEhci = 2,
UsbXhci = 3,
UsbDwc2 = 4
} UsbHcType;
struct UsbDevHc {
UsbDevHc *next;
uintptr_t reg_base;
pcidev_t pcidev; // 0 if not used (eg on ARM)
UsbHcType type;
int latest_address;
UsbDev *devices[128]; // dev 0 is root hub, 127 is last addressable
/* start(): Resume operation. */
void (*start)(UsbDevHc *controller);
/* stop(): Stop operation but keep controller initialized. */
void (*stop)(UsbDevHc *controller);
/* reset(): Perform a controller reset. The controller needs to
be (re)initialized afterwards to work (again). */
void (*reset)(UsbDevHc *controller);
/* init(): Initialize a (previously reset) controller
to a working state. */
void (*init)(UsbDevHc *controller);
/* shutdown(): Stop operation, detach host controller and shutdown
this driver instance. After calling shutdown() any
other usage of this UsbDevHc* is invalid. */
void (*shutdown)(UsbDevHc *controller);
int (*bulk)(UsbEndpoint *ep, int size, uint8_t *data, int finalize);
int (*control)(UsbDev *dev, UsbDirection pid, int dr_length,
void *devreq, int data_length, uint8_t *data);
void* (*create_intr_queue)(UsbEndpoint *ep, int reqsize, int reqcount,
int reqtiming);
void (*destroy_intr_queue)(UsbEndpoint *ep, void *queue);
uint8_t* (*poll_intr_queue)(void *queue);
void *instance;
/* set_address(): Tell the usb device its address (xHCI
controllers want to do this by
themselves). Also, allocate the usbdev
structure, initialize enpoint 0
(including MPS) and return it. */
UsbDev *(*set_address)(UsbDevHc *controller, UsbSpeed speed,
int hubport, int hubaddr);
/* finish_device_config(): Another hook for xHCI,
returns 0 on success. */
int (*finish_device_config)(UsbDev *dev);
/* destroy_device(): Finally, destroy all structures that
were allocated during set_address()
and finish_device_config(). */
void (*destroy_device)(UsbDevHc *controller, int devaddr);
};
UsbDevHc *usb_add_mmio_hc(UsbHcType type, void *bar);
UsbDevHc *new_controller(void);
void detach_controller(UsbDevHc *controller);
void usb_poll(void);
UsbDev *init_device_entry(UsbDevHc *controller, int num);
int usb_decode_mps0(UsbSpeed speed, uint8_t bMaxPacketSize0);
int usb_set_feature(UsbDev *dev, int endp, int feature, int rtype);
int usb_get_status(UsbDev *dev, int endp, int rtype, int len, void *data);
int usb_get_descriptor(UsbDev *dev, int rtype, int descType, int descIdx,
void *data, size_t len);
int usb_set_configuration(UsbDev *dev);
int usb_clear_feature(UsbDev *dev, int endp, int feature, int rtype);
int usb_clear_stall(UsbEndpoint *ep);
void usb_nop_init(UsbDev *dev);
void usb_hub_init(UsbDev *dev);
void usb_hid_init(UsbDev *dev);
void usb_msc_init(UsbDev *dev);
void usb_generic_init(UsbDev *dev);
int usb_closest_usb2_hub(const UsbDev *dev, int *const addr, int *const port);
static inline unsigned char usb_gen_bmRequestType(UsbDevReqDir dir,
UsbDevReqType type,
UsbDevReqRecp recp)
{
return (dir << 7) | (type << 5) | recp;
}
// Default "set address" handler.
UsbDev *usb_generic_set_address(UsbDevHc *controller, UsbSpeed speed,
int hubport, int hubaddr);
void usb_detach_device(UsbDevHc *controller, int devno);
int usb_attach_device(UsbDevHc *controller, int hubaddress, int port,
UsbSpeed speed);
uint32_t usb_quirk_check(uint16_t vendor, uint16_t device);
int usb_interface_check(uint16_t vendor, uint16_t device);
enum {
USB_QUIRK_MSC_FORCE_PROTO_SCSI = 1 << 0,
USB_QUIRK_MSC_FORCE_PROTO_ATAPI = 1 << 1,
USB_QUIRK_MSC_FORCE_PROTO_UFI = 1 << 2,
USB_QUIRK_MSC_FORCE_PROTO_RBC = 1 << 3,
USB_QUIRK_MSC_FORCE_TRANS_BBB = 1 << 4,
USB_QUIRK_MSC_FORCE_TRANS_CBI = 1 << 5,
USB_QUIRK_MSC_FORCE_TRANS_CBI_I = 1 << 6,
USB_QUIRK_MSC_NO_TEST_UNIT_READY = 1 << 7,
USB_QUIRK_MSC_SHORT_INQUIRY = 1 << 8,
USB_QUIRK_TEST = 1 << 31,
USB_QUIRK_NONE = 0
};
static inline void usb_debug(const char *fmt, ...)
{
#ifdef USB_DEBUG
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
#endif
}
/**
* To be implemented by libpayload-client. It's called by the USB stack
* when a new USB device is found which isn't claimed by a built in driver,
* so the client has the chance to know about it.
*
* @param dev descriptor for the USB device
*/
void __attribute__((weak)) usb_generic_create(UsbDev *dev);
/**
* To be implemented by libpayload-client. It's called by the USB stack
* when it finds out that a USB device is removed which wasn't claimed by a
* built in driver.
*
* @param dev descriptor for the USB device
*/
void __attribute__((weak)) usb_generic_remove(UsbDev *dev);
int usb_initialize(void);
int usb_exit(void);
#endif