Changeset fd07e526 in mainline for uspace/drv/bus/usb/uhci/hc.c


Ignore:
Timestamp:
2011-09-16T14:50:20Z (13 years ago)
Author:
Jan Vesely <jano.vesely@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
432a269, d1e18573
Parents:
47fecbb (diff), 82a31261 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge USB changes from bzr://krabicka.net/orome/helenos/usb/

  • Move common HC code from uhci/ohci drivers to libusbhost
  • Rewrite USB HC interface to have common read/write functions for all transfer types.
  • Restructure hc drivers to avoid some hooks and void* casts
  • Cleanup the code and remove unnecessary mallocs.
File:
1 edited

Legend:

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

    r47fecbb rfd07e526  
    4141
    4242#include "hc.h"
     43#include "uhci_batch.h"
    4344
    4445#define UHCI_INTR_ALLOW_INTERRUPTS \
     
    4647#define UHCI_STATUS_USED_INTERRUPTS \
    4748    (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)
     49
    4850
    4951static const irq_cmd_t uhci_irq_commands[] =
     
    5759};
    5860
     61static void hc_init_hw(const hc_t *instance);
     62static int hc_init_mem_structures(hc_t *instance);
    5963static int hc_init_transfer_lists(hc_t *instance);
    60 static int hc_init_mem_structures(hc_t *instance);
    61 static void hc_init_hw(hc_t *instance);
     64static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch);
    6265
    6366static int hc_interrupt_emulator(void *arg);
     
    9598        cmds[3].addr = (void*)&registers->usbsts;
    9699        return EOK;
     100}
     101/*----------------------------------------------------------------------------*/
     102/** Take action based on the interrupt cause.
     103 *
     104 * @param[in] instance UHCI structure to use.
     105 * @param[in] status Value of the status register at the time of interrupt.
     106 *
     107 * Interrupt might indicate:
     108 * - transaction completed, either by triggering IOC, SPD, or an error
     109 * - some kind of device error
     110 * - resume from suspend state (not implemented)
     111 */
     112void hc_interrupt(hc_t *instance, uint16_t status)
     113{
     114        assert(instance);
     115        /* Lower 2 bits are transaction error and transaction complete */
     116        if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) {
     117                LIST_INITIALIZE(done);
     118                transfer_list_remove_finished(
     119                    &instance->transfers_interrupt, &done);
     120                transfer_list_remove_finished(
     121                    &instance->transfers_control_slow, &done);
     122                transfer_list_remove_finished(
     123                    &instance->transfers_control_full, &done);
     124                transfer_list_remove_finished(
     125                    &instance->transfers_bulk_full, &done);
     126
     127                while (!list_empty(&done)) {
     128                        link_t *item = list_first(&done);
     129                        list_remove(item);
     130                        uhci_transfer_batch_t *batch =
     131                            uhci_transfer_batch_from_link(item);
     132                        uhci_transfer_batch_call_dispose(batch);
     133                }
     134        }
     135        /* Resume interrupts are not supported */
     136        if (status & UHCI_STATUS_RESUME) {
     137                usb_log_error("Resume interrupt!\n");
     138        }
     139
     140        /* Bits 4 and 5 indicate hc error */
     141        if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) {
     142                usb_log_error("UHCI hardware failure!.\n");
     143                ++instance->hw_failures;
     144                transfer_list_abort_all(&instance->transfers_interrupt);
     145                transfer_list_abort_all(&instance->transfers_control_slow);
     146                transfer_list_abort_all(&instance->transfers_control_full);
     147                transfer_list_abort_all(&instance->transfers_bulk_full);
     148
     149                if (instance->hw_failures < UHCI_ALLOWED_HW_FAIL) {
     150                        /* reinitialize hw, this triggers virtual disconnect*/
     151                        hc_init_hw(instance);
     152                } else {
     153                        usb_log_fatal("Too many UHCI hardware failures!.\n");
     154                        hc_fini(instance);
     155                }
     156        }
    97157}
    98158/*----------------------------------------------------------------------------*/
     
    132192            "Device registers at %p (%zuB) accessible.\n", io, reg_size);
    133193
     194        ret = hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11,
     195            bandwidth_count_usb11);
     196        CHECK_RET_RETURN(ret, "Failed to initialize HCD generic driver: %s.\n",
     197            str_error(ret));
     198
     199        instance->generic.private_data = instance;
     200        instance->generic.schedule = hc_schedule;
     201        instance->generic.ep_add_hook = NULL;
     202
     203#undef CHECK_RET_DEST_FUN_RETURN
     204
    134205        ret = hc_init_mem_structures(instance);
    135         CHECK_RET_RETURN(ret,
    136             "Failed to initialize UHCI memory structures: %s.\n",
    137             str_error(ret));
     206        if (ret != EOK) {
     207                usb_log_error(
     208                    "Failed to initialize UHCI memory structures: %s.\n",
     209                    str_error(ret));
     210                hcd_destroy(&instance->generic);
     211                return ret;
     212        }
    138213
    139214        hc_init_hw(instance);
     
    146221
    147222        return EOK;
    148 #undef CHECK_RET_DEST_FUN_RETURN
    149223}
    150224/*----------------------------------------------------------------------------*/
     
    154228 * For magic values see UHCI Design Guide
    155229 */
    156 void hc_init_hw(hc_t *instance)
     230void hc_init_hw(const hc_t *instance)
    157231{
    158232        assert(instance);
     
    198272 *
    199273 * Structures:
    200  *  - interrupt code (I/O addressses are customized per instance)
    201274 *  - transfer lists (queue heads need to be accessible by the hw)
    202275 *  - frame list page (needs to be one UHCI hw accessible 4K page)
     
    205278{
    206279        assert(instance);
    207 #define CHECK_RET_RETURN(ret, message...) \
    208         if (ret != EOK) { \
    209                 usb_log_error(message); \
    210                 return ret; \
    211         } else (void) 0
     280
     281        /* Init USB frame list page */
     282        instance->frame_list = get_page();
     283        if (!instance->frame_list) {
     284                return ENOMEM;
     285        }
     286        usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
    212287
    213288        /* Init transfer lists */
    214289        int ret = hc_init_transfer_lists(instance);
    215         CHECK_RET_RETURN(ret, "Failed to initialize transfer lists.\n");
     290        if (ret != EOK) {
     291                usb_log_error("Failed to initialize transfer lists.\n");
     292                return_page(instance->frame_list);
     293                return ENOMEM;
     294        }
    216295        usb_log_debug("Initialized transfer lists.\n");
    217296
    218         /* Init device keeper */
    219         usb_device_keeper_init(&instance->manager);
    220         usb_log_debug("Initialized device keeper.\n");
    221 
    222         ret = usb_endpoint_manager_init(&instance->ep_manager,
    223             BANDWIDTH_AVAILABLE_USB11);
    224         CHECK_RET_RETURN(ret, "Failed to initialize endpoint manager: %s.\n",
    225             str_error(ret));
    226 
    227         /* Init USB frame list page*/
    228         instance->frame_list = get_page();
    229         if (!instance->frame_list) {
    230                 usb_log_error("Failed to get frame list page.\n");
    231                 usb_endpoint_manager_destroy(&instance->ep_manager);
    232                 return ENOMEM;
    233         }
    234         usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);
    235297
    236298        /* Set all frames to point to the first queue head */
     
    243305
    244306        return EOK;
    245 #undef CHECK_RET_RETURN
    246307}
    247308/*----------------------------------------------------------------------------*/
     
    316377 * Checks for bandwidth availability and appends the batch to the proper queue.
    317378 */
    318 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch)
    319 {
     379int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch)
     380{
     381        assert(hcd);
     382        hc_t *instance = hcd->private_data;
    320383        assert(instance);
    321384        assert(batch);
     385        uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch);
     386        if (!uhci_batch) {
     387                usb_log_error("Failed to create UHCI transfer structures.\n");
     388                return ENOMEM;
     389        }
    322390
    323391        transfer_list_t *list =
    324392            instance->transfers[batch->ep->speed][batch->ep->transfer_type];
    325393        assert(list);
    326         transfer_list_add_batch(list, batch);
    327 
    328         return EOK;
    329 }
    330 /*----------------------------------------------------------------------------*/
    331 /** Take action based on the interrupt cause.
    332  *
    333  * @param[in] instance UHCI structure to use.
    334  * @param[in] status Value of the status register at the time of interrupt.
    335  *
    336  * Interrupt might indicate:
    337  * - transaction completed, either by triggering IOC, SPD, or an error
    338  * - some kind of device error
    339  * - resume from suspend state (not implemented)
    340  */
    341 void hc_interrupt(hc_t *instance, uint16_t status)
    342 {
    343         assert(instance);
    344         /* Lower 2 bits are transaction error and transaction complete */
    345         if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) {
    346                 LIST_INITIALIZE(done);
    347                 transfer_list_remove_finished(
    348                     &instance->transfers_interrupt, &done);
    349                 transfer_list_remove_finished(
    350                     &instance->transfers_control_slow, &done);
    351                 transfer_list_remove_finished(
    352                     &instance->transfers_control_full, &done);
    353                 transfer_list_remove_finished(
    354                     &instance->transfers_bulk_full, &done);
    355 
    356                 while (!list_empty(&done)) {
    357                         link_t *item = list_first(&done);
    358                         list_remove(item);
    359                         usb_transfer_batch_t *batch =
    360                             list_get_instance(item, usb_transfer_batch_t, link);
    361                         usb_transfer_batch_finish(batch);
    362                 }
    363         }
    364         /* Resume interrupts are not supported */
    365         if (status & UHCI_STATUS_RESUME) {
    366                 usb_log_error("Resume interrupt!\n");
    367         }
    368 
    369         /* Bits 4 and 5 indicate hc error */
    370         if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) {
    371                 usb_log_error("UHCI hardware failure!.\n");
    372                 ++instance->hw_failures;
    373                 transfer_list_abort_all(&instance->transfers_interrupt);
    374                 transfer_list_abort_all(&instance->transfers_control_slow);
    375                 transfer_list_abort_all(&instance->transfers_control_full);
    376                 transfer_list_abort_all(&instance->transfers_bulk_full);
    377 
    378                 if (instance->hw_failures < UHCI_ALLOWED_HW_FAIL) {
    379                         /* reinitialize hw, this triggers virtual disconnect*/
    380                         hc_init_hw(instance);
    381                 } else {
    382                         usb_log_fatal("Too many UHCI hardware failures!.\n");
    383                         hc_fini(instance);
    384                 }
    385         }
     394        transfer_list_add_batch(list, uhci_batch);
     395
     396        return EOK;
    386397}
    387398/*----------------------------------------------------------------------------*/
     
    403414                if (status != 0)
    404415                        usb_log_debug2("UHCI status: %x.\n", status);
    405 // Qemu fails to report stalled communication
    406 // see https://bugs.launchpad.net/qemu/+bug/757654
    407 // This is a simple workaround to force queue processing every time
    408         //      status |= 1;
    409416                hc_interrupt(instance, status);
    410417                async_usleep(UHCI_INT_EMULATOR_TIMEOUT);
     
    412419        return EOK;
    413420}
    414 /*---------------------------------------------------------------------------*/
     421/*----------------------------------------------------------------------------*/
    415422/** Debug function, checks consistency of memory structures.
    416423 *
Note: See TracChangeset for help on using the changeset viewer.