Ignore:
File:
1 edited

Legend:

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

    r58563585 rd930980  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
    28 
    2928/** @addtogroup drvusbuhcihc
    3029 * @{
     
    3332 * @brief UHCI Host controller driver routines
    3433 */
    35 
     34#include <errno.h>
     35#include <str_error.h>
    3636#include <adt/list.h>
    37 #include <assert.h>
    38 #include <async.h>
    3937#include <ddi.h>
    40 #include <device/hw_res_parsed.h>
    41 #include <fibril.h>
    42 #include <errno.h>
    43 #include <macros.h>
    44 #include <mem.h>
    45 #include <stdlib.h>
    46 #include <str_error.h>
    47 #include <sys/types.h>
    4838
    4939#include <usb/debug.h>
    5040#include <usb/usb.h>
    51 #include <usb/host/utils/malloc32.h>
    52 
     41
     42#include "hc.h"
    5343#include "uhci_batch.h"
    54 #include "hc.h"
    5544
    5645#define UHCI_INTR_ALLOW_INTERRUPTS \
     
    9685static int hc_init_mem_structures(hc_t *instance);
    9786static int hc_init_transfer_lists(hc_t *instance);
    98 
     87static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch);
     88
     89static int hc_interrupt_emulator(void *arg);
    9990static int hc_debug_checker(void *arg);
    10091
     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};
    101101
    102102/** Generate IRQ code.
    103  * @param[out] code IRQ code structure.
    104  * @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 Physical address of device's registers.
     108 * @param[in] reg_size Size of the register area (bytes).
    105109 *
    106110 * @return Error code.
    107111 */
    108 int uhci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res)
    109 {
    110         assert(code);
    111         assert(hw_res);
    112 
    113         if (hw_res->irqs.count != 1 || hw_res->io_ranges.count != 1)
    114                 return EINVAL;
    115         const addr_range_t regs = hw_res->io_ranges.ranges[0];
    116 
    117         if (RNGSZ(regs) < sizeof(uhci_regs_t))
     112int
     113hc_get_irq_code(irq_pio_range_t ranges[], size_t ranges_size, irq_cmd_t cmds[],
     114    size_t cmds_size, uintptr_t regs, size_t reg_size)
     115{
     116        if ((ranges_size < sizeof(uhci_irq_pio_ranges)) ||
     117            (cmds_size < sizeof(uhci_irq_commands)) ||
     118            (reg_size < sizeof(uhci_regs_t)))
    118119                return EOVERFLOW;
    119120
    120         code->ranges = malloc(sizeof(uhci_irq_pio_ranges));
    121         if (code->ranges == NULL)
    122                 return ENOMEM;
    123 
    124         code->cmds = malloc(sizeof(uhci_irq_commands));
    125         if (code->cmds == NULL) {
    126                 free(code->ranges);
    127                 return ENOMEM;
    128         }
    129 
    130         code->rangecount = ARRAY_SIZE(uhci_irq_pio_ranges);
    131         code->cmdcount = ARRAY_SIZE(uhci_irq_commands);
    132 
    133         memcpy(code->ranges, uhci_irq_pio_ranges, sizeof(uhci_irq_pio_ranges));
    134         code->ranges[0].base = RNGABS(regs);
    135 
    136         memcpy(code->cmds, uhci_irq_commands, sizeof(uhci_irq_commands));
    137         uhci_regs_t *registers = (uhci_regs_t *) RNGABSPTR(regs);
    138         code->cmds[0].addr = (void*)&registers->usbsts;
    139         code->cmds[3].addr = (void*)&registers->usbsts;
    140 
    141         usb_log_debug("I/O regs at %p (size %zu), IRQ %d.\n",
    142             RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]);
    143 
    144         return hw_res->irqs.irqs[0];
     121        memcpy(ranges, uhci_irq_pio_ranges, sizeof(uhci_irq_pio_ranges));
     122        ranges[0].base = regs;
     123
     124        memcpy(cmds, uhci_irq_commands, sizeof(uhci_irq_commands));
     125        uhci_regs_t *registers = (uhci_regs_t *) regs;
     126        cmds[0].addr = &registers->usbsts;
     127        cmds[3].addr = &registers->usbsts;
     128
     129        return EOK;
     130}
     131
     132/** Register interrupt handler.
     133 *
     134 * @param[in] device Host controller DDF device
     135 * @param[in] reg_base Register range base
     136 * @param[in] reg_size Register range size
     137 * @param[in] irq Interrupt number
     138 * @paran[in] handler Interrupt handler
     139 *
     140 * @return EOK on success or negative error code
     141 */
     142int hc_register_irq_handler(ddf_dev_t *device, uintptr_t reg_base, size_t reg_size,
     143    int irq, interrupt_handler_t handler)
     144{
     145        int rc;
     146        irq_pio_range_t irq_ranges[hc_irq_pio_range_count];
     147        irq_cmd_t irq_cmds[hc_irq_cmd_count];
     148        rc = hc_get_irq_code(irq_ranges, sizeof(irq_ranges), irq_cmds,
     149            sizeof(irq_cmds), reg_base, reg_size);
     150        if (rc != EOK) {
     151                usb_log_error("Failed to generate IRQ commands: %s.\n",
     152                    str_error(rc));
     153                return rc;
     154        }
     155
     156        irq_code_t irq_code = {
     157                .rangecount = hc_irq_pio_range_count,
     158                .ranges = irq_ranges,
     159                .cmdcount = hc_irq_cmd_count,
     160                .cmds = irq_cmds
     161        };
     162
     163        /* Register handler to avoid interrupt lockup */
     164        rc = register_interrupt_handler(device, irq, handler, &irq_code);
     165        if (rc != EOK) {
     166                usb_log_error("Failed to register interrupt handler: %s.\n",
     167                    str_error(rc));
     168                return rc;
     169        }
     170
     171        return EOK;
    145172}
    146173
    147174/** Take action based on the interrupt cause.
    148175 *
    149  * @param[in] hcd HCD structure to use.
     176 * @param[in] instance UHCI structure to use.
    150177 * @param[in] status Value of the status register at the time of interrupt.
    151178 *
     
    155182 * - resume from suspend state (not implemented)
    156183 */
    157 void uhci_hc_interrupt(hcd_t *hcd, uint32_t status)
    158 {
    159         assert(hcd);
    160         hc_t *instance = hcd_get_driver_data(hcd);
     184void hc_interrupt(hc_t *instance, uint16_t status)
     185{
    161186        assert(instance);
    162187        /* Lower 2 bits are transaction error and transaction complete */
     
    172197                    &instance->transfers_bulk_full, &done);
    173198
    174                 list_foreach_safe(done, current, next) {
    175                         list_remove(current);
     199                while (!list_empty(&done)) {
     200                        link_t *item = list_first(&done);
     201                        list_remove(item);
    176202                        uhci_transfer_batch_t *batch =
    177                             uhci_transfer_batch_from_link(current);
     203                            uhci_transfer_batch_from_link(item);
    178204                        uhci_transfer_batch_finish_dispose(batch);
    179205                }
     
    206232 *
    207233 * @param[in] instance Memory place to initialize.
    208  * @param[in] regs Range of device's I/O control registers.
     234 * @param[in] regs Address of I/O control registers.
     235 * @param[in] reg_size Size of I/O control registers.
    209236 * @param[in] interrupts True if hw interrupts should be used.
    210237 * @return Error code.
     
    214241 * interrupt fibrils.
    215242 */
    216 int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)
    217 {
    218         assert(instance);
    219         assert(hw_res);
    220         if (hw_res->io_ranges.count != 1 ||
    221             hw_res->io_ranges.ranges[0].size < sizeof(uhci_regs_t))
    222             return EINVAL;
     243int hc_init(hc_t *instance, void *regs, size_t reg_size, bool interrupts)
     244{
     245        assert(reg_size >= sizeof(uhci_regs_t));
     246        int rc;
    223247
    224248        instance->hw_interrupts = interrupts;
     
    226250
    227251        /* allow access to hc control registers */
    228         int ret = pio_enable_range(&hw_res->io_ranges.ranges[0],
    229             (void **) &instance->registers);
    230         if (ret != EOK) {
    231                 usb_log_error("Failed to gain access to registers: %s.\n",
    232                     str_error(ret));
    233                 return ret;
    234         }
    235 
    236         usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.\n",
    237             hw_res->io_ranges.ranges[0].address.absolute,
    238             hw_res->io_ranges.ranges[0].size);
    239 
    240         ret = hc_init_mem_structures(instance);
    241         if (ret != EOK) {
    242                 usb_log_error("Failed to init UHCI memory structures: %s.\n",
    243                     str_error(ret));
    244                 // TODO: we should disable pio here
    245                 return ret;
    246         }
     252        uhci_regs_t *io;
     253        rc = pio_enable(regs, reg_size, (void **)&io);
     254        if (rc != EOK) {
     255                usb_log_error("Failed to gain access to registers at %p: %s.\n",
     256                    io, str_error(rc));
     257                return rc;
     258        }
     259
     260        instance->registers = io;
     261        usb_log_debug(
     262            "Device registers at %p (%zuB) accessible.\n", io, reg_size);
     263
     264        rc = hc_init_mem_structures(instance);
     265        if (rc != EOK) {
     266                usb_log_error("Failed to initialize UHCI memory structures: %s.\n",
     267                    str_error(rc));
     268                return rc;
     269        }
     270
     271        hcd_init(&instance->generic, USB_SPEED_FULL,
     272            BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11);
     273
     274        instance->generic.private_data = instance;
     275        instance->generic.schedule = hc_schedule;
     276        instance->generic.ep_add_hook = NULL;
    247277
    248278        hc_init_hw(instance);
     279        if (!interrupts) {
     280                instance->interrupt_emulator =
     281                    fibril_create(hc_interrupt_emulator, instance);
     282                fibril_add_ready(instance->interrupt_emulator);
     283        }
    249284        (void)hc_debug_checker;
    250285
    251         uhci_rh_init(&instance->rh, instance->registers->ports, "uhci");
    252 
    253         return EOK;
    254 }
    255 
    256 /** Safely dispose host controller internal structures
    257  *
    258  * @param[in] instance Host controller structure to use.
    259  */
    260 void hc_fini(hc_t *instance)
    261 {
    262         assert(instance);
    263         //TODO Implement
     286        return EOK;
    264287}
    265288
     
    409432}
    410433
    411 int uhci_hc_status(hcd_t *hcd, uint32_t *status)
    412 {
    413         assert(hcd);
    414         assert(status);
    415         hc_t *instance = hcd_get_driver_data(hcd);
    416         assert(instance);
    417 
    418         *status = 0;
    419         if (instance->registers) {
    420                 uint16_t s = pio_read_16(&instance->registers->usbsts);
    421                 pio_write_16(&instance->registers->usbsts, s);
    422                 *status = s;
    423         }
    424         return EOK;
    425 }
    426 
    427434/** Schedule batch for execution.
    428435 *
     
    433440 * Checks for bandwidth availability and appends the batch to the proper queue.
    434441 */
    435 int uhci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
     442int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
    436443{
    437444        assert(hcd);
    438         hc_t *instance = hcd_get_driver_data(hcd);
     445        hc_t *instance = hcd->private_data;
    439446        assert(instance);
    440447        assert(batch);
    441 
    442         if (batch->ep->address == uhci_rh_get_address(&instance->rh))
    443                 return uhci_rh_schedule(&instance->rh, batch);
    444 
    445448        uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch);
    446449        if (!uhci_batch) {
     
    454457        transfer_list_add_batch(list, uhci_batch);
    455458
     459        return EOK;
     460}
     461
     462/** Polling function, emulates interrupts.
     463 *
     464 * @param[in] arg UHCI hc structure to use.
     465 * @return EOK (should never return)
     466 */
     467int hc_interrupt_emulator(void* arg)
     468{
     469        usb_log_debug("Started interrupt emulator.\n");
     470        hc_t *instance = arg;
     471        assert(instance);
     472
     473        while (1) {
     474                /* Read and clear status register */
     475                uint16_t status = pio_read_16(&instance->registers->usbsts);
     476                pio_write_16(&instance->registers->usbsts, status);
     477                if (status != 0)
     478                        usb_log_debug2("UHCI status: %x.\n", status);
     479                hc_interrupt(instance, status);
     480                async_usleep(UHCI_INT_EMULATOR_TIMEOUT);
     481        }
    456482        return EOK;
    457483}
Note: See TracChangeset for help on using the changeset viewer.