Changeset b4b534ac in mainline for uspace/drv/bus/usb/ehci
- Timestamp:
- 2016-07-22T08:24:47Z (10 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- f76d2c2
- Parents:
- 5b18137 (diff), 8351f9a4 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - Location:
- uspace/drv/bus/usb/ehci
- Files:
-
- 15 added
- 4 edited
- 5 moved
-
Makefile (modified) (3 diffs)
-
ehci_batch.c (added)
-
ehci_batch.h (added)
-
ehci_endpoint.c (added)
-
ehci_endpoint.h (moved) (moved from uspace/drv/bus/usb/uhcirh/root_hub.h ) (1 diff)
-
ehci_regs.h (added)
-
ehci_rh.c (added)
-
ehci_rh.h (moved) (moved from uspace/drv/bus/usb/uhci/root_hub.c ) (2 diffs)
-
endpoint_list.c (added)
-
endpoint_list.h (added)
-
hc.c (added)
-
hc.h (added)
-
hw_struct/fstn.h (moved) (moved from uspace/drv/bus/usb/uhci/uhci.h ) (2 diffs)
-
hw_struct/iso_transfer_descriptor.h (added)
-
hw_struct/link_pointer.h (moved) (moved from uspace/lib/usb/include/usb/ddfiface.h ) (2 diffs)
-
hw_struct/mem_access.h (moved) (moved from uspace/drv/bus/usb/uhci/res.h ) (2 diffs)
-
hw_struct/queue_head.c (added)
-
hw_struct/queue_head.h (added)
-
hw_struct/split_iso_transfer_descriptor.h (added)
-
hw_struct/transfer_descriptor.c (added)
-
hw_struct/transfer_descriptor.h (added)
-
main.c (modified) (3 diffs)
-
res.c (modified) (8 diffs)
-
res.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/ehci/Makefile
r5b18137 rb4b534ac 31 31 LIBS = \ 32 32 $(LIBUSBHOST_PREFIX)/libusbhost.a \ 33 $(LIBUSBVIRT_PREFIX)/libusbvirt.a \ 33 34 $(LIBUSB_PREFIX)/libusb.a \ 34 35 $(LIBDRV_PREFIX)/libdrv.a … … 36 37 EXTRA_CFLAGS += \ 37 38 -I$(LIBUSB_PREFIX)/include \ 39 -I$(LIBUSBDEV_PREFIX)/include \ 38 40 -I$(LIBUSBHOST_PREFIX)/include \ 41 -I$(LIBUSBVIRT_PREFIX)/include \ 39 42 -I$(LIBDRV_PREFIX)/include 40 43 … … 42 45 43 46 SOURCES = \ 47 ehci_batch.c \ 48 ehci_endpoint.c \ 49 ehci_rh.c \ 50 endpoint_list.c \ 51 hc.c \ 52 hw_struct/queue_head.c \ 53 hw_struct/transfer_descriptor.c \ 44 54 main.c \ 45 55 res.c -
uspace/drv/bus/usb/ehci/ehci_endpoint.h
r5b18137 rb4b534ac 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup drvusb uhcirh28 /** @addtogroup drvusbehci 29 29 * @{ 30 30 */ 31 31 /** @file 32 * @brief UHCI driver32 * @brief EHCI driver 33 33 */ 34 #ifndef DRV_ UHCI_ROOT_HUB_H35 #define DRV_ UHCI_ROOT_HUB_H34 #ifndef DRV_EHCI_HCD_ENDPOINT_H 35 #define DRV_EHCI_HCD_ENDPOINT_H 36 36 37 #include <ddf/driver.h> 38 #include <device/hw_res_parsed.h> 37 #include <assert.h> 38 #include <adt/list.h> 39 #include <usb/host/endpoint.h> 40 #include <usb/host/hcd.h> 39 41 40 #include "port.h" 42 #include "hw_struct/queue_head.h" 43 #include "hw_struct/transfer_descriptor.h" 41 44 42 #define UHCI_ROOT_HUB_PORT_COUNT 2 43 #define ROOT_HUB_WAIT_USEC 250000 /* 250 miliseconds */ 45 /** Connector structure linking ED to to prepared TD. */ 46 typedef struct ehci_endpoint { 47 /** EHCI endpoint descriptor */ 48 qh_t *qh; 49 /** Linked list used by driver software */ 50 link_t link; 51 } ehci_endpoint_t; 44 52 45 /** UHCI root hub drvier structure */ 46 typedef struct root_hub { 47 /** Ports provided by the hub */ 48 uhci_port_t ports[UHCI_ROOT_HUB_PORT_COUNT]; 49 } uhci_root_hub_t; 53 int ehci_endpoint_init(hcd_t *hcd, endpoint_t *ep); 54 void ehci_endpoint_fini(hcd_t *hcd, endpoint_t *ep); 50 55 51 int uhci_root_hub_init(uhci_root_hub_t *instance, addr_range_t *regs, 52 ddf_dev_t *rh); 56 /** Get and convert assigned ehci_endpoint_t structure 57 * @param[in] ep USBD endpoint structure. 58 * @return Pointer to assigned hcd endpoint structure 59 */ 60 static inline ehci_endpoint_t * ehci_endpoint_get(const endpoint_t *ep) 61 { 62 assert(ep); 63 return ep->hc_data.data; 64 } 53 65 54 void uhci_root_hub_fini(uhci_root_hub_t *instance); 66 static inline ehci_endpoint_t * ehci_endpoint_list_instance(link_t *l) 67 { 68 return list_get_instance(l, ehci_endpoint_t, link); 69 } 70 55 71 #endif 56 72 /** 57 73 * @} 58 74 */ 75 -
uspace/drv/bus/usb/ehci/ehci_rh.h
r5b18137 rb4b534ac 1 1 /* 2 * Copyright (c) 201 1Jan Vesely2 * Copyright (c) 2013 Jan Vesely 3 3 * All rights reserved. 4 4 * … … 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup drvusb uhci28 /** @addtogroup drvusbehci 29 29 * @{ 30 30 */ 31 31 /** @file 32 * @brief UHCI driver32 * @brief EHCI driver 33 33 */ 34 #ifndef DRV_EHCI_EHCI_RH_H 35 #define DRV_EHCI_EHCI_RH_H 36 34 37 #include <assert.h> 35 #include <errno.h> 36 #include <str_error.h> 37 #include <stdio.h> 38 #include <device/hw_res_parsed.h> 38 #include <sys/types.h> 39 39 40 #include <usb/debug.h> 40 #include <usb/usb.h> 41 #include <usb/classes/hub.h> 42 #include <usb/host/usb_transfer_batch.h> 43 #include <usbvirt/virthub_base.h> 41 44 42 #include " root_hub.h"45 #include "ehci_regs.h" 43 46 44 /** Root hub initialization 45 * @param[in] instance RH structure to initialize 46 * @param[in] fun DDF function representing UHCI root hub 47 * @param[in] reg_addr Address of root hub status and control registers. 48 * @param[in] reg_size Size of accessible address space. 49 * @return Error code. 47 enum { 48 EHCI_MAX_PORTS = 15, 49 }; 50 51 typedef struct { 52 /** Virtual hub instance */ 53 virthub_base_t base; 54 /** EHCI device registers */ 55 ehci_regs_t *registers; 56 /** Number of downstream ports, EHCI limits this to 15 */ 57 unsigned port_count; 58 /** USB hub descriptor describing the EHCI root hub */ 59 struct { 60 usb_hub_descriptor_header_t header; 61 uint8_t rempow[STATUS_BYTES(EHCI_MAX_PORTS) * 2]; 62 } __attribute__((packed)) hub_descriptor; 63 /** interrupt transfer waiting for an actual interrupt to occur */ 64 usb_transfer_batch_t *unfinished_interrupt_transfer; 65 bool reset_flag[EHCI_MAX_PORTS]; 66 bool resume_flag[EHCI_MAX_PORTS]; 67 } ehci_rh_t; 68 69 int ehci_rh_init(ehci_rh_t *instance, ehci_caps_regs_t *caps, ehci_regs_t *regs, 70 const char *name); 71 int ehci_rh_schedule(ehci_rh_t *instance, usb_transfer_batch_t *batch); 72 int ehci_rh_interrupt(ehci_rh_t *instance); 73 74 /** Get EHCI rh address. 75 * 76 * @param instance UHCI rh instance. 77 * @return USB address assigned to the hub. 78 * Wrapper for virtual hub address 50 79 */ 51 int 52 rh_init(rh_t *instance, ddf_fun_t *fun, addr_range_t *regs, uintptr_t reg_addr, 53 size_t reg_size) 80 static inline usb_address_t ehci_rh_get_address(ehci_rh_t *instance) 54 81 { 55 82 assert(instance); 56 assert(fun); 57 58 /* Crop the PIO window to the absolute address range of UHCI I/O. */ 59 instance->pio_window.mem.base = 0; 60 instance->pio_window.mem.size = 0; 61 instance->pio_window.io.base = RNGABS(*regs); 62 instance->pio_window.io.size = RNGSZ(*regs); 63 64 /* Initialize resource structure */ 65 instance->resource_list.count = 1; 66 instance->resource_list.resources = &instance->io_regs; 67 68 instance->io_regs.type = IO_RANGE; 69 instance->io_regs.res.io_range.address = reg_addr; 70 instance->io_regs.res.io_range.size = reg_size; 71 instance->io_regs.res.io_range.relative = true; 72 instance->io_regs.res.io_range.endianness = LITTLE_ENDIAN; 73 74 const int ret = ddf_fun_add_match_id(fun, "usb&uhci&root-hub", 100); 75 if (ret != EOK) { 76 usb_log_error("Failed to add root hub match id: %s\n", 77 str_error(ret)); 78 } 79 return ret; 83 return virthub_base_get_address(&instance->base); 80 84 } 85 #endif 81 86 /** 82 87 * @} -
uspace/drv/bus/usb/ehci/hw_struct/fstn.h
r5b18137 rb4b534ac 1 1 /* 2 * Copyright (c) 201 1Jan Vesely2 * Copyright (c) 2013 Jan Vesely 3 3 * All rights reserved. 4 4 * … … 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 29 /** @addtogroup drvusbuhci 28 /** @addtogroup drvusbehci 30 29 * @{ 31 30 */ 32 31 /** @file 33 * @brief UHCI driver main structure for both host controller and root-hub.32 * @brief EHCI driver 34 33 */ 35 #ifndef DRV_UHCI_UHCI_H 36 #define DRV_UHCI_UHCI_H 37 #include <ddf/driver.h> 34 #ifndef DRV_EHCI_HW_STRUCT_FSTN_H 35 #define DRV_EHCI_HW_STRUCT_FSTN_H 38 36 39 int device_setup_uhci(ddf_dev_t *device); 37 #include "link_pointer.h" 38 39 typedef struct fstn { 40 link_pointer_t normal_path; 41 link_pointer_t back_path; 42 } fstn_t; 43 40 44 #endif 41 45 /** 42 46 * @} 43 47 */ 48 -
uspace/drv/bus/usb/ehci/hw_struct/link_pointer.h
r5b18137 rb4b534ac 1 1 /* 2 * Copyright (c) 201 1 Vojtech Horky2 * Copyright (c) 2013 Jan Vesely 3 3 * All rights reserved. 4 4 * … … 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 29 /** @addtogroup libusb 28 /** @addtogroup drvusbehci 30 29 * @{ 31 30 */ 32 31 /** @file 33 * Implementations of DDF interfaces functions.32 * @brief EHCI driver 34 33 */ 35 36 #ifndef LIBUSB_DDFIFACE_H_ 37 #define LIBUSB_DDFIFACE_H_ 34 #ifndef DRV_EHCI_HW_STRUCT_LINK_POINTER_H 35 #define DRV_EHCI_HW_STRUCT_LINK_POINTER_H 38 36 39 37 #include <sys/types.h> 40 #include <usb_iface.h>41 38 42 extern int usb_iface_get_hc_handle_device_impl(ddf_fun_t *, devman_handle_t *); 43 extern int usb_iface_get_my_address_forward_impl(ddf_fun_t *, usb_address_t *); 44 extern usb_iface_t usb_iface_hub_impl; 39 /** EHCI link pointer, used by many data structures */ 40 typedef volatile uint32_t link_pointer_t; 45 41 46 extern int usb_iface_get_my_address_from_device_data(ddf_fun_t *, usb_address_t *); 47 extern usb_iface_t usb_iface_hub_child_impl; 42 #define LINK_POINTER_ADDRESS_MASK 0xfffffff0 /* upper 28 bits */ 48 43 49 extern int usb_iface_get_hc_handle_hc_impl(ddf_fun_t *, devman_handle_t *); 44 #define LINK_POINTER_TERMINATE_FLAG (1 << 0) 45 46 enum { 47 LINK_POINTER_TYPE_iTD = 0x0 << 1, 48 LINK_POINTER_TYPE_QH = 0x1 << 1, 49 LINK_POINTER_TYPE_siTD = 0x2 << 1, 50 LINK_POINTER_TYPE_FSTN = 0x3 << 1, 51 LINK_POINTER_TYPE_MASK = 0x3 << 1, 52 }; 53 54 #define LINK_POINTER_QH(address) \ 55 ((address & LINK_POINTER_ADDRESS_MASK) | LINK_POINTER_TYPE_QH) 56 57 #define LINK_POINTER_TD(address) \ 58 (address & LINK_POINTER_ADDRESS_MASK) 59 60 #define LINK_POINTER_TERM \ 61 ((link_pointer_t)LINK_POINTER_TERMINATE_FLAG) 50 62 51 63 #endif 52 53 64 /** 54 65 * @} -
uspace/drv/bus/usb/ehci/hw_struct/mem_access.h
r5b18137 rb4b534ac 1 1 /* 2 * Copyright (c) 201 0 Vojtech Horky2 * Copyright (c) 2013 Jan Vesely 3 3 * All rights reserved. 4 4 * … … 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 29 /** @addtogroup drvusbuhcihc 28 /** @addtogroup drvusbehci 30 29 * @{ 31 30 */ 32 31 /** @file 33 * @brief UHCI driver PCI helper functions32 * @brief EHCI driver 34 33 */ 35 #ifndef DRV_ UHCI_PCI_H36 #define DRV_ UHCI_PCI_H34 #ifndef DRV_EHCI_HW_MEM_ACCESS_H 35 #define DRV_EHCI_HW_MEM_ACCESS_H 37 36 38 #include < ddf/driver.h>39 #include < device/hw_res_parsed.h>37 #include <byteorder.h> 38 #include <libarch/barrier.h> 40 39 41 int get_my_registers(ddf_dev_t *, addr_range_t *, int *); 42 int enable_interrupts(ddf_dev_t *); 43 int disable_legacy(ddf_dev_t *); 40 #define EHCI_MEM32_WR(reg, val) reg = host2uint32_t_le(val) 41 #define EHCI_MEM32_RD(reg) uint32_t_le2host(reg) 42 #define EHCI_MEM32_SET(reg, val) reg |= host2uint32_t_le(val) 43 #define EHCI_MEM32_CLR(reg, val) reg &= host2uint32_t_le(~val) 44 44 45 45 #endif 46 /** 46 47 /* 47 48 * @} 48 49 */ -
uspace/drv/bus/usb/ehci/main.c
r5b18137 rb4b534ac 33 33 * Main routines of EHCI driver. 34 34 */ 35 36 35 #include <ddf/driver.h> 37 36 #include <ddf/interrupt.h> 38 37 #include <device/hw_res.h> 39 38 #include <errno.h> 40 #include <stdbool.h>41 39 #include <str_error.h> 40 #include <io/logctl.h> 42 41 43 42 #include <usb_iface.h> 44 #include <usb/ddfiface.h>45 43 #include <usb/debug.h> 46 #include <usb/host/ hcd.h>44 #include <usb/host/ddf_helpers.h> 47 45 48 46 #include "res.h" 47 #include "hc.h" 48 #include "ehci_endpoint.h" 49 49 50 50 #define NAME "ehci" 51 51 52 static int ehci_dev_add(ddf_dev_t *device); 52 static int ehci_driver_init(hcd_t *, const hw_res_list_parsed_t *, bool); 53 static void ehci_driver_fini(hcd_t *); 53 54 54 static driver_ops_t ehci_driver_ops = { 55 .dev_add = ehci_dev_add, 55 static const ddf_hc_driver_t ehci_hc_driver = { 56 .claim = disable_legacy, 57 .hc_speed = USB_SPEED_HIGH, 58 .irq_code_gen = ehci_hc_gen_irq_code, 59 .init = ehci_driver_init, 60 .fini = ehci_driver_fini, 61 .name = "EHCI-PCI", 62 .ops = { 63 .schedule = ehci_hc_schedule, 64 .ep_add_hook = ehci_endpoint_init, 65 .ep_remove_hook = ehci_endpoint_fini, 66 .irq_hook = ehci_hc_interrupt, 67 .status_hook = ehci_hc_status, 68 } 56 69 }; 57 70 58 static driver_t ehci_driver = {59 .name = NAME,60 .driver_ops = &ehci_driver_ops61 };62 static ddf_dev_ops_t hc_ops = {63 .interfaces[USBHC_DEV_IFACE] = &hcd_iface,64 };65 71 72 static int ehci_driver_init(hcd_t *hcd, const hw_res_list_parsed_t *res, bool irq) 73 { 74 assert(hcd); 75 assert(hcd_get_driver_data(hcd) == NULL); 76 77 hc_t *instance = malloc(sizeof(hc_t)); 78 if (!instance) 79 return ENOMEM; 80 81 const int ret = hc_init(instance, res, irq); 82 if (ret == EOK) { 83 hcd_set_implementation(hcd, instance, &ehci_hc_driver.ops); 84 } else { 85 free(instance); 86 } 87 return ret; 88 } 89 90 static void ehci_driver_fini(hcd_t *hcd) 91 { 92 assert(hcd); 93 hc_t *hc = hcd_get_driver_data(hcd); 94 if (hc) 95 hc_fini(hc); 96 97 free(hc); 98 hcd_set_implementation(hcd, NULL, NULL); 99 } 66 100 67 101 /** Initializes a new ddf driver instance of EHCI hcd. … … 72 106 static int ehci_dev_add(ddf_dev_t *device) 73 107 { 74 ddf_fun_t *hc_fun = NULL; 75 bool fun_bound = false; 76 108 usb_log_debug("ehci_dev_add() called\n"); 77 109 assert(device); 78 110 79 addr_range_t reg_range; 80 int irq = 0; 111 return hcd_ddf_add_hc(device, &ehci_hc_driver); 81 112 82 int rc = get_my_registers(device, ®_range, &irq); 83 if (rc != EOK) { 84 usb_log_error("Failed to get memory addresses for %" PRIun 85 ": %s.\n", ddf_dev_get_handle(device), str_error(rc)); 86 goto error; 87 } 113 } 88 114 89 usb_log_info("Memory mapped regs at %p (size %zu), IRQ %d.\n",90 RNGABSPTR(reg_range), RNGSZ(reg_range), irq);91 115 92 rc = disable_legacy(device, ®_range); 93 if (rc != EOK) { 94 usb_log_error("Failed to disable legacy USB: %s.\n", 95 str_error(rc)); 96 goto error; 97 } 116 static const driver_ops_t ehci_driver_ops = { 117 .dev_add = ehci_dev_add, 118 }; 98 119 99 hc_fun = ddf_fun_create(device, fun_exposed, "ehci_hc"); 100 if (hc_fun == NULL) { 101 usb_log_error("Failed to create EHCI function.\n"); 102 rc = ENOMEM; 103 goto error; 104 } 120 static const driver_t ehci_driver = { 121 .name = NAME, 122 .driver_ops = &ehci_driver_ops 123 }; 105 124 106 hcd_t *ehci_hc = ddf_fun_data_alloc(hc_fun, sizeof(hcd_t));107 if (ehci_hc == NULL) {108 usb_log_error("Failed to alloc generic HC driver.\n");109 rc = ENOMEM;110 goto error;111 }112 113 /* High Speed, no bandwidth */114 hcd_init(ehci_hc, USB_SPEED_HIGH, 0, NULL);115 ddf_fun_set_ops(hc_fun, &hc_ops);116 117 rc = ddf_fun_bind(hc_fun);118 if (rc != EOK) {119 usb_log_error("Failed to bind EHCI function: %s.\n",120 str_error(rc));121 goto error;122 }123 124 fun_bound = true;125 126 rc = ddf_fun_add_to_category(hc_fun, USB_HC_CATEGORY);127 if (rc != EOK) {128 usb_log_error("Failed to add EHCI to HC class: %s.\n",129 str_error(rc));130 goto error;131 }132 133 usb_log_info("Controlling new EHCI device `%s' (handle %" PRIun ").\n",134 ddf_dev_get_name(device), ddf_dev_get_handle(device));135 136 return EOK;137 error:138 if (fun_bound)139 ddf_fun_unbind(hc_fun);140 if (hc_fun != NULL)141 ddf_fun_destroy(hc_fun);142 return rc;143 }144 125 145 126 /** Initializes global driver structures (NONE). … … 154 135 { 155 136 log_init(NAME); 137 logctl_set_log_level(NAME, LVL_NOTE); 156 138 return ddf_driver_main(&ehci_driver); 157 139 } -
uspace/drv/bus/usb/ehci/res.c
r5b18137 rb4b534ac 46 46 47 47 #include "res.h" 48 49 #define HCC_PARAMS_OFFSET 0x8 50 #define HCC_PARAMS_EECP_MASK 0xff 51 #define HCC_PARAMS_EECP_OFFSET 8 52 53 #define CMD_OFFSET 0x0 54 #define STS_OFFSET 0x4 55 #define INT_OFFSET 0x8 56 #define CFG_OFFSET 0x40 57 58 #define USBCMD_RUN 1 59 #define USBSTS_HALTED (1 << 12) 48 #include "ehci_regs.h" 60 49 61 50 #define USBLEGSUP_OFFSET 0 … … 67 56 #define WAIT_STEP 10 68 57 69 70 /** Get address of registers and IRQ for given device.71 *72 * @param[in] dev Device asking for the addresses.73 * @param[out] mem_regs_p Pointer to the register range.74 * @param[out] irq_no IRQ assigned to the device.75 * @return Error code.76 */77 int get_my_registers(ddf_dev_t *dev,78 addr_range_t *mem_regs_p, int *irq_no)79 {80 assert(dev);81 82 async_sess_t *parent_sess = devman_parent_device_connect(83 ddf_dev_get_handle(dev), IPC_FLAG_BLOCKING);84 if (!parent_sess)85 return ENOMEM;86 87 hw_res_list_parsed_t hw_res;88 hw_res_list_parsed_init(&hw_res);89 const int ret = hw_res_get_list_parsed(parent_sess, &hw_res, 0);90 async_hangup(parent_sess);91 if (ret != EOK) {92 return ret;93 }94 95 if (hw_res.irqs.count != 1 || hw_res.mem_ranges.count != 1) {96 hw_res_list_parsed_clean(&hw_res);97 return ENOENT;98 }99 100 if (mem_regs_p)101 *mem_regs_p = hw_res.mem_ranges.ranges[0];102 if (irq_no)103 *irq_no = hw_res.irqs.irqs[0];104 105 hw_res_list_parsed_clean(&hw_res);106 return EOK;107 }108 109 /** Calls the PCI driver with a request to enable interrupts110 *111 * @param[in] device Device asking for interrupts112 * @return Error code.113 */114 int enable_interrupts(ddf_dev_t *device)115 {116 async_sess_t *parent_sess = devman_parent_device_connect(117 ddf_dev_get_handle(device), IPC_FLAG_BLOCKING);118 if (!parent_sess)119 return ENOMEM;120 121 const bool enabled = hw_res_enable_interrupt(parent_sess);122 async_hangup(parent_sess);123 124 return enabled ? EOK : EIO;125 }126 127 58 /** Implements BIOS hands-off routine as described in EHCI spec 128 59 * … … 131 62 * @return Error code. 132 63 */ 133 static int disable_extended_caps( ddf_dev_t *device, unsigned eecp)64 static int disable_extended_caps(async_sess_t *parent_sess, unsigned eecp) 134 65 { 135 66 /* nothing to do */ … … 137 68 return EOK; 138 69 139 async_sess_t *parent_sess = devman_parent_device_connect(140 ddf_dev_get_handle(device), IPC_FLAG_BLOCKING);141 if (!parent_sess)142 return ENOMEM;143 144 70 /* Read the first EEC. i.e. Legacy Support register */ 145 71 uint32_t usblegsup; 146 int r c= pci_config_space_read_32(parent_sess,72 int ret = pci_config_space_read_32(parent_sess, 147 73 eecp + USBLEGSUP_OFFSET, &usblegsup); 148 if (rc != EOK) { 149 usb_log_error("Failed to read USBLEGSUP: %s.\n", 150 str_error(rc)); 151 goto error; 152 } 153 154 usb_log_debug("USBLEGSUP: %" PRIx32 ".\n", usblegsup); 74 if (ret != EOK) { 75 usb_log_error("Failed to read USBLEGSUP: %s.\n", str_error(ret)); 76 return ret; 77 } 78 usb_log_debug2("USBLEGSUP: %" PRIx32 ".\n", usblegsup); 155 79 156 80 /* Request control from firmware/BIOS by writing 1 to highest 157 81 * byte. (OS Control semaphore)*/ 158 82 usb_log_debug("Requesting OS control.\n"); 159 r c= pci_config_space_write_8(parent_sess,83 ret = pci_config_space_write_8(parent_sess, 160 84 eecp + USBLEGSUP_OFFSET + 3, 1); 161 if (r c!= EOK) {85 if (ret != EOK) { 162 86 usb_log_error("Failed to request OS EHCI control: %s.\n", 163 str_error(r c));164 goto error;87 str_error(ret)); 88 return ret; 165 89 } 166 90 167 91 size_t wait = 0; 168 92 /* Wait for BIOS to release control. */ 169 r c= pci_config_space_read_32(93 ret = pci_config_space_read_32( 170 94 parent_sess, eecp + USBLEGSUP_OFFSET, &usblegsup); 171 if (rc != EOK) { 172 usb_log_error("Failed reading PCI config space: %s.\n", 173 str_error(rc)); 174 goto error; 175 } 176 177 while ((wait < DEFAULT_WAIT) && (usblegsup & USBLEGSUP_BIOS_CONTROL)) { 95 while ((ret == EOK) && (wait < DEFAULT_WAIT) 96 && (usblegsup & USBLEGSUP_BIOS_CONTROL)) { 178 97 async_usleep(WAIT_STEP); 179 r c= pci_config_space_read_32(parent_sess,98 ret = pci_config_space_read_32(parent_sess, 180 99 eecp + USBLEGSUP_OFFSET, &usblegsup); 181 if (rc != EOK) {182 usb_log_error("Failed reading PCI config space: %s.\n",183 str_error(rc));184 goto error;185 }186 100 wait += WAIT_STEP; 187 101 } … … 189 103 if ((usblegsup & USBLEGSUP_BIOS_CONTROL) == 0) { 190 104 usb_log_info("BIOS released control after %zu usec.\n", wait); 191 async_hangup(parent_sess);192 105 return EOK; 193 106 } … … 196 109 usb_log_warning( "BIOS failed to release control after " 197 110 "%zu usecs, force it.\n", wait); 198 r c= pci_config_space_write_32(parent_sess,111 ret = pci_config_space_write_32(parent_sess, 199 112 eecp + USBLEGSUP_OFFSET, USBLEGSUP_OS_CONTROL); 200 if (r c!= EOK) {201 usb_log_error("Failed to force OS control: "202 "%s.\n", str_error(rc));203 goto error;113 if (ret != EOK) { 114 usb_log_error("Failed to force OS control: %s.\n", 115 str_error(ret)); 116 return ret; 204 117 } 205 118 … … 213 126 /* Read the second EEC Legacy Support and Control register */ 214 127 uint32_t usblegctlsts; 215 r c= pci_config_space_read_32(parent_sess,128 ret = pci_config_space_read_32(parent_sess, 216 129 eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts); 217 if (r c!= EOK) {130 if (ret != EOK) { 218 131 usb_log_error("Failed to get USBLEGCTLSTS: %s.\n", 219 str_error(r c));220 goto error;132 str_error(ret)); 133 return ret; 221 134 } 222 223 usb_log_debug("USBLEGCTLSTS: %" PRIx32 ".\n", usblegctlsts); 135 usb_log_debug2("USBLEGCTLSTS: %" PRIx32 ".\n", usblegctlsts); 224 136 /* 225 137 * Zero SMI enables in legacy control register. … … 227 139 * interfering. NOTE: Three upper bits are WC 228 140 */ 229 r c= pci_config_space_write_32(parent_sess,141 ret = pci_config_space_write_32(parent_sess, 230 142 eecp + USBLEGCTLSTS_OFFSET, 0xe0000000); 231 if (rc != EOK) { 232 usb_log_error("Failed(%d) zero USBLEGCTLSTS.\n", rc); 233 goto error; 143 if (ret != EOK) { 144 usb_log_error("Failed to zero USBLEGCTLSTS: %s\n", 145 str_error(ret)); 146 return ret; 234 147 } 235 148 236 149 udelay(10); 237 rc = pci_config_space_read_32(parent_sess, 150 /* read again to amke sure it's zeroed */ 151 ret = pci_config_space_read_32(parent_sess, 238 152 eecp + USBLEGCTLSTS_OFFSET, &usblegctlsts); 239 if (r c!= EOK) {153 if (ret != EOK) { 240 154 usb_log_error("Failed to get USBLEGCTLSTS 2: %s.\n", 241 str_error(r c));242 goto error;155 str_error(ret)); 156 return ret; 243 157 } 244 245 usb_log_debug("Zeroed USBLEGCTLSTS: %" PRIx32 ".\n", 158 usb_log_debug2("Zeroed USBLEGCTLSTS: %" PRIx32 ".\n", 246 159 usblegctlsts); 247 160 } 248 161 249 162 /* Read again Legacy Support register */ 250 r c= pci_config_space_read_32(parent_sess,163 ret = pci_config_space_read_32(parent_sess, 251 164 eecp + USBLEGSUP_OFFSET, &usblegsup); 252 if (r c!= EOK) {165 if (ret != EOK) { 253 166 usb_log_error("Failed to read USBLEGSUP: %s.\n", 254 str_error(rc)); 255 goto error; 256 } 257 258 usb_log_debug("USBLEGSUP: %" PRIx32 ".\n", usblegsup); 259 async_hangup(parent_sess); 260 return EOK; 261 error: 262 async_hangup(parent_sess); 263 return rc; 167 str_error(ret)); 168 return ret; 169 } 170 usb_log_debug2("USBLEGSUP: %" PRIx32 ".\n", usblegsup); 171 return ret; 264 172 } 265 173 266 int disable_legacy(ddf_dev_t *device , addr_range_t *reg_range)174 int disable_legacy(ddf_dev_t *device) 267 175 { 268 176 assert(device); 177 178 async_sess_t *parent_sess = devman_parent_device_connect( 179 ddf_dev_get_handle(device), IPC_FLAG_BLOCKING); 180 if (!parent_sess) 181 return ENOMEM; 182 269 183 usb_log_debug("Disabling EHCI legacy support.\n"); 184 185 hw_res_list_parsed_t res; 186 hw_res_list_parsed_init(&res); 187 int ret = hw_res_get_list_parsed(parent_sess, &res, 0); 188 if (ret != EOK) { 189 usb_log_error("Failed to get resource list: %s\n", 190 str_error(ret)); 191 goto clean; 192 } 193 194 if (res.mem_ranges.count < 1) { 195 usb_log_error("Incorrect mem range count: %zu", 196 res.mem_ranges.count); 197 ret = EINVAL; 198 goto clean; 199 } 270 200 271 201 /* Map EHCI registers */ 272 202 void *regs = NULL; 273 int rc = pio_enable_range(reg_range, ®s);274 if (r c!= EOK) {203 ret = pio_enable_range(&res.mem_ranges.ranges[0], ®s); 204 if (ret != EOK) { 275 205 usb_log_error("Failed to map registers %p: %s.\n", 276 RNGABSPTR(*reg_range), str_error(rc)); 277 return rc; 278 } 279 280 usb_log_debug2("Registers mapped at: %p.\n", regs); 281 282 const uint32_t hcc_params = 283 *(uint32_t*)(regs + HCC_PARAMS_OFFSET); 284 usb_log_debug("Value of hcc params register: %x.\n", hcc_params); 206 RNGABSPTR(res.mem_ranges.ranges[0]), str_error(ret)); 207 goto clean; 208 } 209 210 usb_log_debug("Registers mapped at: %p.\n", regs); 211 212 ehci_caps_regs_t *ehci_caps = regs; 213 214 const uint32_t hcc_params = EHCI_RD(ehci_caps->hccparams); 215 usb_log_debug2("Value of hcc params register: %x.\n", hcc_params); 285 216 286 217 /* Read value of EHCI Extended Capabilities Pointer 287 218 * position of EEC registers (points to PCI config space) */ 288 219 const uint32_t eecp = 289 (hcc_params >> HCC_PARAMS_EECP_OFFSET) & HCC_PARAMS_EECP_MASK;290 usb_log_debug ("Value of EECP: %x.\n", eecp);291 292 r c = disable_extended_caps(device, eecp);293 if (r c!= EOK) {220 (hcc_params >> EHCI_CAPS_HCC_EECP_SHIFT) & EHCI_CAPS_HCC_EECP_MASK; 221 usb_log_debug2("Value of EECP: %x.\n", eecp); 222 223 ret = disable_extended_caps(parent_sess, eecp); 224 if (ret != EOK) { 294 225 usb_log_error("Failed to disable extended capabilities: %s.\n", 295 str_error(rc)); 296 return rc; 297 } 298 299 /* 300 * TURN OFF EHCI FOR NOW, DRIVER WILL REINITIALIZE IT IF NEEDED 301 */ 302 303 /* Get size of capability registers in memory space. */ 304 const unsigned operation_offset = *(uint8_t*)regs; 305 usb_log_debug("USBCMD offset: %d.\n", operation_offset); 306 307 /* Zero USBCMD register. */ 308 volatile uint32_t *usbcmd = 309 (uint32_t*)((uint8_t*)regs + operation_offset + CMD_OFFSET); 310 volatile uint32_t *usbsts = 311 (uint32_t*)((uint8_t*)regs + operation_offset + STS_OFFSET); 312 volatile uint32_t *usbconf = 313 (uint32_t*)((uint8_t*)regs + operation_offset + CFG_OFFSET); 314 volatile uint32_t *usbint = 315 (uint32_t*)((uint8_t*)regs + operation_offset + INT_OFFSET); 316 usb_log_debug("USBCMD value: %x.\n", *usbcmd); 317 if (*usbcmd & USBCMD_RUN) { 318 *usbsts = 0x3f; /* ack all interrupts */ 319 *usbint = 0; /* disable all interrupts */ 320 *usbconf = 0; /* release control of RH ports */ 321 322 *usbcmd = 0; 323 /* Wait until hc is halted */ 324 while ((*usbsts & USBSTS_HALTED) == 0); 325 usb_log_info("EHCI turned off.\n"); 326 } else { 327 usb_log_info("EHCI was not running.\n"); 328 } 329 usb_log_debug("Registers: \n" 330 "\t USBCMD(%p): %x(0x00080000 = at least 1ms between interrupts)\n" 331 "\t USBSTS(%p): %x(0x00001000 = HC halted)\n" 332 "\t USBINT(%p): %x(0x0 = no interrupts).\n" 333 "\t CONFIG(%p): %x(0x0 = ports controlled by companion hc).\n", 334 usbcmd, *usbcmd, usbsts, *usbsts, usbint, *usbint, usbconf,*usbconf); 335 336 return rc; 226 str_error(ret)); 227 goto clean; 228 } 229 clean: 230 //TODO unmap registers 231 hw_res_list_parsed_clean(&res); 232 async_hangup(parent_sess); 233 return ret; 337 234 } 338 235 -
uspace/drv/bus/usb/ehci/res.h
r5b18137 rb4b534ac 39 39 #include <device/hw_res_parsed.h> 40 40 41 int get_my_registers(ddf_dev_t *, addr_range_t *, int *); 42 int enable_interrupts(ddf_dev_t *); 43 int disable_legacy(ddf_dev_t *, addr_range_t *); 41 int disable_legacy(ddf_dev_t *); 44 42 45 43 #endif
Note:
See TracChangeset
for help on using the changeset viewer.
