📄 usb.c
字号:
ASSERT(pipeHandle);
DBGSHOWBYTES("WritePipe bytes:", data, dataLen);
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 = dataLen;
urb.UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
urb.UrbBulkOrInterruptTransfer.TransferBuffer = data;
urb.UrbBulkOrInterruptTransfer.TransferFlags = USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_OUT;
urb.UrbBulkOrInterruptTransfer.UrbLink = NULL;
status = SubmitUrb(parentFdoExt->topDevObj, &urb, TRUE, NULL, NULL);
return status;
}
NTSTATUS SubmitUrb( PDEVICE_OBJECT pdo,
PURB urb,
BOOLEAN synchronous,
PVOID completionRoutine,
PVOID completionContext)
/*++
Routine Description:
Send the URB to the USB device.
If synchronous is TRUE, ignore the completion info and synchonize the IRP;
otherwise, don't synchronize and set the provided completion routine for the IRP.
Arguments:
Return Value:
NT status code
--*/
{
PIRP irp;
NTSTATUS status;
/*
* Allocate the IRP to send the buffer down the USB stack.
*
* Don't use IoBuildDeviceIoControlRequest (because it queues
* the IRP on the current thread's irp list and may
* cause the calling process to hang if the IopCompleteRequest APC
* does not fire and dequeue the IRP).
*/
irp = IoAllocateIrp(pdo->StackSize, FALSE);
if (irp){
PIO_STACK_LOCATION nextSp;
#if STATUS_ENDPOINT
DBGVERBOSE(("SubmitUrb: submitting URB %ph on IRP %ph (sync=%d)", urb, irp, synchronous));
#endif
nextSp = IoGetNextIrpStackLocation(irp);
nextSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
/*
* Attach the URB to this IRP.
*/
nextSp->Parameters.Others.Argument1 = urb;
if (synchronous){
status = CallDriverSync(pdo, irp);
IoFreeIrp(irp);
}
else {
/*
* Caller's completion routine will free the irp
* when it completes.
*/
ASSERT(completionRoutine);
ASSERT(completionContext);
IoSetCompletionRoutine( irp,
completionRoutine,
completionContext,
TRUE, TRUE, TRUE);
status = IoCallDriver(pdo, irp);
}
}
else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
return status;
}
NTSTATUS SelectConfiguration(PARENTFDOEXT *parentFdoExt)
{
USBD_INTERFACE_LIST_ENTRY interfaceList[2];
NTSTATUS status;
/*
* We only look at vendor-class interfaces
*/
// BUGBUG - limited to one interface
interfaceList[0].InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(
parentFdoExt->configDesc,
parentFdoExt->configDesc,
-1,
-1,
USB_INTERFACE_CLASS_VENDOR,
-1,
-1);
if (interfaceList[0].InterfaceDescriptor){
PURB urb;
interfaceList[1].InterfaceDescriptor = NULL;
urb = USBD_CreateConfigurationRequestEx(parentFdoExt->configDesc, &interfaceList[0]);
if (urb){
status = SubmitUrb(parentFdoExt->topDevObj, urb, TRUE, NULL, NULL);
if (NT_SUCCESS(status)){
PUSBD_INTERFACE_INFORMATION interfaceInfo;
parentFdoExt->configHandle = urb->UrbSelectConfiguration.ConfigurationHandle;
interfaceInfo = &urb->UrbSelectConfiguration.Interface;
parentFdoExt->interfaceInfo = MemDup(interfaceInfo, interfaceInfo->Length);
if (parentFdoExt->interfaceInfo){
DBGVERBOSE(("SelectConfiguration: got interfaceInfo @ %ph.", parentFdoExt->interfaceInfo));
}
else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
else {
DBGERR(("SelectConfiguration: URB failed w/ %xh.", status));
}
FREEPOOL(urb);
}
else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
else {
status = STATUS_DEVICE_DATA_ERROR;
}
return status;
}
NTSTATUS CreatePdoForEachEndpointPair(PARENTFDOEXT *parentFdoExt)
/*++
Routine Description:
Walk the USB endpoints.
For each input/output endpoint pair, create one PDO
which will be exposed as a COM (serial) port interface.
BUGBUG - right now, this only looks at the first interface
(on the default confuguration)
Arguments:
parentFdoExt - device extension for the targetted device object
Return Value:
NT status code
--*/
{
NTSTATUS status;
ULONG maxPossiblePDOs, deviceRelationsSize;
maxPossiblePDOs = (parentFdoExt->interfaceInfo->NumberOfPipes/2);
deviceRelationsSize = sizeof(DEVICE_RELATIONS) + maxPossiblePDOs*sizeof(PDEVICE_OBJECT);
parentFdoExt->deviceRelations = ALLOCPOOL(NonPagedPool, deviceRelationsSize);
if (parentFdoExt->deviceRelations){
ULONG inputPipeIndex = 0, outputPipeIndex = 0, statusPipeIndex = 0, comInterfaceIndex = 0;
RtlZeroMemory(parentFdoExt->deviceRelations, deviceRelationsSize);
status = STATUS_NO_MATCH;
while (TRUE){
UCHAR endPtAddr;
USBD_PIPE_TYPE pipeType;
#if STATUS_ENDPOINT
/*
* In the case of Serial Emulation, the protocol is that all DATA endpoints
* will be of type BULK and all STATUS endpoints will be of type INTERRUPT.
*/
if(parentFdoExt->posFlag & SERIAL_EMULATION) {
while(inputPipeIndex < parentFdoExt->interfaceInfo->NumberOfPipes) {
endPtAddr = parentFdoExt->interfaceInfo->Pipes[inputPipeIndex].EndpointAddress;
pipeType = parentFdoExt->interfaceInfo->Pipes[inputPipeIndex].PipeType;
if((pipeType == UsbdPipeTypeBulk) && (endPtAddr & USB_ENDPOINT_DIRECTION_MASK))
break;
inputPipeIndex++;
}
while(outputPipeIndex < parentFdoExt->interfaceInfo->NumberOfPipes) {
endPtAddr = parentFdoExt->interfaceInfo->Pipes[outputPipeIndex].EndpointAddress;
pipeType = parentFdoExt->interfaceInfo->Pipes[outputPipeIndex].PipeType;
if((pipeType == UsbdPipeTypeBulk) && !(endPtAddr & USB_ENDPOINT_DIRECTION_MASK))
break;
outputPipeIndex++;
}
while(statusPipeIndex < parentFdoExt->interfaceInfo->NumberOfPipes) {
endPtAddr = parentFdoExt->interfaceInfo->Pipes[statusPipeIndex].EndpointAddress;
pipeType = parentFdoExt->interfaceInfo->Pipes[statusPipeIndex].PipeType;
if((pipeType == UsbdPipeTypeInterrupt) && (endPtAddr & USB_ENDPOINT_DIRECTION_MASK))
break;
statusPipeIndex++;
}
if(!(statusPipeIndex < parentFdoExt->interfaceInfo->NumberOfPipes))
break;
}
else {
#endif
/*
* No Serial Emulation required. Find only DATA endpoints
* which can be of either type in this case.
*/
while(inputPipeIndex < parentFdoExt->interfaceInfo->NumberOfPipes) {
endPtAddr = parentFdoExt->interfaceInfo->Pipes[inputPipeIndex].EndpointAddress;
pipeType = parentFdoExt->interfaceInfo->Pipes[inputPipeIndex].PipeType;
if((pipeType == UsbdPipeTypeInterrupt) || (pipeType == UsbdPipeTypeBulk)) {
if(endPtAddr & USB_ENDPOINT_DIRECTION_MASK) {
break;
}
}
inputPipeIndex++;
}
while(outputPipeIndex < parentFdoExt->interfaceInfo->NumberOfPipes) {
endPtAddr = parentFdoExt->interfaceInfo->Pipes[outputPipeIndex].EndpointAddress;
pipeType = parentFdoExt->interfaceInfo->Pipes[outputPipeIndex].PipeType;
if((pipeType == UsbdPipeTypeInterrupt) || (pipeType == UsbdPipeTypeBulk)) {
if(!(endPtAddr & USB_ENDPOINT_DIRECTION_MASK)) {
break;
}
}
outputPipeIndex++;
}
#if STATUS_ENDPOINT
}
#endif
if ((inputPipeIndex < parentFdoExt->interfaceInfo->NumberOfPipes) &&
(outputPipeIndex < parentFdoExt->interfaceInfo->NumberOfPipes)){
/*
* We've found a pair (in/out) of endpoints.
* Create a PDO to represent a COM (serial) port interface on these endpoints.
*/
PUSBD_PIPE_INFORMATION inputPipeInfo = &parentFdoExt->interfaceInfo->Pipes[inputPipeIndex];
PUSBD_PIPE_INFORMATION outputPipeInfo = &parentFdoExt->interfaceInfo->Pipes[outputPipeIndex];
ENDPOINTINFO inputEndpointInfo, outputEndpointInfo, statusEndpointInfo;
#if EPSON_PRINTER
/*
* On the EPSON printer, we want to talk to the endpoints size 0x40,
* not the other pair with length 8.
*/
if ((inputPipeInfo->MaximumPacketSize == 8) && (outputPipeInfo->MaximumPacketSize == 8)){
inputPipeIndex++, outputPipeIndex++;
continue;
}
#endif
inputEndpointInfo.pipeHandle = inputPipeInfo->PipeHandle;
inputEndpointInfo.pipeLen = inputPipeInfo->MaximumPacketSize;
inputEndpointInfo.endpointIsBusy = FALSE;
outputEndpointInfo.pipeHandle = outputPipeInfo->PipeHandle;
outputEndpointInfo.pipeLen = outputPipeInfo->MaximumPacketSize;
outputEndpointInfo.endpointIsBusy = FALSE;
#if STATUS_ENDPOINT
if(parentFdoExt->posFlag & SERIAL_EMULATION) {
PUSBD_PIPE_INFORMATION statusPipeInfo = &parentFdoExt->interfaceInfo->Pipes[statusPipeIndex];
statusEndpointInfo.pipeHandle = statusPipeInfo->PipeHandle;
statusEndpointInfo.pipeLen = statusPipeInfo->MaximumPacketSize;
statusEndpointInfo.endpointIsBusy = FALSE;
}
#endif
status = CreateCOMPdo(parentFdoExt, comInterfaceIndex++, &inputEndpointInfo, &outputEndpointInfo, &statusEndpointInfo);
if (NT_SUCCESS(status)){
DBGVERBOSE(("CreatePdoForEachEndpointPair: created COMPdo with in/out len %xh/%xh.", inputEndpointInfo.pipeLen, outputEndpointInfo.pipeLen));
inputPipeIndex++, outputPipeIndex++, statusPipeIndex++;
}
else {
DBGERR(("CreatePdoForEachEndpointPair: CreateCOMPdo failed with %xh.", status));
break;
}
}
else {
if((parentFdoExt->posFlag & ODD_ENDPOINT) &&
((inputPipeIndex + outputPipeIndex) < (2 * parentFdoExt->interfaceInfo->NumberOfPipes))) {
/*
* We've found an odd endpoint.
* Create a PDO to represent a COM (serial) port interface on this endpoint.
*/
PUSBD_PIPE_INFORMATION oddPipeInfo = &parentFdoExt->interfaceInfo->Pipes[MIN(inputPipeIndex, outputPipeIndex)];
ENDPOINTINFO oddEndpointInfo;
oddEndpointInfo.pipeHandle = oddPipeInfo->PipeHandle;
oddEndpointInfo.pipeLen = oddPipeInfo->MaximumPacketSize;
oddEndpointInfo.endpointIsBusy = FALSE;
if(inputPipeIndex < parentFdoExt->interfaceInfo->NumberOfPipes)
status = CreateCOMPdo(parentFdoExt, comInterfaceIndex++, &oddEndpointInfo, NULL, NULL);
else
status = CreateCOMPdo(parentFdoExt, comInterfaceIndex++, NULL, &oddEndpointInfo, NULL);
if (NT_SUCCESS(status)){
DBGVERBOSE(("CreatePdoForEachEndpointPair: created <odd> COMPdo with len %xh.", oddEndpointInfo.pipeLen));
}
else {
DBGERR(("CreatePdoForEachEndpointPair: CreateCOMPdo failed with %xh.", status));
break;
}
}
break;
}
}
}
else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
ASSERT(NT_SUCCESS(status));
return status;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -