Changeset 1b0b86e6 in mainline
- Timestamp:
- 2011-03-13T22:02:44Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- b7d8fd9
- Parents:
- 67f54965 (diff), deb4ba7 (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
- Files:
-
- 5 added
- 2 deleted
- 25 edited
- 2 moved
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/ehci-hcd/pci.c
r67f54965 r1b0b86e6 247 247 248 248 249 if ((value & USBLEGSUP_BIOS_CONTROL) != 0) {249 if ((value & USBLEGSUP_BIOS_CONTROL) == 0) { 250 250 usb_log_info("BIOS released control after %d usec.\n", wait); 251 251 } else { 252 252 /* BIOS failed to hand over control, this should not happen. */ 253 usb_log_warning( "BIOS failed to release control after "253 usb_log_warning( "BIOS failed to release control after " 254 254 "%d usecs, force it.\n", wait); 255 255 ret = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE), … … 258 258 CHECK_RET_HANGUP_RETURN(ret, 259 259 "Failed(%d) to force OS EHCI control.\n", ret); 260 /* TODO: This does not seem to work on my machine */261 260 } 262 261 … … 280 279 usb_log_debug2("USBLEGSUP: %x.\n", value); 281 280 282 /*283 * TURN OFF EHCI FOR NOW, REMOVE IF THE DRIVER IS IMPLEMENTED 284 */281 /* 282 * TURN OFF EHCI FOR NOW, DRIVER WILL REINITIALIZE IT 283 */ 285 284 286 285 /* Get size of capability registers in memory space. */ -
uspace/drv/uhci-hcd/Makefile
r67f54965 r1b0b86e6 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
r67f54965 r1b0b86e6 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", … … 177 172 usb_log_debug("Batch(%p) found error TD(%d):%x.\n", 178 173 instance, i, instance->tds[i].status); 174 td_print_status(&instance->tds[i]); 179 175 180 176 device_keeper_set_toggle(instance->manager, … … 318 314 ++packet; 319 315 } 316 td_set_ioc(&instance->tds[packet - 1]); 320 317 device_keeper_set_toggle(instance->manager, instance->target, toggle); 321 318 } … … 369 366 0, 1, false, low_speed, instance->target, status_stage, NULL, NULL); 370 367 371 372 instance->tds[packet].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG; 368 td_set_ioc(&instance->tds[packet]); 373 369 usb_log_debug2("Control last TD status: %x.\n", 374 370 instance->tds[packet].status); … … 454 450 { 455 451 assert(instance); 456 uhci_ t *hc = fun_to_uhci(instance->fun);452 uhci_hc_t *hc = fun_to_uhci_hc(instance->fun); 457 453 assert(hc); 458 return uhci_ schedule(hc, instance);454 return uhci_hc_schedule(hc, instance); 459 455 } 460 456 /** -
uspace/drv/uhci-hcd/batch.h
r67f54965 r1b0b86e6 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
r67f54965 r1b0b86e6 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);280 assert(hc); 281 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); 282 usb_log_debug("Control WRITE %d:%d %zu(%zu).\n",283 target.address, target.endpoint, size, max_packet_size);279 uhci_hc_t *hc = fun_to_uhci_hc(fun); 280 assert(hc); 281 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); 282 usb_log_debug("Control WRITE (%d) %d:%d %zu(%zu).\n", 283 speed, target.address, target.endpoint, size, max_packet_size); 284 284 285 285 if (setup_size != 8) … … 315 315 { 316 316 assert(fun); 317 uhci_ t *hc = fun_to_uhci(fun);318 assert(hc); 319 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); 320 321 usb_log_debug("Control READ %d:%d %zu(%zu).\n",322 target.address, target.endpoint, size, max_packet_size);317 uhci_hc_t *hc = fun_to_uhci_hc(fun); 318 assert(hc); 319 usb_speed_t speed = device_keeper_speed(&hc->device_manager, target.address); 320 321 usb_log_debug("Control READ(%d) %d:%d %zu(%zu).\n", 322 speed, target.address, target.endpoint, size, max_packet_size); 323 323 batch_t *batch = batch_get(fun, target, USB_TRANSFER_CONTROL, 324 324 max_packet_size, speed, data, size, setup_data, setup_size, callback, … … 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
r67f54965 r1b0b86e6 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
r67f54965 r1b0b86e6 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
r67f54965 r1b0b86e6 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
r67f54965 r1b0b86e6 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
r67f54965 r1b0b86e6 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[low_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 transfer_list_remove_finished(&instance->transfers_interrupt); 375 transfer_list_remove_finished(&instance->transfers_control_slow); 376 transfer_list_remove_finished(&instance->transfers_control_full); 377 transfer_list_remove_finished(&instance->transfers_bulk_full); 378 } 379 /*----------------------------------------------------------------------------*/ 380 /** Polling function, emulates interrupts. 381 * 382 * @param[in] arg UHCI structure to use. 383 * @return EOK 384 */ 385 int uhci_interrupt_emulator(void* arg) 386 { 387 usb_log_debug("Started interrupt emulator.\n"); 388 uhci_t *instance = (uhci_t*)arg; 389 assert(instance); 390 391 while (1) { 392 uint16_t status = pio_read_16(&instance->registers->usbsts); 393 if (status != 0) 394 usb_log_debug2("UHCI status: %x.\n", status); 395 status |= 1; 396 uhci_interrupt(instance, status); 397 pio_write_16(&instance->registers->usbsts, 0x1f); 398 async_usleep(UHCI_CLEANER_TIMEOUT); 399 } 400 return EOK; 401 } 402 /*---------------------------------------------------------------------------*/ 403 /** Debug function, checks consistency of memory structures. 404 * 405 * @param[in] arg UHCI structure to use. 406 * @return EOK 407 */ 408 int uhci_debug_checker(void *arg) 409 { 410 uhci_t *instance = (uhci_t*)arg; 411 assert(instance); 412 413 #define QH(queue) \ 414 instance->transfers_##queue.queue_head 415 416 while (1) { 417 const uint16_t cmd = pio_read_16(&instance->registers->usbcmd); 418 const uint16_t sts = pio_read_16(&instance->registers->usbsts); 419 const uint16_t intr = 420 pio_read_16(&instance->registers->usbintr); 421 422 if (((cmd & UHCI_CMD_RUN_STOP) != 1) || (sts != 0)) { 423 usb_log_debug2("Command: %X Status: %X Intr: %x\n", 424 cmd, sts, intr); 425 } 426 427 uintptr_t frame_list = 428 pio_read_32(&instance->registers->flbaseadd) & ~0xfff; 429 if (frame_list != addr_to_phys(instance->frame_list)) { 430 usb_log_debug("Framelist address: %p vs. %p.\n", 431 frame_list, addr_to_phys(instance->frame_list)); 432 } 433 434 int frnum = pio_read_16(&instance->registers->frnum) & 0x3ff; 435 usb_log_debug2("Framelist item: %d \n", frnum ); 436 437 uintptr_t expected_pa = instance->frame_list[frnum] & (~0xf); 438 uintptr_t real_pa = addr_to_phys(QH(interrupt)); 439 if (expected_pa != real_pa) { 440 usb_log_debug("Interrupt QH: %p vs. %p.\n", 441 expected_pa, real_pa); 442 } 443 444 expected_pa = QH(interrupt)->next_queue & (~0xf); 445 real_pa = addr_to_phys(QH(control_slow)); 446 if (expected_pa != real_pa) { 447 usb_log_debug("Control Slow QH: %p vs. %p.\n", 448 expected_pa, real_pa); 449 } 450 451 expected_pa = QH(control_slow)->next_queue & (~0xf); 452 real_pa = addr_to_phys(QH(control_full)); 453 if (expected_pa != real_pa) { 454 usb_log_debug("Control Full QH: %p vs. %p.\n", 455 expected_pa, real_pa); 456 } 457 458 expected_pa = QH(control_full)->next_queue & (~0xf); 459 real_pa = addr_to_phys(QH(bulk_full)); 460 if (expected_pa != real_pa ) { 461 usb_log_debug("Bulk QH: %p vs. %p.\n", 462 expected_pa, real_pa); 463 } 464 async_usleep(UHCI_DEBUGER_TIMEOUT); 465 } 466 return EOK; 467 #undef QH 468 } 469 /*----------------------------------------------------------------------------*/ 470 /** Checks transfer packets, for USB validity 471 * 472 * @param[in] low_speed Transfer speed. 473 * @param[in] transfer Transer type 474 * @param[in] size Maximum size of used packets 475 * @return EOK 476 */ 477 bool allowed_usb_packet( 478 bool low_speed, usb_transfer_type_t transfer, size_t size) 479 { 480 /* see USB specification chapter 5.5-5.8 for magic numbers used here */ 481 switch(transfer) 482 { 483 case USB_TRANSFER_ISOCHRONOUS: 484 return (!low_speed && size < 1024); 485 case USB_TRANSFER_INTERRUPT: 486 return size <= (low_speed ? 8 : 64); 487 case USB_TRANSFER_CONTROL: /* device specifies its own max size */ 488 return (size <= (low_speed ? 8 : 64)); 489 case USB_TRANSFER_BULK: /* device specifies its own max size */ 490 return (!low_speed && size <= 64); 491 } 492 return false; 493 } 217 #undef CHECK_RET_FINI_RETURN 218 } 219 494 220 /** 495 221 * @} -
uspace/drv/uhci-hcd/uhci.h
r67f54965 r1b0b86e6 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_rh.c
r67f54965 r1b0b86e6 33 33 */ 34 34 #include <assert.h> 35 #include <errno.h> 36 #include <str_error.h> 35 37 #include <stdio.h> 36 38 37 39 #include <usb/debug.h> 38 40 39 #include "port_status.h" 41 #include "uhci_rh.h" 42 #include "uhci_hc.h" 40 43 41 struct flag_name 44 /*----------------------------------------------------------------------------*/ 45 int uhci_rh_init( 46 uhci_rh_t *instance, ddf_fun_t *fun, uintptr_t reg_addr, size_t reg_size) 42 47 { 43 uint16_t flag; 44 const char *name; 45 }; 48 assert(fun); 46 49 47 static const struct flag_name flags[] = 48 { 49 { STATUS_SUSPEND, "suspended" }, 50 { STATUS_IN_RESET, "in reset" }, 51 { STATUS_LOW_SPEED, "low speed device" }, 52 { STATUS_ALWAYS_ONE, "always 1 bit" }, 53 { STATUS_RESUME, "resume" }, 54 { STATUS_LINE_D_MINUS, "line D- value" }, 55 { STATUS_LINE_D_PLUS, "line D+ value" }, 56 { STATUS_ENABLED_CHANGED, "enabled changed" }, 57 { STATUS_ENABLED, "enabled" }, 58 { STATUS_CONNECTED_CHANGED, "connected changed" }, 59 { STATUS_CONNECTED, "connected" } 60 }; 50 char *match_str = NULL; 51 int ret = asprintf(&match_str, "usb&uhci&root-hub"); 52 if (ret < 0) { 53 usb_log_error("Failed to create root hub match string.\n"); 54 return ENOMEM; 55 } 61 56 62 /** Prints portr status in a human readable way. 63 * 64 * @param[in] value Port value to print. 65 * @return Error code. 66 */ 67 void print_port_status(port_status_t value) 68 { 69 unsigned i = 0; 70 for (;i < sizeof(flags)/sizeof(struct flag_name); ++i) { 71 usb_log_debug2("\t%s status: %s.\n", flags[i].name, 72 ((value & flags[i].flag) != 0) ? "YES" : "NO"); 57 ret = ddf_fun_add_match_id(fun, match_str, 100); 58 if (ret != EOK) { 59 usb_log_error("Failed(%d) to add root hub match id: %s\n", 60 ret, str_error(ret)); 61 return ret; 73 62 } 63 64 hw_resource_list_t *resource_list = &instance->resource_list; 65 resource_list->count = 1; 66 resource_list->resources = &instance->io_regs; 67 assert(resource_list->resources); 68 instance->io_regs.type = IO_RANGE; 69 instance->io_regs.res.io_range.address = reg_addr; 70 // ((uintptr_t)hc->registers) + 0x10; // see UHCI design guide 71 instance->io_regs.res.io_range.size = reg_size; 72 instance->io_regs.res.io_range.endianness = LITTLE_ENDIAN; 73 74 return EOK; 74 75 } 75 76 /** -
uspace/drv/uhci-hcd/uhci_rh.h
r67f54965 r1b0b86e6 1 1 /* 2 * Copyright (c) 201 0Jan Vesely2 * Copyright (c) 2011 Jan Vesely 3 3 * All rights reserved. 4 4 * … … 33 33 * @brief UHCI driver 34 34 */ 35 #ifndef DRV_UHCI_ ROOT_HUB_H36 #define DRV_UHCI_ ROOT_HUB_H35 #ifndef DRV_UHCI_UHCI_RH_H 36 #define DRV_UHCI_UHCI_RH_H 37 37 38 38 #include <ddf/driver.h> 39 #include <ops/hw_res.h> 39 40 40 int setup_root_hub(ddf_fun_t **device, ddf_dev_t *hc); 41 typedef struct uhci_rh { 42 hw_resource_list_t resource_list; 43 hw_resource_t io_regs; 44 } uhci_rh_t; 45 46 int uhci_rh_init( 47 uhci_rh_t *instance, ddf_fun_t *fun, uintptr_t reg_addr, size_t reg_size); 41 48 42 49 #endif -
uspace/drv/uhci-hcd/uhci_struct/link_pointer.h
r67f54965 r1b0b86e6 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
r67f54965 r1b0b86e6 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
r67f54965 r1b0b86e6 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, … … 88 96 } 89 97 90 usb_log_debug2("Created TD : %X:%X:%X:%X(%p).\n",91 instance ->next, instance->status, instance->device,98 usb_log_debug2("Created TD(%p): %X:%X:%X:%X(%p).\n", 99 instance, instance->next, instance->status, instance->device, 92 100 instance->buffer_ptr, buffer); 101 td_print_status(instance); 93 102 if (pid == USB_PID_SETUP) { 94 103 usb_log_debug("SETUP BUFFER: %s\n", 95 104 usb_debug_str_buffer(buffer, 8, 8)); 96 105 } 97 106 } … … 126 135 return EOK; 127 136 } 137 /*----------------------------------------------------------------------------*/ 138 /** Print values in status field (dw1) in a human readable way. 139 * 140 * @param[in] instance TD structure to use. 141 */ 142 void td_print_status(td_t *instance) 143 { 144 assert(instance); 145 const uint32_t s = instance->status; 146 usb_log_debug2("TD(%p) status(%#x):%s %d,%s%s%s%s%s%s%s%s%s%s%s %d.\n", 147 instance, instance->status, 148 (s & TD_STATUS_SPD_FLAG) ? " SPD," : "", 149 (s >> TD_STATUS_ERROR_COUNT_POS) & TD_STATUS_ERROR_COUNT_MASK, 150 (s & TD_STATUS_LOW_SPEED_FLAG) ? " LOW SPEED," : "", 151 (s & TD_STATUS_ISOCHRONOUS_FLAG) ? " ISOCHRONOUS," : "", 152 (s & TD_STATUS_IOC_FLAG) ? " IOC," : "", 153 (s & TD_STATUS_ERROR_ACTIVE) ? " ACTIVE," : "", 154 (s & TD_STATUS_ERROR_STALLED) ? " STALLED," : "", 155 (s & TD_STATUS_ERROR_BUFFER) ? " BUFFER," : "", 156 (s & TD_STATUS_ERROR_BABBLE) ? " BABBLE," : "", 157 (s & TD_STATUS_ERROR_NAK) ? " NAK," : "", 158 (s & TD_STATUS_ERROR_CRC) ? " CRC/TIMEOUT," : "", 159 (s & TD_STATUS_ERROR_BIT_STUFF) ? " BIT_STUFF," : "", 160 (s & TD_STATUS_ERROR_RESERVED) ? " RESERVED," : "", 161 (s >> TD_STATUS_ACTLEN_POS) & TD_STATUS_ACTLEN_MASK 162 ); 163 } 128 164 /** 129 165 * @} -
uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.h
r67f54965 r1b0b86e6 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 ) 55 #define TD_STATUS_ COMPLETE_INTERRUPT_FLAG ( 1 << 24 )53 #define TD_STATUS_IOC_FLAG ( 1 << 24 ) 56 54 57 55 #define TD_STATUS_ERROR_ACTIVE ( 1 << 23 ) … … 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; 91 88 92 89 93 void td_init(td_t *instance, int error_count, size_t size, bool toggle, bool iso,94 bool low_speed, usb_target_t target, usb_packet_id pid, void *buffer,95 td_t *next);90 void td_init(td_t *instance, int error_count, size_t size, bool toggle, 91 bool iso, bool low_speed, usb_target_t target, usb_packet_id pid, 92 void *buffer, td_t *next); 96 93 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 } 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 /*----------------------------------------------------------------------------*/ 129 158 #endif 130 159 /** -
uspace/drv/uhci-rhd/Makefile
r67f54965 r1b0b86e6 35 35 main.c \ 36 36 port.c \ 37 port_status.c \38 37 root_hub.c 39 38 -
uspace/drv/uhci-rhd/port.c
r67f54965 r1b0b86e6 44 44 45 45 #include "port.h" 46 #include "port_status.h"47 46 48 47 static int uhci_port_new_device(uhci_port_t *port, usb_speed_t speed); … … 67 66 { 68 67 assert(port); 68 asprintf(&port->id_string, "Port (%p - %d)", port, number); 69 if (port->id_string == NULL) { 70 return ENOMEM; 71 } 69 72 70 73 port->address = address; … … 116 119 assert(instance); 117 120 118 /* Iteration count, for debug purposes only */119 unsigned count = 0;120 121 121 while (1) { 122 122 async_usleep(instance->wait_period_usec); 123 123 124 124 /* read register value */ 125 port_status_t port_status = port_status_read(instance->address); 126 127 /* debug print mutex */ 128 static fibril_mutex_t dbg_mtx = 129 FIBRIL_MUTEX_INITIALIZER(dbg_mtx); 130 fibril_mutex_lock(&dbg_mtx); 131 usb_log_debug2("Port(%p - %d): Status: %#04x. === %u\n", 132 instance->address, instance->number, port_status, count++); 133 // print_port_status(port_status); 134 fibril_mutex_unlock(&dbg_mtx); 125 port_status_t port_status = uhci_port_read_status(instance); 126 127 /* print the value if it's interesting */ 128 if (port_status & ~STATUS_ALWAYS_ONE) 129 uhci_port_print_status(instance, port_status); 135 130 136 131 if ((port_status & STATUS_CONNECTED_CHANGED) == 0) 137 132 continue; 138 133 139 usb_log_debug(" Port(%p - %d): Connected change detected: %x.\n",140 instance-> address, instance->number, port_status);134 usb_log_debug("%s: Connected change detected: %x.\n", 135 instance->id_string, port_status); 141 136 142 137 int rc = 143 138 usb_hc_connection_open(&instance->hc_connection); 144 139 if (rc != EOK) { 145 usb_log_error(" Port(%p - %d): Failed to connect to HC.",146 instance-> address, instance->number);140 usb_log_error("%s: Failed to connect to HC.", 141 instance->id_string); 147 142 continue; 148 143 } … … 150 145 /* Remove any old device */ 151 146 if (instance->attached_device) { 152 usb_log_debug2(" Port(%p - %d): Removing device.\n",153 instance-> address, instance->number);147 usb_log_debug2("%s: Removing device.\n", 148 instance->id_string); 154 149 uhci_port_remove_device(instance); 155 150 } … … 163 158 } else { 164 159 /* Write one to WC bits, to ack changes */ 165 port_status_write(instance->address, port_status);166 usb_log_debug(" Port(%p - %d): Change statusACK.\n",167 instance-> address, instance->number);160 uhci_port_write_status(instance, port_status); 161 usb_log_debug("%s: status change ACK.\n", 162 instance->id_string); 168 163 } 169 164 170 165 rc = usb_hc_connection_close(&instance->hc_connection); 171 166 if (rc != EOK) { 172 usb_log_error(" Port(%p - %d): Failed to disconnect.",173 instance-> address, instance->number);167 usb_log_error("%s: Failed to disconnect.", 168 instance->id_string); 174 169 } 175 170 } … … 187 182 uhci_port_t *port = (uhci_port_t *) arg; 188 183 189 usb_log_debug2("Port(%p - %d): new_device_enable_port.\n", 190 port->address, port->number); 184 usb_log_debug2("%s: new_device_enable_port.\n", port->id_string); 191 185 192 186 /* … … 196 190 async_usleep(100000); 197 191 198 199 /* The hub maintains the reset signal to that port for 10 ms 200 * (See Section 11.5.1.5) 192 /* 193 * Resets from root ports should be nominally 50ms 201 194 */ 202 195 { 203 usb_log_debug("Port(%p - %d): Reset Signal start.\n", 204 port->address, port->number); 205 port_status_t port_status = 206 port_status_read(port->address); 196 usb_log_debug("%s: Reset Signal start.\n", port->id_string); 197 port_status_t port_status = uhci_port_read_status(port); 207 198 port_status |= STATUS_IN_RESET; 208 port_status_write(port->address, port_status);209 async_usleep( 10000);210 port_status = port_status_read(port->address);199 uhci_port_write_status(port, port_status); 200 async_usleep(50000); 201 port_status = uhci_port_read_status(port); 211 202 port_status &= ~STATUS_IN_RESET; 212 port_status_write(port->address, port_status); 213 usb_log_debug("Port(%p - %d): Reset Signal stop.\n", 214 port->address, port->number); 215 } 203 uhci_port_write_status(port, port_status); 204 usb_log_debug("%s: Reset Signal stop.\n", port->id_string); 205 } 206 207 /* the reset recovery time 10ms */ 208 async_usleep(10000); 216 209 217 210 /* Enable the port. */ 218 211 uhci_port_set_enabled(port, true); 212 219 213 return EOK; 220 214 } … … 233 227 assert(usb_hc_connection_is_opened(&port->hc_connection)); 234 228 235 usb_log_info("Port(%p-%d): Detected new device.\n", 236 port->address, port->number); 229 usb_log_info("%s: Detected new device.\n", port->id_string); 237 230 238 231 usb_address_t dev_addr; … … 242 235 243 236 if (rc != EOK) { 244 usb_log_error(" Port(%p-%d): Failed(%d) to add device: %s.\n",245 port-> address, port->number, rc, str_error(rc));237 usb_log_error("%s: Failed(%d) to add device: %s.\n", 238 port->id_string, rc, str_error(rc)); 246 239 uhci_port_set_enabled(port, false); 247 240 return rc; 248 241 } 249 242 250 usb_log_info(" Port(%p-%d): New device has address %d (handle %zu).\n",251 port-> address, port->number, dev_addr, port->attached_device);243 usb_log_info("%s: New device has address %d (handle %zu).\n", 244 port->id_string, dev_addr, port->attached_device); 252 245 253 246 return EOK; … … 263 256 int uhci_port_remove_device(uhci_port_t *port) 264 257 { 265 usb_log_error(" Port(%p-%d): Don't know how to remove device %#x.\n",266 port-> address, port->number, (unsigned int)port->attached_device);258 usb_log_error("%s: Don't know how to remove device %d.\n", 259 port->id_string, (unsigned int)port->attached_device); 267 260 return EOK; 268 261 } … … 278 271 279 272 /* Read register value */ 280 port_status_t port_status = port_status_read(port->address);273 port_status_t port_status = uhci_port_read_status(port); 281 274 282 275 /* Set enabled bit */ … … 288 281 289 282 /* Write new value. */ 290 port_status_write(port->address, port_status);291 292 usb_log_info(" Port(%p-%d): %sabled port.\n",293 port-> address, port->number, enabled ? "En" : "Dis");283 uhci_port_write_status(port, port_status); 284 285 usb_log_info("%s: %sabled port.\n", 286 port->id_string, enabled ? "En" : "Dis"); 294 287 return EOK; 295 288 } -
uspace/drv/uhci-rhd/port.h
r67f54965 r1b0b86e6 36 36 37 37 #include <assert.h> 38 #include <stdint.h> 38 39 #include <ddf/driver.h> 39 #include < stdint.h>40 #include <libarch/ddi.h> /* pio_read and pio_write */ 40 41 #include <usb/usbdevice.h> 41 42 42 #include "port_status.h" 43 typedef uint16_t port_status_t; 44 45 #define STATUS_CONNECTED (1 << 0) 46 #define STATUS_CONNECTED_CHANGED (1 << 1) 47 #define STATUS_ENABLED (1 << 2) 48 #define STATUS_ENABLED_CHANGED (1 << 3) 49 #define STATUS_LINE_D_PLUS (1 << 4) 50 #define STATUS_LINE_D_MINUS (1 << 5) 51 #define STATUS_RESUME (1 << 6) 52 #define STATUS_ALWAYS_ONE (1 << 7) 53 54 #define STATUS_LOW_SPEED (1 << 8) 55 #define STATUS_IN_RESET (1 << 9) 56 #define STATUS_SUSPEND (1 << 12) 43 57 44 58 typedef struct uhci_port 45 59 { 60 char *id_string; 46 61 port_status_t *address; 47 62 unsigned number; … … 58 73 59 74 void uhci_port_fini(uhci_port_t *port); 75 76 static inline port_status_t uhci_port_read_status(uhci_port_t *port) 77 { 78 assert(port); 79 return pio_read_16(port->address); 80 } 81 82 static inline void uhci_port_write_status( 83 uhci_port_t *port, port_status_t value) 84 { 85 assert(port); 86 pio_write_16(port->address, value); 87 } 88 89 static inline void uhci_port_print_status( 90 uhci_port_t *port, const port_status_t value) 91 { 92 assert(port); 93 usb_log_debug2("%s Port status(%#x):%s%s%s%s%s%s%s%s%s%s%s.\n", 94 port->id_string, value, 95 (value & STATUS_SUSPEND) ? " SUSPENDED," : "", 96 (value & STATUS_RESUME) ? " IN RESUME," : "", 97 (value & STATUS_IN_RESET) ? " IN RESET," : "", 98 (value & STATUS_LINE_D_MINUS) ? " VD-," : "", 99 (value & STATUS_LINE_D_PLUS) ? " VD+," : "", 100 (value & STATUS_LOW_SPEED) ? " LOWSPEED," : "", 101 (value & STATUS_ENABLED_CHANGED) ? " ENABLED-CHANGE," : "", 102 (value & STATUS_ENABLED) ? " ENABLED," : "", 103 (value & STATUS_CONNECTED_CHANGED) ? " CONNECTED-CHANGE," : "", 104 (value & STATUS_CONNECTED) ? " CONNECTED," : "", 105 (value & STATUS_ALWAYS_ONE) ? " ALWAYS ONE" : " ERROR: NO ALWAYS ONE" 106 ); 107 } 60 108 #endif 61 109 /** -
uspace/drv/usbmouse/init.c
r67f54965 r1b0b86e6 42 42 43 43 /** Mouse polling endpoint description for boot protocol subclass. */ 44 staticusb_endpoint_description_t poll_endpoint_description = {44 usb_endpoint_description_t poll_endpoint_description = { 45 45 .transfer_type = USB_TRANSFER_INTERRUPT, 46 46 .direction = USB_DIRECTION_IN, … … 50 50 .flags = 0 51 51 }; 52 53 /** Initialize poll pipe.54 *55 * Expects that session is already started on control pipe zero.56 *57 * @param mouse Mouse device.58 * @param my_interface Interface number.59 * @return Error code.60 */61 static int intialize_poll_pipe(usb_mouse_t *mouse, int my_interface)62 {63 assert(usb_endpoint_pipe_is_session_started(&mouse->ctrl_pipe));64 65 int rc;66 67 void *config_descriptor;68 size_t config_descriptor_size;69 70 rc = usb_request_get_full_configuration_descriptor_alloc(71 &mouse->ctrl_pipe, 0, &config_descriptor, &config_descriptor_size);72 if (rc != EOK) {73 return rc;74 }75 76 usb_endpoint_mapping_t endpoint_mapping[1] = {77 {78 .pipe = &mouse->poll_pipe,79 .description = &poll_endpoint_description,80 .interface_no = my_interface81 }82 };83 84 rc = usb_endpoint_pipe_initialize_from_configuration(endpoint_mapping,85 1, config_descriptor, config_descriptor_size, &mouse->wire);86 if (rc != EOK) {87 return rc;88 }89 90 if (!endpoint_mapping[0].present) {91 return ENOENT;92 }93 94 mouse->poll_interval_us = 1000 * endpoint_mapping[0].descriptor->poll_interval;95 96 usb_log_debug("prepared polling endpoint %d (interval %zu).\n",97 mouse->poll_pipe.endpoint_no, mouse->poll_interval_us);98 99 return EOK;100 }101 52 102 53 static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *); … … 143 94 * @return Error code. 144 95 */ 145 int usb_mouse_create( ddf_dev_t *dev)96 int usb_mouse_create(usb_device_t *dev) 146 97 { 147 98 usb_mouse_t *mouse = malloc(sizeof(usb_mouse_t)); … … 149 100 return ENOMEM; 150 101 } 151 mouse->dev ice= dev;102 mouse->dev = dev; 152 103 mouse->console_phone = -1; 153 104 154 105 int rc; 155 106 156 /* Initialize the backing connection. */157 rc = usb_device_connection_initialize_from_device(&mouse->wire, dev);158 if (rc != EOK) {159 goto leave;160 }161 162 /* Initialize the default control pipe. */163 rc = usb_endpoint_pipe_initialize_default_control(&mouse->ctrl_pipe,164 &mouse->wire);165 if (rc != EOK) {166 goto leave;167 }168 169 rc = usb_endpoint_pipe_start_session(&mouse->ctrl_pipe);170 if (rc != EOK) {171 goto leave;172 }173 174 rc = intialize_poll_pipe(mouse, usb_device_get_assigned_interface(dev));175 176 /* We can ignore error here. */177 usb_endpoint_pipe_end_session(&mouse->ctrl_pipe);178 179 if (rc != EOK) {180 goto leave;181 }182 183 107 /* Create DDF function. */ 184 mouse->mouse_fun = ddf_fun_create(dev , fun_exposed, "mouse");108 mouse->mouse_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, "mouse"); 185 109 if (mouse->mouse_fun == NULL) { 186 110 rc = ENOMEM; -
uspace/drv/usbmouse/main.c
r67f54965 r1b0b86e6 44 44 * @return Error code. 45 45 */ 46 static int usbmouse_add_device( ddf_dev_t *dev)46 static int usbmouse_add_device(usb_device_t *dev) 47 47 { 48 48 int rc = usb_mouse_create(dev); … … 53 53 } 54 54 55 fid_t poll_fibril = fibril_create(usb_mouse_polling_fibril, dev); 56 if (poll_fibril == 0) { 57 usb_log_error("Failed to initialize polling fibril.\n"); 58 /* FIXME: free allocated resources. */ 59 return ENOMEM; 55 usb_log_debug("Polling pipe at endpoint %d.\n", dev->pipes[0].pipe->endpoint_no); 56 57 rc = usb_device_auto_poll(dev, 0, 58 usb_mouse_polling_callback, dev->pipes[0].pipe->max_packet_size, 59 usb_mouse_polling_ended_callback, dev->driver_data); 60 61 if (rc != EOK) { 62 usb_log_error("Failed to start polling fibril: %s.\n", 63 str_error(rc)); 64 return rc; 60 65 } 61 66 62 fibril_add_ready(poll_fibril);63 64 67 usb_log_info("controlling new mouse (handle %llu).\n", 65 dev-> handle);68 dev->ddf_dev->handle); 66 69 67 70 return EOK; … … 69 72 70 73 /** USB mouse driver ops. */ 71 static driver_ops_t mouse_driver_ops = {74 static usb_driver_ops_t mouse_driver_ops = { 72 75 .add_device = usbmouse_add_device, 73 76 }; 74 77 78 static usb_endpoint_description_t *endpoints[] = { 79 &poll_endpoint_description, 80 NULL 81 }; 82 75 83 /** USB mouse driver. */ 76 static driver_t mouse_driver = {84 static usb_driver_t mouse_driver = { 77 85 .name = NAME, 78 .driver_ops = &mouse_driver_ops 86 .ops = &mouse_driver_ops, 87 .endpoints = endpoints 79 88 }; 80 89 … … 83 92 usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME); 84 93 85 return ddf_driver_main(&mouse_driver);94 return usb_driver_main(&mouse_driver); 86 95 } 87 96 -
uspace/drv/usbmouse/mouse.c
r67f54965 r1b0b86e6 40 40 #include <ipc/mouse.h> 41 41 42 /** Fibril function for polling the mouse device.42 /** Mouse polling callback. 43 43 * 44 * This function shall not terminate unless the device breaks and fails45 * to send data (e.g. stalls on data request).46 * 47 * @param arg ddf_dev_t type representing the mouse device.48 * @return EOK Always.44 * @param dev Device that is being polled. 45 * @param buffer Data buffer. 46 * @param buffer_size Buffer size in bytes. 47 * @param arg Custom argument - points to usb_mouse_t. 48 * @return Always true. 49 49 */ 50 int usb_mouse_polling_fibril(void *arg) 50 bool usb_mouse_polling_callback(usb_device_t *dev, 51 uint8_t *buffer, size_t buffer_size, void *arg) 51 52 { 52 assert(arg != NULL); 53 ddf_dev_t *dev = (ddf_dev_t *) arg; 54 usb_mouse_t *mouse = (usb_mouse_t *) dev->driver_data; 53 usb_mouse_t *mouse = (usb_mouse_t *) arg; 55 54 56 assert(mouse); 55 usb_log_debug2("got buffer: %s.\n", 56 usb_debug_str_buffer(buffer, buffer_size, 0)); 57 57 58 size_t buffer_size = mouse->poll_pipe.max_packet_size; 58 uint8_t butt = buffer[0]; 59 char str_buttons[4] = { 60 butt & 1 ? '#' : '.', 61 butt & 2 ? '#' : '.', 62 butt & 4 ? '#' : '.', 63 0 64 }; 59 65 60 if (buffer_size < 4) { 61 usb_log_error("Weird mouse, results will be skewed.\n"); 62 buffer_size = 4; 66 int shift_x = ((int) buffer[1]) - 127; 67 int shift_y = ((int) buffer[2]) - 127; 68 int wheel = ((int) buffer[3]) - 127; 69 70 if (buffer[1] == 0) { 71 shift_x = 0; 72 } 73 if (buffer[2] == 0) { 74 shift_y = 0; 75 } 76 if (buffer[3] == 0) { 77 wheel = 0; 63 78 } 64 79 65 uint8_t *buffer = malloc(buffer_size); 66 if (buffer == NULL) { 67 usb_log_error("Out of memory, poll fibril aborted.\n"); 68 return ENOMEM; 80 if (mouse->console_phone >= 0) { 81 if ((shift_x != 0) || (shift_y != 0)) { 82 /* FIXME: guessed for QEMU */ 83 async_req_2_0(mouse->console_phone, 84 MEVENT_MOVE, 85 - shift_x / 10, - shift_y / 10); 86 } 87 if (butt) { 88 /* FIXME: proper button clicking. */ 89 async_req_2_0(mouse->console_phone, 90 MEVENT_BUTTON, 1, 1); 91 async_req_2_0(mouse->console_phone, 92 MEVENT_BUTTON, 1, 0); 93 } 69 94 } 70 95 71 while (true) {72 async_usleep(mouse->poll_interval_us);96 usb_log_debug("buttons=%s dX=%+3d dY=%+3d wheel=%+3d\n", 97 str_buttons, shift_x, shift_y, wheel); 73 98 74 size_t actual_size;75 int rc;99 /* Guess. */ 100 async_usleep(1000); 76 101 77 /* 78 * Error checking note: 79 * - failure when starting a session is considered 80 * temporary (e.g. out of phones, next try might succeed) 81 * - failure of transfer considered fatal (probably the 82 * device was unplugged) 83 * - session closing not checked (shall not fail anyway) 84 */ 102 return true; 103 } 85 104 86 rc = usb_endpoint_pipe_start_session(&mouse->poll_pipe); 87 if (rc != EOK) { 88 usb_log_warning("Failed to start session, will try again: %s.\n", 89 str_error(rc)); 90 continue; 91 } 105 /** Callback when polling is terminated. 106 * 107 * @param dev Device where the polling terminated. 108 * @param recurring_errors Whether the polling was terminated due to 109 * recurring errors. 110 * @param arg Custom argument - points to usb_mouse_t. 111 */ 112 void usb_mouse_polling_ended_callback(usb_device_t *dev, 113 bool recurring_errors, void *arg) 114 { 115 usb_mouse_t *mouse = (usb_mouse_t *) arg; 92 116 93 rc = usb_endpoint_pipe_read(&mouse->poll_pipe,94 buffer, buffer_size, &actual_size);95 96 usb_endpoint_pipe_end_session(&mouse->poll_pipe);97 98 if (rc != EOK) {99 usb_log_error("Failed reading mouse input: %s.\n",100 str_error(rc));101 break;102 }103 104 usb_log_debug2("got buffer: %s.\n",105 usb_debug_str_buffer(buffer, buffer_size, 0));106 107 uint8_t butt = buffer[0];108 char str_buttons[4] = {109 butt & 1 ? '#' : '.',110 butt & 2 ? '#' : '.',111 butt & 4 ? '#' : '.',112 0113 };114 115 int shift_x = ((int) buffer[1]) - 127;116 int shift_y = ((int) buffer[2]) - 127;117 int wheel = ((int) buffer[3]) - 127;118 119 if (buffer[1] == 0) {120 shift_x = 0;121 }122 if (buffer[2] == 0) {123 shift_y = 0;124 }125 if (buffer[3] == 0) {126 wheel = 0;127 }128 129 if (mouse->console_phone >= 0) {130 if ((shift_x != 0) || (shift_y != 0)) {131 /* FIXME: guessed for QEMU */132 async_req_2_0(mouse->console_phone,133 MEVENT_MOVE,134 - shift_x / 10, - shift_y / 10);135 }136 if (butt) {137 /* FIXME: proper button clicking. */138 async_req_2_0(mouse->console_phone,139 MEVENT_BUTTON, 1, 1);140 async_req_2_0(mouse->console_phone,141 MEVENT_BUTTON, 1, 0);142 }143 }144 145 usb_log_debug("buttons=%s dX=%+3d dY=%+3d wheel=%+3d\n",146 str_buttons, shift_x, shift_y, wheel);147 }148 149 /*150 * Device was probably unplugged.151 * Hang-up the phone to the console.152 * FIXME: release allocated memory.153 */154 117 async_hangup(mouse->console_phone); 155 118 mouse->console_phone = -1; 156 157 usb_log_error("Mouse polling fibril terminated.\n");158 159 return EOK;160 119 } 161 162 120 163 121 /** -
uspace/drv/usbmouse/mouse.h
r67f54965 r1b0b86e6 37 37 #define USBMOUSE_MOUSE_H_ 38 38 39 #include < ddf/driver.h>39 #include <usb/devdrv.h> 40 40 #include <usb/pipes.h> 41 41 #include <time.h> … … 46 46 typedef struct { 47 47 /** Generic device container. */ 48 ddf_dev_t *device;48 usb_device_t *dev; 49 49 /** Function representing the device. */ 50 50 ddf_fun_t *mouse_fun; 51 /** Representation of connection to the device. */52 usb_device_connection_t wire;53 /** Default (zero) control pipe. */54 usb_endpoint_pipe_t ctrl_pipe;55 /** Polling (in) pipe. */56 usb_endpoint_pipe_t poll_pipe;57 51 /** Polling interval in microseconds. */ 58 52 suseconds_t poll_interval_us; … … 61 55 } usb_mouse_t; 62 56 63 int usb_mouse_create(ddf_dev_t *); 57 #define POLL_PIPE(dev) ((dev)->pipes[0].pipe) 64 58 65 int usb_mouse_polling_fibril(void *); 59 extern usb_endpoint_description_t poll_endpoint_description; 60 61 int usb_mouse_create(usb_device_t *); 62 63 bool usb_mouse_polling_callback(usb_device_t *, uint8_t *, size_t, void *); 64 void usb_mouse_polling_ended_callback(usb_device_t *, bool, void *); 66 65 67 66 #endif -
uspace/lib/usb/Makefile
r67f54965 r1b0b86e6 37 37 src/ddfiface.c \ 38 38 src/debug.c \ 39 src/devdrv.c \ 40 src/devpoll.c \ 39 41 src/dp.c \ 40 42 src/dump.c \ -
uspace/lib/usb/include/usb/pipes.h
r67f54965 r1b0b86e6 106 106 const usb_endpoint_description_t *description; 107 107 /** Interface number the endpoint must belong to (-1 for any). */ 108 constint interface_no;108 int interface_no; 109 109 /** Found descriptor fitting the description. */ 110 110 usb_standard_endpoint_descriptor_t *descriptor; -
uspace/lib/usb/src/pipesinit.c
r67f54965 r1b0b86e6 37 37 #include <usb/pipes.h> 38 38 #include <usb/dp.h> 39 #include <usb/request.h> 39 40 #include <errno.h> 40 41 #include <assert.h> … … 370 371 int rc = usb_endpoint_pipe_initialize(pipe, connection, 371 372 0, USB_TRANSFER_CONTROL, 8, USB_DIRECTION_BOTH); 372 373 if (rc != EOK) { 374 return rc; 375 } 376 rc = usb_endpoint_pipe_start_session(pipe); 377 if (rc != EOK) { 378 return rc; 379 } 380 381 uint8_t first[8]; 382 size_t size = 0; 383 rc = usb_control_request_get(pipe, USB_REQUEST_TYPE_STANDARD, 384 USB_REQUEST_RECIPIENT_DEVICE, USB_DEVREQ_GET_DESCRIPTOR, 1 << 8, 385 0, first, 8, &size); 386 usb_endpoint_pipe_end_session(pipe); 387 if (rc != EOK || size != 8) { 388 return rc; 389 } 390 391 pipe->max_packet_size = first[7]; 373 392 return rc; 374 393 }
Note:
See TracChangeset
for help on using the changeset viewer.