Changes in / [1b0b86e6:67f54965] in mainline
- Location:
- uspace
- Files:
-
- 4 added
- 7 deleted
- 25 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/ehci-hcd/pci.c
r1b0b86e6 r67f54965 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 */ 260 261 } 261 262 … … 279 280 usb_log_debug2("USBLEGSUP: %x.\n", value); 280 281 281 282 * TURN OFF EHCI FOR NOW, DRIVER WILL REINITIALIZE IT 283 282 /* 283 * TURN OFF EHCI FOR NOW, REMOVE IF THE DRIVER IS IMPLEMENTED 284 */ 284 285 285 286 /* Get size of capability registers in memory space. */ -
uspace/drv/uhci-hcd/Makefile
r1b0b86e6 r67f54965 35 35 iface.c \ 36 36 main.c \ 37 root_hub.c \ 37 38 transfer_list.c \ 38 39 uhci.c \ 39 uhci_hc.c \40 uhci_rh.c \41 40 uhci_struct/transfer_descriptor.c \ 42 41 utils/device_keeper.c \ -
uspace/drv/uhci-hcd/batch.c
r1b0b86e6 r67f54965 40 40 #include "batch.h" 41 41 #include "transfer_list.h" 42 #include "uhci _hc.h"42 #include "uhci.h" 43 43 #include "utils/malloc32.h" 44 44 … … 100 100 bzero(instance, sizeof(batch_t)); 101 101 102 instance->qh = malloc32(sizeof(q h_t));102 instance->qh = malloc32(sizeof(queue_head_t)); 103 103 CHECK_NULL_DISPOSE_RETURN(instance->qh, 104 104 "Failed to allocate batch queue head.\n"); 105 q h_init(instance->qh);105 queue_head_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; 116 118 117 119 if (size > 0) { … … 141 143 instance->speed = speed; 142 144 instance->manager = manager; 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)); 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)); 147 152 148 153 usb_log_debug("Batch(%p) %d:%d memory structures ready.\n", … … 172 177 usb_log_debug("Batch(%p) found error TD(%d):%x.\n", 173 178 instance, i, instance->tds[i].status); 174 td_print_status(&instance->tds[i]);175 179 176 180 device_keeper_set_toggle(instance->manager, … … 314 318 ++packet; 315 319 } 316 td_set_ioc(&instance->tds[packet - 1]);317 320 device_keeper_set_toggle(instance->manager, instance->target, toggle); 318 321 } … … 366 369 0, 1, false, low_speed, instance->target, status_stage, NULL, NULL); 367 370 368 td_set_ioc(&instance->tds[packet]); 371 372 instance->tds[packet].status |= TD_STATUS_COMPLETE_INTERRUPT_FLAG; 369 373 usb_log_debug2("Control last TD status: %x.\n", 370 374 instance->tds[packet].status); … … 450 454 { 451 455 assert(instance); 452 uhci_ hc_t *hc = fun_to_uhci_hc(instance->fun);456 uhci_t *hc = fun_to_uhci(instance->fun); 453 457 assert(hc); 454 return uhci_ hc_schedule(hc, instance);458 return uhci_schedule(hc, instance); 455 459 } 456 460 /** -
uspace/drv/uhci-hcd/batch.h
r1b0b86e6 r67f54965 50 50 usb_target_t target; 51 51 usb_transfer_type_t transfer_type; 52 usbhc_iface_transfer_in_callback_t callback_in; 53 usbhc_iface_transfer_out_callback_t callback_out; 52 union { 53 usbhc_iface_transfer_in_callback_t callback_in; 54 usbhc_iface_transfer_out_callback_t callback_out; 55 }; 54 56 void *arg; 55 57 char *transport_buffer; … … 63 65 int error; 64 66 ddf_fun_t *fun; 65 q h_t *qh;67 queue_head_t *qh; 66 68 td_t *tds; 67 69 void (*next_step)(struct batch*); -
uspace/drv/uhci-hcd/iface.c
r1b0b86e6 r67f54965 40 40 41 41 #include "iface.h" 42 #include "uhci _hc.h"42 #include "uhci.h" 43 43 #include "utils/device_keeper.h" 44 44 … … 53 53 { 54 54 assert(fun); 55 uhci_ hc_t *hc = fun_to_uhci_hc(fun);55 uhci_t *hc = fun_to_uhci(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_ hc_t *hc = fun_to_uhci_hc(fun);70 uhci_t *hc = fun_to_uhci(fun); 71 71 assert(hc); 72 72 usb_log_debug("Default address release.\n"); … … 86 86 { 87 87 assert(fun); 88 uhci_ hc_t *hc = fun_to_uhci_hc(fun);88 uhci_t *hc = fun_to_uhci(fun); 89 89 assert(hc); 90 90 assert(address); … … 109 109 { 110 110 assert(fun); 111 uhci_ hc_t *hc = fun_to_uhci_hc(fun);111 uhci_t *hc = fun_to_uhci(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_ hc_t *hc = fun_to_uhci_hc(fun);127 uhci_t *hc = fun_to_uhci(fun); 128 128 assert(hc); 129 129 usb_log_debug("Address release %d.\n", address); … … 148 148 { 149 149 assert(fun); 150 uhci_ hc_t *hc = fun_to_uhci_hc(fun);150 uhci_t *hc = fun_to_uhci(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_ hc_t *hc = fun_to_uhci_hc(fun);182 uhci_t *hc = fun_to_uhci(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_ hc_t *hc = fun_to_uhci_hc(fun);213 uhci_t *hc = fun_to_uhci(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_ hc_t *hc = fun_to_uhci_hc(fun);245 uhci_t *hc = fun_to_uhci(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_ 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);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); 284 284 285 285 if (setup_size != 8) … … 315 315 { 316 316 assert(fun); 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);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); 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_ hc_iface = {332 usbhc_iface_t uhci_iface = { 333 333 .reserve_default_address = reserve_default_address, 334 334 .release_default_address = release_default_address, -
uspace/drv/uhci-hcd/iface.h
r1b0b86e6 r67f54965 38 38 #include <usbhc_iface.h> 39 39 40 extern usbhc_iface_t uhci_ hc_iface;40 extern usbhc_iface_t uhci_iface; 41 41 42 42 #endif -
uspace/drv/uhci-hcd/main.c
r1b0b86e6 r67f54965 33 33 */ 34 34 #include <ddf/driver.h> 35 #include <ddf/interrupt.h> 36 #include <device/hw_res.h> 35 37 #include <errno.h> 36 38 #include <str_error.h> 37 39 40 #include <usb_iface.h> 38 41 #include <usb/ddfiface.h> 39 42 #include <usb/debug.h> 40 43 41 44 #include "iface.h" 45 #include "pci.h" 46 #include "root_hub.h" 42 47 #include "uhci.h" 43 48 … … 55 60 }; 56 61 /*----------------------------------------------------------------------------*/ 57 /** Initializes a new ddf driver instance for uhci hc and hub. 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. 58 78 * 59 79 * @param[in] device DDF instance of the device to initialize. … … 65 85 int uhci_add_device(ddf_dev_t *device) 66 86 { 87 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 } 96 67 97 usb_log_info("uhci_add_device() called\n"); 68 assert(device); 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; 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); 116 if (ret != EOK) { 117 usb_log_warning( 118 "Failed(%d) to enable interrupts, fall back to polling.\n", 119 ret); 73 120 } 121 #endif 74 122 75 int ret = uhci_init(uhci, device); 76 if (ret != EOK) { 77 usb_log_error("Failed to initialzie UHCI driver.\n"); 78 return ret; 79 } 80 device->driver_data = uhci; 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 81 166 return EOK; 167 #undef CHECK_RET_FINI_FREE_RETURN 82 168 } 83 169 /*----------------------------------------------------------------------------*/ -
uspace/drv/uhci-hcd/transfer_list.c
r1b0b86e6 r67f54965 47 47 * @return Error code 48 48 * 49 * Allocates memory for interna l qh_t structure.49 * Allocates memory for internat queue_head_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; 54 55 instance->name = name; 55 instance->queue_head = malloc32(sizeof(q h_t));56 instance->queue_head = malloc32(sizeof(queue_head_t)); 56 57 if (!instance->queue_head) { 57 58 usb_log_error("Failed to allocate queue head.\n"); … … 60 61 instance->queue_head_pa = addr_to_phys(instance->queue_head); 61 62 62 q h_init(instance->queue_head);63 queue_head_init(instance->queue_head); 63 64 list_initialize(&instance->batch_list); 64 65 fibril_mutex_initialize(&instance->guard); … … 71 72 * @param[in] next List to append. 72 73 * @return Error code 73 *74 * Does not check whether there was a next list already.75 74 */ 76 75 void transfer_list_set_next(transfer_list_t *instance, transfer_list_t *next) … … 80 79 if (!instance->queue_head) 81 80 return; 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); 81 queue_head_append_qh(instance->queue_head, next->queue_head_pa); 82 instance->queue_head->element = instance->queue_head->next_queue; 85 83 } 86 84 /*----------------------------------------------------------------------------*/ … … 95 93 assert(instance); 96 94 assert(batch); 97 usb_log_debug2("Queue %s: Adding batch(%p).\n", instance->name, batch); 95 usb_log_debug2( 96 "Adding batch(%p) to queue %s.\n", batch, instance->name); 98 97 99 const uint32_t pa =addr_to_phys(batch->qh);98 uint32_t pa = (uintptr_t)addr_to_phys(batch->qh); 100 99 assert((pa & LINK_POINTER_ADDRESS_MASK) == pa); 100 pa |= LINK_POINTER_QUEUE_HEAD_FLAG; 101 101 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); 102 batch->qh->next_queue = instance->queue_head->next_queue; 105 103 106 104 fibril_mutex_lock(&instance->guard); 107 105 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); 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; 118 114 } 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); 119 122 list_append(&batch->link, &instance->batch_list); 120 123 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", 124 usb_log_debug("Batch(%p) added to queue %s last, first is %p.\n", 124 125 batch, instance->name, first); 125 126 fibril_mutex_unlock(&instance->guard); 126 127 } 127 128 /*----------------------------------------------------------------------------*/ 128 /** Removes a transfer batch from thelist and queue.129 /** Removes a transfer batch from list and queue. 129 130 * 130 131 * @param[in] instance List to use. 131 132 * @param[in] batch Transfer batch to remove. 132 133 * @return Error code 133 *134 * Does not lock the transfer list, caller is responsible for that.135 134 */ 136 135 void transfer_list_remove_batch(transfer_list_t *instance, batch_t *batch) … … 141 140 assert(batch->qh); 142 141 usb_log_debug2( 143 " Queue %s: removing batch(%p).\n", instance->name, batch);142 "Removing batch(%p) from queue %s.\n", batch, instance->name); 144 143 145 const char * pos = NULL;146 144 if (batch->link.prev == &instance->batch_list) { 147 145 /* I'm the first one here */ 148 qh_set_element_qh(instance->queue_head, batch->qh->next); 149 pos = "FIRST"; 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; 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); 151 154 batch_t *prev = 152 155 list_get_instance(batch->link.prev, batch_t, link); 153 qh_set_next_qh(prev->qh, batch->qh->next); 154 pos = "NOT FIRST"; 156 prev->qh->next_queue = batch->qh->next_queue; 155 157 } 156 158 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 batches.161 /** Checks list for finished transfers. 162 162 * 163 163 * @param[in] instance List to use. -
uspace/drv/uhci-hcd/transfer_list.h
r1b0b86e6 r67f54965 44 44 { 45 45 fibril_mutex_t guard; 46 q h_t *queue_head;46 queue_head_t *queue_head; 47 47 uint32_t queue_head_pa; 48 struct transfer_list *next; 48 49 const char *name; 49 50 link_t batch_list; -
uspace/drv/uhci-hcd/uhci.c
r1b0b86e6 r67f54965 26 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 27 */ 28 29 /** @addtogroup drvusbuhci 28 /** @addtogroup usb 30 29 * @{ 31 30 */ … … 35 34 #include <errno.h> 36 35 #include <str_error.h> 37 #include <ddf/interrupt.h> 36 #include <adt/list.h> 37 #include <libarch/ddi.h> 38 39 #include <usb/debug.h> 40 #include <usb/usb.h> 41 #include <usb/ddfiface.h> 38 42 #include <usb_iface.h> 39 #include <usb/ddfiface.h>40 #include <usb/debug.h>41 43 42 44 #include "uhci.h" 43 45 #include "iface.h" 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 /*----------------------------------------------------------------------------*/ 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 */ 62 70 static int usb_iface_get_address( 63 71 ddf_fun_t *fun, devman_handle_t handle, usb_address_t *address) 64 72 { 65 73 assert(fun); 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); 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); 69 79 if (addr < 0) { 70 80 return addr; … … 78 88 } 79 89 /*----------------------------------------------------------------------------*/ 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, 90 static usb_iface_t hc_usb_iface = { 91 .get_hc_handle = usb_iface_get_hc_handle_hc_impl, 100 92 .get_address = usb_iface_get_address 101 93 }; 102 94 /*----------------------------------------------------------------------------*/ 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 */95 static ddf_dev_ops_t uhci_ops = { 96 .interfaces[USB_DEV_IFACE] = &hc_usb_iface, 97 .interfaces[USBHC_DEV_IFACE] = &uhci_iface, 106 98 }; 107 99 /*----------------------------------------------------------------------------*/ 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; 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 134 124 #define CHECK_RET_DEST_FUN_RETURN(ret, message...) \ 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); 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; 150 135 CHECK_RET_DEST_FUN_RETURN(ret, 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); 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); 178 142 CHECK_RET_DEST_FUN_RETURN(ret, 179 143 "Failed(%d) to bind UHCI device function: %s.\n", 180 144 ret, str_error(ret)); 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 216 return EOK; 217 #undef CHECK_RET_FINI_RETURN 218 } 219 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"); 169 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 } 220 494 /** 221 495 * @} -
uspace/drv/uhci-hcd/uhci.h
r1b0b86e6 r67f54965 1 1 /* 2 * Copyright (c) 201 1Jan Vesely2 * Copyright (c) 2010 Jan Vesely 3 3 * All rights reserved. 4 4 * … … 35 35 #ifndef DRV_UHCI_UHCI_H 36 36 #define DRV_UHCI_UHCI_H 37 38 #include <fibril.h> 39 #include <fibril_synch.h> 40 #include <adt/list.h> 37 41 #include <ddi.h> 38 #include <ddf/driver.h>39 42 40 #include "uhci_hc.h" 41 #include "uhci_rh.h" 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 42 82 43 83 typedef struct uhci { 44 ddf_fun_t *hc_fun; 45 ddf_fun_t *rh_fun; 84 device_keeper_t device_manager; 46 85 47 uhci_hc_t hc; 48 uhci_rh_t rh; 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; 49 103 } uhci_t; 50 104 51 int uhci_init(uhci_t *instance, ddf_dev_t *device); 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 52 120 53 121 #endif -
uspace/drv/uhci-hcd/uhci_struct/link_pointer.h
r1b0b86e6 r67f54965 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 51 48 #endif 52 49 /** -
uspace/drv/uhci-hcd/uhci_struct/queue_head.h
r1b0b86e6 r67f54965 43 43 44 44 typedef struct queue_head { 45 volatile link_pointer_t next ;45 volatile link_pointer_t next_queue; 46 46 volatile link_pointer_t element; 47 } __attribute__((packed)) q h_t;48 /*----------------------------------------------------------------------------*/ 49 static inline void q h_init(qh_t *instance)47 } __attribute__((packed)) queue_head_t; 48 49 static inline void queue_head_init(queue_head_t *instance) 50 50 { 51 51 assert(instance); 52 52 53 53 instance->element = 0 | LINK_POINTER_TERMINATE_FLAG; 54 instance->next = 0 | LINK_POINTER_TERMINATE_FLAG;54 instance->next_queue = 0 | LINK_POINTER_TERMINATE_FLAG; 55 55 } 56 /*----------------------------------------------------------------------------*/ 57 static inline void q h_set_next_qh(qh_t *instance, uint32_t pa)56 57 static inline void queue_head_append_qh(queue_head_t *instance, uint32_t pa) 58 58 { 59 /* address is valid and not terminal */ 60 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) { 61 instance->next = (pa & LINK_POINTER_ADDRESS_MASK) 59 if (pa) { 60 instance->next_queue = (pa & LINK_POINTER_ADDRESS_MASK) 62 61 | LINK_POINTER_QUEUE_HEAD_FLAG; 63 } else {64 instance->next = 0 | LINK_POINTER_TERMINATE_FLAG;65 62 } 66 63 } 67 /*----------------------------------------------------------------------------*/ 68 static inline void q h_set_element_qh(qh_t *instance, uint32_t pa)64 65 static inline void queue_head_element_qh(queue_head_t *instance, uint32_t pa) 69 66 { 70 /* address is valid and not terminal */ 71 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) { 72 instance->element = (pa & LINK_POINTER_ADDRESS_MASK) 67 if (pa) { 68 instance->next_queue = (pa & LINK_POINTER_ADDRESS_MASK) 73 69 | LINK_POINTER_QUEUE_HEAD_FLAG; 74 } else {75 instance->element = 0 | LINK_POINTER_TERMINATE_FLAG;76 70 } 77 71 } 78 /*----------------------------------------------------------------------------*/ 79 static inline void q h_set_element_td(qh_t *instance, uint32_t pa)72 73 static inline void queue_head_set_element_td(queue_head_t *instance, uint32_t pa) 80 74 { 81 if (pa && ((pa & LINK_POINTER_TERMINATE_FLAG) == 0)) {75 if (pa) { 82 76 instance->element = (pa & LINK_POINTER_ADDRESS_MASK); 83 } else {84 instance->element = 0 | LINK_POINTER_TERMINATE_FLAG;85 77 } 86 78 } -
uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.c
r1b0b86e6 r67f54965 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 representsIsochronous transfer.46 * @param[in] iso True if TD is for 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 set58 * - if the packet uses PID_IN and is not isochronous SPD is set59 *60 * Dumps 8 bytes of buffer if PID_SETUP is used.61 53 */ 62 54 void td_init(td_t *instance, int err_count, size_t size, bool toggle, bool iso, … … 96 88 } 97 89 98 usb_log_debug2("Created TD (%p): %X:%X:%X:%X(%p).\n",99 instance , instance->next, instance->status, instance->device,90 usb_log_debug2("Created TD: %X:%X:%X:%X(%p).\n", 91 instance->next, instance->status, instance->device, 100 92 instance->buffer_ptr, buffer); 101 td_print_status(instance);102 93 if (pid == USB_PID_SETUP) { 103 94 usb_log_debug("SETUP BUFFER: %s\n", 104 95 usb_debug_str_buffer(buffer, 8, 8)); 105 96 } 106 97 } … … 135 126 return EOK; 136 127 } 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_MASK162 );163 }164 128 /** 165 129 * @} -
uspace/drv/uhci-hcd/uhci_struct/transfer_descriptor.h
r1b0b86e6 r67f54965 45 45 46 46 volatile uint32_t status; 47 47 48 #define TD_STATUS_RESERVED_MASK 0xc000f800 48 49 #define TD_STATUS_SPD_FLAG ( 1 << 29 ) 49 50 #define TD_STATUS_ERROR_COUNT_POS ( 27 ) 50 51 #define TD_STATUS_ERROR_COUNT_MASK ( 0x3 ) 52 #define TD_STATUS_ERROR_COUNT_DEFAULT 3 51 53 #define TD_STATUS_LOW_SPEED_FLAG ( 1 << 26 ) 52 54 #define TD_STATUS_ISOCHRONOUS_FLAG ( 1 << 25 ) 53 #define TD_STATUS_ IOC_FLAG ( 1 << 24 )55 #define TD_STATUS_COMPLETE_INTERRUPT_FLAG ( 1 << 24 ) 54 56 55 57 #define TD_STATUS_ERROR_ACTIVE ( 1 << 23 ) … … 68 70 69 71 volatile uint32_t device; 72 70 73 #define TD_DEVICE_MAXLEN_POS 21 71 74 #define TD_DEVICE_MAXLEN_MASK ( 0x7ff ) … … 82 85 83 86 /* there is 16 bytes of data available here, according to UHCI 84 * Design guide, according to linux kernel the hardware does not care ,85 * it just needs to be aligned,we don't use it anyway87 * Design guide, according to linux kernel the hardware does not care 88 * we don't use it anyway 86 89 */ 87 90 } __attribute__((packed)) td_t; 88 91 89 92 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);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); 93 96 94 97 int td_status(td_t *instance); 95 98 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 */103 99 static inline size_t td_act_size(td_t *instance) 104 100 { 105 101 assert(instance); 106 const uint32_t s = instance->status; 107 return ((s >> TD_STATUS_ACTLEN_POS) + 1) & TD_STATUS_ACTLEN_MASK; 102 return 103 ((instance->status >> TD_STATUS_ACTLEN_POS) + 1) 104 & TD_STATUS_ACTLEN_MASK; 108 105 } 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 */ 106 116 107 static inline bool td_is_short(td_t *instance) 117 108 { … … 123 114 (instance->status | TD_STATUS_SPD_FLAG) && act_size < max_size; 124 115 } 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 */ 116 131 117 static inline int td_toggle(td_t *instance) 132 118 { 133 119 assert(instance); 134 return (instance->device & TD_DEVICE_DATA_TOGGLE_ONE_FLAG) ? 1 : 0; 120 return ((instance->device & TD_DEVICE_DATA_TOGGLE_ONE_FLAG) != 0) 121 ? 1 : 0; 135 122 } 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 */ 123 142 124 static inline bool td_is_active(td_t *instance) 143 125 { … … 145 127 return (instance->status & TD_STATUS_ERROR_ACTIVE) != 0; 146 128 } 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 /*----------------------------------------------------------------------------*/158 129 #endif 159 130 /** -
uspace/drv/uhci-rhd/Makefile
r1b0b86e6 r67f54965 35 35 main.c \ 36 36 port.c \ 37 port_status.c \ 37 38 root_hub.c 38 39 -
uspace/drv/uhci-rhd/port.c
r1b0b86e6 r67f54965 44 44 45 45 #include "port.h" 46 #include "port_status.h" 46 47 47 48 static int uhci_port_new_device(uhci_port_t *port, usb_speed_t speed); … … 66 67 { 67 68 assert(port); 68 asprintf(&port->id_string, "Port (%p - %d)", port, number);69 if (port->id_string == NULL) {70 return ENOMEM;71 }72 69 73 70 port->address = address; … … 119 116 assert(instance); 120 117 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 = 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); 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); 130 135 131 136 if ((port_status & STATUS_CONNECTED_CHANGED) == 0) 132 137 continue; 133 138 134 usb_log_debug(" %s: Connected change detected: %x.\n",135 instance-> id_string, port_status);139 usb_log_debug("Port(%p - %d): Connected change detected: %x.\n", 140 instance->address, instance->number, port_status); 136 141 137 142 int rc = 138 143 usb_hc_connection_open(&instance->hc_connection); 139 144 if (rc != EOK) { 140 usb_log_error(" %s: Failed to connect to HC.",141 instance-> id_string);145 usb_log_error("Port(%p - %d): Failed to connect to HC.", 146 instance->address, instance->number); 142 147 continue; 143 148 } … … 145 150 /* Remove any old device */ 146 151 if (instance->attached_device) { 147 usb_log_debug2(" %s: Removing device.\n",148 instance-> id_string);152 usb_log_debug2("Port(%p - %d): Removing device.\n", 153 instance->address, instance->number); 149 154 uhci_port_remove_device(instance); 150 155 } … … 158 163 } else { 159 164 /* Write one to WC bits, to ack changes */ 160 uhci_port_write_status(instance, port_status);161 usb_log_debug(" %s: status changeACK.\n",162 instance-> id_string);165 port_status_write(instance->address, port_status); 166 usb_log_debug("Port(%p - %d): Change status ACK.\n", 167 instance->address, instance->number); 163 168 } 164 169 165 170 rc = usb_hc_connection_close(&instance->hc_connection); 166 171 if (rc != EOK) { 167 usb_log_error(" %s: Failed to disconnect.",168 instance-> id_string);172 usb_log_error("Port(%p - %d): Failed to disconnect.", 173 instance->address, instance->number); 169 174 } 170 175 } … … 182 187 uhci_port_t *port = (uhci_port_t *) arg; 183 188 184 usb_log_debug2("%s: new_device_enable_port.\n", port->id_string); 189 usb_log_debug2("Port(%p - %d): new_device_enable_port.\n", 190 port->address, port->number); 185 191 186 192 /* … … 190 196 async_usleep(100000); 191 197 192 /* 193 * Resets from root ports should be nominally 50ms 198 199 /* The hub maintains the reset signal to that port for 10 ms 200 * (See Section 11.5.1.5) 194 201 */ 195 202 { 196 usb_log_debug("%s: Reset Signal start.\n", port->id_string); 197 port_status_t port_status = uhci_port_read_status(port); 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); 198 207 port_status |= STATUS_IN_RESET; 199 uhci_port_write_status(port, port_status);200 async_usleep( 50000);201 port_status = uhci_port_read_status(port);208 port_status_write(port->address, port_status); 209 async_usleep(10000); 210 port_status = port_status_read(port->address); 202 211 port_status &= ~STATUS_IN_RESET; 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); 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 } 209 216 210 217 /* Enable the port. */ 211 218 uhci_port_set_enabled(port, true); 212 213 219 return EOK; 214 220 } … … 227 233 assert(usb_hc_connection_is_opened(&port->hc_connection)); 228 234 229 usb_log_info("%s: Detected new device.\n", port->id_string); 235 usb_log_info("Port(%p-%d): Detected new device.\n", 236 port->address, port->number); 230 237 231 238 usb_address_t dev_addr; … … 235 242 236 243 if (rc != EOK) { 237 usb_log_error(" %s: Failed(%d) to add device: %s.\n",238 port-> id_string, rc, str_error(rc));244 usb_log_error("Port(%p-%d): Failed(%d) to add device: %s.\n", 245 port->address, port->number, rc, str_error(rc)); 239 246 uhci_port_set_enabled(port, false); 240 247 return rc; 241 248 } 242 249 243 usb_log_info(" %s: New device has address %d (handle %zu).\n",244 port-> id_string, dev_addr, port->attached_device);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); 245 252 246 253 return EOK; … … 256 263 int uhci_port_remove_device(uhci_port_t *port) 257 264 { 258 usb_log_error(" %s: Don't know how to remove device %d.\n",259 port-> id_string, (unsigned int)port->attached_device);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); 260 267 return EOK; 261 268 } … … 271 278 272 279 /* Read register value */ 273 port_status_t port_status = uhci_port_read_status(port);280 port_status_t port_status = port_status_read(port->address); 274 281 275 282 /* Set enabled bit */ … … 281 288 282 289 /* Write new value. */ 283 uhci_port_write_status(port, port_status);284 285 usb_log_info(" %s: %sabled port.\n",286 port-> id_string, enabled ? "En" : "Dis");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"); 287 294 return EOK; 288 295 } -
uspace/drv/uhci-rhd/port.h
r1b0b86e6 r67f54965 36 36 37 37 #include <assert.h> 38 #include <ddf/driver.h> 38 39 #include <stdint.h> 39 #include <ddf/driver.h>40 #include <libarch/ddi.h> /* pio_read and pio_write */41 40 #include <usb/usbdevice.h> 42 41 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) 42 #include "port_status.h" 57 43 58 44 typedef struct uhci_port 59 45 { 60 char *id_string;61 46 port_status_t *address; 62 47 unsigned number; … … 73 58 74 59 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 }108 60 #endif 109 61 /** -
uspace/drv/usbmouse/init.c
r1b0b86e6 r67f54965 42 42 43 43 /** Mouse polling endpoint description for boot protocol subclass. */ 44 usb_endpoint_description_t poll_endpoint_description = {44 static usb_endpoint_description_t poll_endpoint_description = { 45 45 .transfer_type = USB_TRANSFER_INTERRUPT, 46 46 .direction = USB_DIRECTION_IN, … … 51 51 }; 52 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_interface 81 } 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 53 102 static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *); 54 103 /** Device ops for USB mouse. */ … … 94 143 * @return Error code. 95 144 */ 96 int usb_mouse_create( usb_device_t *dev)145 int usb_mouse_create(ddf_dev_t *dev) 97 146 { 98 147 usb_mouse_t *mouse = malloc(sizeof(usb_mouse_t)); … … 100 149 return ENOMEM; 101 150 } 102 mouse->dev = dev;151 mouse->device = dev; 103 152 mouse->console_phone = -1; 104 153 105 154 int rc; 106 155 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 107 183 /* Create DDF function. */ 108 mouse->mouse_fun = ddf_fun_create(dev ->ddf_dev, fun_exposed, "mouse");184 mouse->mouse_fun = ddf_fun_create(dev, fun_exposed, "mouse"); 109 185 if (mouse->mouse_fun == NULL) { 110 186 rc = ENOMEM; -
uspace/drv/usbmouse/main.c
r1b0b86e6 r67f54965 44 44 * @return Error code. 45 45 */ 46 static int usbmouse_add_device( usb_device_t *dev)46 static int usbmouse_add_device(ddf_dev_t *dev) 47 47 { 48 48 int rc = usb_mouse_create(dev); … … 53 53 } 54 54 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; 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; 65 60 } 66 61 62 fibril_add_ready(poll_fibril); 63 67 64 usb_log_info("controlling new mouse (handle %llu).\n", 68 dev-> ddf_dev->handle);65 dev->handle); 69 66 70 67 return EOK; … … 72 69 73 70 /** USB mouse driver ops. */ 74 static usb_driver_ops_t mouse_driver_ops = {71 static driver_ops_t mouse_driver_ops = { 75 72 .add_device = usbmouse_add_device, 76 73 }; 77 74 78 static usb_endpoint_description_t *endpoints[] = {79 &poll_endpoint_description,80 NULL81 };82 83 75 /** USB mouse driver. */ 84 static usb_driver_t mouse_driver = {76 static driver_t mouse_driver = { 85 77 .name = NAME, 86 .ops = &mouse_driver_ops, 87 .endpoints = endpoints 78 .driver_ops = &mouse_driver_ops 88 79 }; 89 80 … … 92 83 usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME); 93 84 94 return usb_driver_main(&mouse_driver);85 return ddf_driver_main(&mouse_driver); 95 86 } 96 87 -
uspace/drv/usbmouse/mouse.c
r1b0b86e6 r67f54965 40 40 #include <ipc/mouse.h> 41 41 42 /** Mouse polling callback.42 /** Fibril function for polling the mouse device. 43 43 * 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.44 * This function shall not terminate unless the device breaks and fails 45 * 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. 49 49 */ 50 bool usb_mouse_polling_callback(usb_device_t *dev, 51 uint8_t *buffer, size_t buffer_size, void *arg) 50 int usb_mouse_polling_fibril(void *arg) 52 51 { 53 usb_mouse_t *mouse = (usb_mouse_t *) arg; 52 assert(arg != NULL); 53 ddf_dev_t *dev = (ddf_dev_t *) arg; 54 usb_mouse_t *mouse = (usb_mouse_t *) dev->driver_data; 54 55 55 usb_log_debug2("got buffer: %s.\n", 56 usb_debug_str_buffer(buffer, buffer_size, 0)); 56 assert(mouse); 57 57 58 uint8_t butt = buffer[0]; 59 char str_buttons[4] = { 60 butt & 1 ? '#' : '.', 61 butt & 2 ? '#' : '.', 62 butt & 4 ? '#' : '.', 63 0 64 }; 58 size_t buffer_size = mouse->poll_pipe.max_packet_size; 65 59 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; 60 if (buffer_size < 4) { 61 usb_log_error("Weird mouse, results will be skewed.\n"); 62 buffer_size = 4; 78 63 } 79 64 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 } 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; 94 69 } 95 70 96 usb_log_debug("buttons=%s dX=%+3d dY=%+3d wheel=%+3d\n",97 str_buttons, shift_x, shift_y, wheel);71 while (true) { 72 async_usleep(mouse->poll_interval_us); 98 73 99 /* Guess. */100 async_usleep(1000);74 size_t actual_size; 75 int rc; 101 76 102 return true; 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 */ 85 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 } 92 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 0 113 }; 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 async_hangup(mouse->console_phone); 155 mouse->console_phone = -1; 156 157 usb_log_error("Mouse polling fibril terminated.\n"); 158 159 return EOK; 103 160 } 104 161 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 to109 * 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;116 117 async_hangup(mouse->console_phone);118 mouse->console_phone = -1;119 }120 162 121 163 /** -
uspace/drv/usbmouse/mouse.h
r1b0b86e6 r67f54965 37 37 #define USBMOUSE_MOUSE_H_ 38 38 39 #include < usb/devdrv.h>39 #include <ddf/driver.h> 40 40 #include <usb/pipes.h> 41 41 #include <time.h> … … 46 46 typedef struct { 47 47 /** Generic device container. */ 48 usb_device_t *dev;48 ddf_dev_t *device; 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; 51 57 /** Polling interval in microseconds. */ 52 58 suseconds_t poll_interval_us; … … 55 61 } usb_mouse_t; 56 62 57 #define POLL_PIPE(dev) ((dev)->pipes[0].pipe) 63 int usb_mouse_create(ddf_dev_t *); 58 64 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 *); 65 int usb_mouse_polling_fibril(void *); 65 66 66 67 #endif -
uspace/lib/usb/Makefile
r1b0b86e6 r67f54965 37 37 src/ddfiface.c \ 38 38 src/debug.c \ 39 src/devdrv.c \40 src/devpoll.c \41 39 src/dp.c \ 42 40 src/dump.c \ -
uspace/lib/usb/include/usb/pipes.h
r1b0b86e6 r67f54965 106 106 const usb_endpoint_description_t *description; 107 107 /** Interface number the endpoint must belong to (-1 for any). */ 108 int interface_no;108 const int interface_no; 109 109 /** Found descriptor fitting the description. */ 110 110 usb_standard_endpoint_descriptor_t *descriptor; -
uspace/lib/usb/src/pipesinit.c
r1b0b86e6 r67f54965 37 37 #include <usb/pipes.h> 38 38 #include <usb/dp.h> 39 #include <usb/request.h>40 39 #include <errno.h> 41 40 #include <assert.h> … … 371 370 int rc = usb_endpoint_pipe_initialize(pipe, connection, 372 371 0, USB_TRANSFER_CONTROL, 8, USB_DIRECTION_BOTH); 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]; 372 392 373 return rc; 393 374 }
Note:
See TracChangeset
for help on using the changeset viewer.