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)
36 "ehci_queue_head must be 32-byte aligned");
38 "ehci_queue_task_descriptor must be 32-byte aligned");
40 size_t alloc_count = 0;
43 size_t ehci_qh_block_per_alloc =
47 i += ehci_qh_block_per_alloc, alloc_count++) {
58 for (
size_t j = 0; j < ehci_qh_block_per_alloc; j++) {
81 size_t ehci_qtd_block_per_alloc =
84 i += ehci_qtd_block_per_alloc, alloc_count++) {
95 for (
size_t j = 0; j < ehci_qtd_block_per_alloc; j++) {
108 qtd_pool[i + j].task_descriptor = qtd;
118 log(
mod,
"allocate %d Kb for queue cache (%d QH and %d QTD)",
128 if ((p1 - p0) % 32 != 0) {
130 "ERROR: QH alignment salah! sizeof=%d, diff=%d",
137 if ((q1 - q0) % 32 != 0) {
139 "ERROR: qTD alignment salah! sizeof=%d, diff=%d",
144 log(
mod,
"alignment OK — QH stride=%d, qTD stride=%d", p1 - p0,
160 log(
mod,
"first qh: 0x%x", qh);
169 if (
ehci_op->usbsts & (1 << 4)) {
170 log(
mod,
"EHCI: reset failed");
174 log(
mod,
"EHCI: reset engine");
178 log(
mod,
"EHCI: stopping_engine");
182 while (
ehci_op->usbsts & ((1 << 14) | (1 << 15)))
185 log(
mod,
"EHCI: stop_engine");
188 while (!(
ehci_op->usbsts & (1 << 12)))
190 log(
mod,
"EHCI: stop_engine");
197 log(
mod,
"EHCI: start engine");
201 log(
mod,
"periodic: init_que_head");
206 &framelist_phys_addr);
212 IOUtils::memset(qh, 0,
sizeof(*qh));
221 for (
int i = 0; i < 1024; i++) {
244 __sync_synchronize();
247 log(
mod,
"QH dengan interval %d ms dimasukkan ke slot %d", interval_ms,
259#define HCSPARAM_N_PORTS_MASK 0b1111
269 size_t len = (
str->bLength - 2) / 2;
272 for (
size_t i = 0; i <
len && j <
size - 1; i++) {
281 IOUtils::free(
buffer, 255);
288 log(
"EHCI",
"ERROR: controller must be set");
294 log(
mod,
"EHCI: port available : %d ", ports);
295 for (
int i = 0; i < ports; i++) {
303 log(
mod,
"Port %d Available", i);
309 IOUtils::memset(usbDevice, 0,
sizeof(*usbDevice));
318 log(
mod,
" USB Port %d : Descriptor Length : %d", i,
320 log(
mod,
" USB Port %d : Descriptor Type : %d", i,
322 log(
mod,
" USB Port %d : Version : %x", i, dev->
bcdUSB);
323 log(
mod,
" USB Port %d : Device class : %d", i,
325 log(
mod,
" USB Device sub class : %d ",
327 log(
mod,
"USB Device protocol : %d",
329 log(
mod,
"USB Max packet size : %d",
331 log(
mod,
"USB Number of Configuration : %d",
334 char iManufacturer[64] = {0};
337 sizeof(iManufacturer));
338 log(
mod,
"USB Manufacturer: %s", iManufacturer);
339 char iProduct[64] = {0};
342 log(
mod,
"USB Product: %s", iProduct);
343 char iSerialNumber[64] = {0};
347 sizeof(iSerialNumber));
348 log(
mod,
"USB Serial Number: %s",
352 log(
mod,
"USB Serial Number: [Not Provided]");
353 IOUtils::strcopy(iSerialNumber, (
char*)
"None");
365 IOUtils::memset(
data, 0, 0x1000);
376 " USB Port %d : Descriptor Length : %d", i,
378 log(
mod,
" USB Port %d : Descriptor Type : %d",
379 i,
config->bDescriptorType);
380 log(
mod,
" USB Port %d : Total Length : %d", i,
383 " USB Port %d : Number of Interface : %d",
384 i,
config->bNumInterfaces);
386 " USB Port %d : Configuration Value : %d",
387 i,
config->bConfigurationValue);
388 log(
mod,
" USB Port %d : Attribute : %d", i,
390 log(
mod,
" USB Port %d : Max Power : %d", i,
392 log(
mod,
" USB Port %d : iConfiguration : %d",
393 i,
config->iConfiguration);
399 log(
mod,
"USB Configuration Name: %s\n",
411 log(
mod,
"[Interface] Interface length : %d",
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);
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);
427 if (dev_class == 0 && dev_sub_class == 0) {
428 dev_class = interface->bInterfaceClass;
430 interface->bInterfaceSubClass;
432 interface->bInterfaceProtocol;
439 for (
int k = 0; k < interface->bNumEndpoints;
447 if (desc_type == 0x05)
458 log(
mod,
" [Endpoint %d] length : %d",
460 log(
mod,
" [Endpoint %d] type : %d", k,
463 " [Endpoint %d] address : 0x%x", k,
466 " [Endpoint %d] attributes : 0x%x",
468 log(
mod,
" [Endpoint %d] interval : %d",
471 auto& current_endpoint =
476 current_endpoint.attributes =
478 current_endpoint.interval =
480 current_endpoint.max_packet =
491 endpoint_count += interface->bNumEndpoints;
494 log(
mod,
"Get report descriptor");
502 setup->bmRequestType = 0b10000001;
503 setup->bRequest = 0x06;
504 setup->wValue = 0x2200;
510 4096, &in_data_paddr);
517 log(
mod,
"Report Descriptor : ");
518 for (
int i = 0; i < 32; i++) {
523 IOUtils::DMAFree((
void*) in_data_paddr, in_data,
534 usbDevice->
ep_count = endpoint_count;
538 if (dev_class == 0x3) {
539 if (dev_protocol == 1) {
544 "HID Device : Keyboard\n");
545 }
else if (dev_protocol == 2) {
556 auto __aligned_pipe_size =
558 void* mem =
kalloc(__aligned_pipe_size);
561 usbDevice->
pipe = pipe;
573 log(
mod,
"EHCI: resetting port %d ...", port);
581 size_t response_size) {
582 if (!data_phys || !
size)
612 if (response && response_size > 0) {
619 IOUtils::memset(data_qtd, 0,
683 qh->
cap |= ((endpoint & 0xF) << 8);
689 for (
int i = 0; i < 500 && !done; i++) {
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");
710 log(
mod,
"send_async: TIMEOUT");
715 __sync_synchronize();
724 while (!(
ehci_op->usbsts & (1 << 5)) && timeout > 0) {
730 log(
mod,
"ERROR: Asynchronous Advance Doorbell timeout!");
745 for (
int i = 0; i < 100; i++) {
748 if (qtd->
token & (1 << 6)) {
752 }
else if (qtd->
token & (1 << 5)) {
753 log(
mod,
"Data Buffer Error");
756 }
else if (qtd->
token & (1 << 4)) {
757 log(
mod,
"Babble detected");
760 }
else if (qtd->
token & (1 << 3)) {
761 log(
mod,
"Transaction error");
764 }
else if (qtd->
token & (1 << 2)) {
785 cmd->bmRequestType = 0;
787 cmd->bmRequestType = 0;
791 log(
mod,
"cmd : 0x%x", cmd_phys_addr);
806 (
uint8_t*) IOUtils::DMAAlloc(total_size, &base_phys_addr);
810 cmd->bRequest = 0x06;
811 cmd->bmRequestType = 0x80;
812 cmd->wValue = (
type << 8) | index;
822 IOUtils::memcpy((
void*)
data, (
void*) data_buf,
len);
823 IOUtils::DMAFree((
void*) base_phys_addr, (
void*) base_vaddr,
834 if (usb->pipe !=
nullptr) {
842 bool is_error =
false;
843 if (
token & (1 << 6)) {
844 log(
"EHCI IRQ",
"→ HALTED");
847 if (
token & (1 << 5)) {
848 log(
"EHCI IRQ",
"→ Data Buffer Error");
851 if (
token & (1 << 3)) {
852 log(
"EHCI IRQ",
"→ Transaction Error");
874 auto status =
module->ehci_op->usbsts;
881 module->call_completion_callback(node);
886 log(
"EHCI IRQ",
"port change");
889 module->ehci_op->usbsts = status;
904 }
while (!__atomic_compare_exchange_n(&
qh_ring_head, &
h,
h + 1,
false,
921 }
while (!__atomic_compare_exchange_n(&
qtd_ring_head, &
h,
h + 1,
false,
945 }
while (!__atomic_compare_exchange_n(&
qh_ring_tail, &t, t + 1,
false,
970 }
while (!__atomic_compare_exchange_n(&
qtd_ring_tail, &t, t + 1,
false,
983 __sync_synchronize();
void set_controller(ioforge_usb_controller_service *controller)
boolean_t retrieve_qtd(ehci_queue_task_descriptor_node_t **out)
void call_completion_callback(ioforge_device *dev)
boolean_t retrieve_qh(ehci_queue_head_node_t **out)
void store_qtd(ehci_queue_task_descriptor_node_t **in)
void insert_periodic(ehci_queue_head_node_t *qh_node, uint16_t interval_ms)
void usb_get_string_descriptor(uint8_t addr, uint8_t index, char *data, size_t size)
void assign_address(int address)
static void fireHandler()
void usb_get_descriptor(uint8_t addr, uint8_t type, uint8_t index, uint8_t len, uint8_t *data)
ioforge_usb_controller_service * controller
void push_to_qh(ehci_queue_head_node_t *qh_node)
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)
void port_reset(int port)
static EHCIModule * getInstance()
void store_qh(ehci_queue_head_node_t **in)
void procces_async(ehci_queue_task_descriptor *qtd)
ehci_queue_task_descriptor_node_t * data_node_
void on_complete(uint8_t *buf, size_t len, bool error) override
static uint16_t qh_ring[4096]
#define EHCI_MAX_QTD_CACHE_MASK
#define EHCI_MAX_QH_CACHE_MASK
static size_t qtd_ring_tail
#define EHCI_MAX_QH_CACHE
static uint16_t qtd_ring[4096]
#define HCSPARAM_N_PORTS_MASK
static ehci_queue_head_node_t * main_async_qh
static ehci_queue_head_node_t * framelist_node[1024]
static size_t qh_ring_head
#define EHCI_MAX_QTD_CACHE
static ehci_queue_head_node_t qh_pool[4096]
static ehci_queue_task_descriptor_node_t qtd_pool[4096]
static size_t qh_ring_tail
static size_t qtd_ring_head
struct ehci_queue_head_node ehci_queue_head_node_t
#define EHCI_PORT_ENABLED
@ EHCI_QTD_TOKEN_ERROR_COUNT_3
#define EHCI_QH_CAP_HEAD_OF_RECLAMATION
#define EHCI_CONTROLLER_START
volatile uint32_t buffer[5]
struct ehci_queue_task_descriptor_node ehci_queue_task_descriptor_node_t
#define EHCI_PERIODIC_SCHEDULE_ENABLE
#define EHCI_CONTROLLER_RESET
#define EHCI_QTD_TERMINATE
#define EHCI_HC_HALTED_STATUS
#define EHCI_QH_CAP_MAX_PACKET_LENGTH(x)
#define EHCI_START_ASYNC_SCHEDULE
@ EHCI_QTD_TOKEN_PID_SETUP
#define EHCI_QTD_TOKEN_IOC
@ EHCI_QTD_TOKEN_STATUS_ACTIVE
#define EHCI_QTD_TOKEN_DATA
#define EHCI_QTD_TOKEN_LENGTH(l)
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,...)
#define log(mod, fmt,...)
struct ioforge_device * ioforge_get_usb_devices_root()
void * kalloc(size_t size)
kstring str(const char *str)
struct ehci_queue_head * head
volatile uint32_t currentTD
struct ehci_queue_task_descriptor * task_descriptor
volatile uint32_t buffer[5]
volatile uint32_t altlink
struct ioforge_device * first_child
struct ioforge_device * next_sibling
struct ioforge_device base
struct ioforge_usb_controller_service * controller
struct ioforge_usb_endpoint endpoints[16]
const char serial_number[64]
uint8_t bNumConfigurations
@ USB_SETUP_PACKET_SET_ADDRESS