uhci.c

来自「这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统」· C语言 代码 · 共 2,164 行 · 第 1/5 页

C
2,164
字号
BOOLEAN
uhci_release(PDEVICE_OBJECT pdev)
{
    PDEVICE_EXTENSION pdev_ext;
    PUHCI_DEV uhci;

    if (pdev == NULL)
        return FALSE;

    pdev_ext = pdev->DeviceExtension;

    if (pdev_ext == NULL)
        return FALSE;

    uhci = pdev_ext->uhci;
    if (uhci == NULL)
        return FALSE;

    uhci_stop(uhci);
    //pdev_ext->uhci->conn_count = 0;
    pdev_ext->uhci->fsbr_cnt = 0;

    if (pdev_ext->uhci_int)
    {
        IoDisconnectInterrupt(pdev_ext->uhci_int);
        pdev_ext->uhci_int = NULL;
    }
    else
        TRAP();
    destroy_pending_endp_pool(&pdev_ext->uhci->pending_endp_pool);
    //pdev_ext->uhci->pending_endp_pool = NULL;

    uhci_destroy_schedule(uhci);

    release_adapter(pdev_ext->padapter);
    pdev_ext->padapter = NULL;

    uhci_delete_device(pdev);

    return FALSE;

}

// send cmds to start the uhc
// shamelessly copied from linux's uhci.c (reset_hc(), configure_hc() routines)
BOOLEAN
uhci_start(PHCD hcd)
{
    PUHCI_DEV uhci;
    PBYTE io_addr;
    USHORT pirq;
    PCI_SLOT_NUMBER SlotNum;
    int timeout = 10000;

    uhci = uhci_from_hcd(hcd);
    io_addr = uhci->port_base;

    /*
     * Reset the HC - this will force us to get a
     * new notification of any already connected
     * ports due to the virtual disconnect that it
     * implies.
     */
    WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_HCRESET);
    while (READ_PORT_USHORT((PUSHORT) (io_addr + USBCMD)) & USBCMD_HCRESET)
    {
        if (!--timeout)
        {
            break;
        }
    }

    /* Turn on all interrupts */
    WRITE_PORT_USHORT((PUSHORT) (io_addr + USBINTR),
                      USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP);

    /* Start at frame 0 */
    WRITE_PORT_USHORT((PUSHORT) (io_addr + USBFRNUM), 0);
    WRITE_PORT_ULONG((PULONG) (io_addr + USBFLBASEADD), uhci->frame_list_logic_addr.LowPart);

    /* Run and mark it configured with a 64-byte max packet */
    WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_RS | USBCMD_CF | USBCMD_MAXP);

    DbgPrint("uhci_start(): current uhci status=0x%x\n", uhci_status(uhci));

    /* Enable PIRQ */
    pirq = USBLEGSUP_DEFAULT;
    SlotNum.u.AsULONG = 0;
    SlotNum.u.bits.DeviceNumber = ((uhci->pdev_ext->pci_addr & 0xff) >> 3);
    SlotNum.u.bits.FunctionNumber = (uhci->pdev_ext->pci_addr & 0x07);

    DbgPrint("uhci_start(): set bus %d data at slot 0x%x\n", (uhci->pdev_ext->pci_addr >> 8),
        SlotNum.u.AsULONG);

    HalSetBusDataByOffset(PCIConfiguration, (uhci->pdev_ext->pci_addr >> 8), SlotNum.u.AsULONG,
        &pirq, USBLEGSUP, sizeof(pirq));

    return TRUE;
}

VOID
uhci_stop(PUHCI_DEV uhci)
{
    PBYTE io_addr = uhci->port_base;
    // turn off all the interrupt
    WRITE_PORT_USHORT((PUSHORT) (io_addr + USBINTR), 0);
    WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), 0);
}

static VOID
uhci_reset(PUHCI_DEV uhci)
{
    PBYTE io_addr = uhci->port_base;

    uhci_stop(uhci);
    /* Global reset for 50ms */
    WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_GRESET);
    //uhci_wait_ms( uhci, 50 );
    usb_wait_ms_dpc(50);

    WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), 0);
    //uhci_wait_ms( uhci, 10 );
    usb_wait_ms_dpc(10);
}

VOID
uhci_suspend(PUHCI_DEV uhci)
{
    PBYTE io_addr = uhci->port_base;

    //uhci->is_suspended = 1;
    WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_EGSM);

}

VOID
uhci_wakeup(PUHCI_DEV uhci)
{
    PBYTE io_addr;
    unsigned int status;

    io_addr = uhci->port_base;

    WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), 0);

    /* wait for EOP to be sent */
    status = READ_PORT_USHORT((PUSHORT) (io_addr + USBCMD));
    while (status & USBCMD_FGR)
        status = READ_PORT_USHORT((PUSHORT) (io_addr + USBCMD));

    //uhci->is_suspended = 0;

    /* Run and mark it configured with a 64-byte max packet */
    WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_RS | USBCMD_CF | USBCMD_MAXP);

}

BOOLEAN
uhci_init_schedule(PUHCI_DEV uhci, PADAPTER_OBJECT padapter)
{
    int i, irq;

    uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_init_schedule(): entering..., uhci=0x%x\n", uhci));
    if (uhci == NULL || padapter == NULL)
        return FALSE;

    if (init_td_pool_list(&uhci->td_pool, padapter) == FALSE)
    {
        return FALSE;
    }
    if (init_qh_pool(&uhci->qh_pool, padapter) == FALSE)
    {
        return FALSE;
    }

    //since uhci is not started we can freely access all resources.
    for(i = 0; i < UHCI_MAX_SKELTDS; i++)
    {
        uhci->skel_td[i] = alloc_td(&uhci->td_pool);
        uhci_fill_td(uhci->skel_td[i], 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);

        if (i > 0)
        {
            uhci->skel_td[i]->link = uhci->skel_td[i - 1]->phy_addr;
        }
    }

    /*for( i = UHCI_MAX_SKELTDS - 3; i >= 0; i-- )
       {
       InsertTailList( &uhci->skel_int256_td->ptde->hori_link,
       &uhci->skel_td[ i ]->ptde->hori_link );
       } */

    for(i = 0; i < UHCI_MAX_SKELQHS; i++)
    {
        uhci->skel_qh[i] = alloc_qh(&uhci->qh_pool);
        if (i > 0)
        {
            uhci->skel_qh[i - 1]->link = uhci->skel_qh[i]->phy_addr;
        }

        uhci->skel_qh[i]->element = UHCI_PTR_TERM;
    }

    uhci->skel_int1_td->link = uhci->skel_ls_control_qh->phy_addr;

    // Hack for PIIX
    uhci_fill_td(uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
    uhci->skel_term_td->link = uhci->skel_term_td->phy_addr;

    uhci->skel_term_qh->link = UHCI_PTR_TERM;
    uhci->skel_term_qh->element = uhci->skel_term_td->phy_addr;

    InsertTailList(&uhci->skel_term_qh->pqhe->vert_link, &uhci->skel_term_td->ptde->vert_link);

    /*for( i = 0; i < UHCI_MAX_SKELQHS; i++ )
       {
       InsertTailList( &uhci->skel_int256_td->ptde->hori_link,
       &uhci->skel_qh[ i ]->pqhe->hori_link );
       } */

    if (uhci_init_frame_list(uhci, uhci->pdev_ext->padapter) == FALSE)
        uhci_destroy_frame_list(uhci);

    //well all have been chained, now scatter the int tds to frame-list
    //shamelessly pasted from linux's uhci.c :-)
    for(i = 0; i < UHCI_MAX_FRAMES; i++)
    {
        irq = 0;
        if (i & 1)
        {
            irq++;
            if (i & 2)
            {
                irq++;
                if (i & 4)
                {
                    irq++;
                    if (i & 8)
                    {
                        irq++;
                        if (i & 16)
                        {
                            irq++;
                            if (i & 32)
                            {
                                irq++;
                                if (i & 64)
                                    irq++;
                            }
                        }
                    }
                }
            }
        }

        /* Only place we don't use the frame list routines */
        uhci->frame_list[i] = uhci->skel_td[irq]->phy_addr;
    }
    return TRUE;
}

BOOLEAN
uhci_destroy_schedule(PUHCI_DEV uhci)
{
    BOOLEAN ret;

    ret = uhci_destroy_frame_list(uhci);
    ret = destroy_qh_pool(&uhci->qh_pool);
    ret = destroy_td_pool_list(&uhci->td_pool);

    return ret;

}

VOID NTAPI
uhci_cancel_pending_endp_urb(IN PVOID Parameter)
{
    PLIST_ENTRY abort_list;
    PUSB_DEV pdev;
    PURB purb;
    USE_BASIC_NON_PENDING_IRQL;

    abort_list = (PLIST_ENTRY) Parameter;

    if (abort_list == NULL)
        return;

    while (IsListEmpty(abort_list) == FALSE)
    {
        //these devs are protected by urb's ref-count
        purb = (PURB) RemoveHeadList(abort_list);
        pdev = purb->pdev;
        // purb->status is set when they are added to abort_list

        uhci_generic_urb_completion(purb, purb->context);

        lock_dev(pdev, FALSE);
        pdev->ref_count--;
        unlock_dev(pdev, FALSE);
    }
    usb_free_mem(abort_list);
    return;
}

BOOLEAN
uhci_process_pending_endp(PUHCI_DEV uhci)
{
    PUSB_DEV pdev;
    LIST_ENTRY temp_list, abort_list;
    PLIST_ENTRY pthis;
    PURB purb;
    PUSB_ENDPOINT pendp;
    NTSTATUS can_submit = STATUS_UNSUCCESSFUL;
    PWORK_QUEUE_ITEM pwork_item;
    PLIST_ENTRY cancel_list;
    USE_BASIC_IRQL;

    if (uhci == NULL)
        return FALSE;

    InitializeListHead(&temp_list);
    InitializeListHead(&abort_list);

    purb = NULL;
    uhci_dbg_print(DBGLVL_MEDIUM, ("uhci_process_pending_endp(): entering..., uhci=0x%x\n", uhci));

    lock_pending_endp_list(&uhci->pending_endp_list_lock);
    while (IsListEmpty(&uhci->pending_endp_list) == FALSE)
    {

        uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_process_pending_endp(): pending_endp_list=0x%x\n",
                                        &uhci->pending_endp_list));

        pthis = RemoveHeadList(&uhci->pending_endp_list);
        pendp = ((PUHCI_PENDING_ENDP) pthis)->pendp;
        pdev = dev_from_endp(pendp);

        lock_dev(pdev, TRUE);

        if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
        {
            unlock_dev(pdev, TRUE);
            free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
            //delegate to uhci_remove_device for removing the urb queue on the endpoint
            continue;
        }

        if (endp_state(pendp) == USB_ENDP_FLAG_STALL)
        {
            while (IsListEmpty(&pendp->urb_list) == FALSE)
            {
                purb = (PURB) RemoveHeadList(&pendp->urb_list);
                purb->status = USB_STATUS_ENDPOINT_HALTED;
                InsertTailList(&abort_list, (LIST_ENTRY *) purb);
            }
            InitializeListHead(&pendp->urb_list);
            unlock_dev(pdev, TRUE);
            free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
            continue;
        }


        if (IsListEmpty(&pendp->urb_list) == FALSE)
        {
            purb = (PURB) RemoveHeadList(&pendp->urb_list);
            ASSERT(purb);
        }
        else
        {
            InitializeListHead(&pendp->urb_list);
            unlock_dev(pdev, TRUE);
            free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
            continue;
        }

        // if can_submit is STATUS_SUCCESS, the purb is inserted into the schedule
        uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_process_pending_endp(): endp_type=0x%x\n",
                                        endp_type(pendp)));
        switch (endp_type(pendp))
        {
            case USB_ENDPOINT_XFER_BULK:
            {
#ifdef DEMO
                can_submit = STATUS_UNSUCCESSFUL;
#else
                can_submit = uhci_internal_submit_bulk(uhci, purb);
#endif
                break;
            }
            case USB_ENDPOINT_XFER_CONTROL:
            {
                can_submit = uhci_internal_submit_ctrl(uhci, purb);
                break;
            }
            case USB_ENDPOINT_XFER_INT:
            {
                can_submit = uhci_internal_submit_int(uhci, purb);
                break;
            }
            case USB_ENDPOINT_XFER_ISOC:
            {
                can_submit = uhci_internal_submit_iso(uhci, purb);
                break;
            }
        }

        if (can_submit == STATUS_NO_MORE_ENTRIES)
        {
            //no enough bandwidth or tds
            InsertHeadList(&pendp->urb_list, (PLIST_ENTRY) purb);
            InsertTailList(&temp_list, pthis);
        }
        else
        {
            // other error or success
            free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));

            if (can_submit != STATUS_SUCCESS)
            {
                //abort these URBs
                InsertTailList(&abort_list, (LIST_ENTRY *) purb);
                uhci_dbg_print(DBGLVL_MEDIUM, ("uhci_process_pending_endp(): unable to submit urb 0x%x, "
                    "with status=0x%x\n", purb, can_submit));
                purb->status = can_submit;
            }

        }
        unlock_dev(pdev, TRUE);
    }

    if (IsListEmpty(&temp_list) == FALSE)
    {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?