Changes in / [0f3e68c:335382d] in mainline
- Location:
- uspace/drv/uhci-hcd
- Files:
-
- 4 added
- 2 deleted
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/uhci-hcd/Makefile
r0f3e68c r335382d 35 35 iface.c \ 36 36 main.c \ 37 root_hub.c \38 37 transfer_list.c \ 39 38 uhci.c \ 39 uhci_hc.c \ 40 uhci_rh.c \ 40 41 uhci_struct/transfer_descriptor.c \ 41 42 utils/device_keeper.c \ -
uspace/drv/uhci-hcd/batch.c
r0f3e68c r335382d 40 40 #include "batch.h" 41 41 #include "transfer_list.h" 42 #include "uhci .h"42 #include "uhci_hc.h" 43 43 #include "utils/malloc32.h" 44 44 … … 100 100 bzero(instance, sizeof(batch_t)); 101 101 102 instance->qh = malloc32(sizeof(q ueue_head_t));102 instance->qh = malloc32(sizeof(qh_t)); 103 103 CHECK_NULL_DISPOSE_RETURN(instance->qh, 104 104 "Failed to allocate batch queue head.\n"); 105 q ueue_head_init(instance->qh);105 qh_init(instance->qh); 106 106 107 107 instance->packets = (size + max_packet_size - 1) / max_packet_size; … … 114 114 instance->tds, "Failed to allocate transfer descriptors.\n"); 115 115 bzero(instance->tds, sizeof(td_t) * instance->packets); 116 117 // const size_t transport_size = max_packet_size * instance->packets;118 116 119 117 if (size > 0) { … … 143 141 instance->speed = speed; 144 142 instance->manager = manager; 145 146 if (func_out) 147 instance->callback_out = func_out; 148 if (func_in) 149 instance->callback_in = func_in; 150 151 queue_head_set_element_td(instance->qh, addr_to_phys(instance->tds)); 143 instance->callback_out = func_out; 144 instance->callback_in = func_in; 145 146 qh_set_element_td(instance->qh, addr_to_phys(instance->tds)); 152 147 153 148 usb_log_debug("Batch(%p) %d:%d memory structures ready.\n", … … 319 314 ++packet; 320 315 } 321 instance->tds[packet - 1].status |= TD_STATUS_IOC_FLAG;316 td_set_ioc(&instance->tds[packet - 1]); 322 317 device_keeper_set_toggle(instance->manager, instance->target, toggle); 323 318 } … … 371 366 0, 1, false, low_speed, instance->target, status_stage, NULL, NULL); 372 367 373 374 instance->tds[packet].status |= TD_STATUS_IOC_FLAG; 368 td_set_ioc(&instance->tds[packet]); 375 369 usb_log_debug2("Control last TD status: %x.\n", 376 370 instance->tds[packet].status); … … 456 450 { 457 451 assert(instance); 458 uhci_ t *hc = fun_to_uhci(instance->fun);452 uhci_hc_t *hc = fun_to_uhci_hc(instance->fun); 459 453 assert(hc); 460 return uhci_ schedule(hc, instance);454 return uhci_hc_schedule(hc, instance); 461 455 } 462 456 /** -
uspace/drv/uhci-hcd/batch.h
r0f3e68c r335382d 50 50 usb_target_t target; 51 51 usb_transfer_type_t transfer_type; 52 union { 53 usbhc_iface_transfer_in_callback_t callback_in; 54 usbhc_iface_transfer_out_callback_t callback_out; 55 }; 52 usbhc_iface_transfer_in_callback_t callback_in; 53 usbhc_iface_transfer_out_callback_t callback_out; 56 54 void *arg; 57 55 char *transport_buffer; … … 65 63 int error; 66 64 ddf_fun_t *fun; 67 q ueue_head_t *qh;65 qh_t *qh; 68 66 td_t *tds; 69 67 void (*next_step)(struct batch*); -
uspace/drv/uhci-hcd/iface.c
r0f3e68c r335382d 40 40 41 41 #include "iface.h" 42 #include "uhci .h"42 #include "uhci_hc.h" 43 43 #include "utils/device_keeper.h" 44 44 … … 53 53 { 54 54 assert(fun); 55 uhci_ t *hc = fun_to_uhci(fun);55 uhci_hc_t *hc = fun_to_uhci_hc(fun); 56 56 assert(hc); 57 57 usb_log_debug("Default address request with speed %d.\n", speed); … … 68 68 { 69 69 assert(fun); 70 uhci_ t *hc = fun_to_uhci(fun);70 uhci_hc_t *hc = fun_to_uhci_hc(fun); 71 71 assert(hc); 72 72 usb_log_debug("Default address release.\n"); … … 86 86 { 87 87 assert(fun); 88 uhci_ t *hc = fun_to_uhci(fun);88 uhci_hc_t *hc = fun_to_uhci_hc(fun); 89 89 assert(hc); 90 90 assert(address); … … 109 109 { 110 110 assert(fun); 111 uhci_ t *hc = fun_to_uhci(fun);111 uhci_hc_t *hc = fun_to_uhci_hc(fun); 112 112 assert(hc); 113 113 usb_log_debug("Address bind %d-%d.\n", address, handle); … … 125 125 { 126 126 assert(fun); 127 uhci_ t *hc = fun_to_uhci(fun);127 uhci_hc_t *hc = fun_to_uhci_hc(fun); 128 128 assert(hc); 129 129 usb_log_debug("Address release %d.\n", address); … … 148 148 { 149 149 assert(fun); 150 uhci_ t *hc = fun_to_uhci(fun);150 uhci_hc_t *hc = fun_to_uhci_hc(fun); 151 151 assert(hc); 152 152 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); … … 180 180 { 181 181 assert(fun); 182 uhci_ t *hc = fun_to_uhci(fun);182 uhci_hc_t *hc = fun_to_uhci_hc(fun); 183 183 assert(hc); 184 184 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); … … 211 211 { 212 212 assert(fun); 213 uhci_ t *hc = fun_to_uhci(fun);213 uhci_hc_t *hc = fun_to_uhci_hc(fun); 214 214 assert(hc); 215 215 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); … … 243 243 { 244 244 assert(fun); 245 uhci_ t *hc = fun_to_uhci(fun);245 uhci_hc_t *hc = fun_to_uhci_hc(fun); 246 246 assert(hc); 247 247 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); … … 277 277 { 278 278 assert(fun); 279 uhci_ t *hc = fun_to_uhci(fun);279 uhci_hc_t *hc = fun_to_uhci_hc(fun); 280 280 assert(hc); 281 281 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); … … 315 315 { 316 316 assert(fun); 317 uhci_ t *hc = fun_to_uhci(fun);317 uhci_hc_t *hc = fun_to_uhci_hc(fun); 318 318 assert(hc); 319 319 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); … … 330 330 } 331 331 /*----------------------------------------------------------------------------*/ 332 usbhc_iface_t uhci_ iface = {332 usbhc_iface_t uhci_hc_iface = { 333 333 .reserve_default_address = reserve_default_address, 334 334 .release_default_address = release_default_address, -
uspace/drv/uhci-hcd/iface.h
r0f3e68c r335382d 38 38 #include <usbhc_iface.h> 39 39 40 extern usbhc_iface_t uhci_ iface;40 extern usbhc_iface_t uhci_hc_iface; 41 41 42 42 #endif -
uspace/drv/uhci-hcd/main.c
r0f3e68c r335382d 33 33 */ 34 34 #include <ddf/driver.h> 35 #include <ddf/interrupt.h>36 #include <device/hw_res.h>37 35 #include <errno.h> 38 36 #include <str_error.h> 39 37 40 #include <usb_iface.h>41 38 #include <usb/ddfiface.h> 42 39 #include <usb/debug.h> 43 40 44 41 #include "iface.h" 45 #include "pci.h"46 #include "root_hub.h"47 42 #include "uhci.h" 48 43 … … 60 55 }; 61 56 /*----------------------------------------------------------------------------*/ 62 /** IRQ handling callback, identifies devic 63 * 64 * @param[in] dev DDF instance of the device to use. 65 * @param[in] iid (Unused). 66 * @param[in] call Pointer to the call that represents interrupt. 67 */ 68 static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call) 69 { 70 assert(dev); 71 uhci_t *hc = dev_to_uhci(dev); 72 uint16_t status = IPC_GET_ARG1(*call); 73 assert(hc); 74 uhci_interrupt(hc, status); 75 } 76 /*----------------------------------------------------------------------------*/ 77 /** Initializes a new ddf driver instance of UHCI hcd. 57 /** Initializes a new ddf driver instance for uhci hc and hub. 78 58 * 79 59 * @param[in] device DDF instance of the device to initialize. … … 85 65 int uhci_add_device(ddf_dev_t *device) 86 66 { 67 usb_log_info("uhci_add_device() called\n"); 87 68 assert(device); 88 uhci_t *hcd = NULL; 89 #define CHECK_RET_FREE_HC_RETURN(ret, message...) \ 90 if (ret != EOK) { \ 91 usb_log_error(message); \ 92 if (hcd != NULL) \ 93 free(hcd); \ 94 return ret; \ 95 } 69 uhci_t *uhci = malloc(sizeof(uhci_t)); 70 if (uhci == NULL) { 71 usb_log_error("Failed to allocate UHCI driver.\n"); 72 return ENOMEM; 73 } 96 74 97 usb_log_info("uhci_add_device() called\n"); 98 99 uintptr_t io_reg_base = 0; 100 size_t io_reg_size = 0; 101 int irq = 0; 102 103 int ret = 104 pci_get_my_registers(device, &io_reg_base, &io_reg_size, &irq); 105 CHECK_RET_FREE_HC_RETURN(ret, 106 "Failed(%d) to get I/O addresses:.\n", ret, device->handle); 107 usb_log_info("I/O regs at 0x%X (size %zu), IRQ %d.\n", 108 io_reg_base, io_reg_size, irq); 109 110 ret = pci_disable_legacy(device); 111 CHECK_RET_FREE_HC_RETURN(ret, 112 "Failed(%d) to disable legacy USB: %s.\n", ret, str_error(ret)); 113 114 #if 0 115 ret = pci_enable_interrupts(device); 75 int ret = uhci_init(uhci, device); 116 76 if (ret != EOK) { 117 usb_log_warning( 118 "Failed(%d) to enable interrupts, fall back to polling.\n", 119 ret); 77 usb_log_error("Failed to initialzie UHCI driver.\n"); 78 return ret; 120 79 } 121 #endif 122 123 hcd = malloc(sizeof(uhci_t)); 124 ret = (hcd != NULL) ? EOK : ENOMEM; 125 CHECK_RET_FREE_HC_RETURN(ret, 126 "Failed(%d) to allocate memory for uhci hcd.\n", ret); 127 128 ret = uhci_init(hcd, device, (void*)io_reg_base, io_reg_size); 129 CHECK_RET_FREE_HC_RETURN(ret, "Failed(%d) to init uhci-hcd.\n", ret); 130 #undef CHECK_RET_FREE_HC_RETURN 131 132 /* 133 * We might free hcd, but that does not matter since no one 134 * else would access driver_data anyway. 135 */ 136 device->driver_data = hcd; 137 138 ddf_fun_t *rh = NULL; 139 #define CHECK_RET_FINI_FREE_RETURN(ret, message...) \ 140 if (ret != EOK) { \ 141 usb_log_error(message); \ 142 if (hcd != NULL) {\ 143 uhci_fini(hcd); \ 144 free(hcd); \ 145 } \ 146 if (rh != NULL) \ 147 free(rh); \ 148 return ret; \ 149 } 150 151 /* It does no harm if we register this on polling */ 152 ret = register_interrupt_handler(device, irq, irq_handler, 153 &hcd->interrupt_code); 154 CHECK_RET_FINI_FREE_RETURN(ret, 155 "Failed(%d) to register interrupt handler.\n", ret); 156 157 ret = setup_root_hub(&rh, device); 158 CHECK_RET_FINI_FREE_RETURN(ret, 159 "Failed(%d) to setup UHCI root hub.\n", ret); 160 rh->driver_data = hcd->ddf_instance; 161 162 ret = ddf_fun_bind(rh); 163 CHECK_RET_FINI_FREE_RETURN(ret, 164 "Failed(%d) to register UHCI root hub.\n", ret); 165 80 device->driver_data = uhci; 166 81 return EOK; 167 #undef CHECK_RET_FINI_FREE_RETURN168 82 } 169 83 /*----------------------------------------------------------------------------*/ -
uspace/drv/uhci-hcd/transfer_list.c
r0f3e68c r335382d 47 47 * @return Error code 48 48 * 49 * Allocates memory for interna t queue_head_t structure.49 * Allocates memory for internal qh_t structure. 50 50 */ 51 51 int transfer_list_init(transfer_list_t *instance, const char *name) 52 52 { 53 53 assert(instance); 54 instance->next = NULL;55 54 instance->name = name; 56 instance->queue_head = malloc32(sizeof(q ueue_head_t));55 instance->queue_head = malloc32(sizeof(qh_t)); 57 56 if (!instance->queue_head) { 58 57 usb_log_error("Failed to allocate queue head.\n"); … … 61 60 instance->queue_head_pa = addr_to_phys(instance->queue_head); 62 61 63 q ueue_head_init(instance->queue_head);62 qh_init(instance->queue_head); 64 63 list_initialize(&instance->batch_list); 65 64 fibril_mutex_initialize(&instance->guard); … … 72 71 * @param[in] next List to append. 73 72 * @return Error code 73 * 74 * Does not check whether there was a next list already. 74 75 */ 75 76 void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next) … … 79 80 if (!instance->queue_head) 80 81 return; 81 queue_head_append_qh(instance->queue_head, next->queue_head_pa); 82 instance->queue_head->element = instance->queue_head->next_queue; 82 /* set both next and element to point to the same QH */ 83 qh_set_next_qh(instance->queue_head, next->queue_head_pa); 84 qh_set_element_qh(instance->queue_head, next->queue_head_pa); 83 85 } 84 86 /*----------------------------------------------------------------------------*/ … … 93 95 assert(instance); 94 96 assert(batch); 95 usb_log_debug2( 96 "Adding batch(%p) to queue %s.\n", batch, instance->name); 97 usb_log_debug2("Queue %s: Adding batch(%p).\n", instance->name, batch); 97 98 98 uint32_t pa = (uintptr_t)addr_to_phys(batch->qh);99 const uint32_t pa = addr_to_phys(batch->qh); 99 100 assert((pa & LINK_POINTER_ADDRESS_MASK) == pa); 100 pa |= LINK_POINTER_QUEUE_HEAD_FLAG;101 101 102 batch->qh->next_queue = instance->queue_head->next_queue; 102 /* New batch will be added to the end of the current list 103 * so set the link accordingly */ 104 qh_set_next_qh(batch->qh, instance->queue_head->next); 103 105 104 106 fibril_mutex_lock(&instance->guard); 105 107 106 if (instance->queue_head->element == instance->queue_head->next_queue) { 107 /* there is nothing scheduled */ 108 list_append(&batch->link, &instance->batch_list); 109 instance->queue_head->element = pa; 110 usb_log_debug("Batch(%p) added to queue %s first.\n", 111 batch, instance->name); 112 fibril_mutex_unlock(&instance->guard); 113 return; 108 if (list_empty(&instance->batch_list)) { 109 /* There is nothing scheduled */ 110 qh_t *qh = instance->queue_head; 111 assert(qh->element == qh->next); 112 qh_set_element_qh(qh, pa); 113 } else { 114 /* There is something scheduled */ 115 batch_t *last = list_get_instance( 116 instance->batch_list.prev, batch_t, link); 117 qh_set_next_qh(last->qh, pa); 114 118 } 115 /* now we can be sure that there is someting scheduled */116 assert(!list_empty(&instance->batch_list));117 batch_t *first = list_get_instance(118 instance->batch_list.next, batch_t, link);119 batch_t *last = list_get_instance(120 instance->batch_list.prev, batch_t, link);121 queue_head_append_qh(last->qh, pa);122 119 list_append(&batch->link, &instance->batch_list); 123 120 124 usb_log_debug("Batch(%p) added to queue %s last, first is %p.\n", 121 batch_t *first = list_get_instance( 122 instance->batch_list.next, batch_t, link); 123 usb_log_debug("Batch(%p) added to queue %s, first is %p.\n", 125 124 batch, instance->name, first); 126 125 fibril_mutex_unlock(&instance->guard); 127 126 } 128 127 /*----------------------------------------------------------------------------*/ 129 /** Removes a transfer batch from list and queue.128 /** Removes a transfer batch from the list and queue. 130 129 * 131 130 * @param[in] instance List to use. 132 131 * @param[in] batch Transfer batch to remove. 133 132 * @return Error code 133 * 134 * Does not lock the transfer list, caller is responsible for that. 134 135 */ 135 136 void transfer_list_remove_batch(transfer_list_t *instance, batch_t *batch) … … 140 141 assert(batch->qh); 141 142 usb_log_debug2( 142 " Removing batch(%p) from queue %s.\n", batch, instance->name);143 "Queue %s: removing batch(%p).\n", instance->name, batch); 143 144 145 const char * pos = NULL; 144 146 if (batch->link.prev == &instance->batch_list) { 145 147 /* I'm the first one here */ 146 usb_log_debug( 147 "Batch(%p) removed (FIRST) from %s, next element %x.\n", 148 batch, instance->name, batch->qh->next_queue); 149 instance->queue_head->element = batch->qh->next_queue; 148 qh_set_element_qh(instance->queue_head, batch->qh->next); 149 pos = "FIRST"; 150 150 } else { 151 usb_log_debug(152 "Batch(%p) removed (FIRST:NO) from %s, next element %x.\n",153 batch, instance->name, batch->qh->next_queue);154 151 batch_t *prev = 155 152 list_get_instance(batch->link.prev, batch_t, link); 156 prev->qh->next_queue = batch->qh->next_queue; 153 qh_set_next_qh(prev->qh, batch->qh->next); 154 pos = "NOT FIRST"; 157 155 } 158 156 list_remove(&batch->link); 157 usb_log_debug("Batch(%p) removed (%s) from %s, next element %x.\n", 158 batch, pos, instance->name, batch->qh->next); 159 159 } 160 160 /*----------------------------------------------------------------------------*/ 161 /** Checks list for finished transfers.161 /** Checks list for finished batches. 162 162 * 163 163 * @param[in] instance List to use. -
uspace/drv/uhci-hcd/transfer_list.h
r0f3e68c r335382d 44 44 { 45 45 fibril_mutex_t guard; 46 q ueue_head_t *queue_head;46 qh_t *queue_head; 47 47 uint32_t queue_head_pa; 48 struct transfer_list *next;49 48 const char *name; 50 49 link_t batch_list; -
uspace/drv/uhci-hcd/uhci.c
r0f3e68c r335382d 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 /** @addtogroup usb 28 29 /** @addtogroup drvusbuhci 29 30 * @{ 30 31 */ … … 34 35 #include <errno.h> 35 36 #include <str_error.h> 36 #include < adt/list.h>37 #include < libarch/ddi.h>38 37 #include <ddf/interrupt.h> 38 #include <usb_iface.h> 39 #include <usb/ddfiface.h> 39 40 #include <usb/debug.h> 40 #include <usb/usb.h>41 #include <usb/ddfiface.h>42 #include <usb_iface.h>43 41 44 42 #include "uhci.h" 45 43 #include "iface.h" 46 47 static irq_cmd_t uhci_cmds[] = { 48 { 49 .cmd = CMD_PIO_READ_16, 50 .addr = NULL, /* patched for every instance */ 51 .dstarg = 1 52 }, 53 { 54 .cmd = CMD_PIO_WRITE_16, 55 .addr = NULL, /* pathed for every instance */ 56 .value = 0x1f 57 }, 58 { 59 .cmd = CMD_ACCEPT 60 } 61 }; 62 63 /** Gets USB address of the calling device. 64 * 65 * @param[in] fun UHCI hc function. 66 * @param[in] handle Handle of the device seeking address. 67 * @param[out] address Place to store found address. 68 * @return Error code. 69 */ 44 #include "pci.h" 45 46 47 /** IRQ handling callback, identifies device 48 * 49 * @param[in] dev DDF instance of the device to use. 50 * @param[in] iid (Unused). 51 * @param[in] call Pointer to the call that represents interrupt. 52 */ 53 static void irq_handler(ddf_dev_t *dev, ipc_callid_t iid, ipc_call_t *call) 54 { 55 assert(dev); 56 uhci_hc_t *hc = &((uhci_t*)dev->driver_data)->hc; 57 uint16_t status = IPC_GET_ARG1(*call); 58 assert(hc); 59 uhci_hc_interrupt(hc, status); 60 } 61 /*----------------------------------------------------------------------------*/ 70 62 static int usb_iface_get_address( 71 63 ddf_fun_t *fun, devman_handle_t handle, usb_address_t *address) 72 64 { 73 65 assert(fun); 74 uhci_t *hc = fun_to_uhci(fun); 75 assert(hc); 76 77 usb_address_t addr = device_keeper_find(&hc->device_manager, 78 handle); 66 device_keeper_t *manager = &((uhci_t*)fun->dev->driver_data)->hc.device_manager; 67 68 usb_address_t addr = device_keeper_find(manager, handle); 79 69 if (addr < 0) { 80 70 return addr; … … 88 78 } 89 79 /*----------------------------------------------------------------------------*/ 90 static usb_iface_t hc_usb_iface = { 91 .get_hc_handle = usb_iface_get_hc_handle_hc_impl, 80 /** Gets handle of the respective hc (this or parent device). 81 * 82 * @param[in] root_hub_fun Root hub function seeking hc handle. 83 * @param[out] handle Place to write the handle. 84 * @return Error code. 85 */ 86 static int usb_iface_get_hc_handle( 87 ddf_fun_t *fun, devman_handle_t *handle) 88 { 89 assert(handle); 90 ddf_fun_t *hc_fun = ((uhci_t*)fun->dev->driver_data)->hc_fun; 91 assert(hc_fun != NULL); 92 93 *handle = hc_fun->handle; 94 return EOK; 95 } 96 /*----------------------------------------------------------------------------*/ 97 /** This iface is generic for both RH and HC. */ 98 static usb_iface_t usb_iface = { 99 .get_hc_handle = usb_iface_get_hc_handle, 92 100 .get_address = usb_iface_get_address 93 101 }; 94 102 /*----------------------------------------------------------------------------*/ 95 static ddf_dev_ops_t uhci_ops = { 96 .interfaces[USB_DEV_IFACE] = &hc_usb_iface, 97 .interfaces[USBHC_DEV_IFACE] = &uhci_iface, 98 }; 99 /*----------------------------------------------------------------------------*/ 100 static int uhci_init_transfer_lists(uhci_t *instance); 101 static int uhci_init_mem_structures(uhci_t *instance); 102 static void uhci_init_hw(uhci_t *instance); 103 104 static int uhci_interrupt_emulator(void *arg); 105 static int uhci_debug_checker(void *arg); 106 107 static bool allowed_usb_packet( 108 bool low_speed, usb_transfer_type_t transfer, size_t size); 109 /*----------------------------------------------------------------------------*/ 110 /** Initializes UHCI hcd driver structure 111 * 112 * @param[in] instance Memory place to initialize. 113 * @param[in] dev DDF device. 114 * @param[in] regs Address of I/O control registers. 115 * @param[in] size Size of I/O control registers. 116 * @return Error code. 117 * @note Should be called only once on any structure. 118 */ 119 int uhci_init(uhci_t *instance, ddf_dev_t *dev, void *regs, size_t reg_size) 120 { 121 assert(reg_size >= sizeof(regs_t)); 122 int ret; 123 103 static ddf_dev_ops_t uhci_hc_ops = { 104 .interfaces[USB_DEV_IFACE] = &usb_iface, 105 .interfaces[USBHC_DEV_IFACE] = &uhci_hc_iface, /* see iface.h/c */ 106 }; 107 /*----------------------------------------------------------------------------*/ 108 /** Gets root hub hw resources. 109 * 110 * @param[in] fun Root hub function. 111 * @return Pointer to the resource list used by the root hub. 112 */ 113 static hw_resource_list_t *get_resource_list(ddf_fun_t *fun) 114 { 115 assert(fun); 116 return &((uhci_rh_t*)fun->driver_data)->resource_list; 117 } 118 /*----------------------------------------------------------------------------*/ 119 static hw_res_ops_t hw_res_iface = { 120 .get_resource_list = get_resource_list, 121 .enable_interrupt = NULL 122 }; 123 /*----------------------------------------------------------------------------*/ 124 static ddf_dev_ops_t uhci_rh_ops = { 125 .interfaces[USB_DEV_IFACE] = &usb_iface, 126 .interfaces[HW_RES_DEV_IFACE] = &hw_res_iface 127 }; 128 /*----------------------------------------------------------------------------*/ 129 int uhci_init(uhci_t *instance, ddf_dev_t *device) 130 { 131 assert(instance); 132 instance->hc_fun = NULL; 133 instance->rh_fun = NULL; 124 134 #define CHECK_RET_DEST_FUN_RETURN(ret, message...) \ 125 if (ret != EOK) { \ 126 usb_log_error(message); \ 127 if (instance->ddf_instance) \ 128 ddf_fun_destroy(instance->ddf_instance); \ 129 return ret; \ 130 } else (void) 0 131 132 /* Create UHCI function. */ 133 instance->ddf_instance = ddf_fun_create(dev, fun_exposed, "uhci"); 134 ret = (instance->ddf_instance == NULL) ? ENOMEM : EOK; 135 if (ret != EOK) { \ 136 usb_log_error(message); \ 137 if (instance->hc_fun) \ 138 ddf_fun_destroy(instance->hc_fun); \ 139 if (instance->rh_fun) \ 140 ddf_fun_destroy(instance->rh_fun); \ 141 return ret; \ 142 } 143 144 uintptr_t io_reg_base = 0; 145 size_t io_reg_size = 0; 146 int irq = 0; 147 148 int ret = 149 pci_get_my_registers(device, &io_reg_base, &io_reg_size, &irq); 135 150 CHECK_RET_DEST_FUN_RETURN(ret, 136 "Failed to create UHCI device function.\n"); 137 138 instance->ddf_instance->ops = &uhci_ops; 139 instance->ddf_instance->driver_data = instance; 140 141 ret = ddf_fun_bind(instance->ddf_instance); 151 "Failed(%d) to get I/O addresses:.\n", ret, device->handle); 152 usb_log_info("I/O regs at 0x%X (size %zu), IRQ %d.\n", 153 io_reg_base, io_reg_size, irq); 154 155 ret = pci_disable_legacy(device); 156 CHECK_RET_DEST_FUN_RETURN(ret, 157 "Failed(%d) to disable legacy USB: %s.\n", ret, str_error(ret)); 158 159 #if 0 160 ret = pci_enable_interrupts(device); 161 if (ret != EOK) { 162 usb_log_warning( 163 "Failed(%d) to enable interrupts, fall back to polling.\n", 164 ret); 165 } 166 #endif 167 168 instance->hc_fun = ddf_fun_create(device, fun_exposed, "uhci-hc"); 169 ret = (instance->hc_fun == NULL) ? ENOMEM : EOK; 170 CHECK_RET_DEST_FUN_RETURN(ret, "Failed(%d) to create HC function.\n", ret); 171 172 ret = uhci_hc_init( 173 &instance->hc, instance->hc_fun, (void*)io_reg_base, io_reg_size); 174 CHECK_RET_DEST_FUN_RETURN(ret, "Failed(%d) to init uhci-hcd.\n", ret); 175 instance->hc_fun->ops = &uhci_hc_ops; 176 instance->hc_fun->driver_data = &instance->hc; 177 ret = ddf_fun_bind(instance->hc_fun); 142 178 CHECK_RET_DEST_FUN_RETURN(ret, 143 179 "Failed(%d) to bind UHCI device function: %s.\n", 144 180 ret, str_error(ret)); 145 146 /* allow access to hc control registers */ 147 regs_t *io; 148 ret = pio_enable(regs, reg_size, (void**)&io); 149 CHECK_RET_DEST_FUN_RETURN(ret, 150 "Failed(%d) to gain access to registers at %p: %s.\n", 151 ret, str_error(ret), io); 152 instance->registers = io; 153 usb_log_debug("Device registers at %p(%u) accessible.\n", 154 io, reg_size); 155 156 ret = uhci_init_mem_structures(instance); 157 CHECK_RET_DEST_FUN_RETURN(ret, 158 "Failed to initialize UHCI memory structures.\n"); 159 160 uhci_init_hw(instance); 161 instance->cleaner = 162 fibril_create(uhci_interrupt_emulator, instance); 163 fibril_add_ready(instance->cleaner); 164 165 instance->debug_checker = fibril_create(uhci_debug_checker, instance); 166 fibril_add_ready(instance->debug_checker); 167 168 usb_log_info("Started UHCI driver.\n"); 181 #undef CHECK_RET_HC_RETURN 182 183 #define CHECK_RET_FINI_RETURN(ret, message...) \ 184 if (ret != EOK) { \ 185 usb_log_error(message); \ 186 if (instance->hc_fun) \ 187 ddf_fun_destroy(instance->hc_fun); \ 188 if (instance->rh_fun) \ 189 ddf_fun_destroy(instance->rh_fun); \ 190 uhci_hc_fini(&instance->hc); \ 191 return ret; \ 192 } 193 194 /* It does no harm if we register this on polling */ 195 ret = register_interrupt_handler(device, irq, irq_handler, 196 &instance->hc.interrupt_code); 197 CHECK_RET_FINI_RETURN(ret, 198 "Failed(%d) to register interrupt handler.\n", ret); 199 200 instance->rh_fun = ddf_fun_create(device, fun_inner, "uhci-rh"); 201 ret = (instance->rh_fun == NULL) ? ENOMEM : EOK; 202 CHECK_RET_FINI_RETURN(ret, 203 "Failed(%d) to create root hub function.\n", ret); 204 205 ret = uhci_rh_init(&instance->rh, instance->rh_fun, 206 (uintptr_t)instance->hc.registers + 0x10, 4); 207 CHECK_RET_FINI_RETURN(ret, 208 "Failed(%d) to setup UHCI root hub.\n", ret); 209 210 instance->rh_fun->ops = &uhci_rh_ops; 211 instance->rh_fun->driver_data = &instance->rh; 212 ret = ddf_fun_bind(instance->rh_fun); 213 CHECK_RET_FINI_RETURN(ret, 214 "Failed(%d) to register UHCI root hub.\n", ret); 215 169 216 return EOK; 170 #undef CHECK_RET_DEST_FUN_RETURN 171 } 172 /*----------------------------------------------------------------------------*/ 173 /** Initializes UHCI hcd hw resources. 174 * 175 * @param[in] instance UHCI structure to use. 176 */ 177 void uhci_init_hw(uhci_t *instance) 178 { 179 assert(instance); 180 regs_t *registers = instance->registers; 181 182 /* Reset everything, who knows what touched it before us */ 183 pio_write_16(®isters->usbcmd, UHCI_CMD_GLOBAL_RESET); 184 async_usleep(10000); /* 10ms according to USB spec */ 185 pio_write_16(®isters->usbcmd, 0); 186 187 /* Reset hc, all states and counters */ 188 pio_write_16(®isters->usbcmd, UHCI_CMD_HCRESET); 189 do { async_usleep(10); } 190 while ((pio_read_16(®isters->usbcmd) & UHCI_CMD_HCRESET) != 0); 191 192 /* Set framelist pointer */ 193 const uint32_t pa = addr_to_phys(instance->frame_list); 194 pio_write_32(®isters->flbaseadd, pa); 195 196 /* Enable all interrupts, but resume interrupt */ 197 // pio_write_16(&instance->registers->usbintr, 198 // UHCI_INTR_CRC | UHCI_INTR_COMPLETE | UHCI_INTR_SHORT_PACKET); 199 200 uint16_t status = pio_read_16(®isters->usbcmd); 201 if (status != 0) 202 usb_log_warning("Previous command value: %x.\n", status); 203 204 /* Start the hc with large(64B) packet FSBR */ 205 pio_write_16(®isters->usbcmd, 206 UHCI_CMD_RUN_STOP | UHCI_CMD_MAX_PACKET | UHCI_CMD_CONFIGURE); 207 } 208 /*----------------------------------------------------------------------------*/ 209 /** Initializes UHCI hcd memory structures. 210 * 211 * @param[in] instance UHCI structure to use. 212 * @return Error code 213 * @note Should be called only once on any structure. 214 */ 215 int uhci_init_mem_structures(uhci_t *instance) 216 { 217 assert(instance); 218 #define CHECK_RET_DEST_CMDS_RETURN(ret, message...) \ 219 if (ret != EOK) { \ 220 usb_log_error(message); \ 221 if (instance->interrupt_code.cmds != NULL) \ 222 free(instance->interrupt_code.cmds); \ 223 return ret; \ 224 } else (void) 0 225 226 /* Init interrupt code */ 227 instance->interrupt_code.cmds = malloc(sizeof(uhci_cmds)); 228 int ret = (instance->interrupt_code.cmds == NULL) ? ENOMEM : EOK; 229 CHECK_RET_DEST_CMDS_RETURN(ret, 230 "Failed to allocate interrupt cmds space.\n"); 231 232 { 233 irq_cmd_t *interrupt_commands = instance->interrupt_code.cmds; 234 memcpy(interrupt_commands, uhci_cmds, sizeof(uhci_cmds)); 235 interrupt_commands[0].addr = 236 (void*)&instance->registers->usbsts; 237 interrupt_commands[1].addr = 238 (void*)&instance->registers->usbsts; 239 instance->interrupt_code.cmdcount = 240 sizeof(uhci_cmds) / sizeof(irq_cmd_t); 241 } 242 243 /* Init transfer lists */ 244 ret = uhci_init_transfer_lists(instance); 245 CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to init transfer lists.\n"); 246 usb_log_debug("Initialized transfer lists.\n"); 247 248 /* Init USB frame list page*/ 249 instance->frame_list = get_page(); 250 ret = instance ? EOK : ENOMEM; 251 CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to get frame list page.\n"); 252 usb_log_debug("Initialized frame list.\n"); 253 254 /* Set all frames to point to the first queue head */ 255 const uint32_t queue = 256 instance->transfers_interrupt.queue_head_pa 257 | LINK_POINTER_QUEUE_HEAD_FLAG; 258 259 unsigned i = 0; 260 for(; i < UHCI_FRAME_LIST_COUNT; ++i) { 261 instance->frame_list[i] = queue; 262 } 263 264 /* Init device keeper*/ 265 device_keeper_init(&instance->device_manager); 266 usb_log_debug("Initialized device manager.\n"); 267 268 return EOK; 269 #undef CHECK_RET_DEST_CMDS_RETURN 270 } 271 /*----------------------------------------------------------------------------*/ 272 /** Initializes UHCI hcd transfer lists. 273 * 274 * @param[in] instance UHCI structure to use. 275 * @return Error code 276 * @note Should be called only once on any structure. 277 */ 278 int uhci_init_transfer_lists(uhci_t *instance) 279 { 280 assert(instance); 281 #define CHECK_RET_CLEAR_RETURN(ret, message...) \ 282 if (ret != EOK) { \ 283 usb_log_error(message); \ 284 transfer_list_fini(&instance->transfers_bulk_full); \ 285 transfer_list_fini(&instance->transfers_control_full); \ 286 transfer_list_fini(&instance->transfers_control_slow); \ 287 transfer_list_fini(&instance->transfers_interrupt); \ 288 return ret; \ 289 } else (void) 0 290 291 /* initialize TODO: check errors */ 292 int ret; 293 ret = transfer_list_init(&instance->transfers_bulk_full, "BULK_FULL"); 294 CHECK_RET_CLEAR_RETURN(ret, "Failed to init BULK list."); 295 296 ret = transfer_list_init( 297 &instance->transfers_control_full, "CONTROL_FULL"); 298 CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL FULL list."); 299 300 ret = transfer_list_init( 301 &instance->transfers_control_slow, "CONTROL_SLOW"); 302 CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL SLOW list."); 303 304 ret = transfer_list_init(&instance->transfers_interrupt, "INTERRUPT"); 305 CHECK_RET_CLEAR_RETURN(ret, "Failed to init INTERRUPT list."); 306 307 transfer_list_set_next(&instance->transfers_control_full, 308 &instance->transfers_bulk_full); 309 transfer_list_set_next(&instance->transfers_control_slow, 310 &instance->transfers_control_full); 311 transfer_list_set_next(&instance->transfers_interrupt, 312 &instance->transfers_control_slow); 313 314 /*FSBR*/ 315 #ifdef FSBR 316 transfer_list_set_next(&instance->transfers_bulk_full, 317 &instance->transfers_control_full); 318 #endif 319 320 /* Assign pointers to be used during scheduling */ 321 instance->transfers[USB_SPEED_FULL][USB_TRANSFER_INTERRUPT] = 322 &instance->transfers_interrupt; 323 instance->transfers[USB_SPEED_LOW][USB_TRANSFER_INTERRUPT] = 324 &instance->transfers_interrupt; 325 instance->transfers[USB_SPEED_FULL][USB_TRANSFER_CONTROL] = 326 &instance->transfers_control_full; 327 instance->transfers[USB_SPEED_LOW][USB_TRANSFER_CONTROL] = 328 &instance->transfers_control_slow; 329 instance->transfers[USB_SPEED_FULL][USB_TRANSFER_BULK] = 330 &instance->transfers_bulk_full; 331 332 return EOK; 333 #undef CHECK_RET_CLEAR_RETURN 334 } 335 /*----------------------------------------------------------------------------*/ 336 /** Schedules batch for execution. 337 * 338 * @param[in] instance UHCI structure to use. 339 * @param[in] batch Transfer batch to schedule. 340 * @return Error code 341 */ 342 int uhci_schedule(uhci_t *instance, batch_t *batch) 343 { 344 assert(instance); 345 assert(batch); 346 const int low_speed = (batch->speed == USB_SPEED_LOW); 347 if (!allowed_usb_packet( 348 low_speed, batch->transfer_type, batch->max_packet_size)) { 349 usb_log_warning( 350 "Invalid USB packet specified %s SPEED %d %zu.\n", 351 low_speed ? "LOW" : "FULL" , batch->transfer_type, 352 batch->max_packet_size); 353 return ENOTSUP; 354 } 355 /* TODO: check available bandwith here */ 356 357 transfer_list_t *list = 358 instance->transfers[batch->speed][batch->transfer_type]; 359 assert(list); 360 transfer_list_add_batch(list, batch); 361 362 return EOK; 363 } 364 /*----------------------------------------------------------------------------*/ 365 /** Takes action based on the interrupt cause. 366 * 367 * @param[in] instance UHCI structure to use. 368 * @param[in] status Value of the stsatus regiser at the time of interrupt. 369 */ 370 void uhci_interrupt(uhci_t *instance, uint16_t status) 371 { 372 assert(instance); 373 /* TODO: Check interrupt cause here */ 374 /* Lower 2 bits are transaction error and transaction complete */ 375 if (status & 0x3) { 376 transfer_list_remove_finished(&instance->transfers_interrupt); 377 transfer_list_remove_finished(&instance->transfers_control_slow); 378 transfer_list_remove_finished(&instance->transfers_control_full); 379 transfer_list_remove_finished(&instance->transfers_bulk_full); 380 } 381 } 382 /*----------------------------------------------------------------------------*/ 383 /** Polling function, emulates interrupts. 384 * 385 * @param[in] arg UHCI structure to use. 386 * @return EOK 387 */ 388 int uhci_interrupt_emulator(void* arg) 389 { 390 usb_log_debug("Started interrupt emulator.\n"); 391 uhci_t *instance = (uhci_t*)arg; 392 assert(instance); 393 394 while (1) { 395 /* read and ack interrupts */ 396 uint16_t status = pio_read_16(&instance->registers->usbsts); 397 pio_write_16(&instance->registers->usbsts, 0x1f); 398 if (status != 0) 399 usb_log_debug2("UHCI status: %x.\n", status); 400 uhci_interrupt(instance, status); 401 async_usleep(UHCI_CLEANER_TIMEOUT); 402 } 403 return EOK; 404 } 405 /*---------------------------------------------------------------------------*/ 406 /** Debug function, checks consistency of memory structures. 407 * 408 * @param[in] arg UHCI structure to use. 409 * @return EOK 410 */ 411 int uhci_debug_checker(void *arg) 412 { 413 uhci_t *instance = (uhci_t*)arg; 414 assert(instance); 415 416 #define QH(queue) \ 417 instance->transfers_##queue.queue_head 418 419 while (1) { 420 const uint16_t cmd = pio_read_16(&instance->registers->usbcmd); 421 const uint16_t sts = pio_read_16(&instance->registers->usbsts); 422 const uint16_t intr = 423 pio_read_16(&instance->registers->usbintr); 424 425 if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) { 426 usb_log_debug2("Command: %X Status: %X Intr: %x\n", 427 cmd, sts, intr); 428 } 429 430 uintptr_t frame_list = 431 pio_read_32(&instance->registers->flbaseadd) & ~0xfff; 432 if (frame_list != addr_to_phys(instance->frame_list)) { 433 usb_log_debug("Framelist address: %p vs. %p.\n", 434 frame_list, addr_to_phys(instance->frame_list)); 435 } 436 437 int frnum = pio_read_16(&instance->registers->frnum) & 0x3ff; 438 439 uintptr_t expected_pa = instance->frame_list[frnum] & (~0xf); 440 uintptr_t real_pa = addr_to_phys(QH(interrupt)); 441 if (expected_pa != real_pa) { 442 usb_log_debug("Interrupt QH: %p(frame: %d) vs. %p.\n", 443 expected_pa, frnum, real_pa); 444 } 445 446 expected_pa = QH(interrupt)->next_queue & (~0xf); 447 real_pa = addr_to_phys(QH(control_slow)); 448 if (expected_pa != real_pa) { 449 usb_log_debug("Control Slow QH: %p vs. %p.\n", 450 expected_pa, real_pa); 451 } 452 453 expected_pa = QH(control_slow)->next_queue & (~0xf); 454 real_pa = addr_to_phys(QH(control_full)); 455 if (expected_pa != real_pa) { 456 usb_log_debug("Control Full QH: %p vs. %p.\n", 457 expected_pa, real_pa); 458 } 459 460 expected_pa = QH(control_full)->next_queue & (~0xf); 461 real_pa = addr_to_phys(QH(bulk_full)); 462 if (expected_pa != real_pa ) { 463 usb_log_debug("Bulk QH: %p vs. %p.\n", 464 expected_pa, real_pa); 465 } 466 async_usleep(UHCI_DEBUGER_TIMEOUT); 467 } 468 return EOK; 469 #undef QH 470 } 471 /*----------------------------------------------------------------------------*/ 472 /** Checks transfer packets, for USB validity 473 * 474 * @param[in] low_speed Transfer speed. 475 * @param[in] transfer Transer type 476 * @param[in] size Maximum size of used packets 477 * @return EOK 478 */ 479 bool allowed_usb_packet( 480 bool low_speed, usb_transfer_type_t transfer, size_t size) 481 { 482 /* see USB specification chapter 5.5-5.8 for magic numbers used here */ 483 switch(transfer) 484 { 485 case USB_TRANSFER_ISOCHRONOUS: 486 return (!low_speed && size < 1024); 487 case USB_TRANSFER_INTERRUPT: 488 return size <= (low_speed ? 8 : 64); 489 case USB_TRANSFER_CONTROL: /* device specifies its own max size */ 490 return (size <= (low_speed ? 8 : 64)); 491 case USB_TRANSFER_BULK: /* device specifies its own max size */ 492 return (!low_speed && size <= 64); 493 } 494 return false; 495 } 217 #undef CHECK_RET_FINI_RETURN 218 } 219 496 220 /** 497 221 * @} -
uspace/drv/uhci-hcd/uhci.h
r0f3e68c r335382d 1 1 /* 2 * Copyright (c) 201 0Jan Vesely2 * Copyright (c) 2011 Jan Vesely 3 3 * All rights reserved. 4 4 * … … 35 35 #ifndef DRV_UHCI_UHCI_H 36 36 #define DRV_UHCI_UHCI_H 37 #include <ddi.h> 38 #include <ddf/driver.h> 37 39 38 #include <fibril.h> 39 #include <fibril_synch.h> 40 #include <adt/list.h> 41 #include <ddi.h> 42 43 #include <usbhc_iface.h> 44 45 #include "batch.h" 46 #include "transfer_list.h" 47 #include "utils/device_keeper.h" 48 49 typedef struct uhci_regs { 50 uint16_t usbcmd; 51 #define UHCI_CMD_MAX_PACKET (1 << 7) 52 #define UHCI_CMD_CONFIGURE (1 << 6) 53 #define UHCI_CMD_DEBUG (1 << 5) 54 #define UHCI_CMD_FORCE_GLOBAL_RESUME (1 << 4) 55 #define UHCI_CMD_FORCE_GLOBAL_SUSPEND (1 << 3) 56 #define UHCI_CMD_GLOBAL_RESET (1 << 2) 57 #define UHCI_CMD_HCRESET (1 << 1) 58 #define UHCI_CMD_RUN_STOP (1 << 0) 59 60 uint16_t usbsts; 61 #define UHCI_STATUS_HALTED (1 << 5) 62 #define UHCI_STATUS_PROCESS_ERROR (1 << 4) 63 #define UHCI_STATUS_SYSTEM_ERROR (1 << 3) 64 #define UHCI_STATUS_RESUME (1 << 2) 65 #define UHCI_STATUS_ERROR_INTERRUPT (1 << 1) 66 #define UHCI_STATUS_INTERRUPT (1 << 0) 67 68 uint16_t usbintr; 69 #define UHCI_INTR_SHORT_PACKET (1 << 3) 70 #define UHCI_INTR_COMPLETE (1 << 2) 71 #define UHCI_INTR_RESUME (1 << 1) 72 #define UHCI_INTR_CRC (1 << 0) 73 74 uint16_t frnum; 75 uint32_t flbaseadd; 76 uint8_t sofmod; 77 } regs_t; 78 79 #define UHCI_FRAME_LIST_COUNT 1024 80 #define UHCI_CLEANER_TIMEOUT 10000 81 #define UHCI_DEBUGER_TIMEOUT 5000000 40 #include "uhci_hc.h" 41 #include "uhci_rh.h" 82 42 83 43 typedef struct uhci { 84 device_keeper_t device_manager; 44 ddf_fun_t *hc_fun; 45 ddf_fun_t *rh_fun; 85 46 86 regs_t *registers; 87 88 link_pointer_t *frame_list; 89 90 transfer_list_t transfers_bulk_full; 91 transfer_list_t transfers_control_full; 92 transfer_list_t transfers_control_slow; 93 transfer_list_t transfers_interrupt; 94 95 transfer_list_t *transfers[2][4]; 96 97 irq_code_t interrupt_code; 98 99 fid_t cleaner; 100 fid_t debug_checker; 101 102 ddf_fun_t *ddf_instance; 47 uhci_hc_t hc; 48 uhci_rh_t rh; 103 49 } uhci_t; 104 50 105 /* init uhci specifics in device.driver_data */ 106 int uhci_init(uhci_t *instance, ddf_dev_t *dev, void *regs, size_t reg_size); 107 108 static inline void uhci_fini(uhci_t *instance) {}; 109 110 int uhci_schedule(uhci_t *instance, batch_t *batch); 111 112 void uhci_interrupt(uhci_t *instance, uint16_t status); 113 114 static inline uhci_t * dev_to_uhci(ddf_dev_t *dev) 115 { return (uhci_t*)dev->driver_data; } 116 117 static inline uhci_t * fun_to_uhci(ddf_fun_t *fun) 118 { return (uhci_t*)fun->driver_data; } 119 51 int uhci_init(uhci_t *instance, ddf_dev_t *device); 120 52 121 53 #endif -
uspace/drv/uhci-hcd/uhci_struct/link_pointer.h
r0f3e68c r335382d 46 46 #define LINK_POINTER_ADDRESS_MASK 0xfffffff0 /* upper 28 bits */ 47 47 48 #define LINK_POINTER_QH(address) \ 49 ((address & LINK_POINTER_ADDRESS_MASK) | LINK_POINTER_QUEUE_HEAD_FLAG) 50 48 51 #endif 49 52 /** -
uspace/drv/uhci-hcd/uhci_struct/queue_head.h
r0f3e68c r335382d 43 43 44 44 typedef struct queue_head { 45 volatile link_pointer_t next _queue;45 volatile link_pointer_t next; 46 46 volatile link_pointer_t element; 47 } __attribute__((packed)) q ueue_head_t;48 49 static inline void q ueue_head_init(queue_head_t *instance)47 } __attribute__((packed)) qh_t; 48 /*----------------------------------------------------------------------------*/ 49 static inline void qh_init(qh_t *instance) 50 50 { 51 51 assert(instance); 52 52 53 53 instance->element = 0 | LINK_POINTER_TERMINATE_FLAG; 54 instance->next _queue= 0 | LINK_POINTER_TERMINATE_FLAG;54 instance->next = 0 | LINK_POINTER_TERMINATE_FLAG; 55 55 } 56 57 static inline void q ueue_head_append_qh(queue_head_t *instance, uint32_t pa)56 /*----------------------------------------------------------------------------*/ 57 static inline void qh_set_next_qh(qh_t *instance, uint32_t pa) 58 58 { 59 if (pa) { 60 instance->next_queue = (pa & LINK_POINTER_ADDRESS_MASK) 59 /* address is valid and not terminal */ 60 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) { 61 instance->next = (pa & LINK_POINTER_ADDRESS_MASK) 61 62 | LINK_POINTER_QUEUE_HEAD_FLAG; 63 } else { 64 instance->next = 0 | LINK_POINTER_TERMINATE_FLAG; 62 65 } 63 66 } 64 65 static inline void q ueue_head_element_qh(queue_head_t *instance, uint32_t pa)67 /*----------------------------------------------------------------------------*/ 68 static inline void qh_set_element_qh(qh_t *instance, uint32_t pa) 66 69 { 67 if (pa) { 68 instance->next_queue = (pa & LINK_POINTER_ADDRESS_MASK) 70 /* address is valid and not terminal */ 71 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) { 72 instance->element = (pa & LINK_POINTER_ADDRESS_MASK) 69 73 | LINK_POINTER_QUEUE_HEAD_FLAG; 74 } else { 75 instance->element = 0 | LINK_POINTER_TERMINATE_FLAG; 70 76 } 71 77 } 72 73 static inline void q ueue_head_set_element_td(queue_head_t *instance, uint32_t pa)78 /*----------------------------------------------------------------------------*/ 79 static inline void qh_set_element_td(qh_t *instance, uint32_t pa) 74 80 { 75 if (pa ) {81 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) { 76 82 instance->element = (pa & LINK_POINTER_ADDRESS_MASK); 83 } else { 84 instance->element = 0 | LINK_POINTER_TERMINATE_FLAG; 77 85 } 78 86 } -
uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.c
r0f3e68c r335382d 44 44 * @param[in] size Size of data source. 45 45 * @param[in] toggle Value of toggle bit. 46 * @param[in] iso True if TD is forIsochronous transfer.46 * @param[in] iso True if TD represents Isochronous transfer. 47 47 * @param[in] low_speed Target device's speed. 48 48 * @param[in] target Address and endpoint receiving the transfer. … … 51 51 * @param[in] next Net TD in transaction. 52 52 * @return Error code. 53 * 54 * Uses a mix of supplied and default values. 55 * Implicit values: 56 * - all TDs have vertical flag set (makes transfers to endpoints atomic) 57 * - in the error field only active it is set 58 * - if the packet uses PID_IN and is not isochronous SPD is set 59 * 60 * Dumps 8 bytes of buffer if PID_SETUP is used. 53 61 */ 54 62 void td_init(td_t *instance, int err_count, size_t size, bool toggle, bool iso, … … 94 102 if (pid == USB_PID_SETUP) { 95 103 usb_log_debug("SETUP BUFFER: %s\n", 96 104 usb_debug_str_buffer(buffer, 8, 8)); 97 105 } 98 106 } … … 128 136 } 129 137 /*----------------------------------------------------------------------------*/ 138 /** Print values in status field (dw1) in a human readable way. 139 * 140 * @param[in] instance TD structure to use. 141 */ 130 142 void td_print_status(td_t *instance) 131 143 { -
uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.h
r0f3e68c r335382d 45 45 46 46 volatile uint32_t status; 47 48 47 #define TD_STATUS_RESERVED_MASK 0xc000f800 49 48 #define TD_STATUS_SPD_FLAG ( 1 << 29 ) 50 49 #define TD_STATUS_ERROR_COUNT_POS ( 27 ) 51 50 #define TD_STATUS_ERROR_COUNT_MASK ( 0x3 ) 52 #define TD_STATUS_ERROR_COUNT_DEFAULT 353 51 #define TD_STATUS_LOW_SPEED_FLAG ( 1 << 26 ) 54 52 #define TD_STATUS_ISOCHRONOUS_FLAG ( 1 << 25 ) … … 70 68 71 69 volatile uint32_t device; 72 73 70 #define TD_DEVICE_MAXLEN_POS 21 74 71 #define TD_DEVICE_MAXLEN_MASK ( 0x7ff ) … … 85 82 86 83 /* there is 16 bytes of data available here, according to UHCI 87 * Design guide, according to linux kernel the hardware does not care 88 * we don't use it anyway84 * Design guide, according to linux kernel the hardware does not care, 85 * it just needs to be aligned, we don't use it anyway 89 86 */ 90 87 } __attribute__((packed)) td_t; … … 97 94 int td_status(td_t *instance); 98 95 96 void td_print_status(td_t *instance); 97 /*----------------------------------------------------------------------------*/ 98 /** Helper function for parsing actual size out of TD. 99 * 100 * @param[in] instance TD structure to use. 101 * @return Parsed actual size. 102 */ 99 103 static inline size_t td_act_size(td_t *instance) 100 104 { 101 105 assert(instance); 102 return 103 ((instance->status >> TD_STATUS_ACTLEN_POS) + 1) 104 & TD_STATUS_ACTLEN_MASK; 106 const uint32_t s = instance->status; 107 return ((s >> TD_STATUS_ACTLEN_POS) + 1) & TD_STATUS_ACTLEN_MASK; 105 108 } 106 109 /*----------------------------------------------------------------------------*/ 110 /** Checks whether less than max data were recieved and packet is marked as SPD. 111 * 112 * @param[in] instance TD structure to use. 113 * @return True if packet is short (less than max bytes and SPD set), false 114 * otherwise. 115 */ 107 116 static inline bool td_is_short(td_t *instance) 108 117 { … … 114 123 (instance->status | TD_STATUS_SPD_FLAG) && act_size < max_size; 115 124 } 116 125 /*----------------------------------------------------------------------------*/ 126 /** Helper function for parsing value of toggle bit. 127 * 128 * @param[in] instance TD structure to use. 129 * @return Toggle bit value. 130 */ 117 131 static inline int td_toggle(td_t *instance) 118 132 { 119 133 assert(instance); 120 return ((instance->device & TD_DEVICE_DATA_TOGGLE_ONE_FLAG) != 0) 121 ? 1 : 0; 134 return (instance->device & TD_DEVICE_DATA_TOGGLE_ONE_FLAG) ? 1 : 0; 122 135 } 123 136 /*----------------------------------------------------------------------------*/ 137 /** Helper function for parsing value of active bit 138 * 139 * @param[in] instance TD structure to use. 140 * @return Active bit value. 141 */ 124 142 static inline bool td_is_active(td_t *instance) 125 143 { … … 127 145 return (instance->status & TD_STATUS_ERROR_ACTIVE) != 0; 128 146 } 129 130 void td_print_status(td_t *instance); 147 /*----------------------------------------------------------------------------*/ 148 /** Helper function for setting IOC bit. 149 * 150 * @param[in] instance TD structure to use. 151 */ 152 static inline void td_set_ioc(td_t *instance) 153 { 154 assert(instance); 155 instance->status |= TD_STATUS_IOC_FLAG; 156 } 157 /*----------------------------------------------------------------------------*/ 131 158 #endif 132 159 /**
Note:
See TracChangeset
for help on using the changeset viewer.