Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/uhci-hcd/hc.c

    r8986412 r4c28d17  
    4444#include "hc.h"
    4545
    46 #define UHCI_INTR_ALLOW_INTERRUPTS \
    47     (UHCI_INTR_CRC | UHCI_INTR_COMPLETE | UHCI_INTR_SHORT_PACKET)
    48 #define UHCI_STATUS_USED_INTERRUPTS \
    49     (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)
    50 
    51 
     46static irq_cmd_t uhci_cmds[] = {
     47        {
     48                .cmd = CMD_PIO_READ_16,
     49                .addr = NULL, /* patched for every instance */
     50                .dstarg = 1
     51        },
     52        {
     53                .cmd = CMD_PIO_WRITE_16,
     54                .addr = NULL, /* pathed for every instance */
     55                .value = 0x1f
     56        },
     57        {
     58                .cmd = CMD_ACCEPT
     59        }
     60};
     61/*----------------------------------------------------------------------------*/
    5262static int hc_init_transfer_lists(hc_t *instance);
    5363static int hc_init_mem_structures(hc_t *instance);
     
    5666static int hc_interrupt_emulator(void *arg);
    5767static int hc_debug_checker(void *arg);
     68#if 0
     69static bool usb_is_allowed(
     70    bool low_speed, usb_transfer_type_t transfer, size_t size);
     71#endif
    5872/*----------------------------------------------------------------------------*/
    5973/** Initialize UHCI hcd driver structure
     
    7589        int ret;
    7690
    77 #define CHECK_RET_RETURN(ret, message...) \
     91#define CHECK_RET_DEST_FUN_RETURN(ret, message...) \
    7892        if (ret != EOK) { \
    7993                usb_log_error(message); \
     94                if (instance->ddf_instance) \
     95                        ddf_fun_destroy(instance->ddf_instance); \
    8096                return ret; \
    8197        } else (void) 0
     
    8399        instance->hw_interrupts = interrupts;
    84100        instance->hw_failures = 0;
     101
     102        /* Setup UHCI function. */
     103        instance->ddf_instance = fun;
    85104
    86105        /* allow access to hc control registers */
    87106        regs_t *io;
    88107        ret = pio_enable(regs, reg_size, (void**)&io);
    89         CHECK_RET_RETURN(ret,
     108        CHECK_RET_DEST_FUN_RETURN(ret,
    90109            "Failed(%d) to gain access to registers at %p: %s.\n",
    91             ret, io, str_error(ret));
     110            ret, str_error(ret), io);
    92111        instance->registers = io;
    93         usb_log_debug("Device registers at %p (%zuB) accessible.\n",
     112        usb_log_debug("Device registers at %p(%u) accessible.\n",
    94113            io, reg_size);
    95114
    96115        ret = hc_init_mem_structures(instance);
    97         CHECK_RET_RETURN(ret,
    98             "Failed(%d) to initialize UHCI memory structures: %s.\n",
    99             ret, str_error(ret));
     116        CHECK_RET_DEST_FUN_RETURN(ret,
     117            "Failed to initialize UHCI memory structures.\n");
    100118
    101119        hc_init_hw(instance);
    102120        if (!interrupts) {
    103                 instance->interrupt_emulator =
     121                instance->cleaner =
    104122                    fibril_create(hc_interrupt_emulator, instance);
    105                 fibril_add_ready(instance->interrupt_emulator);
    106         }
    107         (void)hc_debug_checker;
     123                fibril_add_ready(instance->cleaner);
     124        } else {
     125                /* TODO: enable interrupts here */
     126        }
     127
     128        instance->debug_checker =
     129            fibril_create(hc_debug_checker, instance);
     130//      fibril_add_ready(instance->debug_checker);
    108131
    109132        return EOK;
     
    141164                /* Enable all interrupts, but resume interrupt */
    142165                pio_write_16(&instance->registers->usbintr,
    143                     UHCI_INTR_ALLOW_INTERRUPTS);
     166                    UHCI_INTR_CRC | UHCI_INTR_COMPLETE | UHCI_INTR_SHORT_PACKET);
    144167        }
    145168
     
    167190{
    168191        assert(instance);
    169 #define CHECK_RET_RETURN(ret, message...) \
     192#define CHECK_RET_DEST_CMDS_RETURN(ret, message...) \
    170193        if (ret != EOK) { \
    171194                usb_log_error(message); \
     195                if (instance->interrupt_code.cmds != NULL) \
     196                        free(instance->interrupt_code.cmds); \
    172197                return ret; \
    173198        } else (void) 0
    174199
    175200        /* Init interrupt code */
    176         instance->interrupt_code.cmds = instance->interrupt_commands;
     201        instance->interrupt_code.cmds = malloc(sizeof(uhci_cmds));
     202        int ret = (instance->interrupt_code.cmds == NULL) ? ENOMEM : EOK;
     203        CHECK_RET_DEST_CMDS_RETURN(ret,
     204            "Failed to allocate interrupt cmds space.\n");
     205
    177206        {
    178                 /* Read status register */
    179                 instance->interrupt_commands[0].cmd = CMD_PIO_READ_16;
    180                 instance->interrupt_commands[0].dstarg = 1;
    181                 instance->interrupt_commands[0].addr =
    182                     &instance->registers->usbsts;
    183 
    184                 /* Test whether we are the interrupt cause */
    185                 instance->interrupt_commands[1].cmd = CMD_BTEST;
    186                 instance->interrupt_commands[1].value =
    187                     UHCI_STATUS_USED_INTERRUPTS | UHCI_STATUS_NM_INTERRUPTS;
    188                 instance->interrupt_commands[1].srcarg = 1;
    189                 instance->interrupt_commands[1].dstarg = 2;
    190 
    191                 /* Predicate cleaning and accepting */
    192                 instance->interrupt_commands[2].cmd = CMD_PREDICATE;
    193                 instance->interrupt_commands[2].value = 2;
    194                 instance->interrupt_commands[2].srcarg = 2;
    195 
    196                 /* Write clean status register */
    197                 instance->interrupt_commands[3].cmd = CMD_PIO_WRITE_A_16;
    198                 instance->interrupt_commands[3].srcarg = 1;
    199                 instance->interrupt_commands[3].addr =
    200                     &instance->registers->usbsts;
    201 
    202                 /* Accept interrupt */
    203                 instance->interrupt_commands[4].cmd = CMD_ACCEPT;
    204 
    205                 instance->interrupt_code.cmdcount = UHCI_NEEDED_IRQ_COMMANDS;
     207                irq_cmd_t *interrupt_commands = instance->interrupt_code.cmds;
     208                memcpy(interrupt_commands, uhci_cmds, sizeof(uhci_cmds));
     209                interrupt_commands[0].addr =
     210                    (void*)&instance->registers->usbsts;
     211                interrupt_commands[1].addr =
     212                    (void*)&instance->registers->usbsts;
     213                instance->interrupt_code.cmdcount =
     214                    sizeof(uhci_cmds) / sizeof(irq_cmd_t);
    206215        }
    207216
    208217        /* Init transfer lists */
    209         int ret = hc_init_transfer_lists(instance);
    210         CHECK_RET_RETURN(ret, "Failed to init transfer lists.\n");
     218        ret = hc_init_transfer_lists(instance);
     219        CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to init transfer lists.\n");
    211220        usb_log_debug("Initialized transfer lists.\n");
    212221
     
    214223        instance->frame_list = get_page();
    215224        ret = instance ? EOK : ENOMEM;
    216         CHECK_RET_RETURN(ret, "Failed to get frame list page.\n");
     225        CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to get frame list page.\n");
    217226        usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
    218227
    219228        /* Set all frames to point to the first queue head */
    220         const uint32_t queue = LINK_POINTER_QH(
    221                 addr_to_phys(instance->transfers_interrupt.queue_head));
     229        const uint32_t queue =
     230          instance->transfers_interrupt.queue_head_pa
     231          | LINK_POINTER_QUEUE_HEAD_FLAG;
    222232
    223233        unsigned i = 0;
     
    226236        }
    227237
    228         /* Init device keeper */
     238        /* Init device keeper*/
    229239        usb_device_keeper_init(&instance->manager);
    230240        usb_log_debug("Initialized device manager.\n");
     
    232242        ret = usb_endpoint_manager_init(&instance->ep_manager,
    233243            BANDWIDTH_AVAILABLE_USB11);
    234         CHECK_RET_RETURN(ret, "Failed to initialize endpoint manager: %s.\n",
    235             str_error(ret));
     244        assert(ret == EOK);
    236245
    237246        return EOK;
    238 #undef CHECK_RET_RETURN
     247#undef CHECK_RET_DEST_CMDS_RETURN
    239248}
    240249/*----------------------------------------------------------------------------*/
     
    251260{
    252261        assert(instance);
    253 #define SETUP_TRANSFER_LIST(type, name) \
    254 do { \
    255         int ret = transfer_list_init(&instance->transfers_##type, name); \
     262#define CHECK_RET_CLEAR_RETURN(ret, message...) \
    256263        if (ret != EOK) { \
    257                 usb_log_error("Failed(%d) to setup %s transfer list: %s.\n", \
    258                     ret, name, str_error(ret)); \
     264                usb_log_error(message); \
    259265                transfer_list_fini(&instance->transfers_bulk_full); \
    260266                transfer_list_fini(&instance->transfers_control_full); \
     
    262268                transfer_list_fini(&instance->transfers_interrupt); \
    263269                return ret; \
    264         } \
    265 } while (0)
    266 
    267         SETUP_TRANSFER_LIST(bulk_full, "BULK FULL");
    268         SETUP_TRANSFER_LIST(control_full, "CONTROL FULL");
    269         SETUP_TRANSFER_LIST(control_slow, "CONTROL LOW");
    270         SETUP_TRANSFER_LIST(interrupt, "INTERRUPT");
    271 #undef SETUP_TRANSFER_LIST
    272         /* Connect lists into one schedule */
     270        } else (void) 0
     271
     272        /* initialize TODO: check errors */
     273        int ret;
     274        ret = transfer_list_init(&instance->transfers_bulk_full, "BULK_FULL");
     275        CHECK_RET_CLEAR_RETURN(ret, "Failed to init BULK list.");
     276
     277        ret = transfer_list_init(
     278            &instance->transfers_control_full, "CONTROL_FULL");
     279        CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL FULL list.");
     280
     281        ret = transfer_list_init(
     282            &instance->transfers_control_slow, "CONTROL_SLOW");
     283        CHECK_RET_CLEAR_RETURN(ret, "Failed to init CONTROL SLOW list.");
     284
     285        ret = transfer_list_init(&instance->transfers_interrupt, "INTERRUPT");
     286        CHECK_RET_CLEAR_RETURN(ret, "Failed to init INTERRUPT list.");
     287
    273288        transfer_list_set_next(&instance->transfers_control_full,
    274289                &instance->transfers_bulk_full);
     
    281296#ifdef FSBR
    282297        transfer_list_set_next(&instance->transfers_bulk_full,
    283             &instance->transfers_control_full);
     298                &instance->transfers_control_full);
    284299#endif
    285300
     
    314329
    315330        transfer_list_t *list =
    316             instance->transfers[batch->ep->speed][batch->ep->transfer_type];
     331            instance->transfers[batch->speed][batch->transfer_type];
    317332        assert(list);
    318333        transfer_list_add_batch(list, batch);
     
    334349{
    335350        assert(instance);
     351//      status |= 1; //Uncomment to work around qemu hang
     352        /* TODO: Resume interrupts are not supported */
    336353        /* Lower 2 bits are transaction error and transaction complete */
    337         if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) {
     354        if (status & 0x3) {
    338355                LIST_INITIALIZE(done);
    339356                transfer_list_remove_finished(
     
    354371                }
    355372        }
    356         /* Resume interrupts are not supported */
    357         if (status & UHCI_STATUS_RESUME) {
    358                 usb_log_error("Resume interrupt!\n");
    359         }
    360 
    361         /* Bits 4 and 5 indicate hc error */
    362         if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) {
     373        /* bits 4 and 5 indicate hc error */
     374        if (status & 0x18) {
    363375                usb_log_error("UHCI hardware failure!.\n");
    364376                ++instance->hw_failures;
     
    386398{
    387399        usb_log_debug("Started interrupt emulator.\n");
    388         hc_t *instance = arg;
     400        hc_t *instance = (hc_t*)arg;
    389401        assert(instance);
    390402
    391403        while (1) {
    392                 /* Read and clear status register */
     404                /* read and ack interrupts */
    393405                uint16_t status = pio_read_16(&instance->registers->usbsts);
    394                 pio_write_16(&instance->registers->usbsts, status);
     406                pio_write_16(&instance->registers->usbsts, 0x1f);
    395407                if (status != 0)
    396408                        usb_log_debug2("UHCI status: %x.\n", status);
    397 // Qemu fails to report stalled communication
    398 // see https://bugs.launchpad.net/qemu/+bug/757654
    399 // This is a simple workaround to force queue processing every time
    400         //      status |= 1;
    401409                hc_interrupt(instance, status);
    402                 async_usleep(UHCI_INT_EMULATOR_TIMEOUT);
     410                async_usleep(UHCI_CLEANER_TIMEOUT);
    403411        }
    404412        return EOK;
     
    412420int hc_debug_checker(void *arg)
    413421{
    414         hc_t *instance = arg;
     422        hc_t *instance = (hc_t*)arg;
    415423        assert(instance);
    416424
     
    433441                if (frame_list != addr_to_phys(instance->frame_list)) {
    434442                        usb_log_debug("Framelist address: %p vs. %p.\n",
    435                             (void *) frame_list,
    436                             (void *) addr_to_phys(instance->frame_list));
     443                            frame_list, addr_to_phys(instance->frame_list));
    437444                }
    438445
     
    443450                uintptr_t real_pa = addr_to_phys(QH(interrupt));
    444451                if (expected_pa != real_pa) {
    445                         usb_log_debug("Interrupt QH: %p (frame %d) vs. %p.\n",
    446                             (void *) expected_pa, frnum, (void *) real_pa);
     452                        usb_log_debug("Interrupt QH: %p(frame: %d) vs. %p.\n",
     453                            expected_pa, frnum, real_pa);
    447454                }
    448455
     
    451458                if (expected_pa != real_pa) {
    452459                        usb_log_debug("Control Slow QH: %p vs. %p.\n",
    453                             (void *) expected_pa, (void *) real_pa);
     460                            expected_pa, real_pa);
    454461                }
    455462
     
    458465                if (expected_pa != real_pa) {
    459466                        usb_log_debug("Control Full QH: %p vs. %p.\n",
    460                             (void *) expected_pa, (void *) real_pa);
     467                            expected_pa, real_pa);
    461468                }
    462469
     
    465472                if (expected_pa != real_pa ) {
    466473                        usb_log_debug("Bulk QH: %p vs. %p.\n",
    467                             (void *) expected_pa, (void *) real_pa);
     474                            expected_pa, real_pa);
    468475                }
    469476                async_usleep(UHCI_DEBUGER_TIMEOUT);
     
    472479#undef QH
    473480}
     481/*----------------------------------------------------------------------------*/
     482/** Check transfers for USB validity
     483 *
     484 * @param[in] low_speed Transfer speed.
     485 * @param[in] transfer Transer type
     486 * @param[in] size Size of data packets
     487 * @return True if transaction is allowed by USB specs, false otherwise
     488 */
     489#if 0
     490bool usb_is_allowed(
     491    bool low_speed, usb_transfer_type_t transfer, size_t size)
     492{
     493        /* see USB specification chapter 5.5-5.8 for magic numbers used here */
     494        switch(transfer)
     495        {
     496        case USB_TRANSFER_ISOCHRONOUS:
     497                return (!low_speed && size < 1024);
     498        case USB_TRANSFER_INTERRUPT:
     499                return size <= (low_speed ? 8 : 64);
     500        case USB_TRANSFER_CONTROL: /* device specifies its own max size */
     501                return (size <= (low_speed ? 8 : 64));
     502        case USB_TRANSFER_BULK: /* device specifies its own max size */
     503                return (!low_speed && size <= 64);
     504        }
     505        return false;
     506}
     507#endif
    474508/**
    475509 * @}
Note: See TracChangeset for help on using the changeset viewer.