include: one folder per subsystem, and includes that name it
Sixty-five headers sat side by side in include/, so `#include "irq.h"` said nothing about where irq.h was or what it belonged to, and errno.h, stat.h and fcntl.h at the top shadowed the system's for any host tool built with -I./include. They are in folders now -- arch/ core/ fs/ dev/ gfx/ net/ uapi/ (and ldls/ for the Linux driver layer) -- and every include names the folder, as Linux's do: "core/proc.h". Done mechanically and checked the hard way: the kernel built from this tree disassembles identically to the one built from the tree before it. The full image boots, and userland is the same set of programs. Paths in docs and comments follow; docs/guides/layout.md has a table of what is where, and tools/fix-includes.py rewrites old-style includes from the folders in the tree, for code written before this. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
0e39e711f1
commit
a1c965da1e
267 changed files with 1560 additions and 1440 deletions
302
include/dev/usb.h
Normal file
302
include/dev/usb.h
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
#pragma once
|
||||
|
||||
#include "dev/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);
|
||||
|
||||
Loading…
Reference in a new issue