usb: plug and play -- hot-plug, unplug, every interface, real mice
Devices can now arrive and leave after boot. A "usbhotplug" kernel thread handles root-port changes, which it is told about by Port Status Change events and also checks for every quarter second. It also handles changes behind hubs, which each hub reports on its status-change endpoint. An unplugged device has its endpoints closed and any transfer in flight failed. Then its drivers' disconnect hooks run, the slot is disabled and its memory is freed. Everything behind a hub that goes goes with it. This needed the interrupt handler to file command and endpoint-0 completions for their waiters, so that enumeration can run while keyboards interrupt. On real hardware: the controller is taken from the firmware through USB Legacy Support before reset, with SMIs off. On Intel 7/8/9 series parts the ports are switched over from EHCI, which is where firmware leaves them. Every interface of a device is offered to the class drivers, not just the first, so a receiver's mouse on interface 1 gets a driver. Configure Endpoint now copies the slot context from the controller. Before, it rebuilt it and lost the route string and TT fields of devices behind hubs. HID: pointers are read in report protocol from their report descriptor. That covers buttons, X/Y and wheel, relative or absolute, and report IDs. Boot protocol is kept as the fallback for mice and for keyboards. Non-pointer HID interfaces are declined rather than treated as tablets. USB keyboards get software key repeat. Mass storage handles up to four sticks, each unregistered from the block layer when it is pulled out, along with its cached blocks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HH7xukt4aaiGj1nQEAoQf1
This commit is contained in:
parent
c1e52e172f
commit
fa7669254e
13 changed files with 1367 additions and 240 deletions
|
|
@ -56,18 +56,43 @@ interrupts disabled and no scheduler, so a driver that waited for an interrupt
|
|||
during probe would wait forever.
|
||||
|
||||
Interrupts are registered afterwards, for when a device is actually delivering
|
||||
data.
|
||||
data. From then on the interrupt handler is the event ring's only reader:
|
||||
command completions and endpoint-0 completions are filed per slot, and whoever
|
||||
issued them is woken to collect them. That is what lets enumeration happen
|
||||
again later, from a thread, while keyboards are interrupting.
|
||||
|
||||
Before reset the driver takes the controller from the firmware (USB Legacy
|
||||
Support: OS Owned, wait for BIOS Owned to clear, SMIs off), and on Intel 7/8/9
|
||||
series chipsets switches the ports over from the EHCI controllers, which is
|
||||
where the firmware leaves them.
|
||||
|
||||
### Hot-plug
|
||||
|
||||
The `usbhotplug` kernel thread owns every enumeration after boot. It looks at
|
||||
the root ports whenever the controller reports a port change and every quarter
|
||||
second regardless, and at hubs whenever their status-change endpoint reports
|
||||
one. A device that arrives is debounced for 100 ms and enumerated exactly as at
|
||||
boot; one that leaves has its endpoints closed (failing any transfer in flight),
|
||||
its drivers' `disconnect` called, its slot disabled and its memory freed, and
|
||||
the same for everything behind it if it was a hub. A device that will not
|
||||
enumerate is left alone until it is unplugged, not retried for ever.
|
||||
|
||||
The thread also drives key repeat for USB keyboards, which do not repeat by
|
||||
themselves: 500 ms, then about 33 a second, as the PS/2 keyboard's firmware
|
||||
does.
|
||||
|
||||
## Class drivers
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **HID** (`usb/hid/`) | Boot protocol keyboard and mouse, driven from the IRQ handler, feeding the same input paths as PS/2. |
|
||||
| **Mass storage** (`usb/storage/`) | Bulk-only transport and SCSI, presenting a block device. A superblock reads back through `bread()`. |
|
||||
| **Hub** (`usb/hub/`) | Route strings, hub slot contexts, per-port reset and power. |
|
||||
| **HID** (`usb/hid/`) | Keyboards in boot protocol. Pointers in report protocol, from their report descriptor: buttons, X, Y and wheel, relative (mice) or absolute (tablets, VM pointers), with report IDs. A boot mouse whose descriptor cannot be used falls back to boot protocol. Feeds the same input paths as PS/2. |
|
||||
| **Mass storage** (`usb/storage/`) | Bulk-only transport and SCSI. Up to four sticks, `usb0`..`usb3`, each registered with the block layer with its partitions; pulling one out unregisters it. |
|
||||
| **Hub** (`usb/hub/`) | Route strings, hub slot contexts, per-port reset and power, and the status-change endpoint for hot-plug behind the hub. |
|
||||
|
||||
Class drivers are offered a device by the core once its interface descriptor has
|
||||
been read, from the list in `kernel/drivers/registry.c`. Whichever claims it
|
||||
Class drivers are offered **every interface** of a device, each as its own
|
||||
`usb_dev`, once the configuration has been read, from the list in
|
||||
`kernel/drivers/registry.c` — a wireless receiver's keyboard and mouse are
|
||||
interfaces 0 and 1 and get a driver each. Whichever claims it
|
||||
publishes a `struct device` in the bus-agnostic list, **with the class the driver
|
||||
chose rather than the one the descriptor claimed** — the descriptor says what the
|
||||
device says it is, and the driver knows what it made of it.
|
||||
|
|
@ -100,17 +125,15 @@ working one.
|
|||
|
||||
## What it does not do
|
||||
|
||||
- **A USB disk cannot be mounted or booted from.** The block device works and
|
||||
`bread()` reads a superblock off it; the root device is compiled in rather than
|
||||
selectable, so nothing can be told to use it. This is the largest single gap
|
||||
and it is item 1 of [../plan/roadmap.md](../plan/roadmap.md).
|
||||
- **Boot protocol only** for HID. No report descriptor parsing, so anything that
|
||||
is not a plain keyboard or mouse is not understood.
|
||||
- **Pulling out a stick a filesystem is mounted from panics** on that
|
||||
filesystem's next read, by the rule in `blkdev_rw()`: a filesystem that went on
|
||||
with missing blocks would be guessing.
|
||||
- **HID is keyboards and pointers.** Consumer-control interfaces (volume keys),
|
||||
game pads and the rest are declined. Keyboard LEDs are not driven.
|
||||
- **USB 3 hubs** are not driven: the hub driver speaks the USB 2 hub protocol.
|
||||
- **No isochronous transfers**, so no audio and no cameras.
|
||||
- **No USB 3 SuperSpeed-specific features** beyond what enumeration needs — the
|
||||
USB2 and USB3 descriptor paths both work, the rest of the difference is unused.
|
||||
- **16 device slots**, compile-time.
|
||||
- **No hot-unplug.** A device removed is not noticed; the device model has no
|
||||
removal path either.
|
||||
- **One controller.** A second xHCI card would bind and then contend for state
|
||||
the driver keeps per-driver rather than per-instance.
|
||||
|
|
|
|||
|
|
@ -14,13 +14,13 @@ boxes, is now `usb`, `networking.md`, `graphics.md` and `devices.md` over there.
|
|||
|
||||
## 1. Storage and the boot path
|
||||
|
||||
**Make a USB disk mountable and bootable.** The xHCI stack, the bulk-only
|
||||
transport, the SCSI layer and the block device all work — a superblock reads back
|
||||
through `bread()`. What is missing is that **the root device is compiled in
|
||||
rather than selectable**, so nothing can be told to mount it.
|
||||
**Done: a USB disk, a SATA disk and their partitions can be booted from.** The
|
||||
root is chosen at boot from what is present (`rootdev_mount()` in
|
||||
`kernel/proc/proc.c`), and `make disk` builds a GPT image with an ESP and a SchFS
|
||||
partition that a PC boots from a stick or a disk.
|
||||
|
||||
This is also the first piece of the installer, and it is the single change that
|
||||
would most enlarge what SchOS can boot from.
|
||||
**Next: NVMe**, through the same block registry, and an installer that writes
|
||||
that layout to a disk.
|
||||
|
||||
## 2. Graphics
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue