You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
711 lines
20 KiB
711 lines
20 KiB
#include "usbcom.h"
|
|
#include "usbsc.h"
|
|
#include <usbutil.h>
|
|
#include <usb.h>
|
|
#include <usbdlib.h>
|
|
|
|
|
|
NTSTATUS
|
|
UsbWrite(
|
|
PREADER_EXTENSION ReaderExtension,
|
|
PUCHAR pData,
|
|
ULONG DataLen,
|
|
LONG Timeout)
|
|
/*++
|
|
Description:
|
|
Write data to the usb port
|
|
|
|
Arguments:
|
|
ReaderExtension context of call
|
|
pData ptr to data buffer
|
|
DataLen length of data buffer
|
|
|
|
Return Value:
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PURB pUrb = NULL;
|
|
PDEVICE_OBJECT DeviceObject;
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
ULONG ulSize;
|
|
|
|
__try
|
|
{
|
|
|
|
SmartcardDebug( DEBUG_TRACE, ("%s!UsbWrite Enter\n",DRIVER_NAME ));
|
|
|
|
DeviceObject = ReaderExtension->DeviceObject;
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
|
|
ulSize = sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
|
|
pUrb = ExAllocatePool( NonPagedPool,
|
|
ulSize );
|
|
|
|
if(pUrb == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
} else {
|
|
|
|
UsbBuildInterruptOrBulkTransferRequest(pUrb,
|
|
(USHORT)ulSize,
|
|
ReaderExtension->BulkOutHandle,
|
|
pData,
|
|
NULL,
|
|
DataLen,
|
|
USBD_SHORT_TRANSFER_OK,
|
|
NULL);
|
|
|
|
status = USBCallSync(DeviceExtension->LowerDeviceObject,
|
|
pUrb,
|
|
Timeout,
|
|
&DeviceExtension->RemoveLock);
|
|
ExFreePool( pUrb );
|
|
pUrb = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
__finally
|
|
{
|
|
if (pUrb) {
|
|
ExFreePool(pUrb);
|
|
pUrb = NULL;
|
|
}
|
|
|
|
SmartcardDebug( DEBUG_TRACE, ("%s!UsbWrite Exit : 0x%x\n",DRIVER_NAME, status ));
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
UsbRead(
|
|
PREADER_EXTENSION ReaderExtension,
|
|
PUCHAR pData,
|
|
ULONG DataLen,
|
|
LONG Timeout)
|
|
/*++
|
|
Description:
|
|
Read data from the USB bus
|
|
|
|
Arguments:
|
|
ReaderExtension context of call
|
|
pData ptr to data buffer
|
|
DataLen length of data buffer
|
|
pNBytes number of bytes returned
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS
|
|
STATUS_BUFFER_TOO_SMALL
|
|
STATUS_UNSUCCESSFUL
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PURB pUrb = NULL;
|
|
PDEVICE_OBJECT DeviceObject;
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
ULONG ulSize;
|
|
|
|
__try
|
|
{
|
|
|
|
SmartcardDebug( DEBUG_TRACE, ("%s!UsbRead Enter\n",DRIVER_NAME ));
|
|
|
|
DeviceObject = ReaderExtension->DeviceObject;
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
ulSize = sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
|
|
pUrb = ExAllocatePool( NonPagedPool,
|
|
ulSize );
|
|
|
|
if(pUrb == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
__leave;
|
|
|
|
} else {
|
|
|
|
UsbBuildInterruptOrBulkTransferRequest(pUrb,
|
|
(USHORT)ulSize,
|
|
ReaderExtension->BulkInHandle,
|
|
pData,
|
|
NULL,
|
|
DataLen,
|
|
USBD_SHORT_TRANSFER_OK,
|
|
NULL);
|
|
|
|
status = USBCallSync(DeviceExtension->LowerDeviceObject,
|
|
pUrb,
|
|
Timeout,
|
|
&DeviceExtension->RemoveLock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
__finally
|
|
{
|
|
|
|
if (pUrb) {
|
|
ExFreePool(pUrb);
|
|
pUrb = NULL;
|
|
}
|
|
SmartcardDebug( DEBUG_TRACE, ("%s!UsbRead Exit : 0x%x\n",DRIVER_NAME, status ));
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
UsbConfigureDevice(
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Initializes a given instance of the device on the USB and
|
|
selects and saves the configuration.
|
|
Also saves the Class Descriptor and the pipe handles.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to the physical device object for this instance of the device.
|
|
|
|
|
|
Return Value:
|
|
|
|
NT status code
|
|
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION pDevExt;
|
|
PSMARTCARD_EXTENSION smartcardExt;
|
|
PREADER_EXTENSION readerExt;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PURB pUrb = NULL;
|
|
ULONG ulSize;
|
|
PUSB_CONFIGURATION_DESCRIPTOR
|
|
ConfigurationDescriptor = NULL;
|
|
PUSB_COMMON_DESCRIPTOR
|
|
comDesc;
|
|
UINT i;
|
|
|
|
__try
|
|
{
|
|
|
|
SmartcardDebug( DEBUG_TRACE, ("%s!UsbConfigureDevice Enter\n",DRIVER_NAME ));
|
|
|
|
pDevExt = DeviceObject->DeviceExtension;
|
|
smartcardExt = &pDevExt->SmartcardExtension;
|
|
readerExt = smartcardExt->ReaderExtension;
|
|
|
|
pUrb = ExAllocatePool(NonPagedPool,
|
|
sizeof( struct _URB_CONTROL_DESCRIPTOR_REQUEST ));
|
|
|
|
if( pUrb == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
__leave;
|
|
|
|
}
|
|
|
|
//
|
|
// Get the device descriptor
|
|
//
|
|
pDevExt->DeviceDescriptor = ExAllocatePool(NonPagedPool,
|
|
sizeof(USB_DEVICE_DESCRIPTOR));
|
|
|
|
if(pDevExt->DeviceDescriptor == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
__leave;
|
|
|
|
}
|
|
|
|
UsbBuildGetDescriptorRequest(pUrb,
|
|
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
|
|
USB_DEVICE_DESCRIPTOR_TYPE,
|
|
0,
|
|
0,
|
|
pDevExt->DeviceDescriptor,
|
|
NULL,
|
|
sizeof(USB_DEVICE_DESCRIPTOR),
|
|
NULL);
|
|
|
|
// Send the urb to the USB driver
|
|
status = USBCallSync(pDevExt->LowerDeviceObject,
|
|
pUrb,
|
|
0,
|
|
&pDevExt->RemoveLock);
|
|
|
|
if(!NT_SUCCESS(status)) {
|
|
|
|
__leave;
|
|
|
|
}
|
|
|
|
|
|
// When USB_CONFIGURATION_DESCRIPTOR_TYPE is specified for DescriptorType
|
|
// in a call to UsbBuildGetDescriptorRequest(),
|
|
// all interface, endpoint, class-specific, and vendor-specific descriptors
|
|
// for the configuration also are retrieved.
|
|
// The caller must allocate a buffer large enough to hold all of this
|
|
// information or the data is truncated without error.
|
|
// Therefore the 'siz' set below is just a guess, and we may have to retry
|
|
ulSize = sizeof( USB_CONFIGURATION_DESCRIPTOR );
|
|
|
|
// We will break out of this 'retry loop' when UsbBuildGetDescriptorRequest()
|
|
// has a big enough deviceExtension->UsbConfigurationDescriptor buffer not to truncate
|
|
while( 1 ) {
|
|
|
|
ConfigurationDescriptor = ExAllocatePool( NonPagedPool, ulSize );
|
|
|
|
if(ConfigurationDescriptor == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
__leave;
|
|
|
|
}
|
|
|
|
UsbBuildGetDescriptorRequest(pUrb,
|
|
sizeof( struct _URB_CONTROL_DESCRIPTOR_REQUEST ),
|
|
USB_CONFIGURATION_DESCRIPTOR_TYPE,
|
|
0,
|
|
0,
|
|
ConfigurationDescriptor,
|
|
NULL,
|
|
ulSize,
|
|
NULL );
|
|
|
|
status = USBCallSync(pDevExt->LowerDeviceObject,
|
|
pUrb,
|
|
0,
|
|
&pDevExt->RemoveLock);
|
|
|
|
// if we got some data see if it was enough.
|
|
// NOTE: we may get an error in URB because of buffer overrun
|
|
if (pUrb->UrbControlDescriptorRequest.TransferBufferLength == 0 ||
|
|
ConfigurationDescriptor->wTotalLength <= ulSize) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ulSize = ConfigurationDescriptor->wTotalLength;
|
|
ExFreePool(ConfigurationDescriptor);
|
|
ConfigurationDescriptor = NULL;
|
|
|
|
}
|
|
|
|
//
|
|
// We have the configuration descriptor for the configuration we want.
|
|
// Now we issue the select configuration command to get
|
|
// the pipes associated with this configuration.
|
|
//
|
|
if(!NT_SUCCESS(status)) {
|
|
|
|
__leave;
|
|
|
|
}
|
|
|
|
status = UsbSelectInterfaces(DeviceObject,
|
|
ConfigurationDescriptor);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
__leave;
|
|
|
|
}
|
|
|
|
//
|
|
// Get the pipe handles from the interface
|
|
//
|
|
for (i = 0; i < pDevExt->Interface->NumberOfPipes; i++) {
|
|
|
|
if (pDevExt->Interface->Pipes[i].PipeType == USB_ENDPOINT_TYPE_INTERRUPT) {
|
|
|
|
readerExt->InterruptHandle = pDevExt->Interface->Pipes[i].PipeHandle;
|
|
readerExt->InterruptIndex = i;
|
|
|
|
} else if (pDevExt->Interface->Pipes[i].PipeType == USB_ENDPOINT_TYPE_BULK) {
|
|
|
|
if (pDevExt->Interface->Pipes[i].EndpointAddress & 0x80) { // Bulk-in pipe
|
|
|
|
readerExt->BulkInHandle = pDevExt->Interface->Pipes[i].PipeHandle;
|
|
readerExt->BulkInIndex = i;
|
|
|
|
} else { // Bulk-out pipe
|
|
|
|
readerExt->BulkOutHandle = pDevExt->Interface->Pipes[i].PipeHandle;
|
|
readerExt->BulkOutIndex = i;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get CCID Class Descriptor
|
|
//
|
|
|
|
comDesc = USBD_ParseDescriptors(ConfigurationDescriptor,
|
|
ConfigurationDescriptor->wTotalLength,
|
|
ConfigurationDescriptor,
|
|
CCID_CLASS_DESCRIPTOR_TYPE);
|
|
|
|
ASSERT(comDesc);
|
|
|
|
|
|
|
|
readerExt->ClassDescriptor = *((CCID_CLASS_DESCRIPTOR *) comDesc);
|
|
readerExt->ExchangeLevel = (WORD) (readerExt->ClassDescriptor.dwFeatures >> 16);
|
|
|
|
|
|
|
|
}
|
|
|
|
__finally
|
|
{
|
|
|
|
if( pUrb ) {
|
|
|
|
ExFreePool( pUrb );
|
|
pUrb = NULL;
|
|
|
|
}
|
|
|
|
if( ConfigurationDescriptor ) {
|
|
|
|
ExFreePool( ConfigurationDescriptor );
|
|
ConfigurationDescriptor = NULL;
|
|
|
|
}
|
|
|
|
if (!NT_SUCCESS(status) && pDevExt->DeviceDescriptor) {
|
|
|
|
ExFreePool(pDevExt->DeviceDescriptor);
|
|
pDevExt->DeviceDescriptor = NULL;
|
|
|
|
}
|
|
|
|
SmartcardDebug( DEBUG_TRACE, ("%s!UsbConfigureDevice Exit : 0x%x\n",DRIVER_NAME, status ));
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
UsbSelectInterfaces(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Initializes a USB reader with (possibly) multiple interfaces;
|
|
|
|
|
|
Arguments:
|
|
DeviceObject - pointer to the device object for this instance of the device.
|
|
|
|
ConfigurationDescriptor - pointer to the USB configuration
|
|
descriptor containing the interface and endpoint
|
|
descriptors.
|
|
|
|
|
|
Return Value:
|
|
|
|
NT status code
|
|
|
|
--*/
|
|
{
|
|
|
|
PDEVICE_EXTENSION pDevExt;
|
|
NTSTATUS status;
|
|
PURB pUrb = NULL;
|
|
USHORT usSize;
|
|
ULONG ulNumberOfInterfaces, i;
|
|
UCHAR ucNumberOfPipes,
|
|
ucAlternateSetting,
|
|
ucMyInterfaceNumber;
|
|
PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
|
|
PUSBD_INTERFACE_INFORMATION InterfaceObject;
|
|
USBD_INTERFACE_LIST_ENTRY interfaces[2];
|
|
|
|
|
|
__try
|
|
{
|
|
|
|
SmartcardDebug( DEBUG_TRACE, ("%s!UsbSelectInterfaces Enter\n",DRIVER_NAME ));
|
|
|
|
pDevExt = DeviceObject->DeviceExtension;
|
|
|
|
ASSERT(pDevExt->Interface == NULL);
|
|
|
|
//
|
|
// USBD_ParseConfigurationDescriptorEx searches a given configuration
|
|
// descriptor and returns a pointer to an interface that matches the
|
|
// given search criteria.
|
|
//
|
|
InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor,
|
|
ConfigurationDescriptor, //search from start of config descriptro
|
|
-1, // interface number not a criteria;
|
|
-1, // not interested in alternate setting here either
|
|
0x0b, // CCID Device Class
|
|
-1, // interface subclass not a criteria
|
|
-1); // interface protocol not a criteria
|
|
|
|
ASSERT( InterfaceDescriptor != NULL );
|
|
|
|
if (InterfaceDescriptor == NULL) {
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
__leave;
|
|
|
|
}
|
|
|
|
interfaces[0].InterfaceDescriptor = InterfaceDescriptor;
|
|
interfaces[1].InterfaceDescriptor = NULL;
|
|
|
|
pUrb = USBD_CreateConfigurationRequestEx(ConfigurationDescriptor,
|
|
interfaces);
|
|
|
|
if (pUrb == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
__leave;
|
|
|
|
}
|
|
ASSERT(pDevExt->LowerDeviceObject);
|
|
|
|
status = USBCallSync(pDevExt->LowerDeviceObject,
|
|
pUrb,
|
|
0,
|
|
&pDevExt->RemoveLock);
|
|
|
|
|
|
if(!NT_SUCCESS(status)) {
|
|
|
|
__leave;
|
|
|
|
}
|
|
|
|
// save a copy of the interface information returned
|
|
InterfaceObject = interfaces[0].Interface;
|
|
|
|
ASSERT(pDevExt->Interface == NULL);
|
|
pDevExt->Interface = ExAllocatePool(NonPagedPool,
|
|
InterfaceObject->Length);
|
|
|
|
if (pDevExt->Interface == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
__leave;
|
|
|
|
}
|
|
|
|
|
|
RtlCopyMemory(pDevExt->Interface,
|
|
InterfaceObject,
|
|
InterfaceObject->Length);
|
|
|
|
|
|
}
|
|
|
|
__finally
|
|
{
|
|
|
|
if (pUrb) {
|
|
|
|
ExFreePool(pUrb);
|
|
pUrb = NULL;
|
|
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
if (pDevExt->Interface) {
|
|
|
|
ExFreePool(pDevExt->Interface);
|
|
pDevExt->Interface = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SmartcardDebug( DEBUG_TRACE, ("%s!UsbSelectInterfaces Exit : 0x%x\n",DRIVER_NAME, status ));
|
|
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
GetStringDescriptor(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
UCHAR StringIndex,
|
|
PUCHAR StringBuffer,
|
|
PUSHORT StringLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Retrieves an ASCII string descriptor from the USB Reader
|
|
|
|
Arguments:
|
|
DeviceObject - The device object
|
|
StringIndex - The index of the string to be retrieved
|
|
StringBuffer - Caller allocated buffer to hold the string
|
|
StringLength - Length of the string
|
|
|
|
Return Value:
|
|
NT status value
|
|
|
|
--*/
|
|
{
|
|
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
USB_STRING_DESCRIPTOR
|
|
USD,
|
|
*pFullUSD = NULL;
|
|
PURB pUrb;
|
|
USHORT langID = 0x0409; // US English
|
|
PDEVICE_EXTENSION pDevExt;
|
|
UNICODE_STRING uString;
|
|
ANSI_STRING aString;
|
|
|
|
__try
|
|
{
|
|
|
|
SmartcardDebug( DEBUG_TRACE, ("%s!GetStringDescriptor Enter\n",DRIVER_NAME ));
|
|
|
|
pDevExt = DeviceObject->DeviceExtension;
|
|
|
|
pUrb = ExAllocatePool(NonPagedPool,
|
|
sizeof( struct _URB_CONTROL_DESCRIPTOR_REQUEST ));
|
|
|
|
if( pUrb == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
__leave;
|
|
|
|
}
|
|
|
|
UsbBuildGetDescriptorRequest(pUrb, // points to the URB to be filled in
|
|
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
|
|
USB_STRING_DESCRIPTOR_TYPE,
|
|
StringIndex, // index of string descriptor
|
|
langID, // language ID of string.
|
|
&USD, // points to a USB_STRING_DESCRIPTOR.
|
|
NULL,
|
|
sizeof(USB_STRING_DESCRIPTOR),
|
|
NULL);
|
|
|
|
status = USBCallSync(pDevExt->LowerDeviceObject,
|
|
pUrb,
|
|
0,
|
|
&pDevExt->RemoveLock);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
__leave;
|
|
|
|
}
|
|
|
|
pFullUSD = ExAllocatePool(NonPagedPool, USD.bLength);
|
|
|
|
UsbBuildGetDescriptorRequest(pUrb, // points to the URB to be filled in
|
|
sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
|
|
USB_STRING_DESCRIPTOR_TYPE,
|
|
StringIndex, // index of string descriptor
|
|
langID, // language ID of string
|
|
pFullUSD,
|
|
NULL,
|
|
USD.bLength,
|
|
NULL);
|
|
|
|
status = USBCallSync(pDevExt->LowerDeviceObject,
|
|
pUrb,
|
|
0,
|
|
&pDevExt->RemoveLock);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
__leave;
|
|
|
|
}
|
|
|
|
uString.MaximumLength = uString.Length = pFullUSD->bLength-2;
|
|
uString.Buffer = pFullUSD->bString;
|
|
|
|
status = RtlUnicodeStringToAnsiString(&aString,
|
|
&uString,
|
|
TRUE);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
__leave;
|
|
|
|
}
|
|
|
|
if (aString.Length > MAXIMUM_ATTR_STRING_LENGTH) {
|
|
aString.Length = MAXIMUM_ATTR_STRING_LENGTH;
|
|
aString.Buffer[aString.Length - 1] = 0;
|
|
}
|
|
|
|
RtlCopyMemory(StringBuffer, aString.Buffer, aString.Length);
|
|
|
|
*StringLength = aString.Length;
|
|
|
|
}
|
|
|
|
__finally
|
|
{
|
|
|
|
SmartcardDebug( DEBUG_TRACE, ("%s!GetStringDescriptor Exit : 0x%x\n",DRIVER_NAME, status ));
|
|
|
|
if (aString.Buffer) {
|
|
|
|
RtlFreeAnsiString(&aString);
|
|
|
|
}
|
|
|
|
if (pUrb) {
|
|
|
|
ExFreePool(pUrb);
|
|
pUrb = NULL;
|
|
|
|
}
|
|
|
|
if (pFullUSD) {
|
|
|
|
ExFreePool(pFullUSD);
|
|
pFullUSD = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|