Read USB mass storage sector count and sector size!
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
239
kernel/device/storage/usbdrv.c
Normal file
239
kernel/device/storage/usbdrv.c
Normal file
@@ -0,0 +1,239 @@
|
||||
#include <device/def_device_op.h>
|
||||
#include <device/device.h>
|
||||
#include <device/storage/usbdrv.h>
|
||||
#include <device/usb/xhci.h>
|
||||
#include <devices.h>
|
||||
#include <libk/endianess.h>
|
||||
#include <libk/string.h>
|
||||
#include <limine/requests.h>
|
||||
#include <mm/malloc.h>
|
||||
#include <mm/pmm.h>
|
||||
#include <proc/proc.h>
|
||||
#include <proc/reschedule.h>
|
||||
#include <status.h>
|
||||
#include <sys/debug.h>
|
||||
#include <sys/stall.h>
|
||||
|
||||
/* 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) {}
|
||||
63
kernel/device/storage/usbdrv.h
Normal file
63
kernel/device/storage/usbdrv.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#ifndef _KERNEL_DEVICE_STORAGE_USBDRV_H
|
||||
#define _KERNEL_DEVICE_STORAGE_USBDRV_H
|
||||
|
||||
#include <device/def_device_op.h>
|
||||
#include <device/usb/usb.h>
|
||||
#include <device/usb/xhci.h>
|
||||
#include <libk/std.h>
|
||||
|
||||
#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
|
||||
@@ -1,6 +0,0 @@
|
||||
#include <device/usb/mass_storage.h>
|
||||
#include <device/usb/usb.h>
|
||||
#include <libk/std.h>
|
||||
#include <sys/debug.h>
|
||||
|
||||
bool usb_mass_storage_init (void) { return true; }
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef _KERNEL_DEVICE_USB_MASS_STORAGE_H
|
||||
#define _KERNEL_DEVICE_USB_MASS_STORAGE_H
|
||||
|
||||
#include <libk/std.h>
|
||||
|
||||
bool usb_mass_storage_init (void);
|
||||
|
||||
#endif // _KERNEL_DEVICE_USB_MASS_STORAGE_H
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +1,36 @@
|
||||
#include <device/usb/mass_storage.h>
|
||||
#include <device/def_device_op.h>
|
||||
#include <device/device.h>
|
||||
#include <device/storage/usbdrv.h>
|
||||
#include <device/usb/usb.h>
|
||||
#include <device/usb/xhci.h>
|
||||
#include <devices.h>
|
||||
#include <libk/lengthof.h>
|
||||
#include <libk/printf.h>
|
||||
#include <libk/std.h>
|
||||
#include <proc/proc.h>
|
||||
#include <proc/reschedule.h>
|
||||
#include <sys/debug.h>
|
||||
|
||||
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},
|
||||
};
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
#define _KERNEL_DEVICE_USB_H
|
||||
|
||||
#include <aux/compiler.h>
|
||||
#include <device/device.h>
|
||||
#include <libk/std.h>
|
||||
#include <proc/proc.h>
|
||||
#include <proc/reschedule.h>
|
||||
|
||||
#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];
|
||||
|
||||
@@ -19,293 +19,12 @@
|
||||
#include <sys/spin_lock.h>
|
||||
#include <sys/stall.h>
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <aux/compiler.h>
|
||||
#include <device/def_device_op.h>
|
||||
#include <device/device.h>
|
||||
#include <device/usb/usb.h>
|
||||
#include <libk/list.h>
|
||||
#include <libk/std.h>
|
||||
@@ -10,6 +11,285 @@
|
||||
#include <proc/reschedule.h>
|
||||
#include <proc/suspension_q.h>
|
||||
|
||||
/* 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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 { \
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user