Skip to content

Commit 0082911

Browse files
xhci initialises now, and detects keyboard. but ints dont deliver yet
1 parent 5481a47 commit 0082911

File tree

5 files changed

+177
-56
lines changed

5 files changed

+177
-56
lines changed

include/usb_xhci.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ struct xhci_hc {
214214
uint8_t *int_buf; /* dma buffer for reports */
215215
uint64_t int_buf_phys;
216216

217+
int port;
218+
int speed;
219+
217220
uint8_t *ctrl_dma; // low-memory bounce for ctrl DATA stage
218221
uint64_t ctrl_dma_phys; // same value as virtual in your setup
219222
uint16_t ctrl_dma_sz; // size of the bounce buffer

src/kernel.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,8 @@ void kmain()
2323
preboot_fail("Failed to mount boot drive to VFS!");
2424
}
2525

26-
init_usb_xhci();
2726
usb_hid_init();
28-
27+
init_usb_xhci();
2928

3029
init_process();
3130
}

src/usb/hid.c

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,42 +5,78 @@ static void hid_keyboard_report_cb(struct usb_dev *ud, const uint8_t *pkt, uint1
55
if (len < 8u) {
66
return;
77
}
8+
dprintf("keyboard report cb\n");
89
/* pkt[2..7] are keycodes; translate via simple table, raise input events */
910
/* Minimal: stash last key, push to your input layer. */
1011
}
1112

12-
static void hid_on_device_added(const struct usb_dev *ud) {
13-
if (ud->dev_class != USB_CLASS_HID) {
13+
static void hid_on_device_added(const struct usb_dev *ud_c)
14+
{
15+
if (!ud_c) return;
16+
17+
/* Only handle HID Boot Keyboard */
18+
if (!(ud_c->dev_class == USB_CLASS_HID &&
19+
ud_c->dev_subclass == USB_SUBCLASS_BOOT &&
20+
ud_c->dev_proto == USB_PROTO_KEYBOARD)) {
21+
dprintf("hid: ignore dev class=%02x sub=%02x proto=%02x\n",
22+
ud_c->dev_class, ud_c->dev_subclass, ud_c->dev_proto);
23+
return;
24+
}
25+
26+
/* xhci_ctrl_xfer expects non-const usb_dev* */
27+
struct usb_dev *ud = (struct usb_dev *)ud_c;
28+
uint8_t __attribute__((aligned(64))) setup[8];
29+
uint16_t iface = 0;
30+
31+
dprintf("hid: attach keyboard VID:PID=%04x:%04x slot=%u\n",
32+
ud->vid, ud->pid, ud->slot_id);
33+
34+
/* 1) SET_CONFIGURATION(1) */
35+
setup[0] = 0x00; setup[1] = 0x09; /* bm=Std Dev OUT, SET_CONFIGURATION */
36+
setup[2] = 0x01; setup[3] = 0x00; /* wValue = 1 */
37+
setup[4] = 0x00; setup[5] = 0x00; /* wIndex = 0 (device) */
38+
setup[6] = 0x00; setup[7] = 0x00; /* wLength = 0 */
39+
if (!xhci_ctrl_xfer(ud, setup, NULL, 0, 0)) {
40+
dprintf("hid: SET_CONFIGURATION(1) failed\n");
41+
return;
42+
}
43+
dprintf("hid: set configuration ok\n");
44+
45+
/* 2) SET_PROTOCOL(BOOT) on interface 0
46+
bmRequestType=0x21 (Class OUT, Interface), bRequest=0x0B, wValue=0 (BOOT) */
47+
setup[0] = 0x21; setup[1] = 0x0B;
48+
setup[2] = 0x00; setup[3] = 0x00; /* wValue = 0 (BOOT) */
49+
setup[4] = (uint8_t)(iface & 0xFF); /* wIndex = interface */
50+
setup[5] = (uint8_t)(iface >> 8);
51+
setup[6] = 0x00; setup[7] = 0x00; /* wLength = 0 */
52+
if (!xhci_ctrl_xfer(ud, setup, NULL, 0, 0)) {
53+
dprintf("hid: SET_PROTOCOL(BOOT) failed\n");
1454
return;
1555
}
16-
/* Boot interface path only for v0 */
17-
if (ud->dev_subclass == USB_SUBCLASS_BOOT && ud->dev_proto == USB_PROTO_KEYBOARD) {
18-
/* SET_PROTOCOL(0)=Boot, SET_IDLE(0), then arm INT-IN 8 bytes */
19-
uint8_t setup[8];
20-
dprintf("setup=%p\n", &setup);
21-
22-
/* SET_PROTOCOL (Class, Interface) bm=0x21, bReq=0x0B, wValue=0, wIndex=interface, wLength=0
23-
We have a single interface in v0; wIndex=0. */
24-
setup[0] = 0x21u; setup[1] = 0x0Bu;
25-
setup[2] = 0u; setup[3] = 0u; /* wValue */
26-
setup[4] = 0u; setup[5] = 0u; /* wIndex */
27-
setup[6] = 0u; setup[7] = 0u; /* wLength */
28-
(void) xhci_ctrl_xfer(ud, setup, 0, 0, 1);
29-
30-
/* SET_IDLE (0) bm=0x21, bReq=0x0A */
31-
setup[0] = 0x21u; setup[1] = 0x0Au;
32-
setup[2] = 0u; setup[3] = 0u;
33-
setup[4] = 0u; setup[5] = 0u;
34-
setup[6] = 0u; setup[7] = 0u;
35-
(void) xhci_ctrl_xfer(ud, setup, 0, 0, 1);
36-
37-
/* Arm 8-byte boot report stream */
38-
(void) xhci_arm_int_in(ud, 8u, hid_keyboard_report_cb);
56+
dprintf("hid: set protocol(boot) ok\n");
57+
58+
/* 3) SET_IDLE(0) on interface 0
59+
bmRequestType=0x21 (Class OUT, Interface), bRequest=0x0A, wValue=0 (duration=0, reportId=0) */
60+
setup[0] = 0x21; setup[1] = 0x0A;
61+
setup[2] = 0x00; setup[3] = 0x00; /* wValue = 0 */
62+
setup[4] = (uint8_t)(iface & 0xFF);
63+
setup[5] = (uint8_t)(iface >> 8);
64+
setup[6] = 0x00; setup[7] = 0x00;
65+
if (!xhci_ctrl_xfer(ud, setup, NULL, 0, 0)) {
66+
dprintf("hid: SET_IDLE(0) failed\n");
67+
return;
68+
}
69+
dprintf("hid: set idle(0) ok\n");
70+
71+
/* 4) Arm EP1 IN for 8-byte boot reports */
72+
if (!xhci_arm_int_in(ud, 8u, hid_keyboard_report_cb)) {
73+
dprintf("hid: arm EP1 IN failed\n");
74+
return;
3975
}
76+
dprintf("hid: keyboard armed (EP1 IN), waiting for interrupts\n");
4077
}
4178

4279
static void hid_on_device_removed(const struct usb_dev *ud) {
43-
(void)ud;
4480
/* Tear-down if you keep per-device state */
4581
}
4682

src/usb/usb_core.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ int usb_core_register_class(uint8_t class_code, const struct usb_class_ops *ops)
3333
if (g_classes[i].ops == NULL) {
3434
g_classes[i].class_code = class_code;
3535
g_classes[i].ops = (struct usb_class_ops *)ops;
36-
dprintf("usb-core: registered class 0x%02x (%s)\n",
37-
class_code, ops && ops->name ? ops->name : "anon");
36+
dprintf("usb-core: registered class 0x%02x (%s)\n", class_code, ops && ops->name ? ops->name : "anon");
3837
return 1;
3938
}
4039
}
@@ -46,6 +45,8 @@ int usb_core_register_class(uint8_t class_code, const struct usb_class_ops *ops)
4645
void usb_core_device_added(const struct usb_dev *dev) {
4746
if (!dev) return;
4847

48+
dprintf("USB CORE: Device added: slot=%d class=%x subclass=%x\n", dev->slot_id, dev->dev_class, dev->dev_subclass);
49+
4950
if (g_dev_count < MAX_DEVICES) {
5051
g_devices[g_dev_count++] = *dev;
5152
}
@@ -63,6 +64,8 @@ void usb_core_device_added(const struct usb_dev *dev) {
6364
void usb_core_device_removed(const struct usb_dev *dev) {
6465
if (!dev) return;
6566

67+
dprintf("USB CORE: Device removed: slot=%d class=%x subclass=%x\n", dev->slot_id, dev->dev_class, dev->dev_subclass);
68+
6669
for (size_t i = 0; i < MAX_CLASS_SLOTS; i++) {
6770
if (!g_classes[i].ops) continue;
6871
if (g_classes[i].class_code == dev->dev_class) {

src/usb/xhci.c

Lines changed: 106 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,30 @@ static int xhci_cmd_submit_wait(struct xhci_hc *hc, struct trb *cmd_trb, uint64_
7676
uint32_t type = (e->ctrl >> 10) & 0x3Fu;
7777
uint64_t evt_ptr = ((uint64_t)e->hi << 32) | e->lo;
7878

79-
dprintf("xhci.dbg: evt[%u] type=%u lo=%08x hi=%08x sts=%08x match=%s\n",
80-
i, type, e->lo, e->hi, e->sts, (evt_ptr == cmd_phys ? "yes" : "no"));
81-
82-
if (type == TRB_CMD_COMPLETION && evt_ptr == cmd_phys) {
83-
/* bump ERDP and consume */
84-
memset(e, 0, sizeof(*e));
85-
uint64_t erdp = mmio_read64(ir0 + IR_ERDP);
86-
erdp = (erdp & ~0x7ull) + 16;
87-
mmio_write64(ir0 + IR_ERDP, erdp | (1ull << 3));
88-
dprintf("xhci.dbg: cmd complete, ERDP=%llx\n", (unsigned long long)(erdp | (1ull << 3)));
89-
return 1;
79+
if (type == TRB_CMD_COMPLETION) {
80+
uint32_t cc = (e->sts >> 24) & 0xFFu;
81+
dprintf("xhci.dbg: evt[%u] type=%u lo=%08x hi=%08x sts=%08x cc=%02x match=%s\n",
82+
i, type, e->lo, e->hi, e->sts, cc, (evt_ptr == cmd_phys ? "yes" : "no"));
83+
84+
if (evt_ptr == cmd_phys) {
85+
/* consume event and bump ERDP */
86+
memset(e, 0, sizeof(*e));
87+
uint64_t erdp = mmio_read64(ir0 + IR_ERDP);
88+
erdp = (erdp & ~0x7ull) + 16;
89+
mmio_write64(ir0 + IR_ERDP, erdp | (1ull << 3));
90+
dprintf("xhci.dbg: cmd complete, ERDP=%llx\n",
91+
(unsigned long long)(erdp | (1ull << 3)));
92+
93+
/* success only if CC == 1 */
94+
if (cc != 0x01u) {
95+
dprintf("xhci.dbg: command failed, cc=%02x\n", cc);
96+
return 0;
97+
}
98+
return 1;
99+
}
100+
} else {
101+
dprintf("xhci.dbg: evt[%u] type=%u lo=%08x hi=%08x sts=%08x match=%s\n",
102+
i, type, e->lo, e->hi, e->sts, (evt_ptr == cmd_phys ? "yes" : "no"));
90103
}
91104
}
92105
if ((int64_t)(get_ticks() - deadline) > 0) break;
@@ -264,10 +277,41 @@ static void ctx_program_ep0(struct ep_ctx *e, uint16_t mps, uint64_t tr_deq_phys
264277
e->dword4 = 8u; /* avg TRB len */
265278
}
266279

267-
static void ctx_program_ep1_in(struct ep_ctx *e, uint16_t mps, uint64_t tr_deq_phys, uint16_t esit_payload) {
268-
e->dword0 = ((uint32_t)mps << 16) | (7u << 3) | (3u << 1); /* Interrupt IN */
269-
e->deq = (tr_deq_phys | 1u);
270-
e->dword4 = ((uint32_t)esit_payload << 16) | (uint32_t)esit_payload;
280+
/* ---- EP context helpers ---- */
281+
static void ctx_program_ep1_in(struct ep_ctx *e,
282+
uint16_t mps,
283+
uint64_t tr_deq_phys,
284+
uint16_t esit_payload /* bytes per interval */)
285+
{
286+
/*
287+
* Dword0:
288+
* bits 31:16 = Max Packet Size
289+
* bits 10:8 = EP Type (7 = Interrupt IN)
290+
* bits 2:1 = CErr (3)
291+
*/
292+
e->dword0 = ((uint32_t)mps << 16) | (7u << 3) | (3u << 1);
293+
294+
/*
295+
* Dword1:
296+
* bits 15:0 = Interval (ESIT interval in microframes/frames encoding).
297+
* A small non-zero works with QEMU/typical HID; set 1 as a safe default.
298+
* (If you later parse the endpoint descriptor, use bInterval here.)
299+
*/
300+
e->dword1 = 1u; /* Interval = 1 (minimum, valid) */
301+
302+
/*
303+
* Dword2/Dword3:
304+
* Transfer Ring Dequeue Pointer (64-bit) with DCS bit set to current ring cycle.
305+
* You already keep your transfer ring's cycle = 1 initially, so set DCS=1.
306+
*/
307+
e->deq = (tr_deq_phys | 1u); /* DCS=1 */
308+
309+
/*
310+
* Dword4:
311+
* bits 31:16 = Average TRB Length (best-effort hint; 8 is fine for 8-byte reports)
312+
* bits 15:0 = Max ESIT Payload (max bytes per service interval)
313+
*/
314+
e->dword4 = ((uint32_t)esit_payload << 16) | (uint32_t)esit_payload;
271315
}
272316

273317
/* ---- tiny inline control transfer used during enum (debug/verbose) ---- */
@@ -505,8 +549,8 @@ static int xhci_enumerate_first_device(struct xhci_hc *hc, struct usb_dev *out_u
505549
}
506550

507551
/* === GET_DESCRIPTOR(Device, first 8 bytes) === */
508-
uint8_t __attribute__((aligned(64))) setup_dev8[8] = { 0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 8, 0x00 };
509-
uint8_t __attribute__((aligned(64))) dev_desc[256];
552+
uint8_t __attribute__((aligned(64))) setup_dev8[8] = { 0x80, 0x06, 0x00, 0x01, 0x00, 0x00, 8, 0x00 };
553+
uint8_t __attribute__((aligned(64))) dev_desc[256];
510554
memset(dev_desc, 0, sizeof(dev_desc));
511555

512556
dprintf("HERE 1 setup8_dev=%p dev_desc=%p\n", &setup_dev8, &dev_desc);
@@ -603,7 +647,6 @@ static int xhci_enumerate_first_device(struct xhci_hc *hc, struct usb_dev *out_u
603647

604648
static void xhci_isr(uint8_t isr, uint64_t error, uint64_t irq, void *opaque)
605649
{
606-
(void)isr; (void)error; (void)irq;
607650
struct xhci_hc *hc = (struct xhci_hc *)opaque;
608651
if (!hc || !hc->cap) return;
609652

@@ -617,6 +660,8 @@ static void xhci_isr(uint8_t isr, uint64_t error, uint64_t irq, void *opaque)
617660
mmio_write32(ir0 + IR_IMAN, iman & ~IR_IMAN_IP);
618661
}
619662

663+
dprintf("xhci int\n");
664+
620665
for (uint32_t i = 0; i < hc->evt.num_trbs; i++) {
621666
struct trb *e = &hc->evt.base[i];
622667
if (e->ctrl == 0 && e->lo == 0 && e->hi == 0 && e->sts == 0) continue;
@@ -626,6 +671,7 @@ static void xhci_isr(uint8_t isr, uint64_t error, uint64_t irq, void *opaque)
626671
i, type, e->lo, e->hi, e->sts);
627672

628673
if (type == TRB_TRANSFER_EVENT) {
674+
dprintf("xhci transfer event\n");
629675
if (hc->dev.int_cb && hc->dev.int_buf && hc->dev.int_pkt_len) {
630676
struct usb_dev ud = {0};
631677
ud.hc = hc;
@@ -650,44 +696,78 @@ static void xhci_isr(uint8_t isr, uint64_t error, uint64_t irq, void *opaque)
650696
}
651697
}
652698

653-
/* ---- public interrupts-in arming ---- */
654699
int xhci_arm_int_in(struct usb_dev *ud, uint16_t pkt_len, xhci_int_in_cb cb) {
655700
if (!ud || !ud->hc || !pkt_len || !cb) return 0;
656701
struct xhci_hc *hc = (struct xhci_hc *) ud->hc;
657702

658703
if (!hc->dev.int_in_tr.base) {
659704
void *v = kmalloc_aligned(4096, 4096);
660705
uint64_t p = (uint64_t)(uintptr_t) v;
706+
if (!v) { dprintf("xhci.dbg: INT-IN TR alloc fail\n"); return 0; }
661707
ring_init(&hc->dev.int_in_tr, 4096, p, v);
662708
}
663709

664710
if (!hc->dev.int_buf) {
665711
hc->dev.int_buf = (uint8_t *) kmalloc_aligned(pkt_len, 64);
712+
if (!hc->dev.int_buf) { dprintf("xhci.dbg: INT-IN buf alloc fail (%u)\n", pkt_len); return 0; }
666713
hc->dev.int_buf_phys = (uint64_t)(uintptr_t) hc->dev.int_buf;
667714
}
668715
hc->dev.int_cb = cb;
669716
hc->dev.int_pkt_len = pkt_len;
670717

671-
/* Configure EP1 IN via Configure Endpoint */
672-
hc->dev.ic->add_flags = 0x00000009u; /* A0(slot) + A3(ep1 in) */
673-
ctx_program_ep1_in(&hc->dev.ic->ep1_in, 8u /* default */, hc->dev.int_in_tr.phys, pkt_len);
718+
/* Input Control Context */
719+
hc->dev.ic->drop_flags = 0;
720+
hc->dev.ic->add_flags = 0x0000000B; /* A0(slot) | A1(ep0) | A3(ep1 IN) */
674721

722+
/* Ensure Slot Context Context Entries covers EPID=3 (slot+ep0+ep1 IN => CE >= 3) */
723+
{
724+
uint32_t s0 = hc->dev.ic->slot.dword0;
725+
uint32_t ce = (s0 >> 27) & 0x1F;
726+
if (ce < 3u) { s0 = (s0 & ~(0x1Fu << 27)) | (3u << 27); hc->dev.ic->slot.dword0 = s0; }
727+
}
728+
729+
/* ICC "config triplet": config=1, interface=0, alt=0 */
730+
*(volatile uint32_t *)((uint8_t*)hc->dev.ic + 0x08) = 1;
731+
*(volatile uint32_t *)((uint8_t*)hc->dev.ic + 0x0C) = 0;
732+
*(volatile uint32_t *)((uint8_t*)hc->dev.ic + 0x10) = 0;
733+
734+
/* Program EP1 IN context (clear first, then set fields) */
735+
memset(&hc->dev.ic->ep1_in, 0, sizeof(hc->dev.ic->ep1_in));
736+
ctx_program_ep1_in(&hc->dev.ic->ep1_in,
737+
8u, /* MPS for boot kbd int IN */
738+
hc->dev.int_in_tr.phys, /* TR Dequeue (DCS set inside) */
739+
pkt_len); /* Max ESIT payload */
740+
741+
dprintf("xhci.dbg: CONFIGURE_EP add_flags=%08x slot.dword0=%08x (CE=%u)\n",
742+
hc->dev.ic->add_flags,
743+
hc->dev.ic->slot.dword0,
744+
(hc->dev.ic->slot.dword0 >> 27) & 0x1F);
745+
746+
/* Issue Configure Endpoint */
675747
struct trb *ce = xhci_cmd_begin(hc);
676748
ce->lo = (uint32_t)(hc->dev.ic_phys & 0xFFFFFFFFu);
677749
ce->hi = (uint32_t)(hc->dev.ic_phys >> 32);
678750
ce->ctrl |= TRB_SET_TYPE(TRB_CONFIGURE_EP) | ((uint32_t)ud->slot_id << 24);
751+
dprintf("xhci.dbg: ring_push for CONFIGURE_EP trb=%08x ic_phys=%08x\n",
752+
(uint32_t)(uintptr_t)ce, (uint32_t)(hc->dev.ic_phys & 0xFFFFFFFFu));
753+
679754
if (!xhci_cmd_submit_wait(hc, ce, NULL)) {
755+
dprintf("xhci.dbg: CONFIGURE_EP timeout/fail\n");
680756
return 0;
681757
}
682758

683-
/* Post first Normal TRB; ISR will keep re-arming */
759+
/* Post first INT-IN Normal TRB and doorbell EP1 IN */
684760
struct trb *n = ring_push(&hc->dev.int_in_tr);
685761
n->lo = (uint32_t)(hc->dev.int_buf_phys & 0xFFFFFFFFu);
686762
n->hi = (uint32_t)(hc->dev.int_buf_phys >> 32);
687763
n->sts = hc->dev.int_pkt_len;
688-
n->ctrl = TRB_SET_TYPE(TRB_NORMAL) | TRB_IOC | (hc->dev.int_in_tr.cycle ? TRB_CYCLE : 0);
764+
n->ctrl = TRB_SET_TYPE(TRB_NORMAL) | TRB_IOC |
765+
(hc->dev.int_in_tr.cycle ? TRB_CYCLE : 0);
766+
dprintf("xhci.dbg: INT-IN normal TRB @%08x lo=%08x hi=%08x len=%u\n",
767+
(uint32_t)(uintptr_t)n, n->lo, n->hi, n->sts);
689768

690769
mmio_write32(hc->db + 4u * ud->slot_id, EPID_EP1_IN);
770+
dprintf("xhci.dbg: doorbell EP1 IN (slot=%u)\n", ud->slot_id);
691771
return 1;
692772
}
693773

@@ -725,12 +805,12 @@ int xhci_probe_and_init(uint8_t bus, uint8_t dev, uint8_t func) {
725805
struct usb_dev ud;
726806
if (!xhci_enumerate_first_device(g_xhci, &ud)) {
727807
dprintf("xhci: controller up, 0 devices present\n");
728-
kprintf("USB xHCI: controller ready (interrupts on), published 0 devices\n");
808+
dprintf("USB xHCI: controller ready (interrupts on), published 0 devices\n");
729809
return 1; /* host is fine; no device yet */
730810
}
731811

732812
usb_core_device_added(&ud);
733-
kprintf("USB xHCI: controller ready (interrupts on), published 1 device\n");
813+
dprintf("USB xHCI: controller ready (interrupts on), published 1 device\n");
734814
return 1;
735815
}
736816

0 commit comments

Comments
 (0)