Skip to content

Commit 7e5f26e

Browse files
interrupt stuff
1 parent 0ee7a96 commit 7e5f26e

File tree

4 files changed

+133
-70
lines changed

4 files changed

+133
-70
lines changed

include/usb_xhci.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ struct usb_ep {
7171
#define TRB_TRANSFER_EVENT 32
7272
#define TRB_CMD_COMPLETION 33
7373
#define TRB_PORT_STATUS 34
74+
#define TRB_BANDWIDTH_REQUEST 35
75+
#define TRB_DOORBELL_EVENT 36
76+
#define TRB_HOST_CONTROLLER_EVENT 37
77+
#define TRB_DEVICE_NOTIFICATION 38
78+
#define TRB_MFINDEX_WRAP_EVENT 39
7479

7580
/* endpoint ids per xHCI: 1=EP0, 2/3=EP1 OUT/IN, ... */
7681
#define EPID_CTRL 1
@@ -96,6 +101,9 @@ struct usb_ep {
96101
#define PORTSC_PLC (1u << 22) /* Port Link State Change */
97102
#define PORTSC_CEC (1u << 23) /* Port Config Error Change */
98103

104+
#define CC_SUCCESS 0x01
105+
#define CC_SHORT_PACKET 0x0D
106+
99107
#define PORTSC_RW1C_MASK (PORTSC_CSC | PORTSC_PEC | PORTSC_WRC | PORTSC_OCC | PORTSC_PRC | PORTSC_PLC | PORTSC_CEC)
100108

101109
/* helper macros to build TRB fields */

src/kernel.c

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

26-
usb_core_init();
26+
/*usb_core_init();
2727
usb_hid_init();
28-
init_usb_xhci();
28+
init_usb_xhci()*/
2929

3030
init_process();
3131
}

src/usb/hid.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,15 @@ static void process_mod_changes(uint8_t prev_mod, uint8_t cur_mod)
151151

152152
static void hid_keyboard_report_cb(struct usb_dev *ud, const uint8_t *pkt, uint16_t len)
153153
{
154-
(void)ud;
155154
if (len < 8u) return;
156155

157-
/* drop identical snapshot (disables HID’s built-in key repeat) */
158-
if (memcmp(pkt, last_report, 8) == 0) return;
156+
dprintf("enter\n");
157+
158+
/* disable HID’s built-in key repeat */
159+
if (memcmp(pkt, last_report, 8) == 0) {
160+
dprintf("leave rep\n");
161+
return;
162+
}
159163

160164
/* 1) modifiers (byte 0) */
161165
process_mod_changes(last_report[0], pkt[0]);
@@ -178,6 +182,8 @@ static void hid_keyboard_report_cb(struct usb_dev *ud, const uint8_t *pkt, uint1
178182
}
179183

180184
memcpy(last_report, pkt, 8);
185+
186+
dprintf("leave\n");
181187
}
182188

183189
static void hid_on_device_added(const struct usb_dev *ud_c)

src/usb/xhci.c

Lines changed: 114 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,76 @@
55

66
static struct xhci_hc* g_xhci; /* single controller */
77

8-
static void xhci_deliver_ep1in(struct xhci_hc *hc, const struct trb *ev);
8+
static void xhci_deliver_ep1in(struct xhci_hc *hc, const struct trb *ev, bool deliver_to_driver);
99

10-
static void xhci_handle_unrelated_transfer_event(struct xhci_hc *hc, const struct trb *e)
10+
static inline uint8_t trb_get_type(const struct trb *e) {
11+
return (uint8_t)((e->ctrl >> 10) & 0x3F);
12+
}
13+
14+
static inline uint8_t trb_get_epid(const struct trb *e) {
15+
return (uint8_t)((e->ctrl >> 16) & 0x1F);
16+
}
17+
18+
static inline uint32_t trb_get_evtl(const struct trb *e) {
19+
return (e->sts & 0x00FFFFFFu);
20+
}
21+
22+
static inline uint8_t trb_get_cc(const struct trb *e)
1123
{
12-
if (!hc || !e) {
13-
return;
14-
}
24+
return (uint8_t)((e->sts >> 24) & 0xFF);
25+
}
1526

16-
uint8_t type = (uint8_t)((e->ctrl >> 10) & 0x3F);
17-
if (type != TRB_TRANSFER_EVENT) {
18-
return;
19-
}
27+
static inline uint32_t trb_get_bytes_remaining(const struct trb *e)
28+
{
29+
return (e->sts & 0x00FFFFFFu);
30+
}
31+
32+
static inline uint8_t trb_get_slotid(const struct trb *e)
33+
{
34+
/* SlotID is bits [7:0] of control dword per xHCI spec */
35+
return (uint8_t)(e->ctrl & 0xFF);
36+
}
37+
38+
static void xhci_handle_unrelated_transfer_event(struct xhci_hc *hc, struct trb *e)
39+
{
40+
if (!hc || !e) return;
41+
42+
switch (trb_get_type(e)) {
43+
case TRB_TRANSFER_EVENT: {
44+
/* If this is our INT IN endpoint, deliver to HID and re-arm */
45+
uint8_t epid = trb_get_epid(e);
46+
if (epid == EPID_EP1_IN &&
47+
hc->dev.int_cb && hc->dev.int_buf && hc->dev.int_pkt_len) {
48+
xhci_deliver_ep1in(hc, e, false);
49+
}
50+
break;
51+
}
2052

21-
uint8_t epid = (uint8_t)((e->ctrl >> 16) & 0x1F);
22-
if (epid == EPID_EP1_IN) {
23-
/* Forward HID report events even during EP0 polling */
24-
xhci_deliver_ep1in(hc, e);
53+
/* We don’t act on other event types here; callers still consume & advance ERDP. */
54+
case TRB_CMD_COMPLETION:
55+
case TRB_PORT_STATUS:
56+
case TRB_HOST_CONTROLLER_EVENT:
57+
default:
58+
break;
2559
}
2660
}
2761

62+
63+
/* Decode a Transfer Event TRB -> slot_id, endpoint_id, cc, bytes (EVTL). */
64+
static inline void xhci_decode_xfer_evt(const struct trb *e, uint8_t *slot_id, uint8_t *ep_id, uint8_t *cc, uint32_t *bytes)
65+
{
66+
/* Dword3: [31:24]=CC, [23:17]=rsvd, [16:8]=EPID, [7:0]=SlotID */
67+
uint32_t ctrl = e->ctrl;
68+
uint32_t sts = e->sts;
69+
*cc = (uint8_t)((sts >> 24) & 0xFF);
70+
*ep_id = (uint8_t)((ctrl >> 16) & 0x1F);
71+
*slot_id= (uint8_t)(ctrl & 0xFF);
72+
*bytes = (sts & 0x00FFFFFFu); /* EVTL: bytes remaining */
73+
}
74+
2875
/* ring_init with debug — set Toggle Cycle (TC) like libpayload */
2976
static void ring_init(struct xhci_ring *r, size_t bytes, uint64_t phys, void *virt) {
30-
dprintf("xhci.dbg: ring_init bytes=%u phys=%llx virt=%llx\n",
31-
(unsigned)bytes, (unsigned long long)phys, (unsigned long long)(uintptr_t)virt);
77+
dprintf("xhci.dbg: ring_init bytes=%lu phys=%lx virt=%p\n", bytes, phys, virt);
3278

3379
r->base = (struct trb *) virt;
3480
r->phys = phys;
@@ -44,23 +90,17 @@ static void ring_init(struct xhci_ring *r, size_t bytes, uint64_t phys, void *vi
4490
link->sts = 0;
4591
link->ctrl = TRB_SET_TYPE(TRB_LINK) | TRB_TOGGLE | TRB_CYCLE;
4692

47-
dprintf("xhci.dbg: TRBs=%u link_trb@%u lo=%08x hi=%08x ctrl=%08x\n",
48-
r->num_trbs, r->num_trbs - 1, link->lo, link->hi, link->ctrl);
93+
dprintf("xhci.dbg: TRBs=%u link_trb@%u lo=%08x hi=%08x ctrl=%08x\n", r->num_trbs, r->num_trbs - 1, link->lo, link->hi, link->ctrl);
4994
}
5095

5196
/* ring_push with debug */
5297
static struct trb *ring_push(struct xhci_ring *r) {
53-
uint32_t before = r->enqueue;
5498
if (r->enqueue == r->num_trbs - 1) {
55-
dprintf("xhci.dbg: ring_push wrap at idx=%u, flip cycle %u->%u\n",
56-
r->enqueue, r->cycle, r->cycle ^ 1u);
5799
r->enqueue = 0;
58100
r->cycle ^= 1u;
59101
}
60102
struct trb *t = &r->base[r->enqueue++];
61103
memset(t, 0, sizeof(*t));
62-
dprintf("xhci.dbg: ring_push from %u to %u, cycle=%u trb=%llx\n",
63-
before, r->enqueue, r->cycle, (unsigned long long)(uintptr_t)t);
64104
return t;
65105
}
66106

@@ -70,8 +110,7 @@ static int xhci_cmd_submit_wait(struct xhci_hc *hc, struct trb *cmd_trb, uint64_
70110
uint64_t cmd_phys = hc->cmd.phys +
71111
(uint64_t)((uintptr_t)cmd_trb - (uintptr_t)hc->cmd.base);
72112

73-
dprintf("xhci.dbg: cmd_submit dbell0, trb_virt=%lx trb_phys=%lx ctrl=%08x\n",
74-
(uintptr_t)cmd_trb, cmd_phys, cmd_trb->ctrl);
113+
dprintf("xhci.dbg: cmd_submit dbell0, trb_virt=%lx trb_phys=%lx ctrl=%08x\n", (uintptr_t)cmd_trb, cmd_phys, cmd_trb->ctrl);
75114

76115
volatile uint8_t *ir0 = hc->rt + XHCI_RT_IR0;
77116

@@ -147,6 +186,7 @@ static struct trb *xhci_cmd_begin(struct xhci_hc *hc) {
147186

148187
static void xhci_irq_sanity_dump(struct xhci_hc *hc, const char *tag)
149188
{
189+
return;
150190
volatile uint8_t *ir0 = hc->rt + XHCI_RT_IR0;
151191

152192
uint32_t usbcmd = mmio_read32(hc->op + XHCI_USBCMD);
@@ -755,47 +795,55 @@ static int xhci_enumerate_first_device(struct xhci_hc *hc, struct usb_dev *out_u
755795
return 1;
756796
}
757797

758-
static inline uint8_t trb_get_type(const struct trb *e) { return (uint8_t)((e->ctrl >> 10) & 0x3F); }
759-
/* xHCI Transfer Event fields (dword 3 in 'sts'):
760-
bits 24..31: Completion Code (we don't need here)
761-
bits 16..20: Endpoint ID (EPID)
762-
bits 24..31 of *lo/hi* are pointer; length remaining is sts & 0x00FFFFFF */
763-
static inline uint8_t trb_get_epid(const struct trb *e) { return (uint8_t)((e->ctrl >> 16) & 0x1F); }
764-
static inline uint32_t trb_get_evtl(const struct trb *e) { return (e->sts & 0x00FFFFFFu); }
765-
766-
static void xhci_deliver_ep1in(struct xhci_hc *hc, const struct trb *ev)
798+
static void xhci_deliver_ep1in(struct xhci_hc *hc, const struct trb *e, bool deliver_to_driver)
767799
{
768-
if (!hc->dev.int_cb || !hc->dev.int_buf || !hc->dev.int_pkt_len) return;
769-
770-
/* Posted length was the TRB->sts TL when we queued (hc->dev.int_pkt_len).
771-
Event Transfer Length (EVTL) is "bytes remaining".
772-
For Normal TRB with ISP, a device short (<= posted) is success. */
773-
uint32_t remaining = trb_get_evtl(ev);
774-
uint32_t posted = (uint32_t)hc->dev.int_pkt_len;
775-
uint32_t actual = (remaining <= posted) ? (posted - remaining) : 0u;
776-
777-
/* Some firmware/hw returns EVTL==0 even on full 8-byte report; treat 0 as "posted". */
778-
if (actual == 0 && remaining == 0) actual = posted;
779-
780-
struct usb_dev ud = {0};
781-
ud.hc = hc;
782-
ud.slot_id = hc->dev.slot_id;
783-
784-
/* Deliver (even if actual<8, leave filtering to upper layer) */
785-
hc->dev.int_cb(&ud, hc->dev.int_buf, (uint16_t)actual);
786-
787-
/* Re-arm EP1-IN: one Normal TRB (IOC|ISP) with same buffer, posted len again */
788-
struct trb *n = ring_push(&hc->dev.int_in_tr);
789-
n->lo = (uint32_t)(hc->dev.int_buf_phys & 0xFFFFFFFFu);
790-
n->hi = (uint32_t)(hc->dev.int_buf_phys >> 32);
791-
n->sts = hc->dev.int_pkt_len; /* TL = posted len */
792-
n->ctrl = TRB_SET_TYPE(TRB_NORMAL) | TRB_IOC | TRB_ISP |
793-
(hc->dev.int_in_tr.cycle ? TRB_CYCLE : 0);
794-
mmio_write32(hc->db + 4u * hc->dev.slot_id, EPID_EP1_IN);
800+
/* Sanity: must be our current device and EP1 IN (EPID=3). */
801+
uint8_t slot_id = trb_get_slotid(e);
802+
uint8_t epid = trb_get_epid(e);
803+
if (slot_id != hc->dev.slot_id || epid != EPID_EP1_IN)
804+
return;
805+
806+
if (!hc->dev.int_cb || !hc->dev.int_buf || !hc->dev.int_pkt_len)
807+
return;
808+
809+
uint8_t cc = trb_get_cc(e);
810+
uint32_t rem = trb_get_bytes_remaining(e);
811+
uint32_t req = hc->dev.int_pkt_len;
812+
uint32_t xfer;
813+
814+
/* Only deliver on Success or Short Packet. Others can be handled if needed. */
815+
if (cc == CC_SUCCESS || cc == CC_SHORT_PACKET) {
816+
/* Actual bytes = requested - remaining; guard against weird reports. */
817+
xfer = (rem <= req) ? (req - rem) : req;
818+
if (xfer == 0) xfer = req; /* many boot keyboards always send 8 */
819+
820+
if (deliver_to_driver) {
821+
struct usb_dev ud = {0};
822+
ud.hc = hc;
823+
ud.slot_id = hc->dev.slot_id;
824+
825+
/* Up-call into HID with the bytes we actually got. */
826+
hc->dev.int_cb(&ud, hc->dev.int_buf, (uint16_t) xfer);
827+
}
828+
829+
/* Re-arm exactly one new Normal TRB to keep a steady queue depth. */
830+
struct trb *n = ring_push(&hc->dev.int_in_tr);
831+
n->lo = (uint32_t)(hc->dev.int_buf_phys & 0xFFFFFFFFu);
832+
n->hi = (uint32_t)(hc->dev.int_buf_phys >> 32);
833+
n->sts = hc->dev.int_pkt_len;
834+
n->ctrl = TRB_SET_TYPE(TRB_NORMAL) | TRB_IOC | TRB_ISP | (hc->dev.int_in_tr.cycle ? TRB_CYCLE : 0);
835+
836+
/* Ring EP1 IN doorbell (per-slot doorbell, target = EPID). */
837+
mmio_write32(hc->db + 4u * hc->dev.slot_id, EPID_EP1_IN);
838+
} else {
839+
/* Optional: recover on errors (stall -> stop/reset EP) */
840+
dprintf("xhci.dbg: EP1-IN TE cc=%u rem=%u (ignored)\n", cc, rem);
841+
}
795842
}
796843

797844
static void xhci_isr(uint8_t isr, uint64_t error, uint64_t irq, void *opaque)
798845
{
846+
dprintf("xhci_isr\n");
799847
struct xhci_hc *hc = (struct xhci_hc *)opaque;
800848
if (!hc || !hc->cap) return;
801849

@@ -810,19 +858,21 @@ static void xhci_isr(uint8_t isr, uint64_t error, uint64_t irq, void *opaque)
810858
volatile uint8_t *ir0 = hc->rt + XHCI_RT_IR0;
811859
uint64_t erdp_cur = mmio_read64(ir0 + IR_ERDP) & ~0x7ull;
812860

861+
/* IMPORTANT: ensure EHB is CLEAR so future interrupts can retrigger */
862+
mmio_write64(ir0 + IR_ERDP, erdp_cur); /* bit3=0 */
863+
813864
for (uint32_t i = 0; i < hc->evt.num_trbs; i++) {
814865
struct trb *e = &hc->evt.base[i];
815866
if ((e->lo | e->hi | e->sts | e->ctrl) == 0u) continue;
816867

817868
uint8_t type = trb_get_type(e);
818-
dprintf("xhci.dbg: ISR evt[%u] type=%u lo=%08x hi=%08x sts=%08x\n",
819-
i, type, e->lo, e->hi, e->sts);
869+
//dprintf("xhci.dbg: ISR evt[%u] type=%u lo=%08x hi=%08x sts=%08x\n", i, type, e->lo, e->hi, e->sts);
820870

821871
if (type == TRB_TRANSFER_EVENT) {
822872
uint8_t epid = trb_get_epid(e);
823873
/* Only deliver to HID for EP1-IN completions */
824874
if (epid == EPID_EP1_IN) {
825-
xhci_deliver_ep1in(hc, e);
875+
xhci_deliver_ep1in(hc, e, true);
826876
}
827877
}
828878

@@ -843,8 +893,7 @@ static void xhci_isr(uint8_t isr, uint64_t error, uint64_t irq, void *opaque)
843893
}
844894

845895
int xhci_arm_int_in(struct usb_dev *ud, uint16_t pkt_len, xhci_int_in_cb cb) {
846-
dprintf("xhci.dbg: ARM INT-IN enter ud=%p hc=%p slot_id=%u pkt_len=%u cb=%p\n",
847-
ud, ud ? ud->hc : 0, ud ? ud->slot_id : 0, (unsigned)pkt_len, cb);
896+
dprintf("xhci.dbg: ARM INT-IN enter ud=%p hc=%p slot_id=%u pkt_len=%u cb=%p\n", ud, ud ? ud->hc : 0, ud ? ud->slot_id : 0, (unsigned)pkt_len, cb);
848897

849898
if (!ud || !ud->hc || !pkt_len || !cb) {
850899
dprintf("xhci.dbg: ARM INT-IN early-exit (arg check) ud=%p hc=%p pkt_len=%u cb=%p\n",

0 commit comments

Comments
 (0)