Changeset 1b0b86e6 in mainline for uspace/drv/uhci-hcd/uhci.c
- 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. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
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 * @}
Note:
See TracChangeset
for help on using the changeset viewer.