Changes in uspace/drv/bus/usb/uhci/hc.c [b5f813c:da904f7] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/uhci/hc.c
rb5f813c rda904f7 32 32 * @brief UHCI Host controller driver routines 33 33 */ 34 34 #include <errno.h> 35 #include <str_error.h> 35 36 #include <adt/list.h> 36 #include <assert.h>37 #include <async.h>38 37 #include <ddi.h> 39 #include <device/hw_res_parsed.h>40 #include <fibril.h>41 #include <errno.h>42 #include <macros.h>43 #include <mem.h>44 #include <stdlib.h>45 #include <str_error.h>46 #include <sys/types.h>47 38 48 39 #include <usb/debug.h> 49 40 #include <usb/usb.h> 50 #include <usb/host/utils/malloc32.h> 51 41 42 #include "hc.h" 52 43 #include "uhci_batch.h" 53 #include "hc.h"54 44 55 45 #define UHCI_INTR_ALLOW_INTERRUPTS \ … … 95 85 static int hc_init_mem_structures(hc_t *instance); 96 86 static int hc_init_transfer_lists(hc_t *instance); 97 87 static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch); 88 89 static int hc_interrupt_emulator(void *arg); 98 90 static int hc_debug_checker(void *arg); 99 91 92 enum { 93 /** Number of PIO ranges used in IRQ code */ 94 hc_irq_pio_range_count = 95 sizeof(uhci_irq_pio_ranges) / sizeof(irq_pio_range_t), 96 97 /* Number of commands used in IRQ code */ 98 hc_irq_cmd_count = 99 sizeof(uhci_irq_commands) / sizeof(irq_cmd_t) 100 }; 100 101 101 102 /** Generate IRQ code. 102 * @param[out] code IRQ code structure. 103 * @param[in] hw_res Device's resources. 103 * @param[out] ranges PIO ranges buffer. 104 * @param[in] ranges_size Size of the ranges buffer (bytes). 105 * @param[out] cmds Commands buffer. 106 * @param[in] cmds_size Size of the commands buffer (bytes). 107 * @param[in] regs Device's register range. 104 108 * 105 109 * @return Error code. 106 110 */ 107 int uhci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res) 108 { 109 assert(code); 110 assert(hw_res); 111 112 if (hw_res->irqs.count != 1 || hw_res->io_ranges.count != 1) 113 return EINVAL; 114 const addr_range_t regs = hw_res->io_ranges.ranges[0]; 115 116 if (RNGSZ(regs) < sizeof(uhci_regs_t)) 111 int 112 hc_get_irq_code(irq_pio_range_t ranges[], size_t ranges_size, irq_cmd_t cmds[], 113 size_t cmds_size, addr_range_t *regs) 114 { 115 if ((ranges_size < sizeof(uhci_irq_pio_ranges)) || 116 (cmds_size < sizeof(uhci_irq_commands)) || 117 (RNGSZ(*regs) < sizeof(uhci_regs_t))) 117 118 return EOVERFLOW; 118 119 119 code->ranges = malloc(sizeof(uhci_irq_pio_ranges)); 120 if (code->ranges == NULL) 121 return ENOMEM; 122 123 code->cmds = malloc(sizeof(uhci_irq_commands)); 124 if (code->cmds == NULL) { 125 free(code->ranges); 126 return ENOMEM; 127 } 128 129 code->rangecount = ARRAY_SIZE(uhci_irq_pio_ranges); 130 code->cmdcount = ARRAY_SIZE(uhci_irq_commands); 131 132 memcpy(code->ranges, uhci_irq_pio_ranges, sizeof(uhci_irq_pio_ranges)); 133 code->ranges[0].base = RNGABS(regs); 134 135 memcpy(code->cmds, uhci_irq_commands, sizeof(uhci_irq_commands)); 136 uhci_regs_t *registers = (uhci_regs_t *) RNGABSPTR(regs); 137 code->cmds[0].addr = (void*)®isters->usbsts; 138 code->cmds[3].addr = (void*)®isters->usbsts; 139 140 usb_log_debug("I/O regs at %p (size %zu), IRQ %d.\n", 141 RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]); 142 143 return hw_res->irqs.irqs[0]; 120 memcpy(ranges, uhci_irq_pio_ranges, sizeof(uhci_irq_pio_ranges)); 121 ranges[0].base = RNGABS(*regs); 122 123 memcpy(cmds, uhci_irq_commands, sizeof(uhci_irq_commands)); 124 uhci_regs_t *registers = (uhci_regs_t *) RNGABSPTR(*regs); 125 cmds[0].addr = (void *) ®isters->usbsts; 126 cmds[3].addr = (void *) ®isters->usbsts; 127 128 return EOK; 129 } 130 131 /** Register interrupt handler. 132 * 133 * @param[in] device Host controller DDF device 134 * @param[in] regs Register range 135 * @param[in] irq Interrupt number 136 * @paran[in] handler Interrupt handler 137 * 138 * @return EOK on success or negative error code 139 */ 140 int hc_register_irq_handler(ddf_dev_t *device, addr_range_t *regs, int irq, 141 interrupt_handler_t handler) 142 { 143 int rc; 144 irq_pio_range_t irq_ranges[hc_irq_pio_range_count]; 145 irq_cmd_t irq_cmds[hc_irq_cmd_count]; 146 rc = hc_get_irq_code(irq_ranges, sizeof(irq_ranges), irq_cmds, 147 sizeof(irq_cmds), regs); 148 if (rc != EOK) { 149 usb_log_error("Failed to generate IRQ commands: %s.\n", 150 str_error(rc)); 151 return rc; 152 } 153 154 irq_code_t irq_code = { 155 .rangecount = hc_irq_pio_range_count, 156 .ranges = irq_ranges, 157 .cmdcount = hc_irq_cmd_count, 158 .cmds = irq_cmds 159 }; 160 161 /* Register handler to avoid interrupt lockup */ 162 rc = register_interrupt_handler(device, irq, handler, &irq_code); 163 if (rc != EOK) { 164 usb_log_error("Failed to register interrupt handler: %s.\n", 165 str_error(rc)); 166 return rc; 167 } 168 169 return EOK; 144 170 } 145 171 146 172 /** Take action based on the interrupt cause. 147 173 * 148 * @param[in] hcd HCDstructure to use.174 * @param[in] instance UHCI structure to use. 149 175 * @param[in] status Value of the status register at the time of interrupt. 150 176 * … … 154 180 * - resume from suspend state (not implemented) 155 181 */ 156 void uhci_hc_interrupt(hcd_t *hcd, uint32_t status) 157 { 158 assert(hcd); 159 hc_t *instance = hcd_get_driver_data(hcd); 182 void hc_interrupt(hc_t *instance, uint16_t status) 183 { 160 184 assert(instance); 161 185 /* Lower 2 bits are transaction error and transaction complete */ … … 171 195 &instance->transfers_bulk_full, &done); 172 196 173 list_foreach_safe(done, current, next) { 174 list_remove(current); 197 while (!list_empty(&done)) { 198 link_t *item = list_first(&done); 199 list_remove(item); 175 200 uhci_transfer_batch_t *batch = 176 uhci_transfer_batch_from_link( current);201 uhci_transfer_batch_from_link(item); 177 202 uhci_transfer_batch_finish_dispose(batch); 178 203 } … … 205 230 * 206 231 * @param[in] instance Memory place to initialize. 232 * @param[in] HC function node 207 233 * @param[in] regs Range of device's I/O control registers. 208 234 * @param[in] interrupts True if hw interrupts should be used. … … 213 239 * interrupt fibrils. 214 240 */ 215 int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts) 216 { 217 assert(instance); 218 assert(hw_res); 219 if (hw_res->io_ranges.count != 1 || 220 hw_res->io_ranges.ranges[0].size < sizeof(uhci_regs_t)) 221 return EINVAL; 241 int hc_init(hc_t *instance, ddf_fun_t *fun, addr_range_t *regs, bool interrupts) 242 { 243 assert(regs->size >= sizeof(uhci_regs_t)); 244 int rc; 222 245 223 246 instance->hw_interrupts = interrupts; … … 225 248 226 249 /* allow access to hc control registers */ 227 int ret = pio_enable_range(&hw_res->io_ranges.ranges[0], 228 (void **) &instance->registers); 229 if (ret != EOK) { 230 usb_log_error("Failed to gain access to registers: %s.\n", 231 str_error(ret)); 232 return ret; 233 } 234 235 usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.\n", 236 hw_res->io_ranges.ranges[0].address.absolute, 237 hw_res->io_ranges.ranges[0].size); 238 239 ret = hc_init_mem_structures(instance); 240 if (ret != EOK) { 241 usb_log_error("Failed to init UHCI memory structures: %s.\n", 242 str_error(ret)); 243 // TODO: we should disable pio here 244 return ret; 245 } 250 uhci_regs_t *io; 251 rc = pio_enable_range(regs, (void **) &io); 252 if (rc != EOK) { 253 usb_log_error("Failed to gain access to registers at %p: %s.\n", 254 io, str_error(rc)); 255 return rc; 256 } 257 258 instance->registers = io; 259 usb_log_debug( 260 "Device registers at %p (%zuB) accessible.\n", io, regs->size); 261 262 rc = hc_init_mem_structures(instance); 263 if (rc != EOK) { 264 usb_log_error("Failed to initialize UHCI memory structures: %s.\n", 265 str_error(rc)); 266 return rc; 267 } 268 269 instance->generic = ddf_fun_data_alloc(fun, sizeof(hcd_t)); 270 if (instance->generic == NULL) { 271 usb_log_error("Out of memory.\n"); 272 return ENOMEM; 273 } 274 275 hcd_init(instance->generic, USB_SPEED_FULL, 276 BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11); 277 278 instance->generic->private_data = instance; 279 instance->generic->schedule = hc_schedule; 280 instance->generic->ep_add_hook = NULL; 246 281 247 282 hc_init_hw(instance); 283 if (!interrupts) { 284 instance->interrupt_emulator = 285 fibril_create(hc_interrupt_emulator, instance); 286 fibril_add_ready(instance->interrupt_emulator); 287 } 248 288 (void)hc_debug_checker; 249 289 250 uhci_rh_init(&instance->rh, instance->registers->ports, "uhci"); 251 252 return EOK; 253 } 254 255 /** Safely dispose host controller internal structures 256 * 257 * @param[in] instance Host controller structure to use. 258 */ 259 void hc_fini(hc_t *instance) 260 { 261 assert(instance); 262 //TODO Implement 290 return EOK; 263 291 } 264 292 … … 404 432 instance->transfers[USB_SPEED_FULL][USB_TRANSFER_BULK] = 405 433 &instance->transfers_bulk_full; 406 407 return EOK; 408 } 409 410 int uhci_hc_status(hcd_t *hcd, uint32_t *status) 411 { 412 assert(hcd); 413 assert(status); 414 hc_t *instance = hcd_get_driver_data(hcd); 415 assert(instance); 416 417 *status = 0; 418 if (instance->registers) { 419 uint16_t s = pio_read_16(&instance->registers->usbsts); 420 pio_write_16(&instance->registers->usbsts, s); 421 *status = s; 422 } 434 instance->transfers[USB_SPEED_LOW][USB_TRANSFER_BULK] = 435 &instance->transfers_bulk_full; 436 423 437 return EOK; 424 438 } … … 432 446 * Checks for bandwidth availability and appends the batch to the proper queue. 433 447 */ 434 int uhci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)448 int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch) 435 449 { 436 450 assert(hcd); 437 hc_t *instance = hcd _get_driver_data(hcd);451 hc_t *instance = hcd->private_data; 438 452 assert(instance); 439 453 assert(batch); 440 441 if (batch->ep->address == uhci_rh_get_address(&instance->rh))442 return uhci_rh_schedule(&instance->rh, batch);443 444 454 uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch); 445 455 if (!uhci_batch) { … … 453 463 transfer_list_add_batch(list, uhci_batch); 454 464 465 return EOK; 466 } 467 468 /** Polling function, emulates interrupts. 469 * 470 * @param[in] arg UHCI hc structure to use. 471 * @return EOK (should never return) 472 */ 473 int hc_interrupt_emulator(void* arg) 474 { 475 usb_log_debug("Started interrupt emulator.\n"); 476 hc_t *instance = arg; 477 assert(instance); 478 479 while (1) { 480 /* Read and clear status register */ 481 uint16_t status = pio_read_16(&instance->registers->usbsts); 482 pio_write_16(&instance->registers->usbsts, status); 483 if (status != 0) 484 usb_log_debug2("UHCI status: %x.\n", status); 485 hc_interrupt(instance, status); 486 async_usleep(UHCI_INT_EMULATOR_TIMEOUT); 487 } 455 488 return EOK; 456 489 }
Note:
See TracChangeset
for help on using the changeset viewer.