#include "usbcom.h" #include "usbsc.h" #include #include #include 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; }