Windows2003-3790/drivers/smartcrd/usbccid/usbcom.c
2020-09-30 16:53:55 +02:00

712 lines
20 KiB
C

#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;
}