Ignore:
File:
1 edited

Legend:

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

    r7de1988c rfccf289  
    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"
     50#include "utils/malloc32.h"
    4551
    4652#include "hc.h"
    47 #include "ohci_endpoint.h"
    4853
    4954#define OHCI_USED_INTERRUPTS \
     
    8489};
    8590
    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 
    9691static void hc_gain_control(hc_t *instance);
    9792static void hc_start(hc_t *instance);
    9893static int hc_init_transfer_lists(hc_t *instance);
    9994static 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);
    10295
    10396/** Generate IRQ code.
     
    10699 * @param[out] cmds Commands buffer.
    107100 * @param[in] cmds_size Size of the commands buffer (bytes).
    108  * @param[in] regs Device's register range.
     101 * @param[in] hw_res Device's resources.
    109102 *
    110103 * @return Error code.
    111104 */
    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, addr_range_t *regs)
    115 {
    116         if ((ranges_size < sizeof(ohci_pio_ranges)) ||
    117             (cmds_size < sizeof(ohci_irq_commands)) ||
    118             (RNGSZ(*regs) < sizeof(ohci_regs_t)))
     105int ohci_hc_gen_irq_code(irq_code_t *code, const hw_res_list_parsed_t *hw_res)
     106{
     107        assert(code);
     108        assert(hw_res);
     109
     110        if (hw_res->irqs.count != 1 || hw_res->mem_ranges.count != 1)
     111                return EINVAL;
     112
     113        const addr_range_t regs = hw_res->mem_ranges.ranges[0];
     114
     115        if (RNGSZ(regs) < sizeof(ohci_regs_t))
    119116                return EOVERFLOW;
    120117
    121         memcpy(ranges, ohci_pio_ranges, sizeof(ohci_pio_ranges));
    122         ranges[0].base = RNGABS(*regs);
    123 
    124         memcpy(cmds, ohci_irq_commands, sizeof(ohci_irq_commands));
    125         ohci_regs_t *registers = (ohci_regs_t *) RNGABSPTR(*regs);
    126         cmds[0].addr = (void *) &registers->interrupt_status;
    127         cmds[3].addr = (void *) &registers->interrupt_status;
    128         OHCI_WR(cmds[1].value, OHCI_USED_INTERRUPTS);
    129 
    130         return EOK;
    131 }
    132 
    133 /** Register interrupt handler.
    134  *
    135  * @param[in] device Host controller DDF device
    136  * @param[in] regs Register range
    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, addr_range_t *regs, int irq,
    143     interrupt_handler_t handler)
    144 {
    145         int rc;
    146 
    147         irq_pio_range_t irq_ranges[hc_irq_pio_range_count];
    148         irq_cmd_t irq_cmds[hc_irq_cmd_count];
    149 
    150         irq_code_t irq_code = {
    151                 .rangecount = hc_irq_pio_range_count,
    152                 .ranges = irq_ranges,
    153                 .cmdcount = hc_irq_cmd_count,
    154                 .cmds = irq_cmds
    155         };
    156 
    157         rc = hc_get_irq_code(irq_ranges, sizeof(irq_ranges), irq_cmds,
    158             sizeof(irq_cmds), regs);
    159         if (rc != EOK) {
    160                 usb_log_error("Failed to generate IRQ code: %s.\n",
    161                     str_error(rc));
    162                 return rc;
    163         }
    164 
    165         /* Register handler to avoid interrupt lockup */
    166         rc = register_interrupt_handler(device, irq, handler, &irq_code);
    167         if (rc != EOK) {
    168                 usb_log_error("Failed to register interrupt handler: %s.\n",
    169                     str_error(rc));
    170                 return rc;
    171         }
    172 
    173         return EOK;
    174 }
    175 
    176 /** Announce OHCI root hub to the DDF
    177  *
    178  * @param[in] instance OHCI driver intance
    179  * @param[in] hub_fun DDF fuction representing OHCI root hub
    180  * @return Error code
    181  */
    182 int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun)
    183 {
    184         bool addr_reqd = false;
    185         bool ep_added = false;
    186         bool fun_bound = false;
    187         int rc;
    188 
    189         assert(instance);
    190         assert(hub_fun);
    191 
    192         /* Try to get address 1 for root hub. */
    193         instance->rh.address = 1;
    194         rc = usb_device_manager_request_address(
    195             &instance->generic.dev_manager, &instance->rh.address, false,
    196             USB_SPEED_FULL);
    197         if (rc != EOK) {
    198                 usb_log_error("Failed to get OHCI root hub address: %s\n",
    199                     str_error(rc));
    200                 goto error;
    201         }
    202 
    203         addr_reqd = true;
    204 
    205         rc = usb_endpoint_manager_add_ep(
    206             &instance->generic.ep_manager, instance->rh.address, 0,
    207             USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL, USB_SPEED_FULL, 64,
    208             0, NULL, NULL);
    209         if (rc != EOK) {
    210                 usb_log_error("Failed to register root hub control endpoint: %s.\n",
    211                     str_error(rc));
    212                 goto error;
    213         }
    214 
    215         ep_added = true;
    216 
    217         rc = ddf_fun_add_match_id(hub_fun, "usb&class=hub", 100);
    218         if (rc != EOK) {
    219                 usb_log_error("Failed to add root hub match-id: %s.\n",
    220                     str_error(rc));
    221                 goto error;
    222         }
    223 
    224         rc = ddf_fun_bind(hub_fun);
    225         if (rc != EOK) {
    226                 usb_log_error("Failed to bind root hub function: %s.\n",
    227                     str_error(rc));
    228                 goto error;
    229         }
    230 
    231         fun_bound = true;
    232 
    233         rc = usb_device_manager_bind_address(&instance->generic.dev_manager,
    234             instance->rh.address, ddf_fun_get_handle(hub_fun));
    235         if (rc != EOK) {
    236                 usb_log_warning("Failed to bind root hub address: %s.\n",
    237                     str_error(rc));
    238         }
    239 
    240         return EOK;
    241 error:
    242         if (fun_bound)
    243                 ddf_fun_unbind(hub_fun);
    244         if (ep_added) {
    245                 usb_endpoint_manager_remove_ep(
    246                     &instance->generic.ep_manager, instance->rh.address, 0,
    247                     USB_DIRECTION_BOTH, NULL, NULL);
    248         }
    249         if (addr_reqd) {
    250                 usb_device_manager_release_address(
    251                     &instance->generic.dev_manager, instance->rh.address);
    252         }
    253         return rc;
     118        code->ranges = malloc(sizeof(ohci_pio_ranges));
     119        if (code->ranges == NULL)
     120                return ENOMEM;
     121
     122        code->cmds = malloc(sizeof(ohci_irq_commands));
     123        if (code->cmds == NULL) {
     124                free(code->ranges);
     125                return ENOMEM;
     126        }
     127
     128        code->rangecount = ARRAY_SIZE(ohci_pio_ranges);
     129        code->cmdcount = ARRAY_SIZE(ohci_irq_commands);
     130
     131        memcpy(code->ranges, ohci_pio_ranges, sizeof(ohci_pio_ranges));
     132        code->ranges[0].base = RNGABS(regs);
     133
     134        memcpy(code->cmds, ohci_irq_commands, sizeof(ohci_irq_commands));
     135        ohci_regs_t *registers = (ohci_regs_t *) RNGABSPTR(regs);
     136        code->cmds[0].addr = (void *) &registers->interrupt_status;
     137        code->cmds[3].addr = (void *) &registers->interrupt_status;
     138        OHCI_WR(code->cmds[1].value, OHCI_USED_INTERRUPTS);
     139
     140        usb_log_debug("Memory mapped 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];
    254144}
    255145
     
    257147 *
    258148 * @param[in] instance Memory place for the structure.
    259  * @param[in] regs Device's I/O registers range.
     149 * @param[in] regs Device's resources
    260150 * @param[in] interrupts True if w interrupts should be used
    261151 * @return Error code
    262152 */
    263 int hc_init(hc_t *instance, addr_range_t *regs, bool interrupts)
    264 {
    265         assert(instance);
    266 
    267         int rc = pio_enable_range(regs, (void **) &instance->registers);
    268         if (rc != EOK) {
    269                 usb_log_error("Failed to gain access to device registers: %s.\n",
    270                     str_error(rc));
    271                 return rc;
    272         }
     153int hc_init(hc_t *instance, const hw_res_list_parsed_t *hw_res, bool interrupts)
     154{
     155        assert(instance);
     156        assert(hw_res);
     157        if (hw_res->mem_ranges.count != 1 ||
     158            hw_res->mem_ranges.ranges[0].size < sizeof(ohci_regs_t))
     159            return EINVAL;
     160
     161        int ret = pio_enable_range(&hw_res->mem_ranges.ranges[0],
     162            (void **) &instance->registers);
     163        if (ret != EOK) {
     164                usb_log_error("Failed to gain access to registers: %s.\n",
     165                    str_error(ret));
     166                return ret;
     167        }
     168        usb_log_debug("Device registers at %" PRIx64 " (%zuB) accessible.\n",
     169            hw_res->mem_ranges.ranges[0].address.absolute,
     170            hw_res->mem_ranges.ranges[0].size);
    273171
    274172        list_initialize(&instance->pending_batches);
    275 
    276         hcd_init(&instance->generic, USB_SPEED_FULL,
    277             BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11);
    278         instance->generic.private_data = instance;
    279         instance->generic.schedule = hc_schedule;
    280         instance->generic.ep_add_hook = ohci_endpoint_init;
    281         instance->generic.ep_remove_hook = ohci_endpoint_fini;
    282 
    283         rc = hc_init_memory(instance);
    284         if (rc != EOK) {
     173        fibril_mutex_initialize(&instance->guard);
     174        instance->hw_interrupts = interrupts;
     175
     176        ret = hc_init_memory(instance);
     177        if (ret != EOK) {
    285178                usb_log_error("Failed to create OHCI memory structures: %s.\n",
    286                     str_error(rc));
    287                 return rc;
    288         }
    289 
    290         fibril_mutex_initialize(&instance->guard);
     179                    str_error(ret));
     180                return ret;
     181        }
    291182
    292183        hc_gain_control(instance);
    293184
    294         if (!interrupts) {
    295                 instance->interrupt_emulator =
    296                     fibril_create((int(*)(void*))interrupt_emulator, instance);
    297                 fibril_add_ready(instance->interrupt_emulator);
    298         }
    299 
    300         rh_init(&instance->rh, instance->registers);
     185        ohci_rh_init(&instance->rh, instance->registers, "ohci rh");
    301186        hc_start(instance);
    302187
    303188        return EOK;
    304189}
     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};
    305200
    306201void hc_enqueue_endpoint(hc_t *instance, const endpoint_t *ep)
     
    372267}
    373268
     269int ohci_hc_status(hcd_t *hcd, uint32_t *status)
     270{
     271        assert(hcd);
     272        assert(status);
     273        hc_t *instance = hcd->driver.data;
     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
    374283/** Add USB transfer to the schedule.
    375284 *
    376  * @param[in] instance OHCI hc driver structure.
     285 * @param[in] hcd HCD driver structure.
    377286 * @param[in] batch Batch representing the transfer.
    378287 * @return Error code.
    379288 */
    380 int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
     289int ohci_hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
    381290{
    382291        assert(hcd);
    383         hc_t *instance = hcd->private_data;
     292        hc_t *instance = hcd->driver.data;
    384293        assert(instance);
    385294
    386295        /* Check for root hub communication */
    387         if (batch->ep->address == instance->rh.address) {
     296        if (batch->ep->address == ohci_rh_get_address(&instance->rh)) {
    388297                usb_log_debug("OHCI root hub request.\n");
    389                 rh_request(&instance->rh, batch);
    390                 return EOK;
     298                return ohci_rh_schedule(&instance->rh, batch);
    391299        }
    392300        ohci_transfer_batch_t *ohci_batch = ohci_transfer_batch_get(batch);
     
    416324/** Interrupt handling routine
    417325 *
    418  * @param[in] instance OHCI hc driver structure.
     326 * @param[in] hcd HCD driver structure.
    419327 * @param[in] status Value of the status register at the time of interrupt.
    420328 */
    421 void hc_interrupt(hc_t *instance, uint32_t status)
    422 {
     329void ohci_hc_interrupt(hcd_t *hcd, uint32_t status)
     330{
     331        assert(hcd);
     332        hc_t *instance = hcd->driver.data;
    423333        status = OHCI_RD(status);
    424334        assert(instance);
     
    427337        usb_log_debug2("OHCI(%p) interrupt: %x.\n", instance, status);
    428338        if (status & I_RHSC)
    429                 rh_interrupt(&instance->rh);
     339                ohci_rh_interrupt(&instance->rh);
    430340
    431341        if (status & I_WDH) {
     
    458368        }
    459369
    460 }
    461 
    462 /** Check status register regularly
    463  *
    464  * @param[in] instance OHCI hc driver structure.
    465  * @return Error code
    466  */
    467 int interrupt_emulator(hc_t *instance)
    468 {
    469         assert(instance);
    470         usb_log_info("Started interrupt emulator.\n");
    471         while (1) {
    472                 const uint32_t status = instance->registers->interrupt_status;
    473                 instance->registers->interrupt_status = status;
    474                 hc_interrupt(instance, status);
    475                 async_usleep(10000);
    476         }
    477         return EOK;
    478370}
    479371
     
    512404                OHCI_SET(instance->registers->command_status, CS_OCR);
    513405                /* Hope that SMM actually knows its stuff or we can hang here */
    514                 while (OHCI_RD(instance->registers->control & C_IR)) {
     406                while (OHCI_RD(instance->registers->control) & C_IR) {
    515407                        async_usleep(1000);
    516408                }
     
    596488
    597489        /* Enable interrupts */
    598         OHCI_WR(instance->registers->interrupt_enable, OHCI_USED_INTERRUPTS);
    599         usb_log_debug("Enabled interrupts: %x.\n",
    600             OHCI_RD(instance->registers->interrupt_enable));
    601         OHCI_WR(instance->registers->interrupt_enable, I_MI);
     490        if (instance->hw_interrupts) {
     491                OHCI_WR(instance->registers->interrupt_enable,
     492                    OHCI_USED_INTERRUPTS);
     493                usb_log_debug("Enabled interrupts: %x.\n",
     494                    OHCI_RD(instance->registers->interrupt_enable));
     495                OHCI_WR(instance->registers->interrupt_enable, I_MI);
     496        }
    602497
    603498        /* Set periodic start to 90% */
     
    625520do { \
    626521        const char *name = usb_str_transfer_type(type); \
    627         int ret = endpoint_list_init(&instance->lists[type], name); \
     522        const int ret = endpoint_list_init(&instance->lists[type], name); \
    628523        if (ret != EOK) { \
    629524                usb_log_error("Failed to setup %s endpoint list: %s.\n", \
Note: See TracChangeset for help on using the changeset viewer.