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

📄 ehci.c

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

BOOLEAN
destroy_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool)
{
    if (pool == NULL)
        return FALSE;

    InitializeListHead(&pool->free_que);
    pool->free_count = pool->total_count = 0;
    usb_free_mem(pool->pending_endp_array);
    pool->pending_endp_array = NULL;

    return TRUE;

}
#else
#define ehci_wait_ms uhci_wait_ms
extern VOID uhci_wait_ms(PEHCI_DEV ehci, LONG ms);

extern BOOLEAN init_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool);

extern BOOLEAN free_pending_endp(PUHCI_PENDING_ENDP_POOL pool, PUHCI_PENDING_ENDP pending_endp);

extern PUHCI_PENDING_ENDP alloc_pending_endp(PUHCI_PENDING_ENDP_POOL pool, LONG count);

extern BOOLEAN destroy_pending_endp_pool(PUHCI_PENDING_ENDP_POOL pool);

#endif

//end of pending endpoint pool funcs

static VOID NTAPI
ehci_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 purb's ref-count
        purb = (PURB) RemoveHeadList(abort_list);
        pdev = purb->pdev;
        // purb->status is set when they are added to abort_list

        ehci_generic_urb_completion(purb, purb->context);

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

static BOOLEAN
ehci_process_pending_endp(PEHCI_DEV ehci)
{
    PUSB_DEV pdev;
    LIST_ENTRY temp_list, abort_list;
    PLIST_ENTRY pthis;
    PURB purb;
    PUSB_ENDPOINT pendp;
    NTSTATUS can_submit = STATUS_SUCCESS;
    PWORK_QUEUE_ITEM pwork_item;
    PLIST_ENTRY cancel_list;
    PUSB_DEV pparent = NULL;
    UCHAR port_idx = 0;
    BOOLEAN tt_needed;
    UCHAR hub_addr = 0;
    USE_BASIC_IRQL;

    if (ehci == NULL)
        return FALSE;

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

    purb = NULL;
    ehci_dbg_print(DBGLVL_MEDIUM, ("ehci_process_pending_endp(): entering..., ehci=0x%x\n", ehci));

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

        ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_process_pending_endp(): pending_endp_list=0x%x\n",
                                        &ehci->pending_endp_list));

        tt_needed = FALSE;
        pthis = RemoveHeadList(&ehci->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(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
            //delegate to ehci_remove_device for remiving the purb queue on the endpoint
            continue;
        }
        if ((pdev->flags & USB_DEV_FLAG_HIGH_SPEED) == 0)
        {
            // prepare split transaction
            unlock_dev(pdev, TRUE);

            // pparent won't be removed when pending_endp_list_lock is acquired.
            get_parent_hs_hub(pdev, pparent, port_idx);

            if (pparent == NULL)
            {
                TRAP();
                ehci_dbg_print(DBGLVL_MEDIUM,
                               ("ehci_process_pending_endp(): full/low speed device with no parent!!!\n"));
                free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
                continue;
            }

            if (hub_lock_tt(pparent, port_idx, (UCHAR) endp_type(pendp)) == FALSE)
            {
                lock_dev(pdev, TRUE);
                if (dev_state(pdev) != USB_DEV_STATE_ZOMB)
                {
                    // reinsert the pending-endp to the list
                    InsertTailList(&temp_list, pthis);
                    unlock_dev(pdev, TRUE);
                }
                else
                {
                    // delegate to ehci_remove_device for purb removal
                    unlock_dev(pdev, TRUE);
                    free_pending_endp(&ehci->pending_endp_pool,
                                      struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
                }
                continue;
            }

            // backup the hub address for future use
            hub_addr = pparent->dev_addr;

            lock_dev(pdev, TRUE);
            if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
            {
                unlock_dev(pdev, TRUE);
                free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
                hub_unlock_tt(pparent, port_idx, (UCHAR) endp_type(pendp));
                continue;
            }
            tt_needed = TRUE;
            // go on processing
        }

        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(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
            if (tt_needed)
                hub_unlock_tt(pparent, port_idx, (UCHAR) endp_type(pendp));
            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(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
            if (tt_needed)
                hub_unlock_tt(pparent, port_idx, (UCHAR) endp_type(pendp));
            continue;
        }

        if (tt_needed)
        {
            ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->hub_addr = hub_addr;
            ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->port_idx = port_idx;
        }

        // if can_submit is STATUS_SUCCESS, the purb is inserted into the schedule
        switch (endp_type(pendp))
        {
            case USB_ENDPOINT_XFER_BULK:
            {
                can_submit = ehci_internal_submit_bulk(ehci, purb);
                break;
            }
            case USB_ENDPOINT_XFER_CONTROL:
            {
                can_submit = ehci_internal_submit_ctrl(ehci, purb);
                break;
            }
            case USB_ENDPOINT_XFER_INT:
            {
                can_submit = ehci_internal_submit_int(ehci, purb);
                break;
            }
            case USB_ENDPOINT_XFER_ISOC:
            {
                can_submit = ehci_internal_submit_iso(ehci, 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
        {
            // otherwise error or success
            free_pending_endp(&ehci->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);
                purb->status = can_submit;
            }
        }
        unlock_dev(pdev, TRUE);
        if (can_submit != STATUS_SUCCESS && tt_needed)
        {
            hub_unlock_tt(pparent, port_idx, (UCHAR) endp_type(pendp));
        }
    }

    if (IsListEmpty(&temp_list) == FALSE)
    {
        //re-append them to the pending_endp_list
        ListFirst(&temp_list, pthis);
        RemoveEntryList(&temp_list);
        MergeList(&ehci->pending_endp_list, pthis);
    }
    unlock_pending_endp_list(&ehci->pending_endp_list_lock);

    if (IsListEmpty(&abort_list) == FALSE)
    {
        PLIST_ENTRY pthis;
        cancel_list = (PLIST_ENTRY) usb_alloc_mem(NonPagedPool, sizeof(WORK_QUEUE_ITEM) + sizeof(LIST_ENTRY));
        ASSERT(cancel_list);

        ListFirst(&abort_list, pthis);
        RemoveEntryList(&abort_list);
        InsertTailList(pthis, cancel_list);

        pwork_item = (PWORK_QUEUE_ITEM) & cancel_list[1];

        // we do not need to worry the ehci_cancel_pending_endp_urb running when the
        // driver is unloading since purb-reference count will prevent the dev_mgr to 
        // quit till all the reference count to the dev drop to zero.
        ExInitializeWorkItem(pwork_item, ehci_cancel_pending_endp_urb, (PVOID) cancel_list);
        ExQueueWorkItem(pwork_item, DelayedWorkQueue);
    }
    return TRUE;
}

NTSTATUS
ehci_submit_urb(PEHCI_DEV ehci, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
{
    int i;
    PUHCI_PENDING_ENDP pending_endp;
    NTSTATUS status;
    USE_BASIC_IRQL;

    if (ehci == NULL)
        return STATUS_INVALID_PARAMETER;

    if (pdev == NULL || pendp == NULL || purb == NULL)
    {
        // give a chance to those pending urb, especially for clearing hub tt
        ehci_process_pending_endp(ehci);
        return STATUS_INVALID_PARAMETER;
    }

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

    if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
    {
        status = purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
        goto LBL_OUT;
    }

    if (dev_class(pdev) == USB_DEV_CLASS_ROOT_HUB)
    {
        unlock_dev(pdev, TRUE);
        unlock_pending_endp_list(&ehci->pending_endp_list_lock);
        status = ehci_rh_submit_urb(pdev, purb);
        return status;
    }

    if (pendp)
        purb->pendp = pendp;
    else
        purb->pendp = &pdev->default_endp;

    if (dev_from_endp(purb->pendp) != pdev)
    {
        status = purb->status = STATUS_INVALID_PARAMETER;
        goto LBL_OUT;
    }

    if (endp_state(purb->pendp) == USB_ENDP_FLAG_STALL)
    {
        status = purb->status = USB_STATUS_ENDPOINT_HALTED;
        goto LBL_OUT;
    }

    if ((pdev->flags & USB_DEV_FLAG_HIGH_SPEED) == 0)
    {
        // wait one ms
        usb_wait_ms_dpc(1);
    }

    purb->pdev = pdev;
    purb->rest_bytes = purb->data_length;

    if (endp_type(purb->pendp) == USB_ENDPOINT_XFER_BULK)
        purb->bytes_to_transfer = (purb->data_length > EHCI_MAX_SIZE_TRANSFER ? EHCI_MAX_SIZE_TRANSFER : purb->data_length);    //multiple transfer for large data block
    else
        purb->bytes_to_transfer = purb->data_length;

    ehci_dbg_print(DBGLVL_MEDIUM, ("ehci_submit_urb(): bytes_to_transfer=0x%x\n", purb->bytes_to_transfer));

    purb->bytes_transfered = 0;
    InitializeListHead(&purb->trasac_list);
    purb->last_finished_td = &purb->trasac_list;
    purb->flags &= ~(URB_FLAG_STATE_MASK | URB_FLAG_IN_SCHEDULE | URB_FLAG_FORCE_CANCEL);
    purb->flags |= URB_FLAG_STATE_PENDING;


    i = IsListEmpty(&pendp->urb_list);
    InsertTailList(&pendp->urb_list, &purb->urb_link);

    pdev->ref_count++;          //for purb reference

    if (i == FALSE)
    {
        //there is purb pending, simply queue it and return
        status = purb->status = STATUS_PENDING;
        goto LBL_OUT;
    }
    else if (usb_endp_busy_count(purb->pendp) && endp_type(purb->pendp) != USB_ENDPOINT_XFER_ISOC)
    {
        //
        //No purb waiting but purb overlap not allowed, 
        //so leave it in queue and return, will be scheduled
        //later
        //
        status = purb->status = STATUS_PENDING;
        goto LBL_OUT;
    }

    pending_endp = alloc_pending_endp(&ehci->pending_endp_pool, 1);
    if (pending_endp == NULL)
    {
        //panic
        status = purb->status = STATUS_UNSUCCESSFUL;
        goto LBL_OUT2;
    }

    pending_endp->pendp = purb->pendp;
    InsertTailList(&ehci->pending_endp_list, (PLIST_ENTRY) pending_endp);

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

    ehci_process_pending_endp(ehci);
    return STATUS_PENDING;

  LBL_OUT2:
    pdev->ref_count--;
    RemoveEntryList((PLIST_ENTRY) purb);

  LBL_OUT:
    unlock_dev(pdev, TRUE);
    unlock_pending_endp_list(&ehci->pending_endp_list_lock);
    ehci_process_pending_endp(ehci);
    return status;
}

static NTSTATUS
ehci_set_error_code(PURB purb, ULONG raw_status)
{
    PURB_HS_PIPE_CONTENT pipe_content;

⌨️ 快捷键说明

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