⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ehci.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:
    pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;

    //test if the purb is canceled
    if (purb->flags & URB_FLAG_FORCE_CANCEL)
    {
        purb->status = STATUS_CANCELLED;
    }
    else if (raw_status == 0)
        purb->status = STATUS_SUCCESS;

    else if (pipe_content->trans_type == USB_ENDPOINT_XFER_INT ||
             pipe_content->trans_type == USB_ENDPOINT_XFER_BULK ||
             pipe_content->trans_type == USB_ENDPOINT_XFER_CONTROL)
    {

        if (raw_status & QTD_STS_BABBLE)
            purb->status = USB_STATUS_DATA_OVERRUN;

        else if (raw_status & QTD_STS_HALT)
            purb->status = USB_STATUS_ENDPOINT_HALTED;

        else if (raw_status & QTD_STS_DBE)
            purb->status = USB_STATUS_BUFFER_OVERRUN;

        else if (raw_status & QTD_STS_XACT)
            purb->status = USB_STATUS_CRC;      // crc is included in xact err.

        else if (raw_status & QTD_STS_MMF)
            purb->status = USB_STATUS_BTSTUFF;

        else
            purb->status = STATUS_UNSUCCESSFUL;
    }
    else if (pipe_content->trans_type == USB_ENDPOINT_XFER_ISOC)
    {
        if (pipe_content->speed_high)
        {
            if (raw_status & ITD_STS_BUFERR)
                purb->status = USB_STATUS_BUFFER_OVERRUN;

            else if (raw_status & ITD_STS_BABBLE)
                purb->status = USB_STATUS_BABBLE_DETECTED;

            else if (raw_status & ITD_STS_XACTERR)      // Xact Err
                purb->status = USB_STATUS_CRC;

            else
                purb->status = STATUS_UNSUCCESSFUL;

        }
        else
        {
            if (raw_status & SITD_STS_ERR)      // ERR is received from hub's tt
                purb->status = USB_STATUS_ERROR;

            else if (raw_status & SITD_STS_DBE)
                purb->status = USB_STATUS_BUFFER_OVERRUN;

            else if (raw_status & SITD_STS_BABBLE)
                purb->status = USB_STATUS_BABBLE_DETECTED;

            else if (raw_status & SITD_STS_XACTERR)     // Xact Error
                purb->status = USB_STATUS_CRC;

            else if (raw_status & SITD_STS_MISSFRM)     // missing microframe
                purb->status = USB_STATUS_DATA_TOGGLE_MISMATCH;

            else
                purb->status = STATUS_UNSUCCESSFUL;
        }
    }
    if (purb->status != STATUS_SUCCESS)
    {
        hcd_dbg_print(DBGLVL_MEDIUM, ("ehci_set_error_code(): error status 0x%x\n", raw_status));
    }
    return purb->status;
}

static BOOLEAN NTAPI
ehci_sync_remove_urb_finished(PVOID context)
{
    PEHCI_DEV ehci;
    PLIST_ENTRY pthis, pnext, ptemp;
    PURB purb;
    PSYNC_PARAM pparam;

    pparam = (PSYNC_PARAM) context;
    ehci = pparam->ehci;
    ptemp = (PLIST_ENTRY) pparam->context;

    if (ehci == NULL)
    {
        return (UCHAR) (pparam->ret = FALSE);
    }

    ListFirst(&ehci->urb_list, pthis);
    while (pthis)
    {
        //remove urbs not in the schedule
        ListNext(&ehci->urb_list, pthis, pnext);
        purb = (PURB) pthis;

        if ((purb->flags & URB_FLAG_IN_SCHEDULE) == 0)
        {
            //finished or canceled( not applied for split bulk ).
            RemoveEntryList(pthis);
            InsertTailList(ptemp, pthis);
        }
        pthis = pnext;
    }
    pparam->ret = TRUE;
    return (UCHAR) TRUE;
}

VOID NTAPI
ehci_dpc_callback(PKDPC dpc, PVOID context, PVOID sysarg1, PVOID sysarg2)
{
    PEHCI_DEV ehci;

    LIST_HEAD temp_list;
    PLIST_ENTRY pthis, pnext;
    PURB purb;
    PEHCI_QH pqh;
    PEHCI_QTD ptd;
    PUHCI_PENDING_ENDP pending_endp;
    PUSB_DEV pdev;
    PUSB_ENDPOINT pendp;

    BOOLEAN finished;
    LONG i;
    ULONG ehci_status, urb_status;

    SYNC_PARAM sync_param;
    UCHAR ep_type;
    USE_BASIC_NON_PENDING_IRQL;

    ehci = (PEHCI_DEV) context;
    if (ehci == NULL)
        return;

    ehci_status = (ULONG) sysarg1;

    InitializeListHead(&temp_list);

    sync_param.ehci = ehci;
    sync_param.context = (PVOID) & temp_list;

    ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_dpc_callback(): entering..., ehci=0x%x\n", ehci));
    //remove finished purb from ehci's purb-list 
    KeSynchronizeExecution(ehci->pdev_ext->ehci_int, ehci_sync_remove_urb_finished, &sync_param);

    //release resources( itds, sitds, fstns, tds, and qhs ) allocated for the purb 
    while (IsListEmpty(&temp_list) == FALSE)
    {
        //not in any public queue, if do not access into dev, no race 
        //condition will occur
        purb = (PURB) RemoveHeadList(&temp_list);
        urb_status = purb->status;
        ep_type = endp_type(purb->pendp);

        if (ep_type == USB_ENDPOINT_XFER_ISOC)
        {
            // collect error for iso transfer
            urb_status = ehci_scan_iso_error(ehci, purb);
        }

        //the only place we do not use this lock on non-pending-endp-list data
        KeAcquireSpinLockAtDpcLevel(&ehci->pending_endp_list_lock);
        while (IsListEmpty(&purb->trasac_list) == FALSE)
        {
            UCHAR em_type;
            pthis = RemoveHeadList(&purb->trasac_list);
            em_type = (UCHAR) elem_type(pthis, TRUE);

            if (em_type == INIT_LIST_FLAG_QH)
            {
                pqh = qh_from_list_entry(pthis);
                elem_safe_free(pthis, TRUE);
            }
            else
            {
                //must be an itd, sitd chain
                InsertHeadList(&purb->trasac_list, pthis);
                for(i = 0, purb->bytes_transfered = 0; i < purb->td_count; i++)
                {
                    PEHCI_QTD_CONTENT ptdc = NULL;
                    PEHCI_ITD_CONTENT pitdc;
                    PEHCI_SITD_CONTENT psitdc;

                    em_type = (UCHAR) elem_type(pthis, TRUE);

                    // accumulate data transfered in tds
                    if (em_type == INIT_LIST_FLAG_QTD)
                    {
                        ptd = qtd_from_list_entry(pthis);
                        ptdc = (PEHCI_QTD_CONTENT) ptd;
                        if ((ptdc->status & QTD_STS_ACTIVE) == 0 && ((ptdc->status & QTD_ANY_ERROR) == 0))
                            purb->bytes_transfered += ptd->bytes_to_transfer;
                    }
                    else if (em_type == INIT_LIST_FLAG_ITD)
                    {
                        int j;
                        pitdc = (PEHCI_ITD_CONTENT) itd_from_list_entry(pthis);
                        for(j = 0; j < 8; j++)
                        {
                            if ((pitdc->status_slot[j].status & ITD_STS_ACTIVE) == 0
                                && (pitdc->status_slot[j].status & ITD_ANY_ERROR) == 0)
                                purb->bytes_transfered += ptdc->bytes_to_transfer;
                        }
                    }
                    else if (em_type == INIT_LIST_FLAG_SITD)
                    {
                        psitdc = (PEHCI_SITD_CONTENT) sitd_from_list_entry(pthis);
                        if ((psitdc->status & SITD_STS_ACTIVE) == 0 && (psitdc->status & SITD_ANY_ERROR) == 0)
                            purb->bytes_transfered += ptdc->bytes_to_transfer;
                    }
                    ListNext(&purb->trasac_list, pthis, pnext);
                    pthis = pnext;
                }

                // check to see if an fstn is there
                ListFirstPrev(&purb->trasac_list, pthis);
                if (elem_type(pthis, TRUE) == INIT_LIST_FLAG_FSTN)
                {
                    RemoveEntryList(pthis);
                    elem_safe_free(pthis, TRUE);
                }

                ListFirst(&purb->trasac_list, pthis);
                RemoveEntryList(&purb->trasac_list);

                // free the tds
                elem_safe_free(pthis, FALSE);

                //termination condition
                InitializeListHead(&purb->trasac_list);
                purb->last_finished_td = NULL;
            }
        }

        if (ep_type == USB_ENDPOINT_XFER_ISOC || ep_type == USB_ENDPOINT_XFER_INT)
            ehci_claim_bandwidth(ehci, purb, FALSE);    //release band-width

        KeReleaseSpinLockFromDpcLevel(&ehci->pending_endp_list_lock);

        ehci_set_error_code(purb, urb_status);

        pdev = dev_from_endp(purb->pendp);
        pendp = purb->pendp;

        // perform clear tt buffer if error on full/low bulk/control pipe
        if (ep_type == USB_ENDPOINT_XFER_BULK || ep_type == USB_ENDPOINT_XFER_CONTROL)
        {
            PURB_HS_PIPE_CONTENT pipe_content;
            PUSB_DEV phub;
            UCHAR port_idx;

            get_parent_hs_hub(pdev, phub, port_idx);
            pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;

            if (pipe_content->speed_high == 0 && purb->status != STATUS_SUCCESS)
            {
                // lets schedule an event to clear the tt buffer
                hub_post_clear_tt_event(phub, port_idx, purb->pipe);
            }
            else if (pipe_content->speed_high == 0)
            {
                if (phub == NULL)
                    TRAP();
                else
                {
                    // release tt if no error
                    hub_unlock_tt(phub, (UCHAR) port_idx, (UCHAR) pipe_content->trans_type);
                }
            }
        }

        finished = TRUE;

        //since the ref_count for the purb is not released, we can safely have one
        //pointer to dev

        if (purb->status == USB_STATUS_BABBLE_DETECTED)
        {
            usb_dbg_print(DBGLVL_MEDIUM,
                          ("ehci_dpc_callback(): alert!!!, babble detected, severe error, reset the whole bus\n"));
            // ehci_start( ehci );
        }

        if (ehci_status & STS_HALT)     //&& !ehci->is_suspended
        {
            ehci_start(&ehci->hcd_interf);
        }

        //this will let the new request in ehci_generic_urb_completion to this endp
        //be processed rather than queued in the pending_endp_list
        lock_dev(pdev, TRUE);
        usb_endp_busy_count_dec(pendp);
        unlock_dev(pdev, TRUE);

        if (usb_success(purb->status) == FALSE)
        {
            // set error code and complete the purb and purb is invalid from this point
            ehci_generic_urb_completion(purb, purb->context);
        }
        else
        {
            if (ep_type == USB_ENDPOINT_XFER_BULK)
            {
                purb->rest_bytes -= purb->bytes_transfered;
                if (purb->rest_bytes)
                {
                    finished = FALSE;
                }
                else
                {
                    ehci_generic_urb_completion(purb, purb->context);
                }
            }
            else
            {
                ehci_generic_urb_completion(purb, purb->context);
                // DbgBreakPoint();
                //purb is now invalid
            }
        }

        KeAcquireSpinLockAtDpcLevel(&ehci->pending_endp_list_lock);
        lock_dev(pdev, TRUE);

        if (finished)
            pdev->ref_count--;

        if (urb_status && ((ep_type == USB_ENDPOINT_XFER_BULK) || (ep_type == USB_ENDPOINT_XFER_INT)))
        {
            // error on int or bulk pipe, cleared in usb_reset_pipe_completion
            pendp->flags &= ~USB_ENDP_FLAG_STAT_MASK;
            pendp->flags |= USB_ENDP_FLAG_STALL;
        }

        if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
        {
            unlock_dev(pdev, TRUE);
            KeReleaseSpinLockFromDpcLevel(&ehci->pending_endp_list_lock);
            if (finished == FALSE)
            {

                purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
                ehci_generic_urb_completion(purb, purb->context);

                lock_dev(pdev, TRUE);
                pdev->ref_count--;
                unlock_dev(pdev, TRUE);
            }
            continue;
        }

        if (finished && IsListEmpty(&pendp->urb_list) == TRUE)
        {
            unlock_dev(pdev, TRUE);
            KeReleaseSpinLockFromDpcLevel(&ehci->pending_endp_list_lock);
            continue;
        }
        else if (finished == TRUE)
        {
            //has purb in the endp's purb-list
            if (usb_endp_busy_count(pendp) > 0)
            {
                //the urbs still have chance to be sheduled but not this time
                unlock_dev(pdev, TRUE);
                KeReleaseSpinLockFromDpcLevel(&ehci->pending_endp_list_lock);
                continue;
            }
        }

        if (finished == FALSE)
        {
            //a split bulk transfer, ( not the high speed split transfer )
            purb->bytes_transfered = 0;
            purb->bytes_to_transfer =
                EHCI_MAX_SIZE_TRANSFER > purb->rest_bytes ? purb->rest_bytes : EHCI_MAX_SIZE_TRANSFER;

            //the purb is not finished
            purb->flags &= ~URB_FLAG_STATE_MASK;
            purb->flags |= URB_FLAG_STATE_PENDING;

            InsertHeadList(&pendp->urb_list, (PLIST_ENTRY) purb);
        }

        pending_endp = alloc_pending_endp(&ehci->pending_endp_pool, 1);
        pending_endp->pendp = pendp;
        InsertTailList(&ehci->pending_endp_list, &pending_endp->endp_link);

        unlock_dev(pdev, TRUE);
        KeReleaseSpinLockFromDpcLevel(&ehci->pending_endp_list_lock);
    }

    //ah...exhausted, let's find some in the pending_endp_list to rock
    ehci_process_pending_endp(ehci);
    return;
}

static BOOLEAN NTAPI
ehci_sync_cancel_urbs_dev(PVOID context)
{
    //cancel all the urbs on one dev
    PEHCI_DEV ehci;

⌨️ 快捷键说明

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