Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/bus/usb/uhci/hc.c

    r9f6cb910 r7de1988c  
    3232 * @brief UHCI Host controller driver routines
    3333 */
    34 
     34#include <errno.h>
     35#include <str_error.h>
    3536#include <adt/list.h>
    36 #include <assert.h>
    37 #include <async.h>
    3837#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>
    4738
    4839#include <usb/debug.h>
    4940#include <usb/usb.h>
    5041
     42#include "hc.h"
    5143#include "uhci_batch.h"
    52 #include "utils/malloc32.h"
    53 #include "hc.h"
    5444
    5545#define UHCI_INTR_ALLOW_INTERRUPTS \
     
    9585static int hc_init_mem_structures(hc_t *instance);
    9686static int hc_init_transfer_lists(hc_t *instance);
    97 
     87static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch);
     88
     89static int hc_interrupt_emulator(void *arg);
    9890static int hc_debug_checker(void *arg);
    9991
     92enum {
     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};
    100101
    101102/** 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.
    104108 *
    105109 * @return Error code.
    106110 */
    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))
     111int
     112hc_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)))
    117118                return EOVERFLOW;
    118119
    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*)&registers->usbsts;
    138         code->cmds[3].addr = (void*)&registers->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 = &registers->usbsts;
     126        cmds[3].addr = &registers->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 */
     140int 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;
    144170}
    145171
    146172/** Take action based on the interrupt cause.
    147173 *
    148  * @param[in] hcd HCD structure to use.
     174 * @param[in] instance UHCI structure to use.
    149175 * @param[in] status Value of the status register at the time of interrupt.
    150176 *
     
    154180 * - resume from suspend state (not implemented)
    155181 */
    156 void uhci_hc_interrupt(hcd_t *hcd, uint32_t status)
    157 {
    158         assert(hcd);
    159         hc_t *instance = hcd->driver.data;
     182void hc_interrupt(hc_t *instance, uint16_t status)
     183{
    160184        assert(instance);
    161185        /* Lower 2 bits are transaction error and transaction complete */
     
    171195                    &instance->transfers_bulk_full, &done);
    172196
    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);
    175200                        uhci_transfer_batch_t *batch =
    176                             uhci_transfer_batch_from_link(current);
     201                            uhci_transfer_batch_from_link(item);
    177202                        uhci_transfer_batch_finish_dispose(batch);
    178203                }
     
    213238 * interrupt fibrils.
    214239 */
    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;
     240int hc_init(hc_t *instance, addr_range_t *regs, bool interrupts)
     241{
     242        assert(regs->size >= sizeof(uhci_regs_t));
     243        int rc;
    222244
    223245        instance->hw_interrupts = interrupts;
     
    225247
    226248        /* 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         }
     249        uhci_regs_t *io;
     250        rc = pio_enable_range(regs, (void **) &io);
     251        if (rc != EOK) {
     252                usb_log_error("Failed to gain access to registers at %p: %s.\n",
     253                    io, str_error(rc));
     254                return rc;
     255        }
     256
     257        instance->registers = io;
     258        usb_log_debug(
     259            "Device registers at %p (%zuB) accessible.\n", io, regs->size);
     260
     261        rc = hc_init_mem_structures(instance);
     262        if (rc != EOK) {
     263                usb_log_error("Failed to initialize UHCI memory structures: %s.\n",
     264                    str_error(rc));
     265                return rc;
     266        }
     267
     268        hcd_init(&instance->generic, USB_SPEED_FULL,
     269            BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11);
     270
     271        instance->generic.private_data = instance;
     272        instance->generic.schedule = hc_schedule;
     273        instance->generic.ep_add_hook = NULL;
    246274
    247275        hc_init_hw(instance);
     276        if (!interrupts) {
     277                instance->interrupt_emulator =
     278                    fibril_create(hc_interrupt_emulator, instance);
     279                fibril_add_ready(instance->interrupt_emulator);
     280        }
    248281        (void)hc_debug_checker;
    249282
    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
     283        return EOK;
    263284}
    264285
     
    408429}
    409430
    410 int uhci_hc_status(hcd_t *hcd, uint32_t *status)
    411 {
    412         assert(hcd);
    413         assert(status);
    414         hc_t *instance = hcd->driver.data;
    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         }
    423         return EOK;
    424 }
    425 
    426431/** Schedule batch for execution.
    427432 *
     
    432437 * Checks for bandwidth availability and appends the batch to the proper queue.
    433438 */
    434 int uhci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
     439int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
    435440{
    436441        assert(hcd);
    437         hc_t *instance = hcd->driver.data;
     442        hc_t *instance = hcd->private_data;
    438443        assert(instance);
    439444        assert(batch);
    440 
    441         if (batch->ep->address == uhci_rh_get_address(&instance->rh))
    442                 return uhci_rh_schedule(&instance->rh, batch);
    443 
    444445        uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch);
    445446        if (!uhci_batch) {
     
    453454        transfer_list_add_batch(list, uhci_batch);
    454455
     456        return EOK;
     457}
     458
     459/** Polling function, emulates interrupts.
     460 *
     461 * @param[in] arg UHCI hc structure to use.
     462 * @return EOK (should never return)
     463 */
     464int hc_interrupt_emulator(void* arg)
     465{
     466        usb_log_debug("Started interrupt emulator.\n");
     467        hc_t *instance = arg;
     468        assert(instance);
     469
     470        while (1) {
     471                /* Read and clear status register */
     472                uint16_t status = pio_read_16(&instance->registers->usbsts);
     473                pio_write_16(&instance->registers->usbsts, status);
     474                if (status != 0)
     475                        usb_log_debug2("UHCI status: %x.\n", status);
     476                hc_interrupt(instance, status);
     477                async_usleep(UHCI_INT_EMULATOR_TIMEOUT);
     478        }
    455479        return EOK;
    456480}
Note: See TracChangeset for help on using the changeset viewer.