Voxia OS v0.0.1
Hobby Project Operating System Targeting x86-64
Loading...
Searching...
No Matches
ehci.cpp
Go to the documentation of this file.
1#include "memory/kalloc.h"
2#include <type.h>
3#include "usb.h"
4#include "ehci/ehci.hpp"
5#include "ioforge/ioforge.h"
6#include "ioforge/ioforge.hpp"
7#include "ehci/ehci_pipe.hpp"
10
11#define EHCI_MAX_QH_CACHE 4096
12#define EHCI_MAX_QH_CACHE_MASK (EHCI_MAX_QH_CACHE - 1)
13#define EHCI_MAX_QTD_CACHE 4096
14#define EHCI_MAX_QTD_CACHE_MASK (EHCI_MAX_QTD_CACHE - 1)
15
16// cache
18static uint16_t qh_ring[EHCI_MAX_QH_CACHE]; // isi = index ke pool
19static size_t qh_ring_head = 0;
20static size_t qh_ring_tail = 0;
21
23static uint16_t qtd_ring[EHCI_MAX_QTD_CACHE]; // isi = index ke pool
24static size_t qtd_ring_head = 0;
25static size_t qtd_ring_tail = 0;
26
27// for periodic
29
30// used qh
32
34
35 static_assert(sizeof(ehci_queue_head) % 32 == 0,
36 "ehci_queue_head must be 32-byte aligned");
37 static_assert(sizeof(ehci_queue_task_descriptor) % 32 == 0,
38 "ehci_queue_task_descriptor must be 32-byte aligned");
39
40 size_t alloc_count = 0;
41 // init qh
42 {
43 size_t ehci_qh_block_per_alloc =
44 0x1000 / sizeof(ehci_queue_head);
45
46 for (size_t i = 0; i < EHCI_MAX_QH_CACHE;
47 i += ehci_qh_block_per_alloc, alloc_count++) {
48
49 uintptr_t physaddr = 0;
50 uintptr_t vaddr = (uintptr_t) IOUtils::DMAAlloc(
51 0x1000, &physaddr);
52
53 if (!vaddr)
54 break;
55
56 ioforge_memset((void*) vaddr, 0, 0x1000);
57
58 for (size_t j = 0; j < ehci_qh_block_per_alloc; j++) {
59 if ((i + j) >= EHCI_MAX_QH_CACHE)
60 break;
61
62 uint32_t offset = j * sizeof(ehci_queue_head);
63 struct ehci_queue_head* qh =
64 (struct ehci_queue_head*) (vaddr
65 + offset);
66
67 // qh[i+ j]->physaddr = (uint32_t) (physaddr + offset);
68 qh_pool[i + j].head = qh;
69 qh_pool[i + j].physaddr =
70 (uint32_t) (physaddr + offset);
71 qh_pool[i + j].next = 0;
72
73 qh_ring[i + j] = i + j;
74 }
75 }
76 qh_ring_head = 0;
78 }
79
80 {
81 size_t ehci_qtd_block_per_alloc =
82 0x1000 / sizeof(ehci_queue_task_descriptor);
83 for (size_t i = 0; i < EHCI_MAX_QTD_CACHE;
84 i += ehci_qtd_block_per_alloc, alloc_count++) {
85
86 uintptr_t physaddr = 0;
87 uintptr_t vaddr = (uintptr_t) IOUtils::DMAAlloc(
88 0x1000, &physaddr);
89
90 if (!vaddr)
91 break;
92
93 ioforge_memset((void*) vaddr, 0, 0x1000);
94
95 for (size_t j = 0; j < ehci_qtd_block_per_alloc; j++) {
96 if ((i + j) >= EHCI_MAX_QTD_CACHE)
97 break;
98
100 j * sizeof(ehci_queue_task_descriptor);
101 struct ehci_queue_task_descriptor* qtd =
102 (struct
104 + offset);
105
106 qtd_pool[i + j].physaddr =
107 (uint32_t) (physaddr + offset);
108 qtd_pool[i + j].task_descriptor = qtd;
109 qtd_pool[i + j].next = 0;
110
111 qtd_ring[i + j] = i + j;
112 }
113 }
114
115 qtd_ring_head = 0;
117
118 log(mod, "allocate %d Kb for queue cache (%d QH and %d QTD)",
119 alloc_count * 0x1000 / 1024, EHCI_MAX_QH_CACHE,
121 }
122
123 // verifikasi allignment
124 // Cek node pertama dan kedua — kalau selisihnya bukan 32 kelipatan, struct salah
125 {
126 uint32_t p0 = qh_pool[0].physaddr;
127 uint32_t p1 = qh_pool[1].physaddr;
128 if ((p1 - p0) % 32 != 0) {
129 log(mod,
130 "ERROR: QH alignment salah! sizeof=%d, diff=%d",
131 sizeof(ehci_queue_head), p1 - p0);
132 return;
133 }
134
135 uint32_t q0 = qtd_pool[0].physaddr;
136 uint32_t q1 = qtd_pool[1].physaddr;
137 if ((q1 - q0) % 32 != 0) {
138 log(mod,
139 "ERROR: qTD alignment salah! sizeof=%d, diff=%d",
140 sizeof(ehci_queue_task_descriptor), q1 - q0);
141 return;
142 }
143
144 log(mod, "alignment OK — QH stride=%d, qTD stride=%d", p1 - p0,
145 q1 - q0);
146 }
147
148 // init first queue head
149 ehci_queue_head_node_t* qh_node = 0;
150 if (!retrieve_qh(&qh_node))
151 return;
152
153 struct ehci_queue_head* qh = qh_node->head;
154 qh->qhlp = qh_node->physaddr | EHCI_Q_SELECT_QH;
157 qh->currentTD = 0;
159
160 log(mod, "first qh: 0x%x", qh);
161 main_async_qh = qh_node;
162 ehci_op->asynclistaddr = (uint32_t) (uintptr_t) qh_node->physaddr;
164}
165
168 while (ehci_op->usbcmd & EHCI_CONTROLLER_RESET) {
169 if (ehci_op->usbsts & (1 << 4)) {
170 log(mod, "EHCI: reset failed");
171 break;
172 }
173 }
174 log(mod, "EHCI: reset engine");
175}
176
178 log(mod, "EHCI: stopping_engine");
179 ehci_op->usbcmd &= ~(1 << 4);
180 ehci_op->usbcmd &= ~(1 << 5);
181
182 while (ehci_op->usbsts & ((1 << 14) | (1 << 15)))
183 ;
184
185 log(mod, "EHCI: stop_engine");
186
187 ehci_op->usbcmd &= ~1;
188 while (!(ehci_op->usbsts & (1 << 12)))
189 ;
190 log(mod, "EHCI: stop_engine");
191}
192
195 while ((ehci_op->usbsts & EHCI_HC_HALTED_STATUS))
196 ;
197 log(mod, "EHCI: start engine");
198}
199
201 log(mod, "periodic: init_que_head");
202
203 // init framelist
204 uintptr_t framelist_phys_addr = 0;
205 framelist = (uint32_t*) IOUtils::DMAAlloc(1024 * sizeof(uint32_t),
206 &framelist_phys_addr);
207 IOUtils::memset(framelist, 0, 1024 * sizeof(uint32_t));
208
209 ehci_queue_head_node_t* qh_node = 0;
210 retrieve_qh(&qh_node);
211 struct ehci_queue_head* qh = qh_node->head;
212 IOUtils::memset(qh, 0, sizeof(*qh));
213 qh->qhlp = qh_node->physaddr | EHCI_Q_SELECT_QH;
216 qh->currentTD = 0;
217 qh->token = 0;
219 qh->cap = 0xFF;
220
221 for (int i = 0; i < 1024; i++) {
222 framelist[i] = ((uint32_t) (uintptr_t) qh_node->physaddr)
224 framelist_node[i] = qh_node;
225 }
226
227 log(mod, "framelist : 0x%x (0x%x)", framelist, framelist_phys_addr);
228 ehci_op->frindex = 0;
229 ehci_op->periodiclistbase = (uint32_t) (uintptr_t) framelist_phys_addr;
230
232}
233
235 uint16_t interval_ms) {
236 // TODO: handle interval ms
237 // Cari slot di framelist yang sesuai dengan interval
238 int ring = 0;
239
240 auto curr_node = framelist_node[ring];
241 struct ehci_queue_head* mq = curr_node->head;
242 uint32_t saved_next = mq->qhlp;
243 qh_node->head->qhlp = saved_next;
244 __sync_synchronize();
245 mq->qhlp = (uint32_t) qh_node->physaddr | EHCI_Q_SELECT_QH;
246
247 log(mod, "QH dengan interval %d ms dimasukkan ke slot %d", interval_ms,
248 ring);
249}
250
254
258
259#define HCSPARAM_N_PORTS_MASK 0b1111
260
262 char* data, size_t size) {
263 uint8_t* buffer = (uint8_t*) kalloc(255);
264 usb_get_descriptor(addr, 0x3, index, 255, buffer);
265
266 struct usb_string_descriptor* str =
268
269 size_t len = (str->bLength - 2) / 2;
270
271 size_t j = 0;
272 for (size_t i = 0; i < len && j < size - 1; i++) {
273 uint16_t ch = str->wData[i];
274
275 if (ch < 128) {
276 data[j++] = (char) ch;
277 }
278 }
279 data[j] = 0;
280
281 IOUtils::free(buffer, 255);
282}
283
285 // TODO: buat fungsi untuk umount device
286
287 if (!controller) {
288 log("EHCI", "ERROR: controller must be set");
289 return;
290 }
291
292 int ports = *hcsparam & HCSPARAM_N_PORTS_MASK;
293 log("DEBUG", "OK");
294 log(mod, "EHCI: port available : %d ", ports);
295 for (int i = 0; i < ports; i++) {
296 uint16_t addr = i + 1;
297 port_reset(i);
298
299 boolean_t available = ehci_op->portsc[i] & EHCI_PORT_ENABLED;
300
301 if (available) {
303 log(mod, "Port %d Available", i);
304
305 // save ke ioforge
306 struct ioforge_usb_device* usbDevice =
307 (struct ioforge_usb_device*) kalloc(
308 sizeof(struct ioforge_usb_device));
309 IOUtils::memset(usbDevice, 0, sizeof(*usbDevice));
310
311 uint8_t* data = (uint8_t*) kalloc(0x1000);
313 sizeof(usb_device_descriptor), data);
314
317
318 log(mod, " USB Port %d : Descriptor Length : %d", i,
319 dev->bLength);
320 log(mod, " USB Port %d : Descriptor Type : %d", i,
321 dev->bDescriptorType);
322 log(mod, " USB Port %d : Version : %x", i, dev->bcdUSB);
323 log(mod, " USB Port %d : Device class : %d", i,
324 dev->bDeviceClass);
325 log(mod, " USB Device sub class : %d ",
326 dev->bDeviceSubClass);
327 log(mod, "USB Device protocol : %d",
328 dev->bDeviceProtocol);
329 log(mod, "USB Max packet size : %d",
330 dev->bMaxPacketSize0);
331 log(mod, "USB Number of Configuration : %d",
332 dev->bNumConfigurations);
333 log(mod, "USB Vendor ID : %d", dev->idVendor);
334 char iManufacturer[64] = {0};
336 iManufacturer,
337 sizeof(iManufacturer));
338 log(mod, "USB Manufacturer: %s", iManufacturer);
339 char iProduct[64] = {0};
341 sizeof(iProduct));
342 log(mod, "USB Product: %s", iProduct);
343 char iSerialNumber[64] = {0};
344 if (dev->iSerialNumber != 0) {
346 addr, dev->iSerialNumber, iSerialNumber,
347 sizeof(iSerialNumber));
348 log(mod, "USB Serial Number: %s",
349 iSerialNumber);
350 } else {
351 // Jika tidak ada serial number, berikan nilai default atau biarkan kosong
352 log(mod, "USB Serial Number: [Not Provided]");
353 IOUtils::strcopy(iSerialNumber, (char*) "None");
354 }
355 IOUtils::strcopy((char*) usbDevice->serial_number,
356 iSerialNumber);
357
358 uint8_t dev_class = dev->bDeviceClass;
359 uint8_t dev_sub_class = dev->bDeviceSubClass;
360 uint8_t dev_protocol = dev->bDeviceProtocol;
361
362 uint8_t endpoint_count = 0;
363
364 for (int j = 0; j < dev->bNumConfigurations; j++) {
365 IOUtils::memset(data, 0, 0x1000);
367 addr, 2, j,
368 sizeof(usb_config_descriptor), data);
372 config->wTotalLength, data);
374
375 log(mod,
376 " USB Port %d : Descriptor Length : %d", i,
377 config->bLength);
378 log(mod, " USB Port %d : Descriptor Type : %d",
379 i, config->bDescriptorType);
380 log(mod, " USB Port %d : Total Length : %d", i,
381 config->wTotalLength);
382 log(mod,
383 " USB Port %d : Number of Interface : %d",
384 i, config->bNumInterfaces);
385 log(mod,
386 " USB Port %d : Configuration Value : %d",
387 i, config->bConfigurationValue);
388 log(mod, " USB Port %d : Attribute : %d", i,
389 config->bmAttributes);
390 log(mod, " USB Port %d : Max Power : %d", i,
391 config->bMaxPower);
392 log(mod, " USB Port %d : iConfiguration : %d",
393 i, config->iConfiguration);
394
395 char iConfiguration[255] = {0};
397 addr, config->iConfiguration,
399 log(mod, "USB Configuration Name: %s\n",
401
402 // ioforge
403 usbDevice->max_power = config->bMaxPower;
404 //
405
406 // interface
407 struct usb_interface* interface =
408 (struct
410 + config->bLength);
411 log(mod, "[Interface] Interface length : %d",
412 interface->bLength);
413 log(mod, "[Interface] Interface number : %d",
414 interface->bInterfaceNumber);
415 log(mod, "[Interface] Interface type : %d",
416 interface->bDescriptorType);
417 log(mod, "[Interface] Interface class : %d",
418 interface->bInterfaceClass);
419 log(mod,
420 "[Interface] USB Device sub class : %d ",
421 interface->bInterfaceSubClass);
422 log(mod, "[Interface] Protocol : %d",
423 interface->bInterfaceProtocol);
424 log(mod, "[Interface] number endpoint : %d",
425 interface->bNumEndpoints);
426
427 if (dev_class == 0 && dev_sub_class == 0) {
428 dev_class = interface->bInterfaceClass;
429 dev_sub_class =
430 interface->bInterfaceSubClass;
431 dev_protocol =
432 interface->bInterfaceProtocol;
433 }
434
435 // endpoint
436 // Ambil pointer endpoint pertama (berada tepat setelah interface descriptor)
437 uint8_t* ptr = (uint8_t*)((uintptr_t)interface + interface->bLength);
438
439 for (int k = 0; k < interface->bNumEndpoints;
440 k++) {
441
442 while (ptr
443 < (uint8_t*) data
444 + config->wTotalLength) {
445 uint8_t desc_len = ptr[0];
446 uint8_t desc_type = ptr[1];
447 if (desc_type == 0x05)
448 break; // Endpoint descriptor
449 if (desc_len == 0)
450 break; // Safety: hindari infinite loop
451 ptr += desc_len;
452 }
453
454 struct usb_endpoint_descriptor* endpoint =
455 (struct
457
458 log(mod, " [Endpoint %d] length : %d",
459 k, endpoint->bLength);
460 log(mod, " [Endpoint %d] type : %d", k,
461 endpoint->bDescriptorType);
462 log(mod,
463 " [Endpoint %d] address : 0x%x", k,
464 endpoint->bEndpointAddress);
465 log(mod,
466 " [Endpoint %d] attributes : 0x%x",
467 k, endpoint->bmAttributes);
468 log(mod, " [Endpoint %d] interval : %d",
469 k, endpoint->bInterval);
470
471 auto& current_endpoint =
472 usbDevice->endpoints
473 [endpoint_count];
474 current_endpoint.address =
475 endpoint->bEndpointAddress;
476 current_endpoint.attributes =
477 endpoint->bmAttributes;
478 current_endpoint.interval =
479 endpoint->bInterval;
480 current_endpoint.max_packet =
481 endpoint->wMaxPacketSize;
482
483 endpoint =
484 (struct
486 endpoint
487 + endpoint->bLength);
488 }
489
490 // current_endpoint.
491 endpoint_count += interface->bNumEndpoints;
492 }
493
494 log(mod, "Get report descriptor");
495 {
496 uintptr_t setup_paddr;
497 struct usb_setup_packet* setup =
498 (struct usb_setup_packet*)
499 IOUtils::DMAAlloc(
500 sizeof(usb_setup_packet),
501 &setup_paddr);
502 setup->bmRequestType = 0b10000001;
503 setup->bRequest = 0x06;
504 setup->wValue = 0x2200;
505 setup->wIndex = 0;
506 setup->wLength = 32;
507
508 uintptr_t in_data_paddr;
509 uint8_t* in_data = (uint8_t*) IOUtils::DMAAlloc(
510 4096, &in_data_paddr);
511
513 addr, 0, (uint32_t) setup_paddr,
514 sizeof(usb_setup_packet), in_data_paddr,
515 32);
516
517 log(mod, "Report Descriptor : ");
518 for (int i = 0; i < 32; i++) {
519 serial2_printf("0x%x ", in_data[i]);
520 }
521 serial2_printf("\n");
522
523 IOUtils::DMAFree((void*) in_data_paddr, in_data,
524 4096);
525 }
526
527 usbDevice->vendor_id = dev->idVendor;
528 usbDevice->product_id = dev->idProduct;
529 usbDevice->class_code = dev_class;
530 usbDevice->subclass_code = dev_sub_class;
531 usbDevice->protocol = dev_protocol;
533 usbDevice->controller = controller;
534 usbDevice->ep_count = endpoint_count;
535
536 usbDevice->addr = addr;
537
538 if (dev_class == 0x3) {
539 if (dev_protocol == 1) {
540 IOUtils::strcopy(
541 (char*) usbDevice->base.name,
542 (char*) "Keyboard");
544 "HID Device : Keyboard\n");
545 } else if (dev_protocol == 2) {
546 IOUtils::strcopy(
547 (char*) usbDevice->base.name,
548 (char*) "Mouse");
549 serial2_printf("HID Device : Mouse\n");
550 }
551 }
552
553 usbDevice->base.type = IOFORGE_USB_DEVICE;
554
555 // TODO: handle free ini kalau dev nya di umount
556 auto __aligned_pipe_size =
557 ((sizeof(EHCIPipe) + 31) & ~31);
558 void* mem = kalloc(__aligned_pipe_size);
559 EHCIPipe* pipe = new (mem) EHCIPipe(this);
560
561 usbDevice->pipe = pipe;
562
564 &usbDevice->base);
565 }
566 }
567}
568
570 uint32_t val = ehci_op->portsc[port];
571 val &= ~(0x2A);
572 ehci_op->portsc[port] = val | EHCI_PORT_RESET;
573 log(mod, "EHCI: resetting port %d ...", port);
574 ehci_op->portsc[port] = val & ~EHCI_PORT_RESET;
575 IOUtils::sleep(10);
576}
577
579 uint32_t data_phys, size_t size,
580 uint32_t response,
581 size_t response_size) {
582 if (!data_phys || !size)
583 return;
584
585 // Alokasi QH
586 ehci_queue_head_node_t* qh_node;
587 retrieve_qh(&qh_node);
588 uintptr_t qh_phys = qh_node->physaddr;
589 struct ehci_queue_head* qh = qh_node->head;
590 IOUtils::memset(qh, 0, sizeof(struct ehci_queue_head));
591
592 // Alokasi qTD setup
594 retrieve_qtd(&setup_node);
595 uintptr_t setup_phys = setup_node->physaddr;
598 setup_node->task_descriptor;
599 IOUtils::memset(setup, 0, sizeof(struct ehci_queue_task_descriptor));
600
601 // Alokasi qTD status
603 retrieve_qtd(&status_node);
604 uintptr_t status_phys = status_node->physaddr;
607 status_node->task_descriptor;
608 IOUtils::memset(status, 0, sizeof(struct ehci_queue_task_descriptor));
609
610 // Bangun chain qTD
612 if (response && response_size > 0) {
613
614 retrieve_qtd(&data_node);
615 uintptr_t data_qtd_phys = data_node->physaddr;
616 struct ehci_queue_task_descriptor* data_qtd =
618 data_node->task_descriptor;
619 IOUtils::memset(data_qtd, 0,
620 sizeof(struct ehci_queue_task_descriptor));
621
622 // Setup → Data
623 setup->link = (uint32_t) data_qtd_phys;
624 setup->altlink = EHCI_QTD_TERMINATE;
629 setup->buffer[0] =
630 (uint32_t) data_phys; // ← packet setup 8 byte
631
632 // Data IN
633 data_qtd->link = (uint32_t) status_phys;
634 data_qtd->altlink = (uint32_t) status_phys;
635 data_qtd->token = EHCI_QTD_TOKEN_LENGTH(response_size);
637 data_qtd->token |= EHCI_QTD_TOKEN_DATA; // DATA1 toggle
638 data_qtd->token |= EHCI_QTD_TOKEN_PID_IN;
640 data_qtd->buffer[0] = (uint32_t) response;
641
642 // Status OUT (kebalikan data IN)
644 status->altlink = EHCI_QTD_TERMINATE;
645 status->token = EHCI_QTD_TOKEN_LENGTH(0);
647 status->token |= EHCI_QTD_TOKEN_DATA; // DATA1
648 status->token |=
649 EHCI_QTD_TOKEN_PID_OUT; // OUT karena data stage IN
651 status->token |= EHCI_QTD_TOKEN_IOC;
652
653 } else {
654 // Tidak ada data stage (contoh: SET_ADDRESS)
655 // Setup → Status langsung
656 setup->link = (uint32_t) status_phys;
657 setup->altlink = EHCI_QTD_TERMINATE;
662 setup->buffer[0] = (uint32_t) data_phys;
663
664 // Status IN (no-data control transfer selalu IN)
666 status->altlink = EHCI_QTD_TERMINATE;
667 status->token = EHCI_QTD_TOKEN_LENGTH(0);
669 status->token |= EHCI_QTD_TOKEN_DATA;
672 status->token |= EHCI_QTD_TOKEN_IOC;
673 }
674
676 qh->nextTD = (uint32_t) setup_phys;
677 qh->currentTD = 0;
678 qh->ch = EHCI_QH_CAP_DTC;
680 qh->ch |= (2 << 12); // EPS = High Speed
681 qh->ch |= (addr & 0x7f); // device address
683 qh->cap |= ((endpoint & 0xF) << 8);
684
685 push_to_qh(qh_node);
686
687 // pooling
688 bool done = false;
689 for (int i = 0; i < 500 && !done; i++) {
690 IOUtils::sleep(10);
691
692 uint32_t tok = status->token;
693
695 continue; // masih jalan
696
697 if (tok & (1 << 6))
698 log(mod, "send_async: HALTED");
699 else if (tok & (1 << 5))
700 log(mod, "send_async: Data Buffer Error");
701 else if (tok & (1 << 4))
702 log(mod, "send_async: Babble");
703 else if (tok & (1 << 3))
704 log(mod, "send_async: Transaction Error");
705
706 done = true;
707 }
708
709 if (!done)
710 log(mod, "send_async: TIMEOUT");
711
712 // ── Detach QH dari schedule ──────────────────────────────────────────
713 // Bypass: main_qh langsung nunjuk ke penerus QH yang mau dilepas
714 auto mq = main_async_qh->head;
715 __sync_synchronize();
716 mq->qhlp = qh->qhlp;
717
718 // doorbell
719 ehci_op->usbcmd |= (1 << 6);
720
721 // Hardware akan merespons dengan menge-set bit ke-5 (IAA) di USBSTS
722 // Beri batas waktu (timeout) agar sistem tidak hang/freeze
723 int timeout = 1000;
724 while (!(ehci_op->usbsts & (1 << 5)) && timeout > 0) {
725 IOUtils::sleep(1);
726 timeout--;
727 }
728
729 if (timeout == 0) {
730 log(mod, "ERROR: Asynchronous Advance Doorbell timeout!");
731 }
732
733 ehci_op->usbsts |= (1 << 5);
734
735 store_qh(&qh_node);
736 store_qtd(&setup_node);
737 store_qtd(&status_node);
738 if (data_node)
739 store_qtd(&data_node);
740}
741
744
745 for (int i = 0; i < 100; i++) {
746 IOUtils::sleep(100);
747 // {
748 if (qtd->token & (1 << 6)) {
749 log(mod, "halted");
750 goto proccess_end;
751 break;
752 } else if (qtd->token & (1 << 5)) {
753 log(mod, "Data Buffer Error");
754 goto proccess_end;
755 break;
756 } else if (qtd->token & (1 << 4)) {
757 log(mod, "Babble detected");
758 goto proccess_end;
759 break;
760 } else if (qtd->token & (1 << 3)) {
761 log(mod, "Transaction error");
762 goto proccess_end;
763 break;
764 } else if (qtd->token & (1 << 2)) {
765 log(mod, "Buffer error");
766 goto proccess_end;
767 break;
768 } else {
769 // log(mod, "Success");
770 // status len
771 // size_t len = qtd->token & 0xffff;
772 // log(mod, "len : %d", len);
773 goto proccess_end;
774 break;
775 }
776 }
777proccess_end:
779}
780
782 uintptr_t cmd_phys_addr = 0;
783 usb_setup_packet* cmd = (usb_setup_packet*) IOUtils::DMAAlloc(
784 sizeof(usb_setup_packet), &cmd_phys_addr);
785 cmd->bmRequestType = 0;
787 cmd->bmRequestType = 0;
788 cmd->wValue = address;
789 cmd->wIndex = 0;
790 cmd->wLength = 0;
791 log(mod, "cmd : 0x%x", cmd_phys_addr);
792
793 // sendAsync((uint32_t) cmd_phys_addr, sizeof(usb_setup_packet));
794 send_async_with_response(0, 0, (uint32_t) cmd_phys_addr,
795 sizeof(usb_setup_packet), 0, 0);
796
797 IOUtils::sleep(2);
798}
799
802
803 size_t total_size = sizeof(struct usb_setup_packet) + len;
804 uintptr_t base_phys_addr = 0;
805 uint8_t* base_vaddr =
806 (uint8_t*) IOUtils::DMAAlloc(total_size, &base_phys_addr);
807
808 struct usb_setup_packet* cmd = (struct usb_setup_packet*) base_vaddr;
809
810 cmd->bRequest = 0x06;
811 cmd->bmRequestType = 0x80; // recieve
812 cmd->wValue = (type << 8) | index;
813 cmd->wIndex = 0;
814 cmd->wLength = len;
815
816 uint8_t* data_buf = base_vaddr + sizeof(usb_setup_packet);
817 uintptr_t data_phys = base_phys_addr + sizeof(usb_setup_packet);
818
819 send_async_with_response(addr, 0, (uint32_t) base_phys_addr,
820 sizeof(usb_setup_packet), data_phys, len);
821
822 IOUtils::memcpy((void*) data, (void*) data_buf, len);
823 IOUtils::DMAFree((void*) base_phys_addr, (void*) base_vaddr,
824 total_size);
825}
826
828 if (!dev)
829 return;
830
831 if (dev->type == IOFORGE_USB_DEVICE) {
832
833 auto usb = (ioforge_usb_device*) dev;
834 if (usb->pipe != nullptr) {
835 EHCIPipe* pipe = (EHCIPipe*) usb->pipe;
836 if (pipe->data_node_) {
837 auto token = pipe->data_node_->task_descriptor
838 ->token;
840 goto next;
841
842 bool is_error = false;
843 if (token & (1 << 6)) {
844 log("EHCI IRQ", "→ HALTED");
845 is_error = true;
846 }
847 if (token & (1 << 5)) {
848 log("EHCI IRQ", "→ Data Buffer Error");
849 is_error = true;
850 }
851 if (token & (1 << 3)) {
852 log("EHCI IRQ", "→ Transaction Error");
853 is_error = true;
854 }
855
856 // log(mod, "interrupt dari %s", dev->name);
857 pipe->on_complete(0, 0, is_error);
858 }
859 // pipe->qh_node_->physaddr ==
860 }
861 }
862
863next:
866}
867
869 // log("EHCI IRQ", "transfer complete");
871 if (!module)
872 return;
873
874 auto status = module->ehci_op->usbsts;
875 if (!(status & 0x3f))
876 return;
877
878 if (status & (1 << 0)) {
879 // USBINT → transfer complete
880 auto node = ioforge_get_usb_devices_root();
881 module->call_completion_callback(node);
882 }
883
884 if (status & (1 << 2)) {
885 // PCD → port change
886 log("EHCI IRQ", "port change");
887 }
888
889 module->ehci_op->usbsts = status;
890}
891
895
896// cache
898 size_t h, t;
899 do {
900 h = __atomic_load_n(&qh_ring_head, __ATOMIC_ACQUIRE);
901 t = __atomic_load_n(&qh_ring_tail, __ATOMIC_ACQUIRE);
902 if (h == t)
903 return false;
904 } while (!__atomic_compare_exchange_n(&qh_ring_head, &h, h + 1, false,
905 __ATOMIC_ACQ_REL,
906 __ATOMIC_ACQUIRE));
907
909 *out = &qh_pool[idx];
910 return true;
911}
912
914 size_t h, t;
915 do {
916 h = __atomic_load_n(&qtd_ring_head, __ATOMIC_ACQUIRE);
917 t = __atomic_load_n(&qtd_ring_tail, __ATOMIC_ACQUIRE);
918 if (h == t)
919 return false;
920
921 } while (!__atomic_compare_exchange_n(&qtd_ring_head, &h, h + 1, false,
922 __ATOMIC_ACQ_REL,
923 __ATOMIC_ACQUIRE));
925 *out = &qtd_pool[idx];
926 return true;
927}
928
930 if (!in || !*in)
931 return;
932
933 ioforge_memset((*in)->head, 0, sizeof(ehci_queue_head));
934
935 uint16_t idx = (uint16_t) ((*in) - &qh_pool[0]); // hitung index
936
937 size_t t, h;
938 do {
939 t = __atomic_load_n(&qh_ring_tail, __ATOMIC_ACQUIRE);
940 h = __atomic_load_n(&qh_ring_head, __ATOMIC_ACQUIRE);
941 if (t - h >= EHCI_MAX_QH_CACHE) {
942 *in = 0;
943 return;
944 }
945 } while (!__atomic_compare_exchange_n(&qh_ring_tail, &t, t + 1, false,
946 __ATOMIC_ACQ_REL,
947 __ATOMIC_ACQUIRE));
948
950 *in = 0;
951}
952
954 if (!in || !*in)
955 return;
956
957 ioforge_memset((*in)->task_descriptor, 0,
959
960 uint16_t idx = (uint16_t) ((*in) - &qtd_pool[0]); // hitung index
961
962 size_t t, h;
963 do {
964 t = __atomic_load_n(&qtd_ring_tail, __ATOMIC_ACQUIRE);
965 h = __atomic_load_n(&qtd_ring_head, __ATOMIC_ACQUIRE);
966 if (t - h >= EHCI_MAX_QTD_CACHE) {
967 *in = 0;
968 return;
969 }
970 } while (!__atomic_compare_exchange_n(&qtd_ring_tail, &t, t + 1, false,
971 __ATOMIC_ACQ_REL,
972 __ATOMIC_ACQUIRE));
973
975 *in = 0;
976}
977
978// hanya software link, tetep perlu atur flag manual
980 struct ehci_queue_head* mq = main_async_qh->head;
981 uint32_t saved_next = mq->qhlp;
982 qh_node->head->qhlp = saved_next; // QH baru → (dulu penerus main_qh)
983 __sync_synchronize();
984 mq->qhlp = (uint32_t) qh_node->physaddr
985 | EHCI_Q_SELECT_QH; // main_qh → QH baru
986}
struct SDT h
Definition acpi.h:0
void set_controller(ioforge_usb_controller_service *controller)
Definition ehci.cpp:892
boolean_t retrieve_qtd(ehci_queue_task_descriptor_node_t **out)
Definition ehci.cpp:913
void call_completion_callback(ioforge_device *dev)
Definition ehci.cpp:827
void probe()
Definition ehci.cpp:284
void init_periodic()
Definition ehci.cpp:200
boolean_t retrieve_qh(ehci_queue_head_node_t **out)
Definition ehci.cpp:897
void store_qtd(ehci_queue_task_descriptor_node_t **in)
Definition ehci.cpp:953
void insert_periodic(ehci_queue_head_node_t *qh_node, uint16_t interval_ms)
Definition ehci.cpp:234
void start_periodic()
Definition ehci.cpp:251
void usb_get_string_descriptor(uint8_t addr, uint8_t index, char *data, size_t size)
Definition ehci.cpp:261
void assign_address(int address)
Definition ehci.cpp:781
void stop_periodic()
Definition ehci.cpp:255
void setup()
uint32_t * framelist
Definition ehci.hpp:243
ehci_operation * ehci_op
Definition ehci.hpp:234
void start_device()
Definition ehci.cpp:193
uint32_t * hcsparam
Definition ehci.hpp:235
static void fireHandler()
Definition ehci.cpp:868
void usb_get_descriptor(uint8_t addr, uint8_t type, uint8_t index, uint8_t len, uint8_t *data)
Definition ehci.cpp:800
void init_controller()
Definition ehci.cpp:33
ioforge_usb_controller_service * controller
Definition ehci.hpp:252
void push_to_qh(ehci_queue_head_node_t *qh_node)
Definition ehci.cpp:979
void reset_device()
Definition ehci.cpp:166
void send_async_with_response(uint8_t addr, uint8_t endpoint, uint32_t data_phys, size_t size, uint32_t response, size_t response_size)
Definition ehci.cpp:578
void port_reset(int port)
Definition ehci.cpp:569
void stop_device()
Definition ehci.cpp:177
static EHCIModule * getInstance()
Definition init.cpp:10
EHCIModule()
Definition init.cpp:8
void store_qh(ehci_queue_head_node_t **in)
Definition ehci.cpp:929
void procces_async(ehci_queue_task_descriptor *qtd)
Definition ehci.cpp:742
ehci_queue_task_descriptor_node_t * data_node_
Definition ehci_pipe.hpp:18
void on_complete(uint8_t *buf, size_t len, bool error) override
Definition pipe.cpp:66
const char * mod
Definition ioforge.hpp:65
volatile uint64_t addr
Definition e1000.hpp:0
volatile uint8_t cmd
Definition e1000.hpp:3
volatile uint8_t status
Definition e1000.hpp:3
static uint16_t qh_ring[4096]
Definition ehci.cpp:18
#define EHCI_MAX_QTD_CACHE_MASK
Definition ehci.cpp:14
#define EHCI_MAX_QH_CACHE_MASK
Definition ehci.cpp:12
static size_t qtd_ring_tail
Definition ehci.cpp:25
#define EHCI_MAX_QH_CACHE
Definition ehci.cpp:11
static uint16_t qtd_ring[4096]
Definition ehci.cpp:23
#define HCSPARAM_N_PORTS_MASK
Definition ehci.cpp:259
static ehci_queue_head_node_t * main_async_qh
Definition ehci.cpp:31
static ehci_queue_head_node_t * framelist_node[1024]
Definition ehci.cpp:28
static size_t qh_ring_head
Definition ehci.cpp:19
#define EHCI_MAX_QTD_CACHE
Definition ehci.cpp:13
static ehci_queue_head_node_t qh_pool[4096]
Definition ehci.cpp:17
static ehci_queue_task_descriptor_node_t qtd_pool[4096]
Definition ehci.cpp:22
static size_t qh_ring_tail
Definition ehci.cpp:20
static size_t qtd_ring_head
Definition ehci.cpp:24
struct ehci_queue_head_node ehci_queue_head_node_t
Definition ehci.hpp:156
#define EHCI_PORT_ENABLED
Definition ehci.hpp:29
@ EHCI_QTD_TOKEN_ERROR_COUNT_3
Definition ehci.hpp:102
@ EHCI_Q_SELECT_QH
Definition ehci.hpp:76
#define EHCI_QH_CAP_HEAD_OF_RECLAMATION
Definition ehci.hpp:57
volatile uint32_t token
Definition ehci.hpp:7
#define EHCI_PORT_RESET
Definition ehci.hpp:30
@ EHCI_QH_CAP_MULT_1
Definition ehci.hpp:107
#define EHCI_QH_CAP_DTC
Definition ehci.hpp:56
#define EHCI_CONTROLLER_START
Definition ehci.hpp:16
volatile uint32_t buffer[5]
Definition ehci.hpp:8
struct ehci_queue_task_descriptor_node ehci_queue_task_descriptor_node_t
Definition ehci.hpp:174
#define EHCI_PERIODIC_SCHEDULE_ENABLE
Definition ehci.hpp:25
#define EHCI_CONTROLLER_RESET
Definition ehci.hpp:17
#define EHCI_QTD_TERMINATE
Definition ehci.hpp:66
#define EHCI_HC_HALTED_STATUS
Definition ehci.hpp:22
uint32_t next
Definition ehci.hpp:7
#define EHCI_QH_CAP_MAX_PACKET_LENGTH(x)
Definition ehci.hpp:58
#define EHCI_START_ASYNC_SCHEDULE
Definition ehci.hpp:19
@ EHCI_QTD_TOKEN_PID_IN
Definition ehci.hpp:84
@ EHCI_QTD_TOKEN_PID_OUT
Definition ehci.hpp:83
@ EHCI_QTD_TOKEN_PID_SETUP
Definition ehci.hpp:85
#define EHCI_QTD_TOKEN_IOC
Definition ehci.hpp:71
@ EHCI_QTD_TOKEN_STATUS_ACTIVE
Definition ehci.hpp:90
#define EHCI_QTD_TOKEN_DATA
Definition ehci.hpp:70
volatile uint32_t ch
Definition ehci.hpp:1
#define EHCI_QTD_TOKEN_LENGTH(l)
Definition ehci.hpp:69
struct fs_data data
Definition filesystem.h:1
uint64_t address
Definition hpet.h:4
void ioforge_memset(void *ptr, uint8_t value, size_t num)
void ioforge_attach(struct ioforge_device *parent, struct ioforge_device *child)
void serial2_printf(const char *fmt,...)
@ IOFORGE_USB_DEVICE
Definition ioforge.h:15
#define log(mod, fmt,...)
Definition ioforge.hpp:12
@ IoForgeUSB_VERSION_2
Definition ioforge_usb.h:11
struct ioforge_device * ioforge_get_usb_devices_root()
void * kalloc(size_t size)
size_t len
Definition oct2bin.h:7
kstring str(const char *str)
struct ehci_queue_head * head
Definition ehci.hpp:158
uint32_t physaddr
Definition ehci.hpp:159
volatile uint32_t currentTD
Definition ehci.hpp:145
volatile uint32_t qhlp
Definition ehci.hpp:142
volatile uint32_t cap
Definition ehci.hpp:144
volatile uint32_t token
Definition ehci.hpp:149
volatile uint32_t altTD
Definition ehci.hpp:148
volatile uint32_t ch
Definition ehci.hpp:143
volatile uint32_t nextTD
Definition ehci.hpp:147
struct ehci_queue_task_descriptor * task_descriptor
Definition ehci.hpp:178
volatile uint32_t buffer[5]
Definition ehci.hpp:167
volatile uint32_t link
Definition ehci.hpp:164
volatile uint32_t token
Definition ehci.hpp:166
volatile uint32_t altlink
Definition ehci.hpp:165
struct ioforge_device * first_child
Definition ioforge.h:36
char name[64]
Definition ioforge.h:30
struct ioforge_device * next_sibling
Definition ioforge.h:37
IoForgeType type
Definition ioforge.h:31
struct ioforge_device base
Definition ioforge_usb.h:35
struct ioforge_usb_controller_service * controller
Definition ioforge_usb.h:52
struct ioforge_usb_endpoint endpoints[16]
Definition ioforge_usb.h:53
const char serial_number[64]
Definition ioforge_usb.h:36
uint16_t idVendor
Definition usb.h:18
uint8_t iSerialNumber
Definition usb.h:23
uint8_t bDeviceProtocol
Definition usb.h:16
uint8_t bNumConfigurations
Definition usb.h:24
uint16_t idProduct
Definition usb.h:19
uint16_t bcdUSB
Definition usb.h:13
uint8_t bDeviceClass
Definition usb.h:14
uint8_t bMaxPacketSize0
Definition usb.h:17
uint8_t iProduct
Definition usb.h:22
uint8_t iManufacturer
Definition usb.h:21
uint8_t bDescriptorType
Definition usb.h:12
uint8_t bDeviceSubClass
Definition usb.h:15
uint8_t bLength
Definition usb.h:11
uint16_t wMaxPacketSize
Definition usb.h:55
uint8_t bEndpointAddress
Definition usb.h:53
uint8_t bInterval
Definition usb.h:56
uint8_t bmAttributes
Definition usb.h:54
uint8_t bDescriptorType
Definition usb.h:52
unsigned short uint16_t
Definition type.h:13
unsigned int uint32_t
Definition type.h:19
uint8_t boolean_t
Definition type.h:89
unsigned long uintptr_t
Definition type.h:73
unsigned char uint8_t
Definition type.h:7
uint8_t iConfiguration
Definition usb.h:5
@ USB_SETUP_PACKET_SET_ADDRESS
Definition usb.h:92
uint16_t ring[64]
Definition virtio-gpu.hpp:2
uint16_t idx
Definition virtio-gpu.hpp:1
uint32_t offset
Definition virtio.h:6
uint8_t type
Definition vnode.h:2
size_t size
Definition vnode.h:3
volatile uint32_t config
Definition xhci.hpp:8
uint64_t ptr
Definition xhci.hpp:0