Changes in uspace/drv/bus/usb/ohci/hc.c [d57122c:ef9460b] in mainline
- File:
-
- 1 edited
-
uspace/drv/bus/usb/ohci/hc.c (modified) (15 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/ohci/hc.c
rd57122c ref9460b 42 42 43 43 #include "hc.h" 44 #include " ohci_endpoint.h"44 #include "hcd_endpoint.h" 45 45 46 46 #define OHCI_USED_INTERRUPTS \ 47 47 (I_SO | I_WDH | I_UE | I_RHSC) 48 48 49 static const irq_pio_range_t ohci_pio_ranges[] = { 50 { 51 .base = 0, /* filled later */ 52 .size = sizeof(ohci_regs_t) 53 } 54 }; 55 56 static const irq_cmd_t ohci_irq_commands[] = { 57 { .cmd = CMD_PIO_READ_32, .dstarg = 1, .addr = NULL /* filled later */ }, 49 static const irq_cmd_t ohci_irq_commands[] = 50 { 51 { .cmd = CMD_MEM_READ_32, .dstarg = 1, .addr = NULL /*filled later*/ }, 58 52 { .cmd = CMD_BTEST, .srcarg = 1, .dstarg = 2, .value = OHCI_USED_INTERRUPTS }, 59 53 { .cmd = CMD_PREDICATE, .srcarg = 2, .value = 2 }, 60 { .cmd = CMD_ PIO_WRITE_A_32, .srcarg = 1, .addr = NULL /* filled later*/ },54 { .cmd = CMD_MEM_WRITE_A_32, .srcarg = 1, .addr = NULL /*filled later*/ }, 61 55 { .cmd = CMD_ACCEPT }, 62 56 }; … … 67 61 static int hc_init_memory(hc_t *instance); 68 62 static int interrupt_emulator(hc_t *instance); 69 static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch); 70 /*----------------------------------------------------------------------------*/ 71 /** Get number of PIO ranges used in IRQ code. 72 * @return Number of ranges. 73 */ 74 size_t hc_irq_pio_range_count(void) 75 { 76 return sizeof(ohci_pio_ranges) / sizeof(irq_pio_range_t); 77 } 78 /*----------------------------------------------------------------------------*/ 63 79 64 /*----------------------------------------------------------------------------*/ 80 65 /** Get number of commands used in IRQ code. … … 86 71 } 87 72 /*----------------------------------------------------------------------------*/ 88 /** Generate IRQ code. 89 * @param[out] ranges PIO ranges buffer. 90 * @param[in] ranges_size Size of the ranges buffer (bytes). 91 * @param[out] cmds Commands buffer. 92 * @param[in] cmds_size Size of the commands buffer (bytes). 73 /** Generate IRQ code commands. 74 * @param[out] cmds Place to store the commands. 75 * @param[in] cmd_size Size of the place (bytes). 93 76 * @param[in] regs Physical address of device's registers. 94 77 * @param[in] reg_size Size of the register area (bytes). … … 96 79 * @return Error code. 97 80 */ 98 int 99 hc_get_irq_code(irq_pio_range_t ranges[], size_t ranges_size, irq_cmd_t cmds[], 100 size_t cmds_size, uintptr_t regs, size_t reg_size) 101 { 102 if ((ranges_size < sizeof(ohci_pio_ranges)) || 103 (cmds_size < sizeof(ohci_irq_commands)) || 104 (reg_size < sizeof(ohci_regs_t))) 81 int hc_get_irq_commands( 82 irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size) 83 { 84 if (cmd_size < sizeof(ohci_irq_commands) 85 || reg_size < sizeof(ohci_regs_t)) 105 86 return EOVERFLOW; 106 87 107 memcpy(ranges, ohci_pio_ranges, sizeof(ohci_pio_ranges)); 108 ranges[0].base = regs; 88 /* Create register mapping to use in IRQ handler. 89 * This mapping should be present in kernel only. 90 * Remove it from here when kernel knows how to create mappings 91 * and accepts physical addresses in IRQ code. 92 * TODO: remove */ 93 ohci_regs_t *registers; 94 const int ret = pio_enable((void*)regs, reg_size, (void**)®isters); 95 if (ret != EOK) 96 return ret; 97 98 /* Some bogus access to force create mapping. DO NOT remove, 99 * unless whole virtual addresses in irq is replaced 100 * NOTE: Compiler won't remove this as ohci_regs_t members 101 * are declared volatile. 102 * 103 * Introducing CMD_MEM set of IRQ code commands broke 104 * assumption that IRQ code does not cause page faults. 105 * If this happens during idling (THREAD == NULL) 106 * it causes kernel panic. 107 */ 108 registers->revision; 109 109 110 110 memcpy(cmds, ohci_irq_commands, sizeof(ohci_irq_commands)); 111 ohci_regs_t *registers = (ohci_regs_t *) regs; 112 cmds[0].addr = (void *)®isters->interrupt_status;113 cmds[ 3].addr = (void *) ®isters->interrupt_status;114 111 112 void *address = (void*)®isters->interrupt_status; 113 cmds[0].addr = address; 114 cmds[3].addr = address; 115 115 return EOK; 116 116 } … … 127 127 assert(hub_fun); 128 128 129 /* Try to get address 1 for root hub. */ 130 instance->rh.address = 1; 131 int ret = usb_device_manager_request_address( 132 &instance->generic.dev_manager, &instance->rh.address, false, 133 USB_SPEED_FULL); 134 if (ret != EOK) { 129 const usb_address_t hub_address = 130 device_keeper_get_free_address(&instance->manager, USB_SPEED_FULL); 131 if (hub_address <= 0) { 135 132 usb_log_error("Failed to get OHCI root hub address: %s\n", 136 str_error(ret)); 137 return ret; 138 } 139 140 #define CHECK_RET_UNREG_RETURN(ret, message...) \ 133 str_error(hub_address)); 134 return hub_address; 135 } 136 instance->rh.address = hub_address; 137 usb_device_keeper_bind( 138 &instance->manager, hub_address, hub_fun->handle); 139 140 #define CHECK_RET_RELEASE(ret, message...) \ 141 141 if (ret != EOK) { \ 142 142 usb_log_error(message); \ 143 usb_endpoint_manager_remove_ep( \ 144 &instance->generic.ep_manager, instance->rh.address, 0, \ 145 USB_DIRECTION_BOTH, NULL, NULL); \ 146 usb_device_manager_release_address( \ 147 &instance->generic.dev_manager, instance->rh.address); \ 143 hc_remove_endpoint(instance, hub_address, 0, USB_DIRECTION_BOTH); \ 144 usb_device_keeper_release(&instance->manager, hub_address); \ 148 145 return ret; \ 149 146 } else (void)0 150 147 151 ret = usb_endpoint_manager_add_ep( 152 &instance->generic.ep_manager, instance->rh.address, 0, 153 USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64, 154 0, NULL, NULL); 155 CHECK_RET_UNREG_RETURN(ret, 156 "Failed to register root hub control endpoint: %s.\n", 157 str_error(ret)); 148 int ret = hc_add_endpoint(instance, hub_address, 0, USB_SPEED_FULL, 149 USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH, 64, 0, 0); 150 CHECK_RET_RELEASE(ret, 151 "Failed to add OHCI root hub endpoint 0: %s.\n", str_error(ret)); 158 152 159 153 ret = ddf_fun_add_match_id(hub_fun, "usb&class=hub", 100); 160 CHECK_RET_ UNREG_RETURN(ret,154 CHECK_RET_RELEASE(ret, 161 155 "Failed to add root hub match-id: %s.\n", str_error(ret)); 162 156 163 157 ret = ddf_fun_bind(hub_fun); 164 CHECK_RET_ UNREG_RETURN(ret,158 CHECK_RET_RELEASE(ret, 165 159 "Failed to bind root hub function: %s.\n", str_error(ret)); 166 167 ret = usb_device_manager_bind_address(&instance->generic.dev_manager,168 instance->rh.address, hub_fun->handle);169 if (ret != EOK)170 usb_log_warning("Failed to bind root hub address: %s.\n",171 str_error(ret));172 160 173 161 return EOK; … … 199 187 200 188 list_initialize(&instance->pending_batches); 201 202 hcd_init(&instance->generic, USB_SPEED_FULL, 203 BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11); 204 instance->generic.private_data = instance; 205 instance->generic.schedule = hc_schedule; 206 instance->generic.ep_add_hook = ohci_endpoint_init; 207 instance->generic.ep_remove_hook = ohci_endpoint_fini; 189 usb_device_keeper_init(&instance->manager); 190 191 ret = usb_endpoint_manager_init(&instance->ep_manager, 192 BANDWIDTH_AVAILABLE_USB11); 193 CHECK_RET_RETURN(ret, "Failed to initialize endpoint manager: %s.\n", 194 str_error(ret)); 208 195 209 196 ret = hc_init_memory(instance); … … 228 215 } 229 216 /*----------------------------------------------------------------------------*/ 230 void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep) 231 { 232 assert(instance); 233 assert(ep); 234 235 endpoint_list_t *list = &instance->lists[ep->transfer_type]; 236 ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ep); 237 assert(list); 238 assert(ohci_ep); 239 240 /* Enqueue ep */ 217 /** Create and register endpoint structures. 218 * 219 * @param[in] instance OHCI driver structure. 220 * @param[in] address USB address of the device. 221 * @param[in] endpoint USB endpoint number. 222 * @param[in] speed Communication speeed of the device. 223 * @param[in] type Endpoint's transfer type. 224 * @param[in] direction Endpoint's direction. 225 * @param[in] mps Maximum packet size the endpoint accepts. 226 * @param[in] size Maximum allowed buffer size. 227 * @param[in] interval Time between transfers(interrupt transfers only). 228 * @return Error code 229 */ 230 int hc_add_endpoint( 231 hc_t *instance, usb_address_t address, usb_endpoint_t endpoint, 232 usb_speed_t speed, usb_transfer_type_t type, usb_direction_t direction, 233 size_t mps, size_t size, unsigned interval) 234 { 235 endpoint_t *ep = 236 endpoint_get(address, endpoint, direction, type, speed, mps); 237 if (ep == NULL) 238 return ENOMEM; 239 240 hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep); 241 if (hcd_ep == NULL) { 242 endpoint_destroy(ep); 243 return ENOMEM; 244 } 245 246 int ret = 247 usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size); 248 if (ret != EOK) { 249 hcd_endpoint_clear(ep); 250 endpoint_destroy(ep); 251 return ret; 252 } 253 254 /* Enqueue hcd_ep */ 241 255 switch (ep->transfer_type) { 242 256 case USB_TRANSFER_CONTROL: 243 257 instance->registers->control &= ~C_CLE; 244 endpoint_list_add_ep(list, ohci_ep); 258 endpoint_list_add_ep( 259 &instance->lists[ep->transfer_type], hcd_ep); 245 260 instance->registers->control_current = 0; 246 261 instance->registers->control |= C_CLE; … … 248 263 case USB_TRANSFER_BULK: 249 264 instance->registers->control &= ~C_BLE; 250 endpoint_list_add_ep(list, ohci_ep); 265 endpoint_list_add_ep( 266 &instance->lists[ep->transfer_type], hcd_ep); 251 267 instance->registers->control |= C_BLE; 252 268 break; … … 254 270 case USB_TRANSFER_INTERRUPT: 255 271 instance->registers->control &= (~C_PLE & ~C_IE); 256 endpoint_list_add_ep(list, ohci_ep); 272 endpoint_list_add_ep( 273 &instance->lists[ep->transfer_type], hcd_ep); 257 274 instance->registers->control |= C_PLE | C_IE; 258 275 break; 259 276 } 260 } 261 /*----------------------------------------------------------------------------*/ 262 void hc_dequeue_endpoint(hc_t *instance, const endpoint_t *ep) 263 { 264 assert(instance); 265 assert(ep); 266 267 /* Dequeue ep */ 268 endpoint_list_t *list = &instance->lists[ep->transfer_type]; 269 ohci_endpoint_t *ohci_ep = ohci_endpoint_get(ep); 270 271 assert(list); 272 assert(ohci_ep); 273 switch (ep->transfer_type) { 274 case USB_TRANSFER_CONTROL: 275 instance->registers->control &= ~C_CLE; 276 endpoint_list_remove_ep(list, ohci_ep); 277 instance->registers->control_current = 0; 278 instance->registers->control |= C_CLE; 279 break; 280 case USB_TRANSFER_BULK: 281 instance->registers->control &= ~C_BLE; 282 endpoint_list_remove_ep(list, ohci_ep); 283 instance->registers->control |= C_BLE; 284 break; 285 case USB_TRANSFER_ISOCHRONOUS: 286 case USB_TRANSFER_INTERRUPT: 287 instance->registers->control &= (~C_PLE & ~C_IE); 288 endpoint_list_remove_ep(list, ohci_ep); 289 instance->registers->control |= C_PLE | C_IE; 290 break; 291 default: 292 break; 293 } 277 278 return EOK; 279 } 280 /*----------------------------------------------------------------------------*/ 281 /** Dequeue and delete endpoint structures 282 * 283 * @param[in] instance OHCI hc driver structure. 284 * @param[in] address USB address of the device. 285 * @param[in] endpoint USB endpoint number. 286 * @param[in] direction Direction of the endpoint. 287 * @return Error code 288 */ 289 int hc_remove_endpoint(hc_t *instance, usb_address_t address, 290 usb_endpoint_t endpoint, usb_direction_t direction) 291 { 292 assert(instance); 293 fibril_mutex_lock(&instance->guard); 294 endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager, 295 address, endpoint, direction, NULL); 296 if (ep == NULL) { 297 usb_log_error("Endpoint unregister failed: No such EP.\n"); 298 fibril_mutex_unlock(&instance->guard); 299 return ENOENT; 300 } 301 302 hcd_endpoint_t *hcd_ep = hcd_endpoint_get(ep); 303 if (hcd_ep) { 304 /* Dequeue hcd_ep */ 305 switch (ep->transfer_type) { 306 case USB_TRANSFER_CONTROL: 307 instance->registers->control &= ~C_CLE; 308 endpoint_list_remove_ep( 309 &instance->lists[ep->transfer_type], hcd_ep); 310 instance->registers->control_current = 0; 311 instance->registers->control |= C_CLE; 312 break; 313 case USB_TRANSFER_BULK: 314 instance->registers->control &= ~C_BLE; 315 endpoint_list_remove_ep( 316 &instance->lists[ep->transfer_type], hcd_ep); 317 instance->registers->control |= C_BLE; 318 break; 319 case USB_TRANSFER_ISOCHRONOUS: 320 case USB_TRANSFER_INTERRUPT: 321 instance->registers->control &= (~C_PLE & ~C_IE); 322 endpoint_list_remove_ep( 323 &instance->lists[ep->transfer_type], hcd_ep); 324 instance->registers->control |= C_PLE | C_IE; 325 break; 326 default: 327 break; 328 } 329 hcd_endpoint_clear(ep); 330 } else { 331 usb_log_warning("Endpoint without hcd equivalent structure.\n"); 332 } 333 int ret = usb_endpoint_manager_unregister_ep(&instance->ep_manager, 334 address, endpoint, direction); 335 fibril_mutex_unlock(&instance->guard); 336 return ret; 337 } 338 /*----------------------------------------------------------------------------*/ 339 /** Get access to endpoint structures 340 * 341 * @param[in] instance OHCI hc driver structure. 342 * @param[in] address USB address of the device. 343 * @param[in] endpoint USB endpoint number. 344 * @param[in] direction Direction of the endpoint. 345 * @param[out] bw Reserved bandwidth. 346 * @return Error code 347 */ 348 endpoint_t * hc_get_endpoint(hc_t *instance, usb_address_t address, 349 usb_endpoint_t endpoint, usb_direction_t direction, size_t *bw) 350 { 351 assert(instance); 352 fibril_mutex_lock(&instance->guard); 353 endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager, 354 address, endpoint, direction, bw); 355 fibril_mutex_unlock(&instance->guard); 356 return ep; 294 357 } 295 358 /*----------------------------------------------------------------------------*/ … … 300 363 * @return Error code. 301 364 */ 302 int hc_schedule(hc d_t *hcd, usb_transfer_batch_t *batch)303 { 304 assert( hcd);305 hc_t *instance = hcd->private_data;306 assert( instance);365 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch) 366 { 367 assert(instance); 368 assert(batch); 369 assert(batch->ep); 307 370 308 371 /* Check for root hub communication */ … … 311 374 return EOK; 312 375 } 313 ohci_transfer_batch_t *ohci_batch = ohci_transfer_batch_get(batch);314 if (!ohci_batch)315 return ENOMEM;316 376 317 377 fibril_mutex_lock(&instance->guard); 318 list_append(& ohci_batch->link, &instance->pending_batches);319 ohci_transfer_batch_commit(ohci_batch);378 list_append(&batch->link, &instance->pending_batches); 379 batch_commit(batch); 320 380 321 381 /* Control and bulk schedules need a kick to start working */ … … 357 417 instance->registers->periodic_current); 358 418 359 link_t *current = list_first(&instance->pending_batches);360 while (current && current!= &instance->pending_batches.head) {419 link_t *current = instance->pending_batches.head.next; 420 while (current != &instance->pending_batches.head) { 361 421 link_t *next = current->next; 362 ohci_transfer_batch_t *batch =363 ohci_transfer_batch_from_link(current);364 365 if ( ohci_transfer_batch_is_complete(batch)) {422 usb_transfer_batch_t *batch = 423 usb_transfer_batch_from_link(current); 424 425 if (batch_is_complete(batch)) { 366 426 list_remove(current); 367 ohci_transfer_batch_finish_dispose(batch);427 usb_transfer_batch_finish(batch); 368 428 } 369 429 … … 374 434 375 435 if (status & I_UE) { 376 usb_log_fatal("Error like no other!\n");377 436 hc_start(instance); 378 437 } … … 584 643 585 644 /*Init HCCA */ 586 instance->hcca = hcca_get();645 instance->hcca = malloc32(sizeof(hcca_t)); 587 646 if (instance->hcca == NULL) 588 647 return ENOMEM; … … 590 649 usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca); 591 650 592 for (unsigned i = 0; i < 32; ++i) { 651 unsigned i = 0; 652 for (; i < 32; ++i) { 593 653 instance->hcca->int_ep[i] = 594 654 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa;
Note:
See TracChangeset
for help on using the changeset viewer.
