#pragma once #include "device.h" // USB, the parts that are the same whatever host controller you have. // // Everything here comes from the USB 2.0 specification chapter 9, which every // USB device implements regardless of speed, class or vendor. That is what // makes enumeration possible at all: before you know anything about a device // you can still ask it what it is, because the question is standardised. // bmRequestType #define USB_DIR_OUT 0x00 #define USB_DIR_IN 0x80 #define USB_TYPE_STANDARD 0x00 #define USB_TYPE_CLASS 0x20 #define USB_RECIP_DEVICE 0x00 #define USB_RECIP_INTERFACE 0x01 #define USB_RECIP_ENDPOINT 0x02 #define USB_RECIP_OTHER 0x03 // a hub's downstream port // bRequest, standard requests #define USB_REQ_GET_STATUS 0 #define USB_REQ_CLEAR_FEATURE 1 #define USB_REQ_SET_FEATURE 3 #define USB_REQ_SET_ADDRESS 5 #define USB_REQ_GET_DESCRIPTOR 6 #define USB_REQ_SET_DESCRIPTOR 7 #define USB_REQ_GET_CONFIG 8 #define USB_REQ_SET_CONFIG 9 #define USB_REQ_GET_INTERFACE 10 #define USB_REQ_SET_INTERFACE 11 // Descriptor types (the high byte of wValue in a GET_DESCRIPTOR) #define USB_DT_DEVICE 1 #define USB_DT_CONFIG 2 #define USB_DT_STRING 3 #define USB_DT_INTERFACE 4 #define USB_DT_ENDPOINT 5 // Class codes we care about #define USB_CLASS_HID 0x03 #define USB_CLASS_MASS_STORAGE 0x08 #define USB_CLASS_HUB 0x09 // HID subclass/protocol. Boot protocol is the one a BIOS uses, and the reason // a USB keyboard works before any operating system has loaded: the report // layout is fixed, so it can be read without parsing a report descriptor. #define USB_HID_SUBCLASS_BOOT 0x01 #define USB_HID_PROTO_KEYBOARD 0x01 #define USB_HID_PROTO_MOUSE 0x02 // Not a USB value: bInterfaceProtocol has no code for "absolute pointer". // A HID device that claims neither boot protocol is treated as a tablet, which // is what a VM offers so its cursor and the guest's can agree. Kept out of the // 0x00-0x02 range the specification defines so it cannot collide. #define USB_HID_PROTO_TABLET 0x80 // Bus speeds. // // These are xHCI's numbering, used as the common currency rather than // translated at the boundary. That is a deliberate choice: there is one host // controller, the values have to reach a slot context eventually, and a // second enum whose only job is to be converted into this one would be // ceremony. If a second controller ever appears, this is the thing to // revisit -- but a class driver still has no business including xhci.h. #define USB_SPEED_FULL 1 // 12 Mb/s #define USB_SPEED_LOW 2 // 1.5 Mb/s #define USB_SPEED_HIGH 3 // 480 Mb/s #define USB_SPEED_SUPER 4 // 5 Gb/s // An eight-byte SETUP packet, the header of every control transfer. struct usb_setup { uint8 bmRequestType; uint8 bRequest; uint16 wValue; uint16 wIndex; uint16 wLength; } __attribute__((packed)); struct usb_device_desc { uint8 bLength; uint8 bDescriptorType; uint16 bcdUSB; uint8 bDeviceClass; uint8 bDeviceSubClass; uint8 bDeviceProtocol; uint8 bMaxPacketSize0; uint16 idVendor; uint16 idProduct; uint16 bcdDevice; uint8 iManufacturer; uint8 iProduct; uint8 iSerialNumber; uint8 bNumConfigurations; } __attribute__((packed)); struct usb_config_desc { uint8 bLength; uint8 bDescriptorType; uint16 wTotalLength; uint8 bNumInterfaces; uint8 bConfigurationValue; uint8 iConfiguration; uint8 bmAttributes; uint8 bMaxPower; } __attribute__((packed)); struct usb_interface_desc { uint8 bLength; uint8 bDescriptorType; uint8 bInterfaceNumber; uint8 bAlternateSetting; uint8 bNumEndpoints; uint8 bInterfaceClass; uint8 bInterfaceSubClass; uint8 bInterfaceProtocol; uint8 iInterface; } __attribute__((packed)); struct usb_endpoint_desc { uint8 bLength; uint8 bDescriptorType; uint8 bEndpointAddress; // bit 7: 1 = IN uint8 bmAttributes; // bits 1:0: 0 ctrl, 1 iso, 2 bulk, 3 interrupt uint16 wMaxPacketSize; uint8 bInterval; } __attribute__((packed)); #define USB_EP_XFERTYPE(a) ((a) & 0x03) #define USB_EP_BULK 2 #define USB_EP_INTERRUPT 3 #define USB_EP_IS_IN(a) (((a) & 0x80) != 0) #define USB_EP_NUM(a) ((a) & 0x0F) // Mass storage: SCSI transparent command set over bulk-only transport. #define USB_MSC_SUBCLASS_SCSI 0x06 #define USB_MSC_PROTO_BOT 0x50 // --------------------------------------------------------------------------- // Hubs // // A hub is a USB device like any other, and everything it does is done by // sending it ordinary control requests. There is no separate bus protocol: // "reset port 3" is a SET_FEATURE addressed to the hub. // --------------------------------------------------------------------------- #define USB_DT_HUB 0x29 // Port features, the wValue of SET_FEATURE / CLEAR_FEATURE on a port. #define PORT_FEAT_ENABLE 1 #define PORT_FEAT_RESET 4 #define PORT_FEAT_POWER 8 #define PORT_FEAT_C_CONNECTION 16 #define PORT_FEAT_C_ENABLE 17 #define PORT_FEAT_C_RESET 20 // wPortStatus, the first half of a port's GET_STATUS reply. #define PORTSTAT_CONNECTION (1 << 0) #define PORTSTAT_ENABLE (1 << 1) #define PORTSTAT_RESET (1 << 4) #define PORTSTAT_POWER (1 << 8) #define PORTSTAT_LOWSPEED (1 << 9) #define PORTSTAT_HIGHSPEED (1 << 10) struct usb_hub_desc { uint8 bDescLength; uint8 bDescriptorType; uint8 bNbrPorts; uint16 wHubCharacteristics; uint8 bPwrOn2PwrGood; // in 2 ms units uint8 bHubContrCurrent; } __attribute__((packed)); // Bits 1:0 of wHubCharacteristics: 00 ganged power, 01 per-port. #define HUB_CHAR_TT_MASK 0x0060 // HID class requests, on the interface rather than the device. #define USB_HID_SET_IDLE 0x0A #define USB_HID_SET_PROTOCOL 0x0B #define USB_HID_PROTOCOL_BOOT 0 #define USB_HID_PROTOCOL_REPORT 1 #define USB_DT_HID 0x21 #define USB_DT_REPORT 0x22 // --------------------------------------------------------------------------- // The interface between the USB core and a host controller // // One host controller exists (xHCI) and one probably always will, but the // core has no business knowing about TRBs and slot IDs, and the controller // has no business knowing what a HID report is. This is where the line goes. // --------------------------------------------------------------------------- struct usb_dev; struct usb_hc_ops { // A control transfer on endpoint 0. `buf`, if any, must be DMA memory. int (*control)(struct usb_dev *, struct usb_setup *, void *buf, int len); // Make an endpoint usable. Returns 0, or -1 if the controller refused. int (*open_ep)(struct usb_dev *, const struct usb_endpoint_desc *); // Queue one IN transfer. Completion arrives via dev->complete. int (*queue_in)(struct usb_dev *, int ep_addr, void *buf, int len); // One bulk transfer, synchronously. Sleeps, so process context only. // Returns bytes transferred, or -1. int (*bulk)(struct usb_dev *, int ep_addr, void *buf, int len); // Bring up a device found on a downstream port of `hub`. The controller // works out the route string from the hub's own position. void (*attach)(struct usb_dev *hub, int hub_port, int speed); // Tell the controller this device is a hub with `nports` ports. It has to // know: a hub is scheduled differently from anything else, and devices // behind it are addressed relative to it. int (*set_hub)(struct usb_dev *, int nports, int mtt); // Whatever is on a hub's downstream port has gone: tear it down, and // everything behind it if it was a hub too. void (*detach)(struct usb_dev *hub, int hub_port); }; #define USB_MAXCONF 512 // bytes of configuration descriptor we keep struct usb_dev { const struct usb_hc_ops *ops; void *hc; // the controller's own handle for this device int slot; int speed; int port; // ROOT hub port this whole branch hangs off // Where the device sits in the tree. // // A USB device has no address of its own that describes its position -- the // controller finds it by being told the path. `route` is xHCI's route // string: five nibbles, one per tier, each holding the downstream port // number taken at that tier. Tier 0 is a device on a root port, and its // route is 0. uint32 route; int tier; // Transaction translator, for a full or low speed device behind a // high-speed hub. The controller has to know which hub is doing the // speed conversion on its behalf, because it is the hub, not the device, // that it actually schedules against. int tt_slot, tt_port; int in_use; // A device with several interfaces is one usb_dev per interface, so that // each can have its own driver -- the keyboard and the mouse on one // wireless receiver are interfaces 0 and 1. `base` is the device's own // usb_dev (the one the controller addressed) for every interface after the // first, and 0 for the first, which is the device itself. struct usb_dev *base; struct usb_device_desc desc; uchar conf[USB_MAXCONF]; // the configuration descriptor and everything int conflen; // that follows it, exactly as the device sent // The first interface, which is all a boot-protocol or bulk-only device // needs, and the endpoints belonging to it. struct usb_interface_desc iface; struct usb_endpoint_desc intr_in; struct usb_endpoint_desc bulk_in; struct usb_endpoint_desc bulk_out; int has_intr_in, has_bulk_in, has_bulk_out; // Filled in by whichever class driver claimed the device. const char *driver; const struct usb_driver *drv; // the same, for calling disconnect void *drvdata; void (*complete)(struct usb_dev *, void *buf, int len); }; // One row per class driver. Matching is on the *interface* descriptor, // because bDeviceClass is very often 0 ("look at the interfaces"). struct usb_driver { const char *name; uint8 class, subclass, protocol; // 0xFF matches anything // What the rest of the kernel should consider this device to be, once this // driver has claimed it. Distinct from `class` above, which is the USB // interface class the descriptor advertises: the driver knows what it made // of the device, the descriptor only says what the device claims to be. enum dev_class devclass; int (*probe)(struct usb_dev *); // The device has been unplugged. Stop using it; the controller frees its // endpoints after this returns. May be 0 for a driver with nothing to undo. void (*disconnect)(struct usb_dev *); }; // Called by a host controller once a device is addressed and its device // descriptor has been read. The core reads the configuration, selects it, and // offers the device to the class drivers. void usb_attach(struct usb_dev *dev); // The device, and every interface of it, is gone. Calls each bound driver's // disconnect. From the controller, before it frees the slot. void usb_detach(struct usb_dev *dev); // Re-check every hub's downstream ports, for devices plugged into or pulled // out of one. From the hot-plug thread; see kernel/drivers/usb/hub/. void usb_hub_poll(void); // The hot-plug thread. After sinit(); see kernel/drivers/bus/xhci/xhci.c. void usb_hotplug_start(void); // Key repeat for USB keyboards, which do not repeat by themselves. Called // every tick from the hot-plug thread; see kernel/drivers/usb/hid/. void usb_hid_tick(void);