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

📄 usb.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
    {
        size = purb->data_length > sizeof(USB_DEVICE_DESC) ? sizeof(USB_DEVICE_DESC) : purb->data_length;

        for(i = 0; i < size; i++)
        {
            purb->data_buffer[i] = ((PBYTE) pdev->pusb_dev_desc)[i];
        }
        purb->status = STATUS_SUCCESS;
    }

LBL_OUT:
    unlock_dev(pdev, FALSE);
    return purb->status;
}

LONG
usb_count_list(PLIST_HEAD list_head)
{
    LONG count;
    PLIST_ENTRY pthis, pnext;

    if (list_head == NULL)
        return 0;

    count = 0;
    ListFirst(list_head, pthis);

    while (pthis)
    {
        ListNext(list_head, pthis, pnext);
        pthis = pnext;
        count++;
    }
    return count;
}

// checks if processor supports Time Stamp Counter
__inline BOOLEAN
usb_query_clicks(PLARGE_INTEGER clicks)
{
    BOOLEAN ret_val;
    //so we have to use intel's cpu???
    ret_val = FALSE;

#ifdef _MSC_VER
    __asm
    {
        push ebx;
        push eax;
        mov eax, 1;             //read version
        cpuid;
        test edx, 0x10;         //timer stamp
        jz LBL_OUT;
        // cpuid                                //serialization
        rdtsc;
        mov ebx, dword ptr[clicks];
        mov dword ptr[ebx], eax;
        mov dword ptr[ebx + 4], edx;
        mov dword ptr[ret_val], TRUE;
LBL_OUT:
        pop eax;
        pop ebx;
    }
#else
    ret_val = FALSE;
#endif
    return ret_val;
}

VOID
usb_wait_ms_dpc(ULONG ms)
{
    LARGE_INTEGER start;
    LARGE_INTEGER ticker;
    LARGE_INTEGER freq;
    ULONG interval;
    ULONG expire_count;

    KeQueryPerformanceCounter(&freq);

    expire_count = 2000000;
    if (cpu_clock_freq)
        expire_count = (cpu_clock_freq / 1000) * ms;

    if (usb_query_clicks(&start) == FALSE)
    {
        ticker.QuadPart = 0;
        while (TRUE)
        {
            KeQuerySystemTime(&ticker);
            interval = ticker.LowPart - start.LowPart;
            if (interval >= ms * 10000)
                break;
        }
    }
    else
    {
        ticker.QuadPart = 0;
        while (TRUE)
        {
            usb_query_clicks(&ticker);
            interval = ticker.LowPart - start.LowPart;
            if (interval >= expire_count)
                break;
        }
    }
}


VOID
usb_wait_us_dpc(ULONG us)
{
    LARGE_INTEGER start;
    LARGE_INTEGER ticker;
    LARGE_INTEGER freq;
    ULONG interval;
    ULONG expire_count;

    KeQueryPerformanceCounter(&freq);

    expire_count = 2000000;
    if (cpu_clock_freq)
        expire_count = (cpu_clock_freq / 1000000) * us;

    if (usb_query_clicks(&start) == FALSE)
    {
        ticker.QuadPart = 0;
        while (TRUE)
        {
            KeQuerySystemTime(&ticker);
            interval = ticker.LowPart - start.LowPart;
            if (interval >= us * 10)
                break;
        }
    }
    else
    {
        ticker.QuadPart = 0;
        while (TRUE)
        {
            usb_query_clicks(&ticker);
            interval = ticker.LowPart - start.LowPart;
            if (interval >= expire_count)
                break;
        }
    }
}

VOID
usb_cal_cpu_freq()
{
    LARGE_INTEGER tick1, tick2;
    LONG i;
    // interval.QuadPart = -40 * 1000 * 1000;

    if (cpu_clock_freq >= 100 * 1000 * 1000)    // assume it is valid
        return;

    if (usb_query_clicks(&tick1))
    {
        for(i = 0; i < 25; i++)
        {
            usb_query_clicks(&tick1);
            KeStallExecutionProcessor(40 * 1000);
            usb_query_clicks(&tick2);
            cpu_clock_freq += (ULONG) (tick2.QuadPart - tick1.QuadPart);
        }
        // cpu_clock_freq *= 1000;
        usb_dbg_print(DBGLVL_MAXIMUM, ("usb_cal_cpu_freq(): cpu frequency = %d Hz\n", cpu_clock_freq));
    }
}

NTSTATUS
usb_set_interface(PURB purb)
{
    ULONG u;
    PURB purb1;
    PCTRL_REQ_STACK pstack;
    PUSB_DEV pdev;
    PUSB_CTRL_SETUP_PACKET psetup;
    PUSB_ENDPOINT pendp;
    NTSTATUS status;

    PHCD hcd;
    USE_BASIC_NON_PENDING_IRQL;

    purb1 = purb;
    pdev = purb->pdev;
    psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;

    lock_dev(pdev, FALSE);
    if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
    {
        unlock_dev(pdev, FALSE);
        return STATUS_DEVICE_NOT_CONNECTED;
    }
    if (dev_state(pdev) < USB_DEV_STATE_CONFIGURED)
    {
        unlock_dev(pdev, FALSE);
        return STATUS_DEVICE_NOT_READY;
    }

    hcd = pdev->hcd;

    if (psetup->wIndex >= pdev->usb_config->if_count)
    {
        unlock_dev(pdev, FALSE);
        return STATUS_INVALID_PARAMETER;
    }
    if (psetup->wValue >= pdev->usb_config->interf[psetup->wIndex].altif_count + 1)
    {
        unlock_dev(pdev, FALSE);
        return STATUS_INVALID_PARAMETER;
    }
    if (pdev->usb_config->interf[psetup->wIndex].pusb_if_desc->bAlternateSetting == psetup->wValue)
    {
        // already the current interface
        unlock_dev(pdev, FALSE);
        return STATUS_SUCCESS;
    }
    // check to see if the endp is busy
    for(u = 0; u < pdev->usb_config->interf[psetup->wIndex].endp_count; u++)
    {
        // This check is not adquate. Since we do not have mechanism to block the new coming
        // request during this request. the caller must guarantee no active or pending
        // usb request on these endpoint.
        pendp = &pdev->usb_config->interf[psetup->wIndex].endp[u];
        if (usb_endp_busy_count(pendp))
        {
            // active urb on that endp
            unlock_dev(pdev, FALSE);
            return STATUS_DEVICE_NOT_READY;
        }
        if (IsListEmpty(&pendp->urb_list))
        {
            // pending urb on that endp
            unlock_dev(pdev, FALSE);
            return STATUS_DEVICE_NOT_READY;
        }
    }
    unlock_dev(pdev, FALSE);

    if (purb1->ctrl_req_context.ctrl_stack_count == 0)
    {
        // ok, we have one stack cell for our use
        if (purb1->completion != NULL)
        {
            purb1->ctrl_req_context.ctrl_stack_count = 1;
            purb1->ctrl_req_context.ctrl_cur_stack = 0;
        }
        else
        {
            // use urb's completion and context
            purb1->completion = usb_set_interface_completion;
            purb1->context = pdev;
        }
    }
    else
    {
        if (purb->ctrl_req_context.ctrl_cur_stack + 1 >= purb->ctrl_req_context.ctrl_stack_count)
        {
            // stack full, let's allocate one new urb, we need stack size one
            purb1 = usb_alloc_mem(NonPagedPool, sizeof(URB));
            if (purb1 == NULL)
                return STATUS_NO_MEMORY;

            RtlCopyMemory(purb1, purb, sizeof(URB));

            // we do not use stack
            RtlZeroMemory(purb1->ctrl_req_stack, sizeof(CTRL_REQ_STACK));
            purb1->context = pdev;
            purb1->completion = usb_set_interface_completion;
            purb1->ctrl_parent_urb = purb;
            purb1->ctrl_req_context.ctrl_req_flags = CTRL_PARENT_URB_VALID;

            goto LBL_SEND_URB;
        }
        else
            purb->ctrl_req_context.ctrl_cur_stack++;
    }

    u = purb1->ctrl_req_context.ctrl_cur_stack;
    RtlZeroMemory(&purb1->ctrl_req_stack[u], sizeof(CTRL_REQ_STACK));
    pstack = &purb1->ctrl_req_stack[u];
    pstack->context = pdev;
    pstack->urb_completion = usb_set_interface_completion;

LBL_SEND_URB:
    if (hcd == NULL)
        return STATUS_INVALID_PARAMETER;

    status = hcd->hcd_submit_urb(hcd, purb->pdev, purb->pendp, purb);
    return status;
}

#define usb_complete_and_free_ctrl_urb( pURB ) \
{\
    UCHAR i, j;\
    i = pURB->ctrl_req_context.ctrl_cur_stack;\
    j = pURB->ctrl_req_context.ctrl_stack_count;\
    usb_call_ctrl_completion( pURB );\
    if( i == 0xff || j == 0 )\
        usb_free_mem( pURB );\
}

VOID
usb_set_interface_completion(PURB purb, PVOID context)
{
    PUSB_CTRL_SETUP_PACKET psetup;
    PUSB_INTERFACE pif, palt_if;
    USB_INTERFACE temp_if;
    UCHAR if_idx, if_alt_idx;
    PUSB_DEV pdev;
    PUSB_ENDPOINT pendp;
    ULONG i;
    PLIST_ENTRY pthis, pnext;

    USE_BASIC_NON_PENDING_IRQL;

    UNREFERENCED_PARAMETER(context);

    if (purb == NULL)
        return;

    if (purb->status == STATUS_SUCCESS)
    {
        psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
        if_idx = (UCHAR) psetup->wIndex;
        if_alt_idx = (UCHAR) psetup->wValue;
        pdev = purb->pdev;
        RtlZeroMemory(&temp_if, sizeof(USB_INTERFACE));

        lock_dev(pdev, TRUE);
        if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
        {
            unlock_dev(pdev, TRUE);
            purb->status = STATUS_DEVICE_NOT_CONNECTED;
            purb->data_length = 0;
        }
        else
        {
            // let's swap the interface
            pif = &pdev->usb_config->interf[if_idx];
            ListFirst(&pif->altif_list, pthis);
            pnext = pthis;
            do
            {
                palt_if = struct_ptr(pthis, USB_INTERFACE, altif_list);
                if (palt_if->pusb_if_desc->bAlternateSetting == if_alt_idx)
                {
                    break;
                }
                palt_if = NULL;
                ListNext(&pif->altif_list, pthis, pnext);
                pthis = pnext;

            } while (pthis);

            if (palt_if != NULL)
            {
                RtlCopyMemory(&temp_if, palt_if, sizeof(USB_INTERFACE));

                palt_if->endp_count = pif->endp_count;
                RtlCopyMemory(palt_if->endp, pif->endp, sizeof(pif->endp));
                palt_if->pif_drv = pif->pif_drv;
                palt_if->pusb_if_desc = pif->pusb_if_desc;
                for(i = 0; i < palt_if->endp_count; i++)
                {
                    pendp = &palt_if->endp[i];
                    InitializeListHead(&pendp->urb_list);
                    pendp->flags = 0;
                }

                RtlCopyMemory(pif->endp, temp_if.endp, sizeof(temp_if.endp));
                pif->endp_count = temp_if.endp_count;
                pif->pusb_if_desc = temp_if.pusb_if_desc;
                for(i = 0; i < pif->endp_count; i++)
                {
                    pendp = &pif->endp[i];
                    InitializeListHead(&pendp->urb_list);
                    pendp->flags = 0;
                }
            }
            else
            {
                TRAP();
                purb->status = STATUS_UNSUCCESSFUL;
            }
        }
        unlock_dev(pdev, TRUE);
    }

    // for recursive reason, we have to store the parameter ahead
    usb_complete_and_free_ctrl_urb(purb);
}

// can only be called when current completion finished and called only in
// urb completion. And this func may be called recursively, if this routine
// is called, the urb must be treated as released.
VOID
usb_call_ctrl_completion(PURB purb)
{
    PURB parent_urb;
    PCTRL_REQ_STACK pstack;
    ULONG i;


    if (purb == NULL)
        return;

    if (purb->ctrl_req_context.ctrl_stack_count != 0)
    {
        i = purb->ctrl_req_context.ctrl_cur_stack;
        if (i > 0 && i < 0x10)
        {
            i--;
            purb->ctrl_req_context.ctrl_cur_stack = (UCHAR) i;
            pstack = &purb->ctrl_req_stack[i];
            if (pstack->urb_completion)
            {
                pstack->urb_completion(purb, pstack->context);
            }
            else
                TRAP();
        }
        else if (i == 0)
        {
            i = purb->ctrl_req_context.ctrl_cur_stack = 0xff;
            if (purb->completion)
            {
                purb->completion(purb, purb->context);
            }
            else
                TRAP();
        }
        else if (i == 0xff)
        {
            // only parent urb's completion, if parent urb exists, can be called
            if (purb->ctrl_req_context.ctrl_req_flags & CTRL_PARENT_URB_VALID)
            {
                parent_urb = purb->ctrl_parent_urb;
                if (parent_urb)
                {
                    pstack = &parent_urb->ctrl_req_stack[parent_urb->ctrl_req_context.ctrl_cur_stack];
                    pstack->urb_completion(parent_urb, pstack->context);
                }
                else
                    TRAP();
            }
        }
        else
            TRAP();
    }
    else if (purb->ctrl_req_context.ctrl_req_flags & CTRL_PARENT_URB_VALID)
    {
        // this is the case when the child urb won't use the stack
        parent_urb = purb->ctrl_parent_urb;
        if (parent_urb)
        {
            // pstack = &parent_urb->ctrl_req_stack[ parent_urb->ctrl_req_context.ctrl_cur_stack ];
            // pstack->urb_completion( parent_urb, pstack->context );
            usb_call_ctrl_completion(parent_urb);
        }
        else
            TRAP();
    }
    else
        return;
}

⌨️ 快捷键说明

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