Ignore:
File:
1 edited

Legend:

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

    r4c28d17 r8986412  
    4444#include "hc.h"
    4545
    46 static 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 /*----------------------------------------------------------------------------*/
     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
    6252static int hc_init_transfer_lists(hc_t *instance);
    6353static int hc_init_mem_structures(hc_t *instance);
     
    6656static int hc_interrupt_emulator(void *arg);
    6757static int hc_debug_checker(void *arg);
    68 #if 0
    69 static bool usb_is_allowed(
    70     bool low_speed, usb_transfer_type_t transfer, size_t size);
    71 #endif
    7258/*----------------------------------------------------------------------------*/
    7359/** Initialize UHCI hcd driver structure
     
    8975        int ret;
    9076
    91 #define CHECK_RET_DEST_FUN_RETURN(ret, message...) \
     77#define CHECK_RET_RETURN(ret, message...) \
    9278        if (ret != EOK) { \
    9379                usb_log_error(message); \
    94                 if (instance->ddf_instance) \
    95                         ddf_fun_destroy(instance->ddf_instance); \
    9680                return ret; \
    9781        } else (void) 0
     
    9983        instance->hw_interrupts = interrupts;
    10084        instance->hw_failures = 0;
    101 
    102         /* Setup UHCI function. */
    103         instance->ddf_instance = fun;
    10485
    10586        /* allow access to hc control registers */
    10687        regs_t *io;
    10788        ret = pio_enable(regs, reg_size, (void**)&io);
    108         CHECK_RET_DEST_FUN_RETURN(ret,
     89        CHECK_RET_RETURN(ret,
    10990            "Failed(%d) to gain access to registers at %p: %s.\n",
    110             ret, str_error(ret), io);
     91            ret, io, str_error(ret));
    11192        instance->registers = io;
    112         usb_log_debug("Device registers at %p(%u) accessible.\n",
     93        usb_log_debug("Device registers at %p (%zuB) accessible.\n",
    11394            io, reg_size);
    11495
    11596        ret = hc_init_mem_structures(instance);
    116         CHECK_RET_DEST_FUN_RETURN(ret,
    117             "Failed to initialize UHCI memory structures.\n");
     97        CHECK_RET_RETURN(ret,
     98            "Failed(%d) to initialize UHCI memory structures: %s.\n",
     99            ret, str_error(ret));
    118100
    119101        hc_init_hw(instance);
    120102        if (!interrupts) {
    121                 instance->cleaner =
     103                instance->interrupt_emulator =
    122104                    fibril_create(hc_interrupt_emulator, instance);
    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);
     105                fibril_add_ready(instance->interrupt_emulator);
     106        }
     107        (void)hc_debug_checker;
    131108
    132109        return EOK;
     
    164141                /* Enable all interrupts, but resume interrupt */
    165142                pio_write_16(&instance->registers->usbintr,
    166                     UHCI_INTR_CRC | UHCI_INTR_COMPLETE | UHCI_INTR_SHORT_PACKET);
     143                    UHCI_INTR_ALLOW_INTERRUPTS);
    167144        }
    168145
     
    190167{
    191168        assert(instance);
    192 #define CHECK_RET_DEST_CMDS_RETURN(ret, message...) \
     169#define CHECK_RET_RETURN(ret, message...) \
    193170        if (ret != EOK) { \
    194171                usb_log_error(message); \
    195                 if (instance->interrupt_code.cmds != NULL) \
    196                         free(instance->interrupt_code.cmds); \
    197172                return ret; \
    198173        } else (void) 0
    199174
    200175        /* Init interrupt code */
    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 
     176        instance->interrupt_code.cmds = instance->interrupt_commands;
    206177        {
    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);
     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;
    215206        }
    216207
    217208        /* Init transfer lists */
    218         ret = hc_init_transfer_lists(instance);
    219         CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to init transfer lists.\n");
     209        int ret = hc_init_transfer_lists(instance);
     210        CHECK_RET_RETURN(ret, "Failed to init transfer lists.\n");
    220211        usb_log_debug("Initialized transfer lists.\n");
    221212
     
    223214        instance->frame_list = get_page();
    224215        ret = instance ? EOK : ENOMEM;
    225         CHECK_RET_DEST_CMDS_RETURN(ret, "Failed to get frame list page.\n");
     216        CHECK_RET_RETURN(ret, "Failed to get frame list page.\n");
    226217        usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
    227218
    228219        /* Set all frames to point to the first queue head */
    229         const uint32_t queue =
    230           instance->transfers_interrupt.queue_head_pa
    231           | LINK_POINTER_QUEUE_HEAD_FLAG;
     220        const uint32_t queue = LINK_POINTER_QH(
     221                addr_to_phys(instance->transfers_interrupt.queue_head));
    232222
    233223        unsigned i = 0;
     
    236226        }
    237227
    238         /* Init device keeper*/
     228        /* Init device keeper */
    239229        usb_device_keeper_init(&instance->manager);
    240230        usb_log_debug("Initialized device manager.\n");
     
    242232        ret = usb_endpoint_manager_init(&instance->ep_manager,
    243233            BANDWIDTH_AVAILABLE_USB11);
    244         assert(ret == EOK);
    245 
    246         return EOK;
    247 #undef CHECK_RET_DEST_CMDS_RETURN
     234        CHECK_RET_RETURN(ret, "Failed to initialize endpoint manager: %s.\n",
     235            str_error(ret));
     236
     237        return EOK;
     238#undef CHECK_RET_RETURN
    248239}
    249240/*----------------------------------------------------------------------------*/
     
    260251{
    261252        assert(instance);
    262 #define CHECK_RET_CLEAR_RETURN(ret, message...) \
     253#define SETUP_TRANSFER_LIST(type, name) \
     254do { \
     255        int ret = transfer_list_init(&instance->transfers_##type, name); \
    263256        if (ret != EOK) { \
    264                 usb_log_error(message); \
     257                usb_log_error("Failed(%d) to setup %s transfer list: %s.\n", \
     258                    ret, name, str_error(ret)); \
    265259                transfer_list_fini(&instance->transfers_bulk_full); \
    266260                transfer_list_fini(&instance->transfers_control_full); \
     
    268262                transfer_list_fini(&instance->transfers_interrupt); \
    269263                return ret; \
    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 
     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 */
    288273        transfer_list_set_next(&instance->transfers_control_full,
    289274                &instance->transfers_bulk_full);
     
    296281#ifdef FSBR
    297282        transfer_list_set_next(&instance->transfers_bulk_full,
    298                 &instance->transfers_control_full);
     283            &instance->transfers_control_full);
    299284#endif
    300285
     
    329314
    330315        transfer_list_t *list =
    331             instance->transfers[batch->speed][batch->transfer_type];
     316            instance->transfers[batch->ep->speed][batch->ep->transfer_type];
    332317        assert(list);
    333318        transfer_list_add_batch(list, batch);
     
    349334{
    350335        assert(instance);
    351 //      status |= 1; //Uncomment to work around qemu hang
    352         /* TODO: Resume interrupts are not supported */
    353336        /* Lower 2 bits are transaction error and transaction complete */
    354         if (status & 0x3) {
     337        if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) {
    355338                LIST_INITIALIZE(done);
    356339                transfer_list_remove_finished(
     
    371354                }
    372355        }
    373         /* bits 4 and 5 indicate hc error */
    374         if (status & 0x18) {
     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)) {
    375363                usb_log_error("UHCI hardware failure!.\n");
    376364                ++instance->hw_failures;
     
    398386{
    399387        usb_log_debug("Started interrupt emulator.\n");
    400         hc_t *instance = (hc_t*)arg;
     388        hc_t *instance = arg;
    401389        assert(instance);
    402390
    403391        while (1) {
    404                 /* read and ack interrupts */
     392                /* Read and clear status register */
    405393                uint16_t status = pio_read_16(&instance->registers->usbsts);
    406                 pio_write_16(&instance->registers->usbsts, 0x1f);
     394                pio_write_16(&instance->registers->usbsts, status);
    407395                if (status != 0)
    408396                        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;
    409401                hc_interrupt(instance, status);
    410                 async_usleep(UHCI_CLEANER_TIMEOUT);
     402                async_usleep(UHCI_INT_EMULATOR_TIMEOUT);
    411403        }
    412404        return EOK;
     
    420412int hc_debug_checker(void *arg)
    421413{
    422         hc_t *instance = (hc_t*)arg;
     414        hc_t *instance = arg;
    423415        assert(instance);
    424416
     
    441433                if (frame_list != addr_to_phys(instance->frame_list)) {
    442434                        usb_log_debug("Framelist address: %p vs. %p.\n",
    443                             frame_list, addr_to_phys(instance->frame_list));
     435                            (void *) frame_list,
     436                            (void *) addr_to_phys(instance->frame_list));
    444437                }
    445438
     
    450443                uintptr_t real_pa = addr_to_phys(QH(interrupt));
    451444                if (expected_pa != real_pa) {
    452                         usb_log_debug("Interrupt QH: %p(frame: %d) vs. %p.\n",
    453                             expected_pa, frnum, real_pa);
     445                        usb_log_debug("Interrupt QH: %p (frame %d) vs. %p.\n",
     446                            (void *) expected_pa, frnum, (void *) real_pa);
    454447                }
    455448
     
    458451                if (expected_pa != real_pa) {
    459452                        usb_log_debug("Control Slow QH: %p vs. %p.\n",
    460                             expected_pa, real_pa);
     453                            (void *) expected_pa, (void *) real_pa);
    461454                }
    462455
     
    465458                if (expected_pa != real_pa) {
    466459                        usb_log_debug("Control Full QH: %p vs. %p.\n",
    467                             expected_pa, real_pa);
     460                            (void *) expected_pa, (void *) real_pa);
    468461                }
    469462
     
    472465                if (expected_pa != real_pa ) {
    473466                        usb_log_debug("Bulk QH: %p vs. %p.\n",
    474                             expected_pa, real_pa);
     467                            (void *) expected_pa, (void *) real_pa);
    475468                }
    476469                async_usleep(UHCI_DEBUGER_TIMEOUT);
     
    479472#undef QH
    480473}
    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
    490 bool 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
    508474/**
    509475 * @}
Note: See TracChangeset for help on using the changeset viewer.