From 1cb1bad3ddb9d1fe9e8dc810d78a3a2a1a219bcd Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Mon, 6 Apr 2026 01:00:54 +0200 Subject: [PATCH] Read USB mass storage sector count and sector size! --- include/devices.h | 3 +- include/status.h | 1 + kernel/device/device.c | 30 ++- kernel/device/device.h | 2 + kernel/device/storage/src.mk | 6 +- kernel/device/storage/usbdrv.c | 239 +++++++++++++++++++ kernel/device/storage/usbdrv.h | 63 +++++ kernel/device/usb/mass_storage.c | 6 - kernel/device/usb/mass_storage.h | 8 - kernel/device/usb/src.mk | 6 +- kernel/device/usb/usb.c | 34 ++- kernel/device/usb/usb.h | 32 +-- kernel/device/usb/xhci.c | 388 ++++++++----------------------- kernel/device/usb/xhci.h | 287 ++++++++++++++++++++++- kernel/libk/endianess.h | 16 ++ kernel/libk/hash.h | 25 ++ libsystem/str_status.h | 1 + 17 files changed, 800 insertions(+), 347 deletions(-) create mode 100644 kernel/device/storage/usbdrv.c create mode 100644 kernel/device/storage/usbdrv.h delete mode 100644 kernel/device/usb/mass_storage.c delete mode 100644 kernel/device/usb/mass_storage.h diff --git a/include/devices.h b/include/devices.h index 5de4ff2..3c3dc0c 100644 --- a/include/devices.h +++ b/include/devices.h @@ -27,6 +27,7 @@ #define XDRV_TYPE_RAMDRV 0 #define XDRV_TYPE_PARTDRV 1 #define XDRV_TYPE_IDEDRV 2 +#define XDRV_TYPE_USBDRV 3 #define XDRV_GET_SIZE 0 #define XDRV_GET_SECTOR_SIZE 1 #define XDRV_GET_DEVICE_TYPE 2 @@ -34,6 +35,6 @@ #define XDRV_WRITE 4 /* usb controller devices */ -#define XUSBCTRL_POLL_DRIVER 0 +#define XUSBCTRL_POLL_DRIVER 0 #endif // _DEVICES_H diff --git a/include/status.h b/include/status.h index c46b714..d1baf0f 100644 --- a/include/status.h +++ b/include/status.h @@ -26,5 +26,6 @@ #define ST_XDRV_READ_ERROR 22 #define ST_XDRV_WRITE_ERROR 23 #define ST_NOT_PARTIAL 24 +#define ST_USB_CTRL_ERROR 25 #endif // _M_STATUS_H diff --git a/kernel/device/device.c b/kernel/device/device.c index 3d79d2c..f92eac4 100644 --- a/kernel/device/device.c +++ b/kernel/device/device.c @@ -41,14 +41,19 @@ struct device* device_find (const char* key) { uint32_t hash = hash_fnv32 (key, key_len); spin_lock (&device_table.lock, &fdt); + hash_find (&device_table, key, key_len, hash, lengthof (device_table.device_buckets), device_buckets, struct device, device_table_link, key, found_link); + spin_unlock (&device_table.lock, fdt); - if (found_link == NULL) + if (found_link == NULL) { return NULL; + } - return hash_entry (found_link, struct device, device_table_link); + struct device* device = hash_entry (found_link, struct device, device_table_link); + + return device; } struct device* device_create (int type, const char* key, device_op_func_t* ops, size_t ops_len, @@ -93,6 +98,27 @@ struct device* device_create (int type, const char* key, device_op_func_t* ops, return device; } +void device_delete (const char* key, struct proc* proc, struct reschedule_ctx* rctx) { + uint64_t fdt; + + size_t key_len = strlen_null (key); + uint32_t hash = hash_fnv32 (key, key_len); + + spin_lock (&device_table.lock, &fdt); + + struct hash_node_link* delete_link; + + hash_delete (&device_table, key, strlen_null (key), hash, lengthof (device_table.device_buckets), + device_buckets, struct device, device_table_link, key, delete_link); + + struct device* device = hash_entry (delete_link, struct device, device_table_link); + + if (device != NULL) + device->fini (device, proc, rctx); + + spin_unlock (&device_table.lock, fdt); +} + size_t device_populate_device_infos (struct device_info* infos, size_t count) { uint64_t fdt, fd; diff --git a/kernel/device/device.h b/kernel/device/device.h index 794e4a2..f2b0de4 100644 --- a/kernel/device/device.h +++ b/kernel/device/device.h @@ -43,6 +43,8 @@ struct device* device_create (int type, const char* key, device_op_func_t* ops, device_init_func_t init, device_fini_func_t fini, void* arg, struct proc* proc, struct reschedule_ctx* rctx); +void device_delete (const char* key, struct proc* proc, struct reschedule_ctx* rctx); + struct device* device_find (const char* key); size_t device_populate_device_infos (struct device_info* infos, size_t count); diff --git a/kernel/device/storage/src.mk b/kernel/device/storage/src.mk index 9051a15..0d6c7b0 100644 --- a/kernel/device/storage/src.mk +++ b/kernel/device/storage/src.mk @@ -1,9 +1,11 @@ c += device/storage/partdrv.c \ device/storage/ramdrv.c \ device/storage/partitions.c \ - device/storage/idedrv.c + device/storage/idedrv.c \ + device/storage/usbdrv.c o += device/storage/partdrv.o \ device/storage/ramdrv.o \ device/storage/partitions.o \ - device/storage/idedrv.o + device/storage/idedrv.o \ + device/storage/usbdrv.o diff --git a/kernel/device/storage/usbdrv.c b/kernel/device/storage/usbdrv.c new file mode 100644 index 0000000..a34d2f2 --- /dev/null +++ b/kernel/device/storage/usbdrv.c @@ -0,0 +1,239 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* REF: https://en.wikipedia.org/wiki/SCSI */ + +static int usb_ms_send_cbw (struct xhci* xhci, struct xhci_usb_device* usb_device, + uint8_t bulk_out_endpoint, uintptr_t cbw_phys, uint64_t* lockflags) { + return xhci_bulk_transfer (xhci, usb_device, bulk_out_endpoint, cbw_phys, + sizeof (struct usb_ms_cbw), lockflags); +} + +static int usb_ms_read_data (struct xhci* xhci, struct xhci_usb_device* usb_device, + uint8_t bulk_in_endpoint, uintptr_t buffer_phys, size_t buffer_size, + uint64_t* lockflags) { + return xhci_bulk_transfer (xhci, usb_device, bulk_in_endpoint, buffer_phys, buffer_size, + lockflags); +} + +static int usb_ms_read_csw (struct xhci* xhci, struct xhci_usb_device* usb_device, + uint8_t bulk_in_endpoint, uintptr_t csw_phys, uint64_t* lockflags) { + return xhci_bulk_transfer (xhci, usb_device, bulk_in_endpoint, csw_phys, + sizeof (struct usb_ms_csw), lockflags); +} + +static int usb_ms_scsi_read_capacity (struct xhci* xhci, struct xhci_usb_device* usb_device, + uint8_t bulk_in_endpoint, uint8_t bulk_out_endpoint, + size_t* sector_size, size_t* sector_count, + uint64_t* lockflags) { + struct limine_hhdm_response* hhdm = limine_hhdm_request.response; + int ret; + + uintptr_t cbw_phys = pmm_alloc (1); + struct usb_ms_cbw* cbw = (struct usb_ms_cbw*)(cbw_phys + (uintptr_t)hhdm->offset); + memset (cbw, 0, PAGE_SIZE); + + uintptr_t data_phys = pmm_alloc (1); + uint8_t* data = (uint8_t*)(data_phys + (uintptr_t)hhdm->offset); + memset (data, 0, PAGE_SIZE); + + uintptr_t csw_phys = pmm_alloc (1); + struct usb_ms_csw* csw = (struct usb_ms_csw*)(csw_phys + (uintptr_t)hhdm->offset); + memset (csw, 0, PAGE_SIZE); + + uint8_t cdb[10] = { + 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + cbw->signature = USB_CBW_SIGNATURE; + cbw->tag = 0x12345678; + cbw->dir = 0x80; + cbw->lun = 0; + cbw->cmd_len = sizeof (cdb); + cbw->length = 8; + memcpy (cbw->data, cdb, sizeof (cdb)); + + if ((ret = usb_ms_send_cbw (xhci, usb_device, bulk_out_endpoint, cbw_phys, lockflags)) < 0) { + goto done; + } + + if ((ret = usb_ms_read_data (xhci, usb_device, bulk_in_endpoint, data_phys, 8, lockflags)) < 0) { + goto done; + } + + if ((ret = usb_ms_read_csw (xhci, usb_device, bulk_in_endpoint, csw_phys, lockflags)) < 0) { + goto done; + } + + if (csw->status != 0 || csw->signature != USB_CSW_SIGNATURE) { + DEBUG ("Failed to read capacity/sect size. CSW status=%u residue=%u\n", csw->status, + csw->residue); + ret = -ST_USB_CTRL_ERROR; + goto done; + } + + uint32_t last_lba = BE2LE32 (*(uint32_t*)&data[0]); + uint32_t blk_len = BE2LE32 (*(uint32_t*)&data[4]); + + *sector_size = blk_len; + *sector_count = (size_t)last_lba + 1; + + ret = ST_OK; + +done: + pmm_free (cbw_phys, 1); + pmm_free (data_phys, 1); + pmm_free (csw_phys, 1); + return ret; +} + +static int usb_ms_scsi_test_unit_ready (struct xhci* xhci, struct xhci_usb_device* usb_device, + uint8_t bulk_in_endpoint, uint8_t bulk_out_endpoint, + uint64_t* lockflags) { + struct limine_hhdm_response* hhdm = limine_hhdm_request.response; + int ret; + + uintptr_t cbw_phys = pmm_alloc (1); + struct usb_ms_cbw* cbw = (struct usb_ms_cbw*)(cbw_phys + (uintptr_t)hhdm->offset); + memset (cbw, 0, PAGE_SIZE); + + uintptr_t csw_phys = pmm_alloc (1); + struct usb_ms_csw* csw = (struct usb_ms_csw*)(csw_phys + (uintptr_t)hhdm->offset); + memset (csw, 0, PAGE_SIZE); + + uint8_t cdb[10] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + + cbw->signature = USB_CBW_SIGNATURE; + cbw->tag = 0x12345678; + cbw->dir = 0x00; + cbw->lun = 0; + cbw->cmd_len = sizeof (cdb); + cbw->length = 0; + memcpy (cbw->data, cdb, sizeof (cdb)); + + if ((ret = usb_ms_send_cbw (xhci, usb_device, bulk_out_endpoint, cbw_phys, lockflags)) < 0) { + goto done; + } + + if ((ret = usb_ms_read_csw (xhci, usb_device, bulk_in_endpoint, csw_phys, lockflags)) < 0) { + goto done; + } + + if (csw->status != 0 || csw->signature != USB_CSW_SIGNATURE) { + ret = -ST_USB_CTRL_ERROR; + goto done; + } + + ret = ST_OK; + +done: + pmm_free (cbw_phys, 1); + pmm_free (csw_phys, 1); + return ret; +} + +static void usbdrv_setup_endpoints (struct usbdrv* usbdrv) { + for (size_t ep = 0; ep < usbdrv->usb_device->endpoints_count; ep++) { + struct xhci_usb_device_endpoint* endpoint = &usbdrv->usb_device->endpoints[ep]; + + uint8_t type = endpoint->desc.attrs & 0x03; + bool in = (endpoint->desc.endpoint_addr & 0x80) != 0; + + uint32_t xhci_type = 0; + + if (type == 2) { + if (in) + xhci_type = XHCI_EP_BULK_IN; + else + xhci_type = XHCI_EP_BULK_OUT; + } else if (type == 3) { + if (in) + xhci_type = XHCI_EP_INTR_IN; + else + xhci_type = XHCI_EP_INTR_OUT; + } + + if (xhci_type == XHCI_EP_BULK_IN) + usbdrv->bulk_in = endpoint->desc; + else if (xhci_type == XHCI_EP_BULK_OUT) + usbdrv->bulk_out = endpoint->desc; + } +} + +DEFINE_DEVICE_OP (usbdrv_read) {} + +DEFINE_DEVICE_OP (usbdrv_write) {} + +DEFINE_DEVICE_OP (usbdrv_get_device_type) { + if (a1 == NULL) + return -ST_BAD_ADDRESS_SPACE; + + int* device_type = (int*)a1; + + *device_type = XDRV_TYPE_USBDRV; + + return ST_OK; +} + +DEFINE_DEVICE_OP (usbdrv_get_sector_size) {} + +DEFINE_DEVICE_OP (usbdrv_get_size) {} + +DEFINE_DEVICE_INIT (usbdrv_init) { + int ret; + struct usbdrv_init* init = arg; + + struct usbdrv* usbdrv = malloc (sizeof (*usbdrv)); + + if (usbdrv == NULL) + return false; + + memset (usbdrv, 0, sizeof (*usbdrv)); + usbdrv->xhci = init->xhci; + usbdrv->usb_device = init->usb_device; + + usbdrv_setup_endpoints (usbdrv); + + ret = + usb_ms_scsi_test_unit_ready (usbdrv->xhci, usbdrv->usb_device, usbdrv->bulk_in.endpoint_addr, + usbdrv->bulk_out.endpoint_addr, init->lockflags); + + if (ret < 0) { + stall_ms (100); + + ret = usb_ms_scsi_test_unit_ready (usbdrv->xhci, usbdrv->usb_device, + usbdrv->bulk_in.endpoint_addr, + usbdrv->bulk_out.endpoint_addr, init->lockflags); + } + + if (ret < 0) + return false; + + ret = usb_ms_scsi_read_capacity (usbdrv->xhci, usbdrv->usb_device, usbdrv->bulk_in.endpoint_addr, + usbdrv->bulk_out.endpoint_addr, &usbdrv->sector_size, + &usbdrv->sector_count, init->lockflags); + + if (ret < 0) + return false; + + DEBUG ("sector_count = %zu, sector_size = %u\n", usbdrv->sector_count, usbdrv->sector_size); + + return true; +} + +DEFINE_DEVICE_FINI (usbdrv_fini) {} diff --git a/kernel/device/storage/usbdrv.h b/kernel/device/storage/usbdrv.h new file mode 100644 index 0000000..d90cef0 --- /dev/null +++ b/kernel/device/storage/usbdrv.h @@ -0,0 +1,63 @@ +#ifndef _KERNEL_DEVICE_STORAGE_USBDRV_H +#define _KERNEL_DEVICE_STORAGE_USBDRV_H + +#include +#include +#include +#include + +#define USB_CBW_SIGNATURE 0x43425355 + +/* command block wrapper */ +struct usb_ms_cbw { + uint32_t signature; + uint32_t tag; + uint32_t length; + uint8_t dir; + uint8_t lun; + uint8_t cmd_len; + uint8_t data[16]; +} PACKED; + +#define USB_CSW_SIGNATURE 0x53425355 + +/* command status wrapper */ +struct usb_ms_csw { + uint32_t signature; + uint32_t tag; + uint32_t residue; + uint8_t status; +} PACKED; + +struct device; + +struct usbdrv_init { + struct xhci* xhci; + struct xhci_usb_device* usb_device; + uint64_t* lockflags; +}; + +struct usbdrv { + struct xhci* xhci; + struct xhci_usb_device* usb_device; + size_t sector_size; + size_t sector_count; + struct usb_endpoint_desc bulk_in; + struct usb_endpoint_desc bulk_out; +}; + +DEFINE_DEVICE_INIT (usbdrv_init); + +DEFINE_DEVICE_FINI (usbdrv_fini); + +DEFINE_DEVICE_OP (usbdrv_read); + +DEFINE_DEVICE_OP (usbdrv_write); + +DEFINE_DEVICE_OP (usbdrv_get_device_type); + +DEFINE_DEVICE_OP (usbdrv_get_sector_size); + +DEFINE_DEVICE_OP (usbdrv_get_size); + +#endif // _KERNEL_DEVICE_STORAGE_USBDRV_H diff --git a/kernel/device/usb/mass_storage.c b/kernel/device/usb/mass_storage.c deleted file mode 100644 index 350066b..0000000 --- a/kernel/device/usb/mass_storage.c +++ /dev/null @@ -1,6 +0,0 @@ -#include -#include -#include -#include - -bool usb_mass_storage_init (void) { return true; } diff --git a/kernel/device/usb/mass_storage.h b/kernel/device/usb/mass_storage.h deleted file mode 100644 index f766121..0000000 --- a/kernel/device/usb/mass_storage.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _KERNEL_DEVICE_USB_MASS_STORAGE_H -#define _KERNEL_DEVICE_USB_MASS_STORAGE_H - -#include - -bool usb_mass_storage_init (void); - -#endif // _KERNEL_DEVICE_USB_MASS_STORAGE_H diff --git a/kernel/device/usb/src.mk b/kernel/device/usb/src.mk index c6ae293..f2fbbbc 100644 --- a/kernel/device/usb/src.mk +++ b/kernel/device/usb/src.mk @@ -1,7 +1,5 @@ c += device/usb/xhci.c \ - device/usb/usb.c \ - device/usb/mass_storage.c + device/usb/usb.c o += device/usb/xhci.o \ - device/usb/usb.o \ - device/usb/mass_storage.o + device/usb/usb.o diff --git a/kernel/device/usb/usb.c b/kernel/device/usb/usb.c index c9f9b68..102d8d1 100644 --- a/kernel/device/usb/usb.c +++ b/kernel/device/usb/usb.c @@ -1,6 +1,36 @@ -#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include + +static atomic_int usb_ms_counter = 0; + +static struct device* usb_ms_init (struct xhci* xhci, struct xhci_usb_device* usb_device, + struct proc* proc, struct reschedule_ctx* rctx, + uint64_t* lockflags) { + static device_op_func_t ops[] = {0}; + + struct usbdrv_init init = { + .xhci = xhci, + .usb_device = usb_device, + .lockflags = lockflags, + }; + + char key[30]; + snprintf (key, sizeof (key), "usbdrv%d", atomic_fetch_add (&usb_ms_counter, 1)); + + return device_create (DEVICE_TYPE_DRIVE, key, ops, lengthof (ops), &usbdrv_init, &usbdrv_fini, + &init, proc, rctx); +} struct usb_driver_info usb_driver_infos[USB_DRIVER_MAX_MATCHES] = { - {.if_class = 0x08, .if_subclass = 0x06, .if_proto = 0x50, .init = &usb_mass_storage_init}, + {.if_class = 0x08, .if_subclass = 0x06, .if_proto = 0x50, .init = &usb_ms_init}, }; diff --git a/kernel/device/usb/usb.h b/kernel/device/usb/usb.h index 5f7cad0..eade7f1 100644 --- a/kernel/device/usb/usb.h +++ b/kernel/device/usb/usb.h @@ -2,7 +2,10 @@ #define _KERNEL_DEVICE_USB_H #include +#include #include +#include +#include #define USB_DRIVER_MAX_MATCHES 1 @@ -21,6 +24,9 @@ #define USB_DESC_DEV_CAPABILITY 16 #define USB_DESC_SS_USB_EP_COMP 48 +struct xhci; +struct xhci_usb_device; + struct usb_desc_hdr { uint8_t length; uint8_t desc_type; @@ -77,34 +83,12 @@ struct usb_endpoint_desc { uint8_t interval; } PACKED; -#define USB_CBW_SIGNATURE 0x43425355 - -/* command block wrapper */ -struct usb_cbw { - uint32_t signature; - uint32_t tag; - uint32_t length; - uint8_t dir; - uint8_t lun; - uint8_t cmd_len; - uint8_t data[16]; -} PACKED; - -#define USB_CSW_SIGNATURE 0x53425355 - -/* command status wrapper */ -struct usb_csw { - uint32_t signature; - uint32_t tag; - uint32_t residue; - uint8_t status; -}; - struct usb_driver_info { uint8_t if_class; uint8_t if_subclass; uint8_t if_proto; - bool (*init) (void); + struct device* (*init) (struct xhci* xhci, struct xhci_usb_device* usb_device, struct proc* proc, + struct reschedule_ctx* rctx, uint64_t* lockflags); }; extern struct usb_driver_info usb_driver_infos[USB_DRIVER_MAX_MATCHES]; diff --git a/kernel/device/usb/xhci.c b/kernel/device/usb/xhci.c index 586a480..a1b6612 100644 --- a/kernel/device/usb/xhci.c +++ b/kernel/device/usb/xhci.c @@ -19,293 +19,12 @@ #include #include -/* REF: - * https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf - */ - -/* clang-format off */ - -/* capability registers */ -#define XHCI_CAPLENGTH 0x00 -#define XHCI_RSVD 0x01 -#define XHCI_HCIVERSION 0x02 -#define XHCI_HCSPARAMS1 0x04 -#define XHCI_HCSPARAMS2 0x08 -#define XHCI_HCSPARAMS3 0x0C -#define XHCI_HCCPARAMS1 0x10 -#define XHCI_DBOFF 0x14 -#define XHCI_RTSOFF 0x18 -#define XHCI_HCCPARAMS2 0x1C - -/* operational registers */ -#define XHCI_USBCMD 0x00 -#define XHCI_USBSTS 0x04 -#define XHCI_PAGESIZE 0x08 -#define XHCI_DNCTRL 0x14 -#define XHCI_CRCR 0x18 -#define XHCI_DCBAAP 0x30 -#define XHCI_CONFIG 0x38 - -/* port registers */ -#define XHCI_PORTSC 0x00 -#define XHCI_PORTPMSC 0x04 -#define XHCI_PORTLI 0x08 - -/* runtime registers */ -#define XHCI_MFINDEX 0x00 -/* + IRQ sets (0x20) */ -#define XHCI_IMAN 0x00 -#define XHCI_IMOD 0x04 -#define XHCI_ERSTSZ 0x08 -#define XHCI_ERSTBA 0x10 -#define XHCI_ERDP 0x18 - -/* HCCPARAMS1 */ -#define XHCI_HCCPARAMS1_AC64 0 -#define XHCI_HCCPARAMS1_BNC 1 -#define XHCI_HCCPARAMS1_CSZ 2 -#define XHCI_HCCPARAMS1_PPC 3 -#define XHCI_HCCPARAMS1_PIND 4 -#define XHCI_HCCPARAMS1_LHRC 5 -#define XHCI_HCCPARAMS1_LTC 6 -#define XHCI_HCCPARAMS1_NSS 7 -#define XHCI_HCCPARAMS1_PAE 8 -#define XHCI_HCCPARAMS1_SPC 9 -#define XHCI_HCCPARAMS1_SEC 10 -#define XHCI_HCCPARAMS1_CFC 11 -#define XHCI_HCCPARAMS1_MAX_PSA_SIZE 12 -#define XHCI_HCCPARAMS1_XECP 16 - -/* XHCI extended capabilities */ -#define XHCI_XECP_CAP_ID 0 -#define XHCI_XECP_NEXT_PTR 8 - -/* USB legacy support capability */ -#define XHCI_USBLEGSUP_CAP_ID 0 -#define XHCI_USBLEGSUP_NEXT_PTR 8 -#define XHCI_USBLEGSUP_BIOS_SEMA 16 -#define XHCI_USBLEGSUP_OS_SEMA 24 - -/* Supported protocol capability */ -#define XHCI_SUPPROTO_DW0_CAP_ID 0 -#define XHCI_SUPPROTO_DW0_NEXT_PTR 8 -#define XHCI_SUPPROTO_DW0_MINOR_REV 16 -#define XHCI_SUPPROTO_DW0_MAJOR_REV 24 -#define XHCI_SUPPROTO_DW1_NAME_STRING 0 -#define XHCI_SUPPROTO_DW2_PORT_OFF 0 -#define XHCI_SUPPROTO_DW2_PORT_COUNT 8 -#define XHCI_SUPPROTO_DW2_PROT_DEF 16 -#define XHCI_SUPPROTO_DW2_PSIC 28 -#define XHCI_SUPPROTO_DW3_SLOT_TYPE 0 - -/* HCSPARAMS1 */ -#define XHCI_HCSPARAMS1_MAX_DEV_SLOTS 0 -#define XHCI_HCSPARAMS1_MAX_INTRS 8 -#define XHCI_HCSPARAMS1_MAX_PORTS 24 - -/* HCSPARAMS2 */ -#define XHCI_HCSPARAMS2_IST 0 -#define XHCI_HCSPARAMS2_ERST_MAX 4 -#define XHCI_HCSPARAMS2_MAX_SCRTCH_HI 21 -#define XHCI_HCSPARAMS2_SPR 26 -#define XHCI_HCSPARAMS2_MAX_SCRTCH_LO 27 - -/* event types */ -#define XHCI_TRB_NORMAL 1 -#define XHCI_TRB_SETUP_STAGE 2 -#define XHCI_TRB_DATA_STAGE 3 -#define XHCI_TRB_STATUS_STAGE 4 -#define XHCI_TRB_ISOCH 5 -#define XHCI_TRB_LINK 6 -#define XHCI_TRB_EVENT_DATA 7 -#define XHCI_TRB_NOOP 8 -#define XHCI_TRB_SLOT_ENAB_CMD 9 -#define XHCI_TRB_SLOT_DISB_CMD 10 -#define XHCI_TRB_ADDR_DEV_CMD 11 -#define XHCI_TRB_CFG_ENDP_CMD 12 -#define XHCI_TRB_EVAL_CTX_CMD 13 -#define XHCI_TRB_RESET_ENDP_CMD 14 -#define XHCI_TRB_STOP_ENDP_CMD 15 -#define XHCI_TRB_SET_DRDQP_CMD 16 -#define XHCI_TRB_RESET_DEV_CMD 17 -#define XHCI_TRB_FORCE_EVT_CMD 18 -#define XHCI_TRB_NEGO_BANDW_CMD 19 -#define XHCI_TRB_SET_LTV_CMD 20 -#define XHCI_TRB_PORT_BANDW_CMD 21 -#define XHCI_TRB_FORCE_HEADER 22 -#define XHCI_TRB_NOOP_CMD 23 -#define XHCI_TRB_GET_EXTPRP_CMD 24 -#define XHCI_TRB_SET_EXTPRP_CMD 25 -#define XHCI_TRB_TRANSFER_EVENT 32 -#define XHCI_TRB_CMD_CMPL_EVENT 33 -#define XHCI_TRB_PORT_STS_CHNG 34 -#define XHCI_TRB_BANDW_RQ_EVENT 35 -#define XHCI_TRB_DOORBELL_EVENT 36 -#define XHCI_TRB_HOST_CTRL_EVNT 37 -#define XHCI_TRB_DEV_NOTIF_EVNT 38 -#define XHCI_TRB_MFINDEX_WRAP 39 - -/* generic TRB bits */ -#define XHCI_GTRB_TRB_TYPE 10 -#define XHCI_GTRB_CYCLE_BIT 0 - -/* command completion event TRB */ -#define XHCI_CCETRB_CTRL_SLOT_ID 24 -#define XHCI_CCETRB_CTRL_VFID 16 -#define XHCI_CCETRB_CTRL_TRB_TYPE 10 -#define XHCI_CCETRB_CTRL_CYCLEBIT 0 -#define XHCI_CCETRB_STS_CMPL_CODE 24 - -/* transfer event TRB */ -#define XHCI_TETRB_CTRL_SLOT_ID 24 -#define XHCI_TETRB_CTRL_ENDPOINT 16 -#define XHCI_TETRB_CTRL_TRB_TYPE 10 -#define XHCI_TETRB_CTRL_EVT_DATA 2 -#define XHCI_TETRB_CTRL_CYCLEBIT 0 -#define XHCI_TETRB_STS_CMPL_CODE 24 - -/* port status change event TRB */ -#define XHCI_PSCETRB_CTRL_TRB_TYPE 10 -#define XHCI_PSCETRB_CTRL_CYCLEBIT 0 -#define XHCI_PSCETRB_STS_CMPL_CODE 24 -#define XHCI_PSCETRB_PARAM_PORT_ID 24 - -/* link TRB */ -#define XHCI_LNKTRB_CTRL_TRB_TYPE 10 -#define XHCI_LNKTRB_CTRL_IOC 5 -#define XHCI_LNKTRB_CTRL_CH 4 -#define XHCI_LNKTRB_CTRL_TC 1 -#define XHCI_LNKTRB_CTRL_CYCLEBIT 0 -#define XHCI_LNKTRB_STS_INTR_TRGT 22 - -/* setup stage TRB */ -#define XHCI_SSTRB_CTRL_TRT 16 -#define XHCI_SSTRB_CTRL_TRB_TYPE 10 -#define XHCI_SSTRB_CTRL_IDT 6 -#define XHCI_SSTRB_CTRL_IOC 5 -#define XHCI_SSTRB_CTRL_CYCLEBIT 0 -#define XHCI_SSTRB_STS_INTR_TRGT 22 -#define XHCI_SSTRB_PARAM_WLENGTH 48 -#define XHCI_SSTRB_PARAM_WINDEX 32 -#define XHCI_SSTRB_PARAM_WVALUE 16 -#define XHCI_SSTRB_PARAM_BREQUEST 8 -#define XHCI_SSTRB_PARAM_BMREQUEST_TYPE 0 - -/* setup stage TRB transfer types */ -#define XHCI_SSTRB_TRT_NO_DATA_STAGE 0 -#define XHCI_SSTRB_TRT_OUT_DATA_STAGE 2 -#define XHCI_SSTRB_TRT_IN_DATA_STAGE 3 - -/* data stage TRB */ -#define XHCI_DSTRB_CTRL_DIR 16 -#define XHCI_DSTRB_CTRL_TRB_TYPE 10 -#define XHCI_DSTRB_CTRL_IDT 6 -#define XHCI_DSTRB_CTRL_IOC 5 -#define XHCI_DSTRB_CTRL_CH 4 -#define XHCI_DSTRB_CTRL_NS 3 -#define XHCI_DSTRB_CTRL_ISP 2 -#define XHCI_DSTRB_CTRL_ENT 1 -#define XHCI_DSTRB_CTRL_CYCLEBIT 0 -#define XHCI_DSTRB_STS_INTR_TRGT 22 -#define XHCI_DSTRB_STS_TD_SIZE 17 - -/* status stage TRB */ -#define XHCI_STSTRB_CTRL_DIR 16 -#define XHCI_STSTRB_CTRL_TRB_TYPE 10 -#define XHCI_STSTRB_CTRL_IOC 5 -#define XHCI_STSTRB_CTRL_CH 4 -#define XHCI_STSTRB_CTRL_ENT 1 -#define XHCI_STSTRB_CTRL_CYCLEBIT 0 -#define XHCI_STSTRB_STS_INTR_TRGT 22 - -/* extended capabilities */ -#define XHCI_EXTCAP_USB_LEGACY_SUPPORT 1 -#define XHCI_EXTCAP_SUPPORTED_PROTOCOL 2 -#define XHCI_EXTCAP_EXT_POWER_MNGMNT 3 -#define XHCI_EXTCAP_IO_VIRT 4 -#define XHCI_EXTCAP_MSG_INTR 5 -#define XHCI_EXTCAP_LOCAL_MEMORY 6 -#define XHCI_EXTCAP_USB_DEBUG 7 -#define XHCI_EXTCAP_EXT_MSG_INTR 8 -#define XHCI_EXTCAP_VENDOR_DEFINED 9 - -/* PORTSC bits */ -#define XHCI_PORTSC_CCS 0 -#define XHCI_PORTSC_PED 1 -#define XHCI_PORTSC_OCA 3 -#define XHCI_PORTSC_PR 4 -#define XHCI_PORTSC_PLS 5 -#define XHCI_PORTSC_PP 9 -#define XHCI_PORTSC_PORTSPEED 10 -#define XHCI_PORTSC_PIC 14 -#define XHCI_PORTSC_LWS 16 -#define XHCI_PORTSC_CSC 17 -#define XHCI_PORTSC_PEC 18 -#define XHCI_PORTSC_WRC 19 -#define XHCI_PORTSC_OCC 20 -#define XHCI_PORTSC_PRC 21 -#define XHCI_PORTSC_PLC 22 -#define XHCI_PORTSC_CEC 23 -#define XHCI_PORTSC_CAS 24 -#define XHCI_PORTSC_WCE 25 -#define XCHI_PORTSC_WDE 26 -#define XHCI_PORTSC_WOE 27 -#define XHCI_PORTSC_DR 30 -#define XHCI_PORTSC_WPR 31 - -/* endpoint context */ -#define XHCI_EPCTX_EP_STATE 0 -#define XHCI_EPCTX_MULT 8 -#define XHCI_EPCTX_MAXPSTRAMS 10 -#define XHCI_EPCTX_LSA 15 -#define XHCI_EPCTX_INTERVAL 16 -#define XHCI_EPCTX_MAX_ESIT_HI 24 -#define XHCI_EPCTX_ERR_COUNT 1 -#define XHCI_EPCTX_EP_TYPE 3 -#define XHCI_EPCTX_HID 7 -#define XHCI_EPCTX_MAX_BURST_SZ 8 -#define XHCI_EPCTX_MAX_PKT_SZ 16 -#define XHCI_EPCTX_DCS 0 -#define XHCI_EPCTX_TR_DQ_PTR 4 -#define XHCI_EPCTX_AVG_TRB_LEN 0 -#define XHCI_EPCTX_MAX_ESIT_LOW 16 - -/* endpoint types */ -#define XHCI_EP_INVALID 0 -#define XHCI_EP_ISOCH_OUT 1 -#define XHCI_EP_BULK_OUT 2 -#define XHCI_EP_INTR_OUT 3 -#define XHCI_EP_CTRL_BI 4 -#define XHCI_EP_ISOCH_IN 5 -#define XHCI_EP_BULK_IN 6 -#define XHCI_EP_INTR_IN 7 - -/* slot context */ -#define XHIC_SLCTX_ROUTE_STR 0 -#define XHCI_SLCTX_SPEED 20 -#define XHCI_SLCTX_MTT 25 -#define XHCI_SLCTX_HUB 26 -#define XHCI_SLCTX_CTX_ENTRIES 27 -#define XHCI_SLCTX_MAXEXITLTNCY 0 -#define XHCI_SLCTX_ROOTHUBPRNUM 16 -#define XHCI_SLCTX_PORT_COUNT 24 -#define XHCI_SLCTX_PRNT_HUB_SLT 0 -#define XHCI_SLCTX_PARENT_PORT 8 -#define XHCI_SLCTX_TT_THINKTIME 16 -#define XHCI_SLCTX_INTR_TARGET 22 -#define XHCI_SLCTX_USB_DEV_ADDR 0 -#define XHCI_SLCTX_SLOT_STATE 27 - -/* clang-format on */ +static uint8_t xhci_get_device_ctx_idx (struct usb_endpoint_desc* endpoint); static void xhci_write8 (uintptr_t base, uint32_t reg, uint8_t value) { *(volatile uint8_t*)(base + reg) = value; } -static void xhci_write16 (uintptr_t base, uint32_t reg, uint16_t value) { - *(volatile uint16_t*)(base + reg) = value; -} - static void xhci_write32 (uintptr_t base, uint32_t reg, uint32_t value) { *(volatile uint32_t*)(base + reg) = value; } @@ -314,10 +33,6 @@ static uint8_t xhci_read8 (uintptr_t base, uint32_t reg) { return *(volatile uint8_t*)(base + reg); } -static uint16_t xhci_read16 (uintptr_t base, uint32_t reg) { - return *(volatile uint16_t*)(base + reg); -} - static uint32_t xhci_read32 (uintptr_t base, uint32_t reg) { return *(volatile uint32_t*)(base + reg); } @@ -347,12 +62,15 @@ static void xhci_create_usb_device (struct xhci* xhci, struct xhci_port* xhci_po list_append (xhci->xhci_usb_devices, &usb_device->usb_devices_link); } -static void xhci_delete_usb_device (struct xhci* xhci, struct xhci_port* xhci_port) { - struct xhci_usb_device* usb_device; +static void xhci_delete_usb_device (struct xhci* xhci, struct xhci_port* xhci_port, + struct proc* proc, struct reschedule_ctx* rctx) { + struct xhci_usb_device* usb_device = NULL; list_find (struct xhci_usb_device, xhci->xhci_usb_devices, usb_device, xhci_port->port_value, xhci_port->port_value, usb_devices_link); + device_delete (usb_device->device->key, proc, rctx); + list_remove (xhci->xhci_usb_devices, &usb_device->usb_devices_link); if (usb_device->endpoint0_ring.phys != 0) @@ -1186,20 +904,24 @@ static bool xhci_usb_device_setup_get_config_full (struct xhci* xhci, static void xhci_poll_setup_init_ifs (struct xhci* xhci, struct xhci_usb_device* usb_device, uint64_t* lockflags) { + struct reschedule_ctx rctx; + memset (&rctx, 0, sizeof (rctx)); + for (size_t if0 = 0; if0 < usb_device->ifs_count; if0++) { struct xhci_usb_device_if* if_ = &usb_device->ifs[if0]; for (size_t i = 0; i < USB_DRIVER_MAX_MATCHES; i++) { struct usb_driver_info* info = &usb_driver_infos[i]; - DEBUG ("%u %u / %u %u / %u %u\n", if_->desc.if_class, info->if_class, if_->desc.if_subclass, - info->if_subclass, if_->desc.if_proto, info->if_proto); - if (if_->desc.if_class == info->if_class && if_->desc.if_subclass == info->if_subclass && if_->desc.if_proto == info->if_proto) { - if (!info->init ()) + struct device* device = info->init (xhci, usb_device, thiscpu->kproc, &rctx, lockflags); + + if (device == NULL) DEBUG ("USB driver failed to initialize. Skipping device!\n"); + + usb_device->device = device; } } } @@ -1227,7 +949,8 @@ static void xhci_poll_setup_devices (struct xhci* xhci, uint64_t* lockflags) { } } -static void xhci_poll_port_changes (struct xhci* xhci) { +static void xhci_poll_port_changes (struct xhci* xhci, struct proc* proc, + struct reschedule_ctx* rctx) { struct list_node_link *port_change_link, *tmp_port_change_link; struct xhci_port* xhci_port; @@ -1248,7 +971,7 @@ static void xhci_poll_port_changes (struct xhci* xhci) { } else { DEBUG ("Device detached from port %u!\n", change->port); - xhci_delete_usb_device (xhci, xhci_port); + xhci_delete_usb_device (xhci, xhci_port, proc, rctx); } } @@ -1256,10 +979,83 @@ static void xhci_poll_port_changes (struct xhci* xhci) { } } +int xhci_bulk_transfer (struct xhci* xhci, struct xhci_usb_device* usb_device, + uint8_t endpoint_addr, uintptr_t buffer_phys, size_t buffer_size, + uint64_t* lockflags) { + struct xhci_usb_device_endpoint* endpoint = NULL; + + for (size_t ep = 0; ep < XHCI_USB_DEVICE_ENDPOINTS_MAX; ep++) { + endpoint = &usb_device->endpoints[ep]; + + if (endpoint->desc.endpoint_addr == endpoint_addr) + break; + } + + if (endpoint == NULL) + return -ST_NOT_FOUND; + + /* not bulk */ + if ((endpoint->desc.attrs & 0x03) != 0x02) + return -ST_NOT_FOUND; + + if (usb_device->slot_id < 0) + return -ST_NOT_FOUND; + + xhci->last_cmpl_code = 0; + atomic_store (&xhci->pending, true); + + uint32_t rem = buffer_size; + uint32_t current = buffer_phys; + + while (rem > 0) { + uint32_t chunk = rem > 0x1FFFFU ? 0x1FFFFU : rem; + + struct xhci_trb trb; + memset (&trb, 0, sizeof (trb)); + trb.param = current; + trb.status = chunk; + + write_memory_barrier (); + + trb.ctrl = (XHCI_TRB_NORMAL << XHCI_GTRB_TRB_TYPE); + + if (rem != chunk) { + trb.ctrl |= (1 << XHCI_DSTRB_CTRL_CH); + } else { + trb.ctrl |= (1 << XHCI_DSTRB_CTRL_IOC) | (1 << XHCI_DSTRB_CTRL_ISP); + } + + xhci_ring_put_trb (&endpoint->transfer_ring, trb); + + current += chunk; + rem -= chunk; + } + + uint32_t dci = xhci_get_device_ctx_idx (&endpoint->desc); + + int timeout = 100; + + spin_unlock (&xhci->device->lock, *lockflags); + + xhci_write32 (xhci->xhci_doorbell_base, usb_device->slot_id * 4, dci); + + while (atomic_load (&xhci->pending) && --timeout > 0) + stall_ms (10); + + spin_lock (&xhci->device->lock, lockflags); + + if (timeout == 0) { + DEBUG ("bulk transfer timed out\n"); + return -ST_TRY_AGAIN; + } + + return xhci->last_cmpl_code == 1 ? ST_OK : -ST_USB_CTRL_ERROR; +} + DEFINE_DEVICE_OP (xhci_poll_driver) { struct xhci* xhci = device->udata; - xhci_poll_port_changes (xhci); + xhci_poll_port_changes (xhci, proc, rctx); xhci_poll_setup_devices (xhci, lockflags); return ST_OK; @@ -1436,7 +1232,7 @@ DEFINE_DEVICE_FINI (xhci_fini) { list_remove (xhci->xhci_ports, &port->ports_link); - xhci_delete_usb_device (xhci, port); + xhci_delete_usb_device (xhci, port, proc, rctx); free (port); } diff --git a/kernel/device/usb/xhci.h b/kernel/device/usb/xhci.h index 84a6426..d6a694b 100644 --- a/kernel/device/usb/xhci.h +++ b/kernel/device/usb/xhci.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -10,6 +11,285 @@ #include #include +/* REF: + * https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf + */ + +/* clang-format off */ + +/* capability registers */ +#define XHCI_CAPLENGTH 0x00 +#define XHCI_RSVD 0x01 +#define XHCI_HCIVERSION 0x02 +#define XHCI_HCSPARAMS1 0x04 +#define XHCI_HCSPARAMS2 0x08 +#define XHCI_HCSPARAMS3 0x0C +#define XHCI_HCCPARAMS1 0x10 +#define XHCI_DBOFF 0x14 +#define XHCI_RTSOFF 0x18 +#define XHCI_HCCPARAMS2 0x1C + +/* operational registers */ +#define XHCI_USBCMD 0x00 +#define XHCI_USBSTS 0x04 +#define XHCI_PAGESIZE 0x08 +#define XHCI_DNCTRL 0x14 +#define XHCI_CRCR 0x18 +#define XHCI_DCBAAP 0x30 +#define XHCI_CONFIG 0x38 + +/* port registers */ +#define XHCI_PORTSC 0x00 +#define XHCI_PORTPMSC 0x04 +#define XHCI_PORTLI 0x08 + +/* runtime registers */ +#define XHCI_MFINDEX 0x00 +/* + IRQ sets (0x20) */ +#define XHCI_IMAN 0x00 +#define XHCI_IMOD 0x04 +#define XHCI_ERSTSZ 0x08 +#define XHCI_ERSTBA 0x10 +#define XHCI_ERDP 0x18 + +/* HCCPARAMS1 */ +#define XHCI_HCCPARAMS1_AC64 0 +#define XHCI_HCCPARAMS1_BNC 1 +#define XHCI_HCCPARAMS1_CSZ 2 +#define XHCI_HCCPARAMS1_PPC 3 +#define XHCI_HCCPARAMS1_PIND 4 +#define XHCI_HCCPARAMS1_LHRC 5 +#define XHCI_HCCPARAMS1_LTC 6 +#define XHCI_HCCPARAMS1_NSS 7 +#define XHCI_HCCPARAMS1_PAE 8 +#define XHCI_HCCPARAMS1_SPC 9 +#define XHCI_HCCPARAMS1_SEC 10 +#define XHCI_HCCPARAMS1_CFC 11 +#define XHCI_HCCPARAMS1_MAX_PSA_SIZE 12 +#define XHCI_HCCPARAMS1_XECP 16 + +/* XHCI extended capabilities */ +#define XHCI_XECP_CAP_ID 0 +#define XHCI_XECP_NEXT_PTR 8 + +/* USB legacy support capability */ +#define XHCI_USBLEGSUP_CAP_ID 0 +#define XHCI_USBLEGSUP_NEXT_PTR 8 +#define XHCI_USBLEGSUP_BIOS_SEMA 16 +#define XHCI_USBLEGSUP_OS_SEMA 24 + +/* Supported protocol capability */ +#define XHCI_SUPPROTO_DW0_CAP_ID 0 +#define XHCI_SUPPROTO_DW0_NEXT_PTR 8 +#define XHCI_SUPPROTO_DW0_MINOR_REV 16 +#define XHCI_SUPPROTO_DW0_MAJOR_REV 24 +#define XHCI_SUPPROTO_DW1_NAME_STRING 0 +#define XHCI_SUPPROTO_DW2_PORT_OFF 0 +#define XHCI_SUPPROTO_DW2_PORT_COUNT 8 +#define XHCI_SUPPROTO_DW2_PROT_DEF 16 +#define XHCI_SUPPROTO_DW2_PSIC 28 +#define XHCI_SUPPROTO_DW3_SLOT_TYPE 0 + +/* HCSPARAMS1 */ +#define XHCI_HCSPARAMS1_MAX_DEV_SLOTS 0 +#define XHCI_HCSPARAMS1_MAX_INTRS 8 +#define XHCI_HCSPARAMS1_MAX_PORTS 24 + +/* HCSPARAMS2 */ +#define XHCI_HCSPARAMS2_IST 0 +#define XHCI_HCSPARAMS2_ERST_MAX 4 +#define XHCI_HCSPARAMS2_MAX_SCRTCH_HI 21 +#define XHCI_HCSPARAMS2_SPR 26 +#define XHCI_HCSPARAMS2_MAX_SCRTCH_LO 27 + +/* event types */ +#define XHCI_TRB_NORMAL 1 +#define XHCI_TRB_SETUP_STAGE 2 +#define XHCI_TRB_DATA_STAGE 3 +#define XHCI_TRB_STATUS_STAGE 4 +#define XHCI_TRB_ISOCH 5 +#define XHCI_TRB_LINK 6 +#define XHCI_TRB_EVENT_DATA 7 +#define XHCI_TRB_NOOP 8 +#define XHCI_TRB_SLOT_ENAB_CMD 9 +#define XHCI_TRB_SLOT_DISB_CMD 10 +#define XHCI_TRB_ADDR_DEV_CMD 11 +#define XHCI_TRB_CFG_ENDP_CMD 12 +#define XHCI_TRB_EVAL_CTX_CMD 13 +#define XHCI_TRB_RESET_ENDP_CMD 14 +#define XHCI_TRB_STOP_ENDP_CMD 15 +#define XHCI_TRB_SET_DRDQP_CMD 16 +#define XHCI_TRB_RESET_DEV_CMD 17 +#define XHCI_TRB_FORCE_EVT_CMD 18 +#define XHCI_TRB_NEGO_BANDW_CMD 19 +#define XHCI_TRB_SET_LTV_CMD 20 +#define XHCI_TRB_PORT_BANDW_CMD 21 +#define XHCI_TRB_FORCE_HEADER 22 +#define XHCI_TRB_NOOP_CMD 23 +#define XHCI_TRB_GET_EXTPRP_CMD 24 +#define XHCI_TRB_SET_EXTPRP_CMD 25 +#define XHCI_TRB_TRANSFER_EVENT 32 +#define XHCI_TRB_CMD_CMPL_EVENT 33 +#define XHCI_TRB_PORT_STS_CHNG 34 +#define XHCI_TRB_BANDW_RQ_EVENT 35 +#define XHCI_TRB_DOORBELL_EVENT 36 +#define XHCI_TRB_HOST_CTRL_EVNT 37 +#define XHCI_TRB_DEV_NOTIF_EVNT 38 +#define XHCI_TRB_MFINDEX_WRAP 39 + +/* generic TRB bits */ +#define XHCI_GTRB_TRB_TYPE 10 +#define XHCI_GTRB_CYCLE_BIT 0 + +/* command completion event TRB */ +#define XHCI_CCETRB_CTRL_SLOT_ID 24 +#define XHCI_CCETRB_CTRL_VFID 16 +#define XHCI_CCETRB_CTRL_TRB_TYPE 10 +#define XHCI_CCETRB_CTRL_CYCLEBIT 0 +#define XHCI_CCETRB_STS_CMPL_CODE 24 + +/* transfer event TRB */ +#define XHCI_TETRB_CTRL_SLOT_ID 24 +#define XHCI_TETRB_CTRL_ENDPOINT 16 +#define XHCI_TETRB_CTRL_TRB_TYPE 10 +#define XHCI_TETRB_CTRL_EVT_DATA 2 +#define XHCI_TETRB_CTRL_CYCLEBIT 0 +#define XHCI_TETRB_STS_CMPL_CODE 24 + +/* port status change event TRB */ +#define XHCI_PSCETRB_CTRL_TRB_TYPE 10 +#define XHCI_PSCETRB_CTRL_CYCLEBIT 0 +#define XHCI_PSCETRB_STS_CMPL_CODE 24 +#define XHCI_PSCETRB_PARAM_PORT_ID 24 + +/* link TRB */ +#define XHCI_LNKTRB_CTRL_TRB_TYPE 10 +#define XHCI_LNKTRB_CTRL_IOC 5 +#define XHCI_LNKTRB_CTRL_CH 4 +#define XHCI_LNKTRB_CTRL_TC 1 +#define XHCI_LNKTRB_CTRL_CYCLEBIT 0 +#define XHCI_LNKTRB_STS_INTR_TRGT 22 + +/* setup stage TRB */ +#define XHCI_SSTRB_CTRL_TRT 16 +#define XHCI_SSTRB_CTRL_TRB_TYPE 10 +#define XHCI_SSTRB_CTRL_IDT 6 +#define XHCI_SSTRB_CTRL_IOC 5 +#define XHCI_SSTRB_CTRL_CYCLEBIT 0 +#define XHCI_SSTRB_STS_INTR_TRGT 22 +#define XHCI_SSTRB_PARAM_WLENGTH 48 +#define XHCI_SSTRB_PARAM_WINDEX 32 +#define XHCI_SSTRB_PARAM_WVALUE 16 +#define XHCI_SSTRB_PARAM_BREQUEST 8 +#define XHCI_SSTRB_PARAM_BMREQUEST_TYPE 0 + +/* setup stage TRB transfer types */ +#define XHCI_SSTRB_TRT_NO_DATA_STAGE 0 +#define XHCI_SSTRB_TRT_OUT_DATA_STAGE 2 +#define XHCI_SSTRB_TRT_IN_DATA_STAGE 3 + +/* data stage TRB */ +#define XHCI_DSTRB_CTRL_DIR 16 +#define XHCI_DSTRB_CTRL_TRB_TYPE 10 +#define XHCI_DSTRB_CTRL_IDT 6 +#define XHCI_DSTRB_CTRL_IOC 5 +#define XHCI_DSTRB_CTRL_CH 4 +#define XHCI_DSTRB_CTRL_NS 3 +#define XHCI_DSTRB_CTRL_ISP 2 +#define XHCI_DSTRB_CTRL_ENT 1 +#define XHCI_DSTRB_CTRL_CYCLEBIT 0 +#define XHCI_DSTRB_STS_INTR_TRGT 22 +#define XHCI_DSTRB_STS_TD_SIZE 17 + +/* status stage TRB */ +#define XHCI_STSTRB_CTRL_DIR 16 +#define XHCI_STSTRB_CTRL_TRB_TYPE 10 +#define XHCI_STSTRB_CTRL_IOC 5 +#define XHCI_STSTRB_CTRL_CH 4 +#define XHCI_STSTRB_CTRL_ENT 1 +#define XHCI_STSTRB_CTRL_CYCLEBIT 0 +#define XHCI_STSTRB_STS_INTR_TRGT 22 + +/* extended capabilities */ +#define XHCI_EXTCAP_USB_LEGACY_SUPPORT 1 +#define XHCI_EXTCAP_SUPPORTED_PROTOCOL 2 +#define XHCI_EXTCAP_EXT_POWER_MNGMNT 3 +#define XHCI_EXTCAP_IO_VIRT 4 +#define XHCI_EXTCAP_MSG_INTR 5 +#define XHCI_EXTCAP_LOCAL_MEMORY 6 +#define XHCI_EXTCAP_USB_DEBUG 7 +#define XHCI_EXTCAP_EXT_MSG_INTR 8 +#define XHCI_EXTCAP_VENDOR_DEFINED 9 + +/* PORTSC bits */ +#define XHCI_PORTSC_CCS 0 +#define XHCI_PORTSC_PED 1 +#define XHCI_PORTSC_OCA 3 +#define XHCI_PORTSC_PR 4 +#define XHCI_PORTSC_PLS 5 +#define XHCI_PORTSC_PP 9 +#define XHCI_PORTSC_PORTSPEED 10 +#define XHCI_PORTSC_PIC 14 +#define XHCI_PORTSC_LWS 16 +#define XHCI_PORTSC_CSC 17 +#define XHCI_PORTSC_PEC 18 +#define XHCI_PORTSC_WRC 19 +#define XHCI_PORTSC_OCC 20 +#define XHCI_PORTSC_PRC 21 +#define XHCI_PORTSC_PLC 22 +#define XHCI_PORTSC_CEC 23 +#define XHCI_PORTSC_CAS 24 +#define XHCI_PORTSC_WCE 25 +#define XCHI_PORTSC_WDE 26 +#define XHCI_PORTSC_WOE 27 +#define XHCI_PORTSC_DR 30 +#define XHCI_PORTSC_WPR 31 + +/* endpoint context */ +#define XHCI_EPCTX_EP_STATE 0 +#define XHCI_EPCTX_MULT 8 +#define XHCI_EPCTX_MAXPSTRAMS 10 +#define XHCI_EPCTX_LSA 15 +#define XHCI_EPCTX_INTERVAL 16 +#define XHCI_EPCTX_MAX_ESIT_HI 24 +#define XHCI_EPCTX_ERR_COUNT 1 +#define XHCI_EPCTX_EP_TYPE 3 +#define XHCI_EPCTX_HID 7 +#define XHCI_EPCTX_MAX_BURST_SZ 8 +#define XHCI_EPCTX_MAX_PKT_SZ 16 +#define XHCI_EPCTX_DCS 0 +#define XHCI_EPCTX_TR_DQ_PTR 4 +#define XHCI_EPCTX_AVG_TRB_LEN 0 +#define XHCI_EPCTX_MAX_ESIT_LOW 16 + +/* endpoint types */ +#define XHCI_EP_INVALID 0 +#define XHCI_EP_ISOCH_OUT 1 +#define XHCI_EP_BULK_OUT 2 +#define XHCI_EP_INTR_OUT 3 +#define XHCI_EP_CTRL_BI 4 +#define XHCI_EP_ISOCH_IN 5 +#define XHCI_EP_BULK_IN 6 +#define XHCI_EP_INTR_IN 7 + +/* slot context */ +#define XHIC_SLCTX_ROUTE_STR 0 +#define XHCI_SLCTX_SPEED 20 +#define XHCI_SLCTX_MTT 25 +#define XHCI_SLCTX_HUB 26 +#define XHCI_SLCTX_CTX_ENTRIES 27 +#define XHCI_SLCTX_MAXEXITLTNCY 0 +#define XHCI_SLCTX_ROOTHUBPRNUM 16 +#define XHCI_SLCTX_PORT_COUNT 24 +#define XHCI_SLCTX_PRNT_HUB_SLT 0 +#define XHCI_SLCTX_PARENT_PORT 8 +#define XHCI_SLCTX_TT_THINKTIME 16 +#define XHCI_SLCTX_INTR_TARGET 22 +#define XHCI_SLCTX_USB_DEV_ADDR 0 +#define XHCI_SLCTX_SLOT_STATE 27 + +/* clang-format on */ + /* event ring segment table entry */ struct xhci_erst_entry { volatile uint64_t ptr; @@ -88,6 +368,7 @@ struct xhci_usb_device { struct list_node_link usb_devices_link; struct xhci_port* xhci_port; int slot_id; + struct device* device; struct xhci_ring endpoint0_ring; @@ -145,10 +426,12 @@ struct xhci { uint8_t last_slot_id; uint8_t last_cmpl_code; struct list_node_link* port_changes; - - spin_lock_t setup_lock; }; +int xhci_bulk_transfer (struct xhci* xhci, struct xhci_usb_device* usb_device, + uint8_t endpoint_addr, uintptr_t buffer_phys, size_t buffer_size, + uint64_t* lockflags); + DEFINE_DEVICE_INIT (xhci_init); DEFINE_DEVICE_FINI (xhci_fini); diff --git a/kernel/libk/endianess.h b/kernel/libk/endianess.h index 0e1fcbb..0e328bb 100644 --- a/kernel/libk/endianess.h +++ b/kernel/libk/endianess.h @@ -3,4 +3,20 @@ #define BE2LE16(x) (((x) << 8) | (((x) >> 8))) +#define BE2LE32(x) \ + ((((x) & 0x000000FF) << 24) | \ + (((x) & 0x0000FF00) << 8) | \ + (((x) & 0x00FF0000) >> 8) | \ + (((x) & 0xFF000000) >> 24)) + +#define BE2LE64(x) \ + ((((x) & 0x00000000000000FFULL) << 56) | \ + (((x) & 0x000000000000FF00ULL) << 40) | \ + (((x) & 0x0000000000FF0000ULL) << 24) | \ + (((x) & 0x00000000FF000000ULL) << 8) | \ + (((x) & 0x000000FF00000000ULL) >> 8) | \ + (((x) & 0x0000FF0000000000ULL) >> 24) | \ + (((x) & 0x00FF000000000000ULL) >> 40) | \ + (((x) & 0xFF00000000000000ULL) >> 56)) + #endif // _KERNEL_LIBK_ENDIANESS_H diff --git a/kernel/libk/hash.h b/kernel/libk/hash.h index 264748a..6678f3d 100644 --- a/kernel/libk/hash.h +++ b/kernel/libk/hash.h @@ -30,6 +30,31 @@ static inline uint32_t hash_fnv32 (const void* data, size_t len) { (table)->buckets_name[__idx] = (new_link); \ } while (0) +#define hash_delete(table, key_ptr, key_size, hash_val, table_size, buckets_name, type, member, \ + key_field, out_link) \ + do { \ + uint32_t __idx = (hash_val) % (table_size); \ + struct hash_node_link* __curr = (table)->buckets_name[__idx]; \ + struct hash_node_link* __prev = NULL; \ + (out_link) = NULL; \ + while (__curr) { \ + if (__curr->hash == (hash_val)) { \ + type* __entry = hash_entry (__curr, type, member); \ + if (memcmp (__entry->key_field, (key_ptr), (key_size)) == 0) { \ + if (__prev != NULL) { \ + __prev->next = __curr->next; \ + } else { \ + (table)->buckets_name[__idx] = __curr->next; \ + } \ + (out_link) = __curr; \ + break; \ + } \ + } \ + __prev = __curr; \ + __curr = __curr->next; \ + } \ + } while (0) + #define hash_find(table, key_ptr, key_size, hash_val, table_size, buckets_name, type, member, \ key_field, out_link) \ do { \ diff --git a/libsystem/str_status.h b/libsystem/str_status.h index ed40fe6..db49551 100644 --- a/libsystem/str_status.h +++ b/libsystem/str_status.h @@ -29,6 +29,7 @@ static const char* str_status[] = { [ST_XDRV_READ_ERROR] = "drive read error", [ST_XDRV_WRITE_ERROR] = "drive write error", [ST_NOT_PARTIAL] = "not a partially created process", + [ST_USB_CTRL_ERROR] = "USB controller error", }; #endif // _LIBSYSTEM_STR_STATUS_H