Ignore:
File:
1 edited

Legend:

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

    r7de1988c r9f6cb910  
    3232 * @brief UHCI Host controller driver routines
    3333 */
     34
     35#include <adt/list.h>
     36#include <assert.h>
     37#include <async.h>
     38#include <ddi.h>
     39#include <device/hw_res_parsed.h>
     40#include <fibril.h>
    3441#include <errno.h>
     42#include <macros.h>
     43#include <mem.h>
     44#include <stdlib.h>
    3545#include <str_error.h>
    36 #include <adt/list.h>
    37 #include <ddi.h>
     46#include <sys/types.h>
    3847
    3948#include <usb/debug.h>
    4049#include <usb/usb.h>
    4150
     51#include "uhci_batch.h"
     52#include "utils/malloc32.h"
    4253#include "hc.h"
    43 #include "uhci_batch.h"
    4454
    4555#define UHCI_INTR_ALLOW_INTERRUPTS \
     
    8595static int hc_init_mem_structures(hc_t *instance);
    8696static int hc_init_transfer_lists(hc_t *instance);
    87 static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch);
    88 
    89 static int hc_interrupt_emulator(void *arg);
     97
    9098static int hc_debug_checker(void *arg);
    9199
    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 };
    101100
    102101/** Generate IRQ code.
    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.
     102 * @param[out] code IRQ code structure.
     103 * @param[in] hw_res Device's resources.
    108104 *
    109105 * @return Error code.
    110106 */
    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)))
     107int 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))
    118117                return EOVERFLOW;
    119118
    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  */
    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;
     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];
    170144}
    171145
    172146/** Take action based on the interrupt cause.
    173147 *
    174  * @param[in] instance UHCI structure to use.
     148 * @param[in] hcd HCD structure to use.
    175149 * @param[in] status Value of the status register at the time of interrupt.
    176150 *
     
    180154 * - resume from suspend state (not implemented)
    181155 */
    182 void hc_interrupt(hc_t *instance, uint16_t status)
    183 {
     156void uhci_hc_interrupt(hcd_t *hcd, uint32_t status)
     157{
     158        assert(hcd);
     159        hc_t *instance = hcd->driver.data;
    184160        assert(instance);
    185161        /* Lower 2 bits are transaction error and transaction complete */
     
    195171                    &instance->transfers_bulk_full, &done);
    196172
    197                 while (!list_empty(&done)) {
    198                         link_t *item = list_first(&done);
    199                         list_remove(item);
     173                list_foreach_safe(done, current, next) {
     174                        list_remove(current);
    200175                        uhci_transfer_batch_t *batch =
    201                             uhci_transfer_batch_from_link(item);
     176                            uhci_transfer_batch_from_link(current);
    202177                        uhci_transfer_batch_finish_dispose(batch);
    203178                }
     
    238213 * interrupt fibrils.
    239214 */
    240 int hc_init(hc_t *instance, addr_range_t *regs, bool interrupts)
    241 {
    242         assert(regs->size >= sizeof(uhci_regs_t));
    243         int rc;
     215int 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;
    244222
    245223        instance->hw_interrupts = interrupts;
     
    247225
    248226        /* allow access to hc control registers */
    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;
     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        }
    274246
    275247        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         }
    281248        (void)hc_debug_checker;
    282249
     250        uhci_rh_init(&instance->rh, instance->registers->ports, "uhci");
     251
    283252        return EOK;
     253}
     254
     255/** Safely dispose host controller internal structures
     256 *
     257 * @param[in] instance Host controller structure to use.
     258 */
     259void hc_fini(hc_t *instance)
     260{
     261        assert(instance);
     262        //TODO Implement
    284263}
    285264
     
    429408}
    430409
     410int 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
    431426/** Schedule batch for execution.
    432427 *
     
    437432 * Checks for bandwidth availability and appends the batch to the proper queue.
    438433 */
    439 int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
     434int uhci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
    440435{
    441436        assert(hcd);
    442         hc_t *instance = hcd->private_data;
     437        hc_t *instance = hcd->driver.data;
    443438        assert(instance);
    444439        assert(batch);
     440
     441        if (batch->ep->address == uhci_rh_get_address(&instance->rh))
     442                return uhci_rh_schedule(&instance->rh, batch);
     443
    445444        uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch);
    446445        if (!uhci_batch) {
     
    454453        transfer_list_add_batch(list, uhci_batch);
    455454
    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  */
    464 int 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         }
    479455        return EOK;
    480456}
Note: See TracChangeset for help on using the changeset viewer.