Ignore:
File:
1 edited

Legend:

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

    rd930980 r58563585  
    2626 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2727 */
     28
    2829/** @addtogroup drvusbuhcihc
    2930 * @{
     
    3233 * @brief UHCI Host controller driver routines
    3334 */
     35
     36#include <adt/list.h>
     37#include <assert.h>
     38#include <async.h>
     39#include <ddi.h>
     40#include <device/hw_res_parsed.h>
     41#include <fibril.h>
    3442#include <errno.h>
     43#include <macros.h>
     44#include <mem.h>
     45#include <stdlib.h>
    3546#include <str_error.h>
    36 #include <adt/list.h>
    37 #include <ddi.h>
     47#include <sys/types.h>
    3848
    3949#include <usb/debug.h>
    4050#include <usb/usb.h>
    41 
     51#include <usb/host/utils/malloc32.h>
     52
     53#include "uhci_batch.h"
    4254#include "hc.h"
    43 #include "uhci_batch.h"
    4455
    4556#define UHCI_INTR_ALLOW_INTERRUPTS \
     
    8596static int hc_init_mem_structures(hc_t *instance);
    8697static 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);
     98
    9099static int hc_debug_checker(void *arg);
    91100
    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 };
    101101
    102102/** 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 Physical address of device's registers.
    108  * @param[in] reg_size Size of the register area (bytes).
     103 * @param[out] code IRQ code structure.
     104 * @param[in] hw_res Device's resources.
    109105 *
    110106 * @return Error code.
    111107 */
    112 int
    113 hc_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)))
     108int 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))
    119118                return EOVERFLOW;
    120119
    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  */
    142 int 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;
     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];
    172145}
    173146
    174147/** Take action based on the interrupt cause.
    175148 *
    176  * @param[in] instance UHCI structure to use.
     149 * @param[in] hcd HCD structure to use.
    177150 * @param[in] status Value of the status register at the time of interrupt.
    178151 *
     
    182155 * - resume from suspend state (not implemented)
    183156 */
    184 void hc_interrupt(hc_t *instance, uint16_t status)
    185 {
     157void uhci_hc_interrupt(hcd_t *hcd, uint32_t status)
     158{
     159        assert(hcd);
     160        hc_t *instance = hcd_get_driver_data(hcd);
    186161        assert(instance);
    187162        /* Lower 2 bits are transaction error and transaction complete */
     
    197172                    &instance->transfers_bulk_full, &done);
    198173
    199                 while (!list_empty(&done)) {
    200                         link_t *item = list_first(&done);
    201                         list_remove(item);
     174                list_foreach_safe(done, current, next) {
     175                        list_remove(current);
    202176                        uhci_transfer_batch_t *batch =
    203                             uhci_transfer_batch_from_link(item);
     177                            uhci_transfer_batch_from_link(current);
    204178                        uhci_transfer_batch_finish_dispose(batch);
    205179                }
     
    232206 *
    233207 * @param[in] instance Memory place to initialize.
    234  * @param[in] regs Address of I/O control registers.
    235  * @param[in] reg_size Size of I/O control registers.
     208 * @param[in] regs Range of device's I/O control registers.
    236209 * @param[in] interrupts True if hw interrupts should be used.
    237210 * @return Error code.
     
    241214 * interrupt fibrils.
    242215 */
    243 int 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;
     216int 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;
    247223
    248224        instance->hw_interrupts = interrupts;
     
    250226
    251227        /* allow access to hc control registers */
    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;
     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        }
    277247
    278248        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         }
    284249        (void)hc_debug_checker;
    285250
     251        uhci_rh_init(&instance->rh, instance->registers->ports, "uhci");
     252
    286253        return EOK;
     254}
     255
     256/** Safely dispose host controller internal structures
     257 *
     258 * @param[in] instance Host controller structure to use.
     259 */
     260void hc_fini(hc_t *instance)
     261{
     262        assert(instance);
     263        //TODO Implement
    287264}
    288265
     
    432409}
    433410
     411int 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
    434427/** Schedule batch for execution.
    435428 *
     
    440433 * Checks for bandwidth availability and appends the batch to the proper queue.
    441434 */
    442 int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
     435int uhci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
    443436{
    444437        assert(hcd);
    445         hc_t *instance = hcd->private_data;
     438        hc_t *instance = hcd_get_driver_data(hcd);
    446439        assert(instance);
    447440        assert(batch);
     441
     442        if (batch->ep->address == uhci_rh_get_address(&instance->rh))
     443                return uhci_rh_schedule(&instance->rh, batch);
     444
    448445        uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch);
    449446        if (!uhci_batch) {
     
    457454        transfer_list_add_batch(list, uhci_batch);
    458455
    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  */
    467 int 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         }
    482456        return EOK;
    483457}
Note: See TracChangeset for help on using the changeset viewer.