📄 usb.c
字号:
{
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 + -