diff options
Diffstat (limited to 'qemu/roms/SLOF/lib/libusb')
-rw-r--r-- | qemu/roms/SLOF/lib/libusb/usb-core.c | 37 | ||||
-rw-r--r-- | qemu/roms/SLOF/lib/libusb/usb-core.h | 7 | ||||
-rw-r--r-- | qemu/roms/SLOF/lib/libusb/usb-ehci.c | 4 | ||||
-rw-r--r-- | qemu/roms/SLOF/lib/libusb/usb-hid.c | 85 | ||||
-rw-r--r-- | qemu/roms/SLOF/lib/libusb/usb-hub.c | 4 | ||||
-rw-r--r-- | qemu/roms/SLOF/lib/libusb/usb-ohci.c | 16 | ||||
-rw-r--r-- | qemu/roms/SLOF/lib/libusb/usb-slof.c | 34 | ||||
-rw-r--r-- | qemu/roms/SLOF/lib/libusb/usb-xhci.c | 236 | ||||
-rw-r--r-- | qemu/roms/SLOF/lib/libusb/usb-xhci.h | 5 |
9 files changed, 316 insertions, 112 deletions
diff --git a/qemu/roms/SLOF/lib/libusb/usb-core.c b/qemu/roms/SLOF/lib/libusb/usb-core.c index 6719c5726..4c720ce2f 100644 --- a/qemu/roms/SLOF/lib/libusb/usb-core.c +++ b/qemu/roms/SLOF/lib/libusb/usb-core.c @@ -383,8 +383,6 @@ int usb_hid_exit(void *vdev) return true; } -#define usb_get_intf_class(x) ((x & 0x00FF0000) >> 16) - int usb_msc_init(void *vdev) { struct usb_dev *dev; @@ -420,7 +418,7 @@ int usb_msc_exit(void *vdev) return true; } -static int usb_msc_reset(struct usb_dev *dev) +int usb_msc_reset(struct usb_dev *dev) { struct usb_dev_req req; @@ -477,7 +475,7 @@ static int usb_handle_device(struct usb_dev *dev, struct usb_dev_config_descr *c case DESCR_TYPE_HUB: break; default: - printf("ptr %p desc_type %d\n", ptr, desc_type); + dprintf("ptr %p desc_type %d\n", ptr, desc_type); } ptr += desc_len; len -= desc_len; @@ -485,7 +483,7 @@ static int usb_handle_device(struct usb_dev *dev, struct usb_dev_config_descr *c return true; } -int setup_new_device(struct usb_dev *dev, unsigned int port) +int usb_setup_new_device(struct usb_dev *dev, unsigned int port) { struct usb_dev_descr descr; struct usb_dev_config_descr cfg; @@ -552,35 +550,6 @@ int setup_new_device(struct usb_dev *dev, unsigned int port) if (!usb_handle_device(dev, &cfg, data, len)) goto fail_mem_free; - switch (usb_get_intf_class(dev->class)) { - case 3: - dprintf("HID found %06X\n", dev->class); - slof_usb_handle(dev); - break; - case 8: - dprintf("MASS STORAGE found %d %06X\n", dev->intf_num, - dev->class); - if ((dev->class & 0x50) != 0x50) { /* Bulk-only supported */ - printf("Device not supported %06X\n", dev->class); - goto fail_mem_free; - } - - if (!usb_msc_reset(dev)) { - printf("%s: bulk reset failed\n", __func__); - goto fail_mem_free; - } - SLOF_msleep(100); - slof_usb_handle(dev); - break; - case 9: - dprintf("HUB found\n"); - slof_usb_handle(dev); - break; - default: - printf("USB Interface class -%x- Not supported\n", dev->class); - break; - } - SLOF_dma_free(data, len); return true; fail_mem_free: diff --git a/qemu/roms/SLOF/lib/libusb/usb-core.h b/qemu/roms/SLOF/lib/libusb/usb-core.h index 7441979e9..a35df3485 100644 --- a/qemu/roms/SLOF/lib/libusb/usb-core.h +++ b/qemu/roms/SLOF/lib/libusb/usb-core.h @@ -261,6 +261,8 @@ struct usb_hcd_ops { unsigned int usb_type; }; +#define usb_get_intf_class(x) ((x & 0x00FF0000) >> 16) + extern void usb_hcd_register(struct usb_hcd_ops *ops); extern struct usb_pipe *usb_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep, char *buf, size_t len); @@ -269,11 +271,12 @@ extern int usb_poll_intr(struct usb_pipe *pipe, uint8_t *buf); extern int usb_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data); extern struct usb_dev *usb_devpool_get(void); extern void usb_devpool_put(struct usb_dev *); -extern int setup_new_device(struct usb_dev *dev, unsigned int port); -extern int slof_usb_handle(struct usb_dev *dev); +extern int usb_setup_new_device(struct usb_dev *dev, unsigned int port); +extern void usb_slof_populate_new_device(struct usb_dev *dev); extern int usb_dev_populate_pipe(struct usb_dev *dev, struct usb_ep_descr *ep, void *buf, size_t len); extern int usb_hid_kbd_init(struct usb_dev *dev); extern int usb_hid_kbd_exit(struct usb_dev *dev); +extern int usb_msc_reset(struct usb_dev *dev); extern void usb_msc_resetrecovery(struct usb_dev *dev); #endif diff --git a/qemu/roms/SLOF/lib/libusb/usb-ehci.c b/qemu/roms/SLOF/lib/libusb/usb-ehci.c index 4cca0da15..60af9e101 100644 --- a/qemu/roms/SLOF/lib/libusb/usb-ehci.c +++ b/qemu/roms/SLOF/lib/libusb/usb-ehci.c @@ -79,7 +79,9 @@ static int ehci_hub_check_ports(struct ehci_hcd *ehcd) dprintf("usb-ehci: allocated device %p\n", dev); dev->hcidev = ehcd->hcidev; dev->speed = USB_HIGH_SPEED; /* TODO: Check for Low/Full speed device */ - if (!setup_new_device(dev, i)) + if (usb_setup_new_device(dev, i)) + usb_slof_populate_new_device(dev); + else printf("usb-ehci: unable to setup device on port %d\n", i); } } diff --git a/qemu/roms/SLOF/lib/libusb/usb-hid.c b/qemu/roms/SLOF/lib/libusb/usb-hid.c index f0cab8a69..ac6616aba 100644 --- a/qemu/roms/SLOF/lib/libusb/usb-hid.c +++ b/qemu/roms/SLOF/lib/libusb/usb-hid.c @@ -28,6 +28,10 @@ #define HID_REQ_SET_IDLE 0x0A #define HID_REQ_SET_PROTOCOL 0x0B +//key position for latin letters +#define KEYP_LATIN_A 4 +#define KEYP_LATIN_Z 29 + //#define KEY_DEBUG /* HID SPEC - 7.2.6 Set_Protocol Request */ @@ -83,6 +87,8 @@ uint8_t set_leds; const uint8_t *key_std = NULL; const uint8_t *key_std_shift = NULL; +uint8_t ctrl; /* modifiers */ + /** * read character from Keyboard-Buffer * @@ -111,6 +117,16 @@ static void write_key(uint8_t key) } /** + * Checks if keypos is a latin key + * @param keypos + * @return - + */ +static bool is_latin(uint8_t keypos) +{ + return keypos >= KEYP_LATIN_A && keypos <= KEYP_LATIN_Z; +} + +/** * Convert keyboard usage-ID to ANSI-Code * * @param Ctrl=Modifier Byte @@ -120,22 +136,24 @@ static void write_key(uint8_t key) static void get_char(uint8_t ctrl, uint8_t keypos) { uint8_t ch; + bool caps = false; #ifdef KEY_DEBUG printf("pos %02X\n", keypos); #endif if (set_leds & LED_CAPS_LOCK) /* is CAPS Lock set ? */ - ctrl |= MODIFIER_SHIFT; /* simulate shift */ + caps = true; - if (ctrl == 0) { + /* caps is a shift only for latin chars */ + if ((!caps && ctrl == 0) || (caps && !is_latin(keypos))) { ch = key_std[keypos]; if (ch != 0) write_key(ch); return; } - if (ctrl & MODIFIER_SHIFT) { + if ((ctrl & MODIFIER_SHIFT) || caps) { ch = key_std_shift[keypos]; if (ch != 0) write_key(ch); @@ -187,36 +205,38 @@ static void check_key_code(uint8_t *buf) set_leds ^= LED_CAPS_LOCK; break; + case 0x36: /*Shift pressed*/ + ctrl |= MODIFIER_SHIFT; + break; + case 0xb6: /*Shift unpressed*/ + ctrl &= ~MODIFIER_SHIFT; + break; case 0x3a: /* F1 */ write_key(0x1b); write_key(0x5b); - write_key(0x31); - write_key(0x31); - write_key(0x7e); + write_key(0x4f); + write_key(0x50); break; case 0x3b: /* F2 */ write_key(0x1b); write_key(0x5b); - write_key(0x31); - write_key(0x32); - write_key(0x7e); + write_key(0x4f); + write_key(0x51); break; case 0x3c: write_key(0x1b); /* F3 */ write_key(0x5b); - write_key(0x31); - write_key(0x33); - write_key(0x7e); + write_key(0x4f); + write_key(0x52); break; case 0x3d: write_key(0x1b); /* F4 */ write_key(0x5b); - write_key(0x31); - write_key(0x34); - write_key(0x7e); + write_key(0x4f); + write_key(0x53); break; case 0x3e: @@ -254,7 +274,7 @@ static void check_key_code(uint8_t *buf) case 0x42: write_key(0x1b); /* F9 */ write_key(0x5b); - write_key(0x31); + write_key(0x32); write_key(0x30); write_key(0x7e); break; @@ -262,7 +282,7 @@ static void check_key_code(uint8_t *buf) case 0x43: write_key(0x1b); /* F10 */ write_key(0x5b); - write_key(0x31); + write_key(0x32); write_key(0x31); write_key(0x7e); break; @@ -270,7 +290,7 @@ static void check_key_code(uint8_t *buf) case 0x44: write_key(0x1b); /* F11 */ write_key(0x5b); - write_key(0x31); + write_key(0x32); write_key(0x33); write_key(0x7e); break; @@ -278,7 +298,7 @@ static void check_key_code(uint8_t *buf) case 0x45: write_key(0x1b); /* F12 */ write_key(0x5b); - write_key(0x31); + write_key(0x32); write_key(0x34); write_key(0x7e); break; @@ -290,36 +310,34 @@ static void check_key_code(uint8_t *buf) case 0x49: write_key(0x1b); /* INS */ write_key(0x5b); - write_key(0x31); + write_key(0x32); write_key(0x7e); break; case 0x4a: write_key(0x1b); /* HOME */ - write_key(0x5b); - write_key(0x32); - write_key(0x7e); + write_key(0x4f); + write_key(0x48); break; case 0x4b: write_key(0x1b); /* PgUp */ write_key(0x5b); - write_key(0x33); + write_key(0x35); write_key(0x7e); break; case 0x4c: write_key(0x1b); /* DEL */ write_key(0x5b); - write_key(0x34); + write_key(0x33); write_key(0x7e); break; case 0x4d: write_key(0x1b); /* END */ - write_key(0x5b); - write_key(0x35); - write_key(0x7e); + write_key(0x4f); + write_key(0x46); break; case 0x4e: @@ -443,11 +461,8 @@ unsigned char usb_key_available(void *dev) unsigned char usb_read_keyb(void *vdev) { - if (!vdev) - return false; - - while (usb_poll_key(vdev)) { - /* loop for all pending keys */ - } - return read_key(); + if (usb_key_available(vdev)) + return read_key(); + else + return 0; } diff --git a/qemu/roms/SLOF/lib/libusb/usb-hub.c b/qemu/roms/SLOF/lib/libusb/usb-hub.c index 7059cd019..bb8a30915 100644 --- a/qemu/roms/SLOF/lib/libusb/usb-hub.c +++ b/qemu/roms/SLOF/lib/libusb/usb-hub.c @@ -175,7 +175,9 @@ unsigned int usb_hub_init(void *hubdev) newdev = usb_devpool_get(); dprintf("usb-hub: allocated device %p\n", newdev); newdev->hcidev = dev->hcidev; - if (!setup_new_device(newdev, i)) + if (usb_setup_new_device(newdev, i)) + usb_slof_populate_new_device(newdev); + else printf("usb-hub: unable to setup device on port %d\n", i); } } diff --git a/qemu/roms/SLOF/lib/libusb/usb-ohci.c b/qemu/roms/SLOF/lib/libusb/usb-ohci.c index 0e8400481..d06c754d1 100644 --- a/qemu/roms/SLOF/lib/libusb/usb-ohci.c +++ b/qemu/roms/SLOF/lib/libusb/usb-ohci.c @@ -192,7 +192,9 @@ static void ohci_hub_check_ports(struct ohci_hcd *ohcd) dev = usb_devpool_get(); dprintf("usb-ohci: Device reset, setting up %p\n", dev); dev->hcidev = ohcd->hcidev; - if (!setup_new_device(dev, i)) + if (usb_setup_new_device(dev, i)) + usb_slof_populate_new_device(dev); + else printf("usb-ohci: unable to setup device on port %d\n", i); } if (port_status & RH_PS_PESC) { @@ -252,7 +254,7 @@ static int ohci_alloc_pipe_pool(struct ohci_hcd *ohcd) return false; ohcd->pool_phys = opipe_phys = SLOF_dma_map_in(opipe, OHCI_PIPE_POOL_SIZE, true); - dprintf("usb-ohci: %s opipe %x, opipe_phys %x size %d count %d\n", + dprintf("usb-ohci: %s opipe %p, opipe_phys %lx size %ld count %d\n", __func__, opipe, opipe_phys, sizeof(*opipe), count); /* Although an array, link them*/ for (i = 0, curr = opipe, prev = NULL; i < count; i++, curr++) { @@ -446,7 +448,7 @@ again: /* Interrupt is there, read from done_head pointer */ td_phys = (struct ohci_td *)(uint64_t) le32_to_cpu(hcca->done_head); if (!td_phys) { - dprintf("Again td_phys null %ld\n"); + dprintf("Again td_phys null\n"); goto again; } hcca->done_head = 0; @@ -553,7 +555,7 @@ static int ohci_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void * attr = EDA_FADDR(pipe->dev->addr) | EDA_MPS(pipe->mps) | EDA_SKIP; ohci_fill_ed(ed, PTR_U32(td_phys), td_next, attr, 0); ed->tailp = 0; /* HACK */ - dprintf("usb-ohci: %s - td_start %x td_end %x req %x\n", __func__, + dprintf("usb-ohci: %s - td_start %p td_end %lx req %lx\n", __func__, td_phys, td_next, req_phys); mb(); ed->attr &= cpu_to_le32(~EDA_SKIP); @@ -642,7 +644,7 @@ static int ohci_transfer_bulk(struct usb_pipe *pipe, void *td_ptr, td = tds = (struct ohci_td *) td_ptr; td_phys = (long)td_phys_ptr; - dprintf("usb-ohci: %s pipe %p data_phys %p len %d DIR_IN %d td %p td_phys %p\n", + dprintf("usb-ohci: %s pipe %p data_phys %p len %d DIR_IN %d td %p td_phys %lx\n", __func__, pipe, data_phys, datalen, dir, td, td_phys); if (!tds) { @@ -672,7 +674,7 @@ static int ohci_transfer_bulk(struct usb_pipe *pipe, void *td_ptr, | EDA_SKIP | pipe->dev->speed | EDA_EP(pipe->epno); td_next = ohci_get_td_phys(td, tds, td_phys); ohci_fill_ed(ed, td_phys, td_next, attr, 0); - dprintf("usb-ohci: %s - tds %p td %p\n", __func__, td_phys, td_next); + dprintf("usb-ohci: %s - tds %lx td %lx\n", __func__, td_phys, td_next); mb(); ed->attr &= cpu_to_le32(~EDA_SKIP); @@ -778,7 +780,7 @@ static int ohci_get_pipe_intr(struct usb_pipe *pipe, struct ohci_hcd *ohcd, td->attr = cpu_to_le32(TDA_DP_IN | TDA_ROUNDING | TDA_CC); td->next_td = cpu_to_le32(td_next); td->be = cpu_to_le32(PTR_U32(ptr) + mps - 1); - dprintf("td %x td++ %x ptr %x be %x\n", + dprintf("td %p td++ %x ptr %p be %x\n", td, le32_to_cpu(td->next_td), ptr, (PTR_U32(ptr) + mps - 1)); } diff --git a/qemu/roms/SLOF/lib/libusb/usb-slof.c b/qemu/roms/SLOF/lib/libusb/usb-slof.c index de841f0fb..ff070559a 100644 --- a/qemu/roms/SLOF/lib/libusb/usb-slof.c +++ b/qemu/roms/SLOF/lib/libusb/usb-slof.c @@ -26,7 +26,7 @@ #define dprintf(_x ...) #endif -int slof_usb_handle(struct usb_dev *dev) +static int slof_usb_handle(struct usb_dev *dev) { struct slof_usb_dev sdev; sdev.port = dev->port; @@ -59,3 +59,35 @@ int slof_usb_handle(struct usb_dev *dev) } return true; } + +void usb_slof_populate_new_device(struct usb_dev *dev) +{ + switch (usb_get_intf_class(dev->class)) { + case 3: + dprintf("HID found %06X\n", dev->class); + slof_usb_handle(dev); + break; + case 8: + dprintf("MASS STORAGE found %d %06X\n", dev->intf_num, + dev->class); + if ((dev->class & 0x50) != 0x50) { /* Bulk-only supported */ + printf("Device not supported %06X\n", dev->class); + break; + } + + if (!usb_msc_reset(dev)) { + printf("%s: bulk reset failed\n", __func__); + break; + } + SLOF_msleep(100); + slof_usb_handle(dev); + break; + case 9: + dprintf("HUB found\n"); + slof_usb_handle(dev); + break; + default: + printf("USB Interface class -%x- Not supported\n", dev->class); + break; + } +} diff --git a/qemu/roms/SLOF/lib/libusb/usb-xhci.c b/qemu/roms/SLOF/lib/libusb/usb-xhci.c index 0c3d6e47f..858cd12f9 100644 --- a/qemu/roms/SLOF/lib/libusb/usb-xhci.c +++ b/qemu/roms/SLOF/lib/libusb/usb-xhci.c @@ -225,11 +225,11 @@ static void xhci_handle_cmd_completion(struct xhci_hcd *xhcd, xhcd->slot_id = 0; } -static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd, - uint32_t event_type) +static uint64_t xhci_poll_event(struct xhci_hcd *xhcd, + uint32_t event_type) { struct xhci_event_trb *event; - uint64_t val; + uint64_t val, retval = 0; uint32_t flags, time; int index; @@ -244,7 +244,7 @@ static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd, mb(); flags = le32_to_cpu(event->flags); if (time < SLOF_GetTimer()) - return NULL; + return 0; } mb(); @@ -273,6 +273,7 @@ static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd, break; } xhcd->ering.deq = (uint64_t) (event + 1); + retval = le64_to_cpu(event->addr); event->addr = 0; event->status = 0; @@ -289,7 +290,11 @@ static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd, dprintf("Update start %x deq %x index %d\n", xhcd->ering.trbs_dma, val, index/sizeof(*event)); write_reg64(&xhcd->run_regs->irs[0].erdp, val); - return event; + + if (retval == 0) + return (uint64_t)event; + else + return retval; } static void xhci_send_cmd(struct xhci_hcd *xhcd, uint32_t field1, @@ -388,10 +393,12 @@ static void xhci_init_seg(struct xhci_seg *seg, uint32_t size, uint32_t type) seg->deq = (uint64_t)seg->trbs; memset((void *)seg->trbs, 0, size); - link =(struct xhci_link_trb *) (seg->trbs + seg->size - 1); - link->addr = cpu_to_le64(seg->trbs_dma); - link->field2 = 0; - link->field3 = cpu_to_le32(0x1 | TRB_CMD_TYPE(TRB_LINK)); + if (type != TYPE_EVENT) { + link =(struct xhci_link_trb *) (seg->trbs + seg->size - 1); + link->addr = cpu_to_le64(seg->trbs_dma); + link->field2 = 0; + link->field3 = cpu_to_le32(0x1 | TRB_CMD_TYPE(TRB_LINK)); + } return; } @@ -601,8 +608,10 @@ static bool xhci_alloc_dev(struct xhci_hcd *xhcd, uint32_t slot_id, uint32_t por dev->port = newport; dev->priv = xdev; xdev->dev = dev; - if (setup_new_device(dev, newport)) + if (usb_setup_new_device(dev, newport)) { + usb_slof_populate_new_device(dev); return true; + } xhci_free_ctx(&xdev->out_ctx, XHCI_CTX_BUF_SIZE); fail_control_seg: @@ -616,6 +625,7 @@ static void xhci_free_dev(struct xhci_dev *xdev) { xhci_free_seg(&xdev->bulk_in, XHCI_DATA_TRBS_SIZE); xhci_free_seg(&xdev->bulk_out, XHCI_DATA_TRBS_SIZE); + xhci_free_seg(&xdev->intr, XHCI_INTR_TRBS_SIZE); xhci_free_seg(&xdev->control, XHCI_CONTROL_TRBS_SIZE); xhci_free_ctx(&xdev->in_ctx, XHCI_CTX_BUF_SIZE); xhci_free_ctx(&xdev->out_ctx, XHCI_CTX_BUF_SIZE); @@ -637,7 +647,25 @@ static bool usb3_dev_init(struct xhci_hcd *xhcd, uint32_t port) return true; } -static int xhci_hub_check_ports(struct xhci_hcd *xhcd) +static int xhci_device_present(uint32_t portsc, uint32_t usb_ver) +{ + if (usb_ver == USB_XHCI) { + /* Device present and enabled state */ + if ((portsc & PORTSC_CCS) && + (portsc & PORTSC_PP) && + (portsc & PORTSC_PED)) { + return true; + } + } else if (usb_ver == USB_EHCI) { + /* Device present and in disabled state */ + if ((portsc & PORTSC_CCS) && (portsc & PORTSC_CSC)) + return true; + } + return false; +} + +static int xhci_port_scan(struct xhci_hcd *xhcd, + uint32_t usb_ver) { uint32_t num_ports, portsc, i; struct xhci_op_regs *op; @@ -645,7 +673,7 @@ static int xhci_hub_check_ports(struct xhci_hcd *xhcd) struct xhci_cap_regs *cap; uint32_t xecp_off; uint32_t *xecp_addr, *base; - uint32_t port_off = 1, port_cnt; + uint32_t port_off = 0, port_cnt; dprintf("enter\n"); @@ -658,14 +686,14 @@ static int xhci_hub_check_ports(struct xhci_hcd *xhcd) base = (uint32_t *)cap; while (xecp_off > 0) { xecp_addr = base + xecp_off; - dprintf(stderr, "xecp_off %d %p %p \n", xecp_off, base, xecp_addr); + dprintf("xecp_off %d %p %p \n", xecp_off, base, xecp_addr); if (XHCI_XECP_CAP_ID(read_reg32(xecp_addr)) == XHCI_XECP_CAP_SP && - XHCI_XECP_CAP_SP_MJ(read_reg32(xecp_addr)) == 3 && + XHCI_XECP_CAP_SP_MJ(read_reg32(xecp_addr)) == usb_ver && XHCI_XECP_CAP_SP_MN(read_reg32(xecp_addr)) == 0) { port_cnt = XHCI_XECP_CAP_SP_PC(read_reg32(xecp_addr + 2)); port_off = XHCI_XECP_CAP_SP_PO(read_reg32(xecp_addr + 2)); - dprintf(stderr, "PortCount %d Portoffset %d\n", port_cnt, port_off); + dprintf("PortCount %d Portoffset %d\n", port_cnt, port_off); } base = xecp_addr; xecp_off = XHCI_XECP_NEXT_PTR(read_reg32(xecp_addr)); @@ -675,10 +703,8 @@ static int xhci_hub_check_ports(struct xhci_hcd *xhcd) for (i = (port_off - 1); i < (port_off + port_cnt - 1); i++) { prs = &op->prs[i]; portsc = read_reg32(&prs->portsc); - if ((portsc & PORTSC_CCS) && - (portsc & PORTSC_PP) && - (portsc & PORTSC_PED)) { - /* Device present and enabled */ + if (xhci_device_present(portsc, usb_ver)) { + /* Device present */ dprintf("Device present on port %d\n", i); /* Reset the port */ portsc = read_reg32(&prs->portsc); @@ -701,6 +727,11 @@ static int xhci_hub_check_ports(struct xhci_hcd *xhcd) return true; } +static int xhci_hub_check_ports(struct xhci_hcd *xhcd) +{ + return xhci_port_scan(xhcd, USB_XHCI) | xhci_port_scan(xhcd, USB_EHCI); +} + static bool xhci_hcd_init(struct xhci_hcd *xhcd) { struct xhci_op_regs *op; @@ -868,6 +899,18 @@ static bool xhci_hcd_exit(struct xhci_hcd *xhcd) SLOF_dma_map_out(xhcd->dcbaap_dma, (void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE); SLOF_dma_free((void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE); } + + /* + * QEMU implementation of XHCI doesn't implement halt + * properly. It basically says that it's halted immediately + * but doesn't actually terminate ongoing activities and + * DMAs. This needs to be fixed in QEMU. + * + * For now, wait for 50ms grace time till qemu stops using + * this device. + */ + SLOF_msleep(50); + return true; } @@ -1079,18 +1122,17 @@ static inline struct xhci_seg *xhci_pipe_get_seg(struct usb_pipe *pipe) static inline void *xhci_get_trb(struct xhci_seg *seg) { uint64_t val, enq; - uint32_t size; + int index; struct xhci_link_trb *link; enq = val = seg->enq; val = val + XHCI_TRB_SIZE; - size = seg->size * XHCI_TRB_SIZE; - /* TRBs being a cyclic buffer, here we cycle back to beginning. */ - if ((val % size) == 0) { + index = (enq - (uint64_t)seg->trbs) / XHCI_TRB_SIZE + 1; + dprintf("%s: enq %llx, val %llx %x\n", __func__, enq, val, index); + /* TRBs being a cyclic buffer, here we cycle back to beginning. */ + if (index == (seg->size - 1)) { + dprintf("%s: rounding \n", __func__); seg->enq = (uint64_t)seg->trbs; - enq = seg->enq; - seg->enq = seg->enq + XHCI_TRB_SIZE; - val = 0; seg->cycle_state ^= seg->cycle_state; link = (struct xhci_link_trb *) (seg->trbs + seg->size - 1); link->addr = cpu_to_le64(seg->trbs_dma); @@ -1105,6 +1147,12 @@ static inline void *xhci_get_trb(struct xhci_seg *seg) return (void *)enq; } +static uint64_t xhci_get_trb_phys(struct xhci_seg *seg, uint64_t trb) +{ + return seg->trbs_dma + (trb - (uint64_t)seg->trbs); +} + +static int usb_kb = false; static int xhci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys, void *data, int datalen) { @@ -1114,7 +1162,8 @@ static int xhci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys, struct xhci_transfer_trb *trb; struct xhci_db_regs *dbr; int ret = true; - uint32_t slot_id, epno; + uint32_t slot_id, epno, time; + uint64_t trb_phys, event_phys; if (!pipe->dev || !pipe->dev->hcidev) { dprintf(" NULL pointer\n"); @@ -1139,13 +1188,26 @@ static int xhci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys, } trb = xhci_get_trb(seg); + trb_phys = xhci_get_trb_phys(seg, (uint64_t)trb); fill_normal_trb(trb, (void *)data, datalen); epno = xhci_get_epno(pipe); write_reg32(&dbr->db[slot_id], epno); - if (!xhci_poll_event(xhcd, 0)) { - dprintf("Bulk failed\n"); - ret = false; + + time = SLOF_GetTimer() + USB_TIMEOUT; + while (1) { + event_phys = xhci_poll_event(xhcd, 0); + if (event_phys == trb_phys) { + break; + } else if (event_phys == 0) { /* polling timed out */ + ret = false; + break; + } else + usb_kb = true; + + /* transfer timed out */ + if (time < SLOF_GetTimer()) + return false; } trb->addr = 0; trb->len = 0; @@ -1214,7 +1276,8 @@ static void xhci_init_bulk_ep(struct usb_dev *dev, struct usb_pipe *pipe) if (!seg->trbs) { if (!xhci_alloc_seg(seg, XHCI_DATA_TRBS_SIZE, TYPE_BULK)) { - dprintf("Failed allocating seg\n"); + printf("usb-xhci: allocation failed for bulk endpoint\n"); + return; } } else { xhci_init_seg(seg, XHCI_DATA_TRBS_SIZE, TYPE_BULK); @@ -1235,6 +1298,61 @@ static void xhci_init_bulk_ep(struct usb_dev *dev, struct usb_pipe *pipe) xpipe->seg = seg; } +static int xhci_get_pipe_intr(struct usb_pipe *pipe, + struct xhci_hcd *xhcd, + char *buf, size_t len) +{ + struct xhci_dev *xdev; + struct xhci_seg *seg; + struct xhci_pipe *xpipe; + struct xhci_control_ctx *ctrl; + struct xhci_ep_ctx *ep; + uint32_t x_epno, val, type; + struct usb_dev *dev; + struct xhci_transfer_trb *trb; + + dev = pipe->dev; + if (dev->class != DEV_HID_KEYB) + return false; + + xdev = dev->priv; + pipe->mps = 8; + seg = xhci_pipe_get_seg(pipe); + xpipe = xhci_pipe_get_xpipe(pipe); + type = EP_INT_IN; + seg = &xdev->intr; + + if (!seg->trbs) { + if (!xhci_alloc_seg(seg, XHCI_INTR_TRBS_SIZE, TYPE_BULK)) { + printf("usb-xhci: allocation failed for interrupt endpoint\n"); + return false; + } + } else { + xhci_init_seg(seg, XHCI_EVENT_TRBS_SIZE, TYPE_BULK); + } + + xpipe->buf = buf; + xpipe->buf_phys = SLOF_dma_map_in(buf, len, false); + xpipe->buflen = len; + + ctrl = xhci_get_control_ctx(&xdev->in_ctx); + x_epno = xhci_get_epno(pipe); + ep = xhci_get_ep_ctx(&xdev->in_ctx, xdev->ctx_size, x_epno); + val = EP_TYPE(type) | MAX_BURST(0) | ERROR_COUNT(3) | + MAX_PACKET_SIZE(pipe->mps); + ep->field2 = cpu_to_le32(val); + ep->deq_addr = cpu_to_le64(seg->trbs_dma | seg->cycle_state); + ep->field4 = cpu_to_le32(8); + ctrl->a_flags = cpu_to_le32(BIT(x_epno) | 0x1); + ctrl->d_flags = 0; + xhci_configure_ep(xhcd, xdev->slot_id, xdev->in_ctx.dma_addr); + xpipe->seg = seg; + + trb = xhci_get_trb(seg); + fill_normal_trb(trb, (void *)xpipe->buf_phys, pipe->mps); + return true; +} + static struct usb_pipe* xhci_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep, char *buf, size_t len) { struct xhci_hcd *xhcd; @@ -1264,6 +1382,12 @@ static struct usb_pipe* xhci_get_pipe(struct usb_dev *dev, struct usb_ep_descr * new->dir = (ep->bEndpointAddress & 0x80) >> 7; new->epno = ep->bEndpointAddress & 0x0f; + if (new->type == USB_EP_TYPE_INTR) { + if (!xhci_get_pipe_intr(new, xhcd, buf, len)) { + printf("usb-xhci: %s alloc_intr failed %p\n", + __func__, new); + } + } if (new->type == USB_EP_TYPE_BULK) xhci_init_bulk_ep(dev, new); @@ -1284,6 +1408,10 @@ static void xhci_put_pipe(struct usb_pipe *pipe) if (pipe->type == USB_EP_TYPE_BULK) { xpipe = xhci_pipe_get_xpipe(pipe); xpipe->seg = NULL; + } else if (pipe->type == USB_EP_TYPE_INTR) { + xpipe = xhci_pipe_get_xpipe(pipe); + SLOF_dma_map_out(xpipe->buf_phys, xpipe->buf, xpipe->buflen); + xpipe->seg = NULL; } if (xhcd->end) xhcd->end->next = pipe; @@ -1298,6 +1426,51 @@ static void xhci_put_pipe(struct usb_pipe *pipe) dprintf("usb-xhci: %s exit\n", __func__); } +static int xhci_poll_intr(struct usb_pipe *pipe, uint8_t *data) +{ + struct xhci_transfer_trb *trb; + struct xhci_seg *seg; + struct xhci_pipe *xpipe; + struct xhci_dev *xdev; + struct xhci_hcd *xhcd; + struct xhci_db_regs *dbr; + uint32_t x_epno; + uint8_t *buf, ret = 1; + + if (!pipe || !pipe->dev || !pipe->dev->hcidev) + return 0; + xdev = pipe->dev->priv; + xhcd = (struct xhci_hcd *)pipe->dev->hcidev->priv; + x_epno = xhci_get_epno(pipe); + seg = xhci_pipe_get_seg(pipe); + xpipe = xhci_pipe_get_xpipe(pipe); + + if (usb_kb == true) { + /* This event was consumed by bulk transfer */ + usb_kb = false; + goto skip_poll; + } + buf = xpipe->buf; + memset(buf, 0, 8); + + mb(); + /* Ring the doorbell - x_epno */ + dbr = xhcd->db_regs; + write_reg32(&dbr->db[xdev->slot_id], x_epno); + if (!xhci_poll_event(xhcd, 0)) { + printf("poll intr failed\n"); + return 0; + } + mb(); + memcpy(data, buf, 8); + +skip_poll: + trb = xhci_get_trb(seg); + fill_normal_trb(trb, (void *)xpipe->buf_phys, pipe->mps); + mb(); + return ret; +} + struct usb_hcd_ops xhci_ops = { .name = "xhci-hcd", .init = xhci_init, @@ -1305,6 +1478,7 @@ struct usb_hcd_ops xhci_ops = { .usb_type = USB_XHCI, .get_pipe = xhci_get_pipe, .put_pipe = xhci_put_pipe, + .poll_intr = xhci_poll_intr, .send_ctrl = xhci_send_ctrl, .transfer_bulk = xhci_transfer_bulk, .next = NULL, diff --git a/qemu/roms/SLOF/lib/libusb/usb-xhci.h b/qemu/roms/SLOF/lib/libusb/usb-xhci.h index faeb07ead..3fc7e7889 100644 --- a/qemu/roms/SLOF/lib/libusb/usb-xhci.h +++ b/qemu/roms/SLOF/lib/libusb/usb-xhci.h @@ -266,6 +266,7 @@ struct xhci_seg { #define XHCI_EVENT_TRBS_SIZE 4096 #define XHCI_CONTROL_TRBS_SIZE 4096 #define XHCI_DATA_TRBS_SIZE 4096 +#define XHCI_INTR_TRBS_SIZE 4096 #define XHCI_ERST_NUM_SEGS 1 #define XHCI_MAX_BULK_SIZE 0xF000 @@ -349,6 +350,7 @@ struct xhci_dev { struct xhci_ctx in_ctx; struct xhci_ctx out_ctx; struct xhci_seg control; + struct xhci_seg intr; struct xhci_seg bulk_in; struct xhci_seg bulk_out; uint32_t ctx_size; @@ -381,6 +383,9 @@ struct xhci_hcd { struct xhci_pipe { struct usb_pipe pipe; struct xhci_seg *seg; + void *buf; + long buf_phys; + uint32_t buflen; }; #endif /* USB_XHCI_H */ |