Ignore:
File:
1 edited

Legend:

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

    rf83666c r58563585  
    3434 */
    3535
     36#include <assert.h>
     37#include <async.h>
    3638#include <errno.h>
    37 #include <stdbool.h>
     39#include <macros.h>
     40#include <mem.h>
     41#include <stdlib.h>
    3842#include <str_error.h>
    39 #include <adt/list.h>
    40 #include <libarch/ddi.h>
     43#include <sys/types.h>
    4144
    4245#include <usb/debug.h>
    4346#include <usb/usb.h>
    44 #include <usb/ddfiface.h>
     47
     48#include "ohci_endpoint.h"
     49#include "ohci_batch.h"
    4550
    4651#include "hc.h"
    47 #include "ohci_endpoint.h"
    4852
    4953#define OHCI_USED_INTERRUPTS \
     
    8488};
    8589
    86 enum {
    87         /** Number of PIO ranges used in IRQ code */
    88         hc_irq_pio_range_count =
    89             sizeof(ohci_pio_ranges) / sizeof(irq_pio_range_t),
    90 
    91         /** Number of commands used in IRQ code */
    92         hc_irq_cmd_count =
    93             sizeof(ohci_irq_commands) / sizeof(irq_cmd_t)
    94 };
    95 
    9690static void hc_gain_control(hc_t *instance);
    9791static void hc_start(hc_t *instance);
    9892static int hc_init_transfer_lists(hc_t *instance);
    9993static int hc_init_memory(hc_t *instance);
    100 static int interrupt_emulator(hc_t *instance);
    101 static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch);
    10294
    10395/** Generate IRQ code.
     
    10698 * @param[out] cmds Commands buffer.
    10799 * @param[in] cmds_size Size of the commands buffer (bytes).
    108  * @param[in] regs Physical address of device's registers.
    109  * @param[in] reg_size Size of the register area (bytes).
     100 * @param[in] hw_res Device's resources.
    110101 *
    111102 * @return Error code.
    112103 */
    113 int
    114 hc_get_irq_code(irq_pio_range_t ranges[], size_t ranges_size, irq_cmd_t cmds[],
    115     size_t cmds_size, uintptr_t regs, size_t reg_size)
    116 {
    117         if ((ranges_size < sizeof(ohci_pio_ranges)) ||
    118             (cmds_size < sizeof(ohci_irq_commands)) ||
    119             (reg_size < sizeof(ohci_regs_t)))
     104int ohci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res)
     105{
     106        assert(code);
     107        assert(hw_res);
     108
     109        if (hw_res->irqs.count != 1 || hw_res->mem_ranges.count != 1)
     110                return EINVAL;
     111
     112        const addr_range_t regs = hw_res->mem_ranges.ranges[0];
     113
     114        if (RNGSZ(regs) < sizeof(ohci_regs_t))
    120115                return EOVERFLOW;
    121116
    122         memcpy(ranges, ohci_pio_ranges, sizeof(ohci_pio_ranges));
    123         ranges[0].base = regs;
    124 
    125         memcpy(cmds, ohci_irq_commands, sizeof(ohci_irq_commands));
    126         ohci_regs_t *registers = (ohci_regs_t *) regs;
    127         cmds[0].addr = (void *) &registers->interrupt_status;
    128         cmds[3].addr = (void *) &registers->interrupt_status;
    129         OHCI_WR(cmds[1].value, OHCI_USED_INTERRUPTS);
    130 
    131         return EOK;
    132 }
    133 
    134 /** Register interrupt handler.
    135  *
    136  * @param[in] device Host controller DDF device
    137  * @param[in] reg_base Register range base
    138  * @param[in] reg_size Register range size
    139  * @param[in] irq Interrupt number
    140  * @paran[in] handler Interrupt handler
    141  *
    142  * @return EOK on success or negative error code
    143  */
    144 int hc_register_irq_handler(ddf_dev_t *device, uintptr_t reg_base, size_t reg_size,
    145     int irq, interrupt_handler_t handler)
    146 {
    147         int rc;
    148 
    149         irq_pio_range_t irq_ranges[hc_irq_pio_range_count];
    150         irq_cmd_t irq_cmds[hc_irq_cmd_count];
    151 
    152         irq_code_t irq_code = {
    153                 .rangecount = hc_irq_pio_range_count,
    154                 .ranges = irq_ranges,
    155                 .cmdcount = hc_irq_cmd_count,
    156                 .cmds = irq_cmds
    157         };
    158 
    159         rc = hc_get_irq_code(irq_ranges, sizeof(irq_ranges), irq_cmds,
    160             sizeof(irq_cmds), reg_base, reg_size);
    161         if (rc != EOK) {
    162                 usb_log_error("Failed to generate IRQ code: %s.\n",
    163                     str_error(rc));
    164                 return rc;
    165         }
    166 
    167         /* Register handler to avoid interrupt lockup */
    168         rc = register_interrupt_handler(device, irq, handler, &irq_code);
    169         if (rc != EOK) {
    170                 usb_log_error("Failed to register interrupt handler: %s.\n",
    171                     str_error(rc));
    172                 return rc;
    173         }
    174 
    175         return EOK;
    176 }
    177 
    178 /** Announce OHCI root hub to the DDF
    179  *
    180  * @param[in] instance OHCI driver intance
    181  * @param[in] hub_fun DDF fuction representing OHCI root hub
    182  * @return Error code
    183  */
    184 int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun)
    185 {
    186         bool addr_reqd = false;
    187         bool ep_added = false;
    188         bool fun_bound = false;
    189         int rc;
    190 
    191         assert(instance);
    192         assert(hub_fun);
    193 
    194         /* Try to get address 1 for root hub. */
    195         instance->rh.address = 1;
    196         rc = usb_device_manager_request_address(
    197             &instance->generic.dev_manager, &instance->rh.address, false,
    198             USB_SPEED_FULL);
    199         if (rc != EOK) {
    200                 usb_log_error("Failed to get OHCI root hub address: %s\n",
    201                     str_error(rc));
    202                 goto error;
    203         }
    204 
    205         addr_reqd = true;
    206 
    207         rc = usb_endpoint_manager_add_ep(
    208             &instance->generic.ep_manager, instance->rh.address, 0,
    209             USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64,
    210             0, NULL, NULL);
    211         if (rc != EOK) {
    212                 usb_log_error("Failed to register root hub control endpoint: %s.\n",
    213                     str_error(rc));
    214                 goto error;
    215         }
    216 
    217         ep_added = true;
    218 
    219         rc = ddf_fun_add_match_id(hub_fun, "usb&class=hub", 100);
    220         if (rc != EOK) {
    221                 usb_log_error("Failed to add root hub match-id: %s.\n",
    222                     str_error(rc));
    223                 goto error;
    224         }
    225 
    226         rc = ddf_fun_bind(hub_fun);
    227         if (rc != EOK) {
    228                 usb_log_error("Failed to bind root hub function: %s.\n",
    229                     str_error(rc));
    230                 goto error;
    231         }
    232 
    233         fun_bound = true;
    234 
    235         rc = usb_device_manager_bind_address(&instance->generic.dev_manager,
    236             instance->rh.address, ddf_fun_get_handle(hub_fun));
    237         if (rc != EOK) {
    238                 usb_log_warning("Failed to bind root hub address: %s.\n",
    239                     str_error(rc));
    240         }
    241 
    242         return EOK;
    243 error:
    244         if (fun_bound)
    245                 ddf_fun_unbind(hub_fun);
    246         if (ep_added) {
    247                 usb_endpoint_manager_remove_ep(
    248                     &instance->generic.ep_manager, instance->rh.address, 0,
    249                     USB_DIRECTION_BOTH, NULL, NULL);
    250         }
    251         if (addr_reqd) {
    252                 usb_device_manager_release_address(
    253                     &instance->generic.dev_manager, instance->rh.address);
    254         }
    255         return rc;
     117        code->ranges = malloc(sizeof(ohci_pio_ranges));
     118        if (code->ranges == NULL)
     119                return ENOMEM;
     120
     121        code->cmds = malloc(sizeof(ohci_irq_commands));
     122        if (code->cmds == NULL) {
     123                free(code->ranges);
     124                return ENOMEM;
     125        }
     126
     127        code->rangecount = ARRAY_SIZE(ohci_pio_ranges);
     128        code->cmdcount = ARRAY_SIZE(ohci_irq_commands);
     129
     130        memcpy(code->ranges, ohci_pio_ranges, sizeof(ohci_pio_ranges));
     131        code->ranges[0].base = RNGABS(regs);
     132
     133        memcpy(code->cmds, ohci_irq_commands, sizeof(ohci_irq_commands));
     134        ohci_regs_t *registers = (ohci_regs_t *) RNGABSPTR(regs);
     135        code->cmds[0].addr = (void *) &registers->interrupt_status;
     136        code->cmds[3].addr = (void *) &registers->interrupt_status;
     137        OHCI_WR(code->cmds[1].value, OHCI_USED_INTERRUPTS);
     138
     139        usb_log_debug("Memory mapped regs at %p (size %zu), IRQ %d.\n",
     140            RNGABSPTR(regs), RNGSZ(regs), hw_res->irqs.irqs[0]);
     141
     142        return hw_res->irqs.irqs[0];
    256143}
    257144
     
    259146 *
    260147 * @param[in] instance Memory place for the structure.
    261  * @param[in] regs Address of the memory mapped I/O registers.
    262  * @param[in] reg_size Size of the memory mapped area.
     148 * @param[in] regs Device's resources
    263149 * @param[in] interrupts True if w interrupts should be used
    264150 * @return Error code
    265151 */
    266 int hc_init(hc_t *instance, uintptr_t regs, size_t reg_size, bool interrupts)
    267 {
    268         assert(instance);
    269 
    270         int rc =
    271             pio_enable((void*)regs, reg_size, (void**)&instance->registers);
    272         if (rc != EOK) {
    273                 usb_log_error("Failed to gain access to device registers: %s.\n",
    274                     str_error(rc));
    275                 return rc;
    276         }
     152int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)
     153{
     154        assert(instance);
     155        assert(hw_res);
     156        if (hw_res->mem_ranges.count != 1 ||
     157            hw_res->mem_ranges.ranges[0].size < sizeof(ohci_regs_t))
     158            return EINVAL;
     159
     160        int ret = pio_enable_range(&hw_res->mem_ranges.ranges[0],
     161            (void **) &instance->registers);
     162        if (ret != EOK) {
     163                usb_log_error("Failed to gain access to registers: %s.\n",
     164                    str_error(ret));
     165                return ret;
     166        }
     167        usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.\n",
     168            hw_res->mem_ranges.ranges[0].address.absolute,
     169            hw_res->mem_ranges.ranges[0].size);
    277170
    278171        list_initialize(&instance->pending_batches);
    279 
    280         hcd_init(&instance->generic, USB_SPEED_FULL,
    281             BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11);
    282         instance->generic.private_data = instance;
    283         instance->generic.schedule = hc_schedule;
    284         instance->generic.ep_add_hook = ohci_endpoint_init;
    285         instance->generic.ep_remove_hook = ohci_endpoint_fini;
    286 
    287         rc = hc_init_memory(instance);
    288         if (rc != EOK) {
     172        fibril_mutex_initialize(&instance->guard);
     173        instance->hw_interrupts = interrupts;
     174
     175        ret = hc_init_memory(instance);
     176        if (ret != EOK) {
    289177                usb_log_error("Failed to create OHCI memory structures: %s.\n",
    290                     str_error(rc));
    291                 return rc;
    292         }
    293 
    294         fibril_mutex_initialize(&instance->guard);
     178                    str_error(ret));
     179                // TODO: We should disable pio access here
     180                return ret;
     181        }
    295182
    296183        hc_gain_control(instance);
    297184
    298         if (!interrupts) {
    299                 instance->interrupt_emulator =
    300                     fibril_create((int(*)(void*))interrupt_emulator, instance);
    301                 fibril_add_ready(instance->interrupt_emulator);
    302         }
    303 
    304         rh_init(&instance->rh, instance->registers);
     185        ohci_rh_init(&instance->rh, instance->registers, "ohci rh");
    305186        hc_start(instance);
    306187
    307188        return EOK;
    308189}
     190
     191/** Safely dispose host controller internal structures
     192 *
     193 * @param[in] instance Host controller structure to use.
     194 */
     195void hc_fini(hc_t *instance)
     196{
     197        assert(instance);
     198        /* TODO: implement*/
     199};
    309200
    310201void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep)
     
    376267}
    377268
     269int ohci_hc_status(hcd_t *hcd, uint32_t *status)
     270{
     271        assert(hcd);
     272        assert(status);
     273        hc_t *instance = hcd_get_driver_data(hcd);
     274        assert(instance);
     275
     276        if (instance->registers){
     277                *status = OHCI_RD(instance->registers->interrupt_status);
     278                OHCI_WR(instance->registers->interrupt_status, *status);
     279        }
     280        return EOK;
     281}
     282
    378283/** Add USB transfer to the schedule.
    379284 *
    380  * @param[in] instance OHCI hc driver structure.
     285 * @param[in] hcd HCD driver structure.
    381286 * @param[in] batch Batch representing the transfer.
    382287 * @return Error code.
    383288 */
    384 int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
     289int ohci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
    385290{
    386291        assert(hcd);
    387         hc_t *instance = hcd->private_data;
     292        hc_t *instance = hcd_get_driver_data(hcd);
    388293        assert(instance);
    389294
    390295        /* Check for root hub communication */
    391         if (batch->ep->address == instance->rh.address) {
     296        if (batch->ep->address == ohci_rh_get_address(&instance->rh)) {
    392297                usb_log_debug("OHCI root hub request.\n");
    393                 rh_request(&instance->rh, batch);
    394                 return EOK;
     298                return ohci_rh_schedule(&instance->rh, batch);
    395299        }
    396300        ohci_transfer_batch_t *ohci_batch = ohci_transfer_batch_get(batch);
     
    420324/** Interrupt handling routine
    421325 *
    422  * @param[in] instance OHCI hc driver structure.
     326 * @param[in] hcd HCD driver structure.
    423327 * @param[in] status Value of the status register at the time of interrupt.
    424328 */
    425 void hc_interrupt(hc_t *instance, uint32_t status)
    426 {
     329void ohci_hc_interrupt(hcd_t *hcd, uint32_t status)
     330{
     331        assert(hcd);
     332        hc_t *instance = hcd_get_driver_data(hcd);
    427333        status = OHCI_RD(status);
    428334        assert(instance);
     
    431337        usb_log_debug2("OHCI(%p) interrupt: %x.\n", instance, status);
    432338        if (status & I_RHSC)
    433                 rh_interrupt(&instance->rh);
     339                ohci_rh_interrupt(&instance->rh);
    434340
    435341        if (status & I_WDH) {
     
    462368        }
    463369
    464 }
    465 
    466 /** Check status register regularly
    467  *
    468  * @param[in] instance OHCI hc driver structure.
    469  * @return Error code
    470  */
    471 int interrupt_emulator(hc_t *instance)
    472 {
    473         assert(instance);
    474         usb_log_info("Started interrupt emulator.\n");
    475         while (1) {
    476                 const uint32_t status = instance->registers->interrupt_status;
    477                 instance->registers->interrupt_status = status;
    478                 hc_interrupt(instance, status);
    479                 async_usleep(10000);
    480         }
    481         return EOK;
    482370}
    483371
     
    505393                    ohci_emulation_reg, OHCI_RD(*ohci_emulation_reg));
    506394                /* Zero everything but A20State */
     395                // TODO: should we ack interrupts before doing this?
    507396                OHCI_CLR(*ohci_emulation_reg, ~0x100);
    508397                usb_log_debug(
     
    514403        if (OHCI_RD(instance->registers->control) & C_IR) {
    515404                usb_log_debug("SMM driver: request ownership change.\n");
     405                // TODO: should we ack interrupts before doing this?
    516406                OHCI_SET(instance->registers->command_status, CS_OCR);
    517407                /* Hope that SMM actually knows its stuff or we can hang here */
    518                 while (OHCI_RD(instance->registers->control & C_IR)) {
     408                while (OHCI_RD(instance->registers->control) & C_IR) {
    519409                        async_usleep(1000);
    520410                }
     
    600490
    601491        /* Enable interrupts */
    602         OHCI_WR(instance->registers->interrupt_enable, OHCI_USED_INTERRUPTS);
    603         usb_log_debug("Enabled interrupts: %x.\n",
    604             OHCI_RD(instance->registers->interrupt_enable));
    605         OHCI_WR(instance->registers->interrupt_enable, I_MI);
     492        if (instance->hw_interrupts) {
     493                OHCI_WR(instance->registers->interrupt_enable,
     494                    OHCI_USED_INTERRUPTS);
     495                usb_log_debug("Enabled interrupts: %x.\n",
     496                    OHCI_RD(instance->registers->interrupt_enable));
     497                OHCI_WR(instance->registers->interrupt_enable, I_MI);
     498        }
    606499
    607500        /* Set periodic start to 90% */
     
    629522do { \
    630523        const char *name = usb_str_transfer_type(type); \
    631         int ret = endpoint_list_init(&instance->lists[type], name); \
     524        const int ret = endpoint_list_init(&instance->lists[type], name); \
    632525        if (ret != EOK) { \
    633526                usb_log_error("Failed to setup %s endpoint list: %s.\n", \
Note: See TracChangeset for help on using the changeset viewer.