📄 usb.c
字号:
/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
usb.c
Abstract: ESC/POS (serial) interface for USB Point-of-Sale devices
Author:
ervinp
Environment:
Kernel mode
Revision History:
--*/
#include <WDM.H>
#include <usbdi.h>
#include "usbdlib.h"
#include <usbioctl.h>
#include "escpos.h"
#include "debug.h"
NTSTATUS InitUSB(PARENTFDOEXT *parentFdoExt)
/*++
Routine Description:
Intialize USB-related data
Arguments:
parentFdoExt - device extension for targetted device object
Return Value:
NT status code
--*/
{
NTSTATUS status;
status = GetDeviceDescriptor(parentFdoExt);
if (NT_SUCCESS(status)){
status = GetConfigDescriptor(parentFdoExt);
if (NT_SUCCESS(status)){
status = SelectConfiguration(parentFdoExt);
}
}
return status;
}
NTSTATUS GetConfigDescriptor(PARENTFDOEXT *parentFdoExt)
/*++
Routine Description:
Function retrieves the configuration descriptor from the device
Arguments:
parentFdoExt - device extension for targetted device object
Return Value:
NT status code
--*/
{
URB urb = { 0 };
USB_CONFIGURATION_DESCRIPTOR configDescBase = { 0 };
NTSTATUS status;
PAGED_CODE();
/*
* Get the first part of the configuration descriptor.
* It will tell us the size of the full configuration descriptor,
* including all the following interface descriptors, etc.
*/
UsbBuildGetDescriptorRequest(&urb,
(USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_CONFIGURATION_DESCRIPTOR_TYPE,
0,
0,
(PVOID)&configDescBase,
NULL,
sizeof(USB_CONFIGURATION_DESCRIPTOR),
NULL);
status = SubmitUrb(parentFdoExt->topDevObj, &urb, TRUE, NULL, NULL);
if (NT_SUCCESS(status)) {
ULONG configDescLen = configDescBase.wTotalLength;
/*
* Now allocate the right-sized buffer for the full configuration descriptor.
*/
ASSERT(configDescLen < 0x1000);
parentFdoExt->configDesc = ALLOCPOOL(NonPagedPool, configDescLen);
if (parentFdoExt->configDesc) {
RtlZeroMemory(parentFdoExt->configDesc, configDescLen);
UsbBuildGetDescriptorRequest(&urb,
(USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_CONFIGURATION_DESCRIPTOR_TYPE,
0,
0,
parentFdoExt->configDesc,
NULL,
configDescLen,
NULL);
status = SubmitUrb(parentFdoExt->topDevObj, &urb, TRUE, NULL, NULL);
if (NT_SUCCESS(status)) {
DBGVERBOSE(("Got config desc @ %ph, len=%xh.", parentFdoExt->configDesc, urb.UrbControlDescriptorRequest.TransferBufferLength));
ASSERT(urb.UrbControlDescriptorRequest.TransferBufferLength == configDescLen);
}
}
else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
ASSERT(NT_SUCCESS(status));
return status;
}
NTSTATUS GetDeviceDescriptor(PARENTFDOEXT *parentFdoExt)
/*++
Routine Description:
Function retrieves the device descriptor from the device
Arguments:
parentFdoExt - device extension for targetted device object
Return Value:
NT status code
--*/
{
URB urb;
NTSTATUS status;
PAGED_CODE();
RtlZeroMemory(&parentFdoExt->deviceDesc, sizeof(parentFdoExt->deviceDesc));
UsbBuildGetDescriptorRequest(&urb,
(USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
USB_DEVICE_DESCRIPTOR_TYPE,
0,
0,
(PVOID)&parentFdoExt->deviceDesc,
NULL,
sizeof(parentFdoExt->deviceDesc),
NULL);
status = SubmitUrb(parentFdoExt->topDevObj, &urb, TRUE, NULL, NULL);
if (NT_SUCCESS(status)){
DBGVERBOSE(("Got device desc @ %ph, len=%xh (should be %xh).", (PVOID)&parentFdoExt->deviceDesc, urb.UrbControlDescriptorRequest.TransferBufferLength, sizeof(parentFdoExt->deviceDesc)));
}
ASSERT(NT_SUCCESS(status));
return status;
}
NTSTATUS ReadPipe( PARENTFDOEXT *parentFdoExt,
USBD_PIPE_HANDLE pipeHandle,
READPACKET *readPacket,
BOOLEAN synchronous
)
{
PURB urb;
NTSTATUS status;
ASSERT(pipeHandle);
DBGVERBOSE(("ReadPipe: dataLen=%xh, sync=%xh", readPacket->length, (ULONG)synchronous));
urb = ALLOCPOOL(NonPagedPool, sizeof(URB));
if (urb){
RtlZeroMemory(urb, sizeof(URB));
urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
urb->UrbBulkOrInterruptTransfer.Hdr.Length = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
urb->UrbBulkOrInterruptTransfer.PipeHandle = pipeHandle;
urb->UrbBulkOrInterruptTransfer.TransferBufferLength = readPacket->length;
urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
urb->UrbBulkOrInterruptTransfer.TransferBuffer = readPacket->data;
urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN;
urb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
if (synchronous){
/*
* Synchronous read.
*/
status = SubmitUrb(parentFdoExt->topDevObj, urb, TRUE, NULL, 0);
readPacket->length = urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
FREEPOOL(urb);
}
else {
/*
* Asynchronous read.
* Completion routine will free URB.
*/
IncrementPendingActionCount(parentFdoExt);
readPacket->urb = urb;
status = SubmitUrb( parentFdoExt->topDevObj,
urb,
FALSE, // asynchronous
ReadPipeCompletion, // completion routine
readPacket // completion context
);
}
}
else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
return status;
}
NTSTATUS ReadPipeCompletion(IN PDEVICE_OBJECT devObj, IN PIRP irp, IN PVOID context)
{
READPACKET *readPacket = (READPACKET *)context;
NTSTATUS status = irp->IoStatus.Status;
POSPDOEXT *pdoExt;
KIRQL oldIrql;
ASSERT(readPacket->signature == READPACKET_SIG);
pdoExt = readPacket->context;
/*
* Set the readPacket's length to the actual length returned by the device.
*/
ASSERT(readPacket->urb->UrbBulkOrInterruptTransfer.TransferBufferLength <= readPacket->length);
readPacket->length = readPacket->urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
DBGVERBOSE(("ReadPipeCompletion: irp=%ph, status=%xh, data=%ph, len=%xh, context=%ph.", irp, status, readPacket->data, readPacket->length, readPacket->context));
FREEPOOL(readPacket->urb);
readPacket->urb = BAD_POINTER;
if (NT_SUCCESS(status)){
DBGSHOWBYTES("READ PIPE result", readPacket->data, readPacket->length);
if (pdoExt){
KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
ASSERT(pdoExt->inputEndpointInfo.endpointIsBusy);
pdoExt->inputEndpointInfo.endpointIsBusy = FALSE;
/*
* Queue this completed readPacket
*/
ASSERT(readPacket->offset == 0);
/*
* Do NOT queue empty readPackets.
*/
if(readPacket->length == 0)
FreeReadPacket(readPacket);
else {
InsertTailList(&pdoExt->completedReadPacketsList, &readPacket->listEntry);
pdoExt->totalQueuedReadDataLength += readPacket->length;
}
KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
/*
* Now try to satisfy pending read IRPs with the completed readPacket data.
*/
SatisfyPendingReads(pdoExt);
}
else {
DBGVERBOSE(("Just debug testing -- not processing read result"));
FreeReadPacket(readPacket);
}
}
else {
FreeReadPacket(readPacket);
}
/*
* If there are more read IRPs pending, issue another read.
*/
if (pdoExt){
BOOLEAN scheduleAnotherRead;
KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
scheduleAnotherRead = !IsListEmpty(&pdoExt->pendingReadIrpsList);
KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
if (scheduleAnotherRead){
DBGVERBOSE(("ReadPipeCompletion: scheduling read workItem"));
ExQueueWorkItem(&pdoExt->readWorkItem, DelayedWorkQueue);
}
}
/*
* This IRP was allocated by SubmitUrb(). Free it here.
* Return STATUS_MORE_PROCESSING_REQUIRED so the kernel does not
* continue processing this IRP.
*/
IoFreeIrp(irp);
DecrementPendingActionCount(pdoExt->parentFdoExt);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS WritePipe(PARENTFDOEXT *parentFdoExt, USBD_PIPE_HANDLE pipeHandle, PUCHAR data, ULONG dataLen)
{
URB urb;
NTSTATUS status;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -