|
|
/**************************************************************************************************************************
* RWIR.C SigmaTel STIR4200 USB, but not NDIS, module ************************************************************************************************************************** * (C) Unpublished Copyright of Sigmatel, Inc. All Rights Reserved. * * * Created: 04/06/2000 * Version 0.9 * Edited: 04/24/2000 * Version 0.91 * Edited: 04/27/2000 * Version 0.92 * Edited: 05/01/2000 * Version 0.93 * Edited: 05/12/2000 * Version 0.94 * Edited: 05/19/2000 * Version 0.95 * Edited: 05/24/2000 * Version 0.96 * Edited: 08/22/2000 * Version 1.02 * Edited: 09/25/2000 * Version 1.10 * Edited: 11/09/2000 * Version 1.12 * * **************************************************************************************************************************/
#include <ndis.h>
#include <ntdef.h>
#include <windef.h>
#include <conio.h>
#include <stdio.h>
#include "usbdi.h"
#include "usbdlib.h"
#include "debug.h"
#include "ircommon.h"
#include "irusb.h"
#include "diags.h"
//
// Local function prototypes.
//
NTSTATUS ReadCustomerData( IN OUT PIR_DEVICE pThisDev );
/*****************************************************************************
* * Function: InitializeProcessing * * Synopsis: Initialize the driver processing (sending and receiving packets) functionality. * * Arguments: pThisDevice - pointer to current ir device object * InitPassiveThread - whether we must initialize the passive thread * * Returns: NDIS_STATUS_SUCCESS - if irp is successfully sent to USB * device object * NDIS_STATUS_RESOURCES - if mem can't be alloc'd * NDIS_STATUS_FAILURE - otherwise * * Notes: * * This routine must be called in IRQL PASSIVE_LEVEL. * *****************************************************************************/ NTSTATUS InitializeProcessing( IN OUT PIR_DEVICE pThisDev, IN BOOLEAN InitPassiveThread ) { NTSTATUS status = STATUS_SUCCESS;
DEBUGMSG(DBG_FUNC, ("+InitializeProcessing\n"));
if( InitPassiveThread ) { //
// Create a thread to run at IRQL PASSIVE_LEVEL.
//
status = PsCreateSystemThread( &pThisDev->hPassiveThread, (ACCESS_MASK)0L, NULL, NULL, NULL, PassiveLevelThread, pThisDev );
if( status != STATUS_SUCCESS ) { DEBUGMSG(DBG_ERROR, (" PsCreateSystemThread PassiveLevelThread failed. Returned 0x%.8x\n", status)); status = STATUS_INSUFFICIENT_RESOURCES; goto done; } }
//
// Create a thread to run at IRQL PASSIVE_LEVEL to be always receiving.
//
status = PsCreateSystemThread( &pThisDev->hPollingThread, (ACCESS_MASK)0L, NULL, NULL, NULL, PollingThread, pThisDev );
if( status != STATUS_SUCCESS ) { DEBUGMSG(DBG_ERROR, (" PsCreateSystemThread PollingThread failed. Returned 0x%.8x\n", status)); status = STATUS_INSUFFICIENT_RESOURCES; goto done; }
pThisDev->fProcessing = TRUE;
done: DEBUGMSG(DBG_FUNC, ("-InitializeProcessing\n")); return status; }
/*****************************************************************************
* * Function: ScheduleWorkItem * * Synopsis: Preapares a work item in such a way that the passive thread can process it * * Arguments: pThisDev - pointer to IR device * Callback - function to call * pInfoBuf - context for the call * InfoBufLen - length of the context * * Returns: TRUE if successful * FALSE otherwise * * Notes: * *****************************************************************************/ BOOLEAN ScheduleWorkItem( IN OUT PIR_DEVICE pThisDev, WORK_PROC Callback, IN PVOID pInfoBuf, ULONG InfoBufLen ) { int i; PIR_WORK_ITEM pWorkItem = NULL; BOOLEAN ItemScheduled = FALSE;
DEBUGMSG(DBG_FUNC, ("+ScheduleWorkItem\n"));
//
// Find an item that is available
//
for( i = 0; i < NUM_WORK_ITEMS; i++ ) { pWorkItem = &(pThisDev->WorkItems[i]);
//
// MS Security bug #554702
//
if( InterlockedCompareExchange( (PLONG)&pWorkItem->fInUse, TRUE, FALSE ) == FALSE ) { ItemScheduled = TRUE; break; } }
//
// Can't fail because can only have one set and one query pending,
// and no more than 8 packets to process
//
IRUSB_ASSERT( NULL != pWorkItem ); IRUSB_ASSERT( i < NUM_WORK_ITEMS );
InterlockedExchangePointer( &pWorkItem->pInfoBuf, pInfoBuf ); InterlockedExchange( (PLONG)&pWorkItem->InfoBufLen, InfoBufLen );
/*
** This interface was designed to use NdisScheduleWorkItem(), which ** would be good except that we're really only supposed to use that ** interface during startup and shutdown, due to the limited pool of ** threads available to service NdisScheduleWorkItem(). Therefore, ** instead of scheduling real work items, we simulate them, and use ** our own thread to process the calls. This also makes it easy to ** expand the size of our own thread pool, if we wish. ** ** Our version is slightly different from actual NDIS_WORK_ITEMs, ** because that is an NDIS 5.0 structure, and we want people to ** (at least temporarily) build this with NDIS 4.0 headers. */ InterlockedExchangePointer( (PVOID *)&pWorkItem->Callback, (PVOID)Callback );
/*
** Our worker thread checks this list for new jobs, whenever its event ** is signalled. */
// wake up worker thread
KeSetEvent( &pThisDev->EventPassiveThread, 0, FALSE );
DEBUGMSG(DBG_FUNC, ("-ScheduleWorkItem\n")); return ItemScheduled; }
/*****************************************************************************
* * Function: FreeWorkItem * * Synopsis: Sets the work item to the reusable state. * * Arguments: pItem - pointer to work item * * Returns: None * * Notes: * *****************************************************************************/ VOID FreeWorkItem( IN OUT PIR_WORK_ITEM pItem ) { InterlockedExchange( (PLONG)&pItem->fInUse, FALSE ); }
/*****************************************************************************
* * Function: MyIoCallDriver * * Synopsis: Calls a device driver and keeps track of the count * * Arguments: pThisDev - pointer to IR device * pDeviceObject - pointer to device driver to call * pIrp - pointer to Irp to submit * * Returns: NT status code * * Notes: * *****************************************************************************/ NTSTATUS MyIoCallDriver( IN PIR_DEVICE pThisDev, IN PDEVICE_OBJECT pDeviceObject, IN OUT PIRP pIrp ) { NTSTATUS ntStatus;
DEBUGMSG( DBG_FUNC,("+MyIoCallDriver\n "));
//
// We will track count of pending irps;
// We May later add logic to actually save array of pending irps
//
IrUsb_IncIoCount( pThisDev ); ntStatus = IoCallDriver( pDeviceObject, pIrp );
DEBUGMSG( DBG_FUNC,("+MyIoCallDriver\n ")); return ntStatus; }
/*****************************************************************************
* * Function: IrUsb_CallUSBD * * Synopsis: Passes a URB to the USBD class driver * The client device driver passes USB request block (URB) structures * to the class driver as a parameter in an IRP with Irp->MajorFunction * set to IRP_MJ_INTERNAL_DEVICE_CONTROL and the next IRP stack location * Parameters.DeviceIoControl.IoControlCode field set to * IOCTL_INTERNAL_USB_SUBMIT_URB. * * Arguments: pThisDev - pointer to the IR device * pUrb - pointer to an already-formatted Urb request block * * Returns: STATUS_SUCCESS if successful, * STATUS_UNSUCCESSFUL otherwise * * Notes: * *****************************************************************************/ NTSTATUS IrUsb_CallUSBD( IN PIR_DEVICE pThisDev, IN PURB pUrb ) { NTSTATUS ntStatus = STATUS_SUCCESS; PDEVICE_OBJECT pUrbTargetDev; PIO_STACK_LOCATION pNextStack;
DEBUGMSG( DBG_FUNC,("+IrUsb_CallUSBD\n"));
IRUSB_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); IRUSB_ASSERT( pThisDev ); IRUSB_ASSERT( NULL == ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb ); //shouldn't be multiple control calls pending
//
// issue a synchronous request (we'll wait )
//
pUrbTargetDev = pThisDev->pUsbDevObj;
IRUSB_ASSERT( pUrbTargetDev );
// make an irp sending to usbhub
((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb = IoAllocateIrp( (CCHAR)(pThisDev->pUsbDevObj->StackSize + 1), FALSE );
if( NULL == ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb ) { DEBUGMSG(DBG_ERR, (" IrUsb_CallUsbd failed to alloc IRP\n")); ntStatus = STATUS_INSUFFICIENT_RESOURCES; goto done; }
((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb->IoStatus.Status = STATUS_PENDING; ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb->IoStatus.Information = 0;
//
// Call the class driver to perform the operation. If the returned status
// is PENDING, wait for the request to complete.
//
pNextStack = IoGetNextIrpStackLocation( ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->IrpSubmitUrb ); IRUSB_ASSERT( pNextStack != NULL );
//
// pass the URB to the USB driver stack
//
pNextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; pNextStack->Parameters.Others.Argument1 = pUrb; pNextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine( ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->IrpSubmitUrb, // irp to use
UsbIoCompleteControl, // routine to call when irp is done
DEV_TO_CONTEXT(pThisDev), // context to pass routine
TRUE, // call on success
TRUE, // call on error
TRUE // call on cancel
);
KeClearEvent( &pThisDev->EventAsyncUrb );
ntStatus = MyIoCallDriver( pThisDev, pUrbTargetDev, ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb );
DEBUGMSG( DBG_OUT,(" IrUsb_CallUSBD () return from IoCallDriver USBD %x\n", ntStatus));
if( (ntStatus == STATUS_PENDING) || (ntStatus == STATUS_SUCCESS) ) { //
// wait, but dump out on timeout
//
if( ntStatus == STATUS_PENDING ) { ntStatus = MyKeWaitForSingleObject( pThisDev, &pThisDev->EventAsyncUrb, 0 );
if( ntStatus == STATUS_TIMEOUT ) { DEBUGMSG( DBG_ERR,(" IrUsb_CallUSBD () TIMED OUT! return from IoCallDriver USBD %x\n", ntStatus)); // MS Security recommendation - cannot cancel IRP.
} else { //
// Update the status to reflect the real return code
//
ntStatus = pThisDev->StatusControl; } } } else { DEBUGMSG( DBG_ERR, ("IrUsb_CallUSBD IoCallDriver FAILED(%x)\n",ntStatus)); }
DEBUGMSG( DBG_OUT,("IrUsb_CallUSBD () URB status = %x IRP status = %x\n", pUrb->UrbHeader.Status, ntStatus ));
done: ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->IrpSubmitUrb = NULL;
DEBUGCOND( DBG_ERR, !NT_SUCCESS( ntStatus ), (" exit IrUsb_CallUSBD FAILED (%x)\n", ntStatus)); DEBUGMSG( DBG_FUNC,("-IrUsb_CallUSBD\n"));
return ntStatus; }
/*****************************************************************************
* * Function: IrUsb_ResetUSBD * * Synopsis: Passes a URB to the USBD class driver, forcing the latter to reset or part * * Arguments: pThisDev - pointer to the IR device * ForceUnload - flag to perform a reset or an unload * * Returns: STATUS_SUCCESS if successful, * STATUS_UNSUCCESSFUL otherwise * * Notes: * *****************************************************************************/ NTSTATUS IrUsb_ResetUSBD( IN PIR_DEVICE pThisDev, BOOLEAN ForceUnload ) { NTSTATUS ntStatus; PDEVICE_OBJECT pUrbTargetDev; PIO_STACK_LOCATION pNextStack;
DEBUGMSG( DBG_FUNC,("+IrUsb_ResetUSBD\n"));
IRUSB_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); IRUSB_ASSERT( pThisDev ); IRUSB_ASSERT( NULL == ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb ); //shouldn't be multiple control calls pending
//
// issue a synchronous request (we'll wait )
//
pUrbTargetDev = pThisDev->pUsbDevObj;
IRUSB_ASSERT( pUrbTargetDev );
// make an irp sending to usbhub
((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb = IoAllocateIrp( (CCHAR)(pThisDev->pUsbDevObj->StackSize + 1), FALSE );
if( NULL == ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb ) { DEBUGMSG(DBG_ERR, (" IrUsb_ResetUSBD failed to alloc IRP\n")); ntStatus = STATUS_INSUFFICIENT_RESOURCES; goto done; }
((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb->IoStatus.Status = STATUS_PENDING; ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb->IoStatus.Information = 0;
//
// Call the class driver to perform the operation. If the returned status
// is PENDING, wait for the request to complete.
//
pNextStack = IoGetNextIrpStackLocation( ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->IrpSubmitUrb ); IRUSB_ASSERT( pNextStack != NULL );
//
// pass the URB to the USB driver stack
//
pNextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; if( ForceUnload ) pNextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_CYCLE_PORT; else pNextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_RESET_PORT;
IoSetCompletionRoutine( ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb, // irp to use
UsbIoCompleteControl, // routine to call when irp is done
DEV_TO_CONTEXT(pThisDev), // context to pass routine
TRUE, // call on success
TRUE, // call on error
TRUE // call on cancel
);
KeClearEvent( &pThisDev->EventAsyncUrb );
ntStatus = MyIoCallDriver( pThisDev, pUrbTargetDev, ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb );
DEBUGMSG( DBG_OUT,(" IrUsb_ResetUSBD () return from IoCallDriver USBD %x\n", ntStatus));
if( (ntStatus == STATUS_PENDING) || (ntStatus == STATUS_SUCCESS) ) { //
// wait, but dump out on timeout
//
if( ntStatus == STATUS_PENDING ) { ntStatus = MyKeWaitForSingleObject( pThisDev, &pThisDev->EventAsyncUrb, 0 );
if( ntStatus == STATUS_TIMEOUT ) { DEBUGMSG( DBG_ERR,(" IrUsb_ResetUSBD () TIMED OUT! return from IoCallDriver USBD %x\n", ntStatus)); // MS Security recommendation - cannot cancel IRP.
} else { //
// Update the status to reflect the real return code
//
ntStatus = pThisDev->StatusControl; } } } else { DEBUGMSG( DBG_ERR, ("IrUsb_ResetUSBD IoCallDriver FAILED(%x)\n",ntStatus)); }
done: ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->IrpSubmitUrb = NULL;
DEBUGCOND( DBG_ERR, !NT_SUCCESS( ntStatus ), (" exit IrUsb_ResetUSBD FAILED (%x)\n", ntStatus)); DEBUGMSG( DBG_FUNC,("-IrUsb_ResetUSBD\n"));
return ntStatus; }
/*****************************************************************************
* * Function: UsbIoCompleteControl * * Synopsis: General completetion routine just to insure cancel-ability of control calls * and keep track of pending irp count * * Arguments: pUsbDevObj - pointer to the device object which * completed the irp * pIrp - the irp which was completed by the device * object * Context - dev ext * * Returns: STATUS_MORE_PROCESSING_REQUIRED - allows the completion routine * (IofCompleteRequest) to stop working on the irp. * * *****************************************************************************/ NTSTATUS UsbIoCompleteControl( IN PDEVICE_OBJECT pUsbDevObj, IN PIRP pIrp, IN PVOID Context ) { PIR_DEVICE pThisDev; NTSTATUS status;
DEBUGMSG(DBG_FUNC, ("+UsbIoCompleteControl\n"));
//
// The context given to IoSetCompletionRoutine is simply the the ir
// device object pointer.
//
pThisDev = CONTEXT_TO_DEV( Context );
status = pIrp->IoStatus.Status;
switch( status ) { case STATUS_SUCCESS: DEBUGMSG(DBG_OUT, (" UsbIoCompleteControl STATUS_SUCCESS\n")); break; // STATUS_SUCCESS
case STATUS_TIMEOUT: DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_TIMEOUT\n")); break;
case STATUS_PENDING: DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_PENDING\n")); break;
case STATUS_DEVICE_DATA_ERROR: // can get during shutdown
DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_DEVICE_DATA_ERROR\n")); break;
case STATUS_UNSUCCESSFUL: DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_UNSUCCESSFUL\n")); break;
case STATUS_INSUFFICIENT_RESOURCES: DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_INSUFFICIENT_RESOURCES\n")); break;
case STATUS_INVALID_PARAMETER: DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_INVALID_PARAMETER\n")); break;
case STATUS_CANCELLED: DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_CANCELLED\n")); break;
case STATUS_DEVICE_NOT_CONNECTED: // can get during shutdown
DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_DEVICE_NOT_CONNECTED\n")); break;
case STATUS_DEVICE_POWER_FAILURE: // can get during shutdown
DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_DEVICE_POWER_FAILURE\n")); break;
default: DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl UNKNOWN WEIRD STATUS = 0x%x, dec %d\n",status,status )); break; }
IrUsb_DecIoCount( pThisDev ); //we track pending irp count
if( pIrp == ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb ) { IRUSB_ASSERT( NULL != ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb );
IoFreeIrp( ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb );
pThisDev->StatusControl = status; // save status because can't use irp after completion routine is hit!
KeSetEvent( &pThisDev->EventAsyncUrb, 0, FALSE ); //signal we're done
} else { DEBUGMSG( DBG_ERR, (" UsbIoCompleteControl UNKNOWN IRP\n")); IRUSB_ASSERT( 0 ); }
DEBUGCOND(DBG_ERR, !( NT_SUCCESS( status ) ), ("UsbIoCompleteControl BAD status = 0x%x\n", status));
DEBUGMSG(DBG_FUNC, ("-UsbIoCompleteControl\n"));
//
// We return STATUS_MORE_PROCESSING_REQUIRED so that the completion
// routine (IofCompleteRequest) will stop working on the irp.
//
return STATUS_MORE_PROCESSING_REQUIRED; }
/*****************************************************************************
* * Function: IrUsb_ConfigureDevice * * Synopsis: Initializes a given instance of the device on the USB and * selects and saves the configuration. * * Arguments: pThisDev - pointer to the IR device * * Returns: NT status code * * Notes: * *****************************************************************************/ NTSTATUS IrUsb_ConfigureDevice( IN OUT PIR_DEVICE pThisDev ) { NTSTATUS ntStatus; PURB pUrb; ULONG UrbSize;
DEBUGMSG(DBG_FUNC,("+IrUsb_ConfigureDevice()\n"));
IRUSB_ASSERT( ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor == NULL );
pUrb = (PURB)&((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->DescriptorUrb; //
// 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 'good guess', and we may have to retry
//
UrbSize = sizeof(USB_CONFIGURATION_DESCRIPTOR) + 512; // Store size, may need to free
//
// We will break out of this 'retry loop' when UsbBuildGetDescriptorRequest()
// has a big enough pThisDev->UsbConfigurationDescriptor buffer not to truncate
//
while( TRUE ) { ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor = MyMemAlloc( UrbSize );
if( !((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbConfigurationDescriptor ) { MyMemFree( pUrb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST) ); return STATUS_INSUFFICIENT_RESOURCES; }
UsbBuildGetDescriptorRequest( pUrb, (USHORT) sizeof( struct _URB_CONTROL_DESCRIPTOR_REQUEST ), USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0, ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor, NULL, UrbSize, NULL );
ntStatus = IrUsb_CallUSBD( pThisDev, pUrb ); //Get Usb Config Descriptor; done in main thread
DEBUGMSG(DBG_OUT,(" IrUsb_ConfigureDevice() Configuration Descriptor = %x, len %x\n", ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbConfigurationDescriptor, pUrb->UrbControlDescriptorRequest.TransferBufferLength)); //
// 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) && (((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor->wTotalLength > UrbSize) && NT_SUCCESS(ntStatus) ) { MyMemFree( ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor, UrbSize ); UrbSize = ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor->wTotalLength; ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor = NULL; } else { break; // we got it on the first try
}
} // end, while (retry loop )
IRUSB_ASSERT( ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbConfigurationDescriptor );
if( !NT_SUCCESS(ntStatus) ) { DEBUGMSG( DBG_ERR,(" IrUsb_ConfigureDevice() Get Config Descriptor FAILURE (%x)\n", ntStatus)); goto done; }
//
// 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.
//
ntStatus = IrUsb_SelectInterface( pThisDev, ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor );
if( !NT_SUCCESS(ntStatus) ) { DEBUGMSG( DBG_ERR,(" IrUsb_ConfigureDevice() IrUsb_SelectInterface() FAILURE (%x)\n", ntStatus)); } done: DEBUGMSG(DBG_FUNC,("-IrUsb_ConfigureDevice (%x)\n", ntStatus)); return ntStatus; }
/*****************************************************************************
* * Function: IrUsb_SelectInterface * * Synopsis: Initializes the ST4200 interfaces; * This minidriver only supports one interface (with multiple endpoints). * * Arguments: pThisDev - pointer to IR device * pConfigurationDescriptor - pointer to USB configuration descriptor * * Returns: NT status code * * Notes: * *****************************************************************************/ NTSTATUS IrUsb_SelectInterface( IN OUT PIR_DEVICE pThisDev, IN PUSB_CONFIGURATION_DESCRIPTOR pConfigurationDescriptor ) { NTSTATUS ntStatus; PURB pUrb = NULL; ULONG i; USHORT DescriptorSize; PUSB_INTERFACE_DESCRIPTOR pInterfaceDescriptor = NULL; PUSBD_INTERFACE_INFORMATION pInterface = NULL;
DEBUGMSG(DBG_FUNC,("+IrUsb_SelectInterface\n"));
IRUSB_ASSERT( pConfigurationDescriptor != NULL ); IRUSB_ASSERT( pThisDev != NULL ); //
// IrUsb driver only supports one interface, we must parse
// the configuration descriptor for the interface
// and remember the pipes. Needs to be aupdated
//
pUrb = USBD_CreateConfigurationRequest( pConfigurationDescriptor, &DescriptorSize );
if( pUrb ) { DEBUGMSG(DBG_OUT,(" USBD_CreateConfigurationRequest created the urb\n"));
//
// USBD_ParseConfigurationDescriptorEx searches a given configuration
// descriptor and returns a pointer to an interface that matches the
// given search criteria. We only support one interface on this device
//
pInterfaceDescriptor = USBD_ParseConfigurationDescriptorEx( pConfigurationDescriptor, pConfigurationDescriptor, // search from start of config descriptor
-1, // interface number not a criteria; we only support one interface
-1, // not interested in alternate setting here either
-1, // interface class not a criteria
-1, // interface subclass not a criteria
-1 // interface protocol not a criteria
);
if( !pInterfaceDescriptor ) { DEBUGMSG(DBG_ERR,("IrUsb_SelectInterface() ParseConfigurationDescriptorEx() failed\n returning STATUS_INSUFFICIENT_RESOURCES\n")); //
// don't call the MyMemFree since the buffer was
// alloced by USBD_CreateConfigurationRequest, not MyMemAlloc()
//
ExFreePool( pUrb ); return STATUS_INSUFFICIENT_RESOURCES; }
pInterface = &pUrb->UrbSelectConfiguration.Interface;
DEBUGMSG(DBG_OUT,(" After USBD_CreateConfigurationRequest, before UsbBuildSelectConfigurationRequest\n" )); //
// Now prepare the pipes
//
for( i=0; i<pInterface->NumberOfPipes; i++ ) { //
// perform any pipe initialization here; mainly set max xfer size
// But Watch out! USB may change these when you select the interface;
// In general USB doesn;t seem to like differing max transfer sizes on the pipes
//
pInterface->Pipes[i].MaximumTransferSize = STIR4200_FIFO_SIZE; }
//
// Initialize the device with the pipe structure found
//
UsbBuildSelectConfigurationRequest( pUrb, DescriptorSize, pConfigurationDescriptor ); ntStatus = IrUsb_CallUSBD( pThisDev, pUrb ); //select config; done in main thread
((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationHandle = pUrb->UrbSelectConfiguration.ConfigurationHandle; } else { DEBUGMSG(DBG_ERR,(" IrUsb_SelectInterface() USBD_CreateConfigurationRequest() failed\n returning STATUS_INSUFFICIENT_RESOURCES\n")); return STATUS_INSUFFICIENT_RESOURCES; }
if( NT_SUCCESS(ntStatus) ) { //
// Save the configuration handle for this device
//
((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbConfigurationHandle = pUrb->UrbSelectConfiguration.ConfigurationHandle;
if( NULL == ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbInterface ) { ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbInterface = MyMemAlloc( pInterface->Length ); }
if( NULL != ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbInterface ) { ULONG j;
//
// save a copy of the interface information returned
//
RtlCopyMemory( ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface, pInterface, pInterface->Length );
//
// Dump the interface to the debugger
//
DEBUGMSG(DBG_FUNC,("---------After Select Config \n")); DEBUGMSG(DBG_FUNC,("NumberOfPipes 0x%x\n", ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface->NumberOfPipes)); DEBUGMSG(DBG_FUNC,("Length 0x%x\n", ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface->Length)); DEBUGMSG(DBG_FUNC,("Alt Setting 0x%x\n", ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface->AlternateSetting)); DEBUGMSG(DBG_FUNC,("Interface Number 0x%x\n", ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface->InterfaceNumber)); DEBUGMSG(DBG_FUNC,("Class, subclass, protocol 0x%x 0x%x 0x%x\n", ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface->Class, ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface->SubClass, ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface->Protocol));
//
// Find our Bulk in and out pipes, save their handles, Dump the pipe info
//
for( j=0; j<pInterface->NumberOfPipes; j++ ) { PUSBD_PIPE_INFORMATION pipeInformation;
pipeInformation = &((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface->Pipes[j];
//
// Find the Bulk In and Out pipes ( these are probably the only two pipes )
//
if( UsbdPipeTypeBulk == pipeInformation->PipeType ) { // endpoint address with bit 0x80 set are input pipes, else output
if( USB_ENDPOINT_DIRECTION_IN( pipeInformation->EndpointAddress ) ) { pThisDev->BulkInPipeHandle = pipeInformation->PipeHandle; }
if( USB_ENDPOINT_DIRECTION_OUT( pipeInformation->EndpointAddress ) ) { pThisDev->BulkOutPipeHandle = pipeInformation->PipeHandle; }
}
DEBUGMSG(DBG_FUNC,("---------\n")); DEBUGMSG(DBG_FUNC,("PipeType 0x%x\n", pipeInformation->PipeType)); DEBUGMSG(DBG_FUNC,("EndpointAddress 0x%x\n", pipeInformation->EndpointAddress)); DEBUGMSG(DBG_FUNC,("MaxPacketSize 0x%x\n", pipeInformation->MaximumPacketSize)); DEBUGMSG(DBG_FUNC,("Interval 0x%x\n", pipeInformation->Interval)); DEBUGMSG(DBG_FUNC,("Handle 0x%x\n", pipeInformation->PipeHandle)); DEBUGMSG(DBG_FUNC,("MaximumTransferSize 0x%x\n", pipeInformation->MaximumTransferSize)); }
DEBUGMSG(DBG_FUNC,("---------\n")); } }
//
// we better have found input and output bulk pipes!
//
IRUSB_ASSERT( pThisDev->BulkInPipeHandle && pThisDev->BulkOutPipeHandle ); if( !pThisDev->BulkInPipeHandle || !pThisDev->BulkOutPipeHandle ) { DEBUGMSG(DBG_ERR,("IrUsb_SelectInterface() failed to get pipes\n")); ntStatus = STATUS_UNSUCCESSFUL; }
if( pUrb ) { //
// don't call the MyMemFree since the buffer was
// alloced by USBD_CreateConfigurationRequest, not MyMemAlloc()
//
ExFreePool( pUrb ); }
DEBUGMSG(DBG_FUNC,("-IrUsb_SelectInterface (%x)\n", ntStatus));
return ntStatus; }
/*****************************************************************************
* * Function: IrUsb_StartDevice * * Synopsis: Initializes a given instance of the device on the USB. * USB client drivers such as us set up URBs (USB Request Packets) to send requests * to the host controller driver (HCD). The URB structure defines a format for all * possible commands that can be sent to a USB device. * Here, we request the device descriptor and store it, and configure the device. * * Arguments: pThisDev - pointer to IR device * * Returns: NT status code * * Notes: * *****************************************************************************/ NTSTATUS IrUsb_StartDevice( IN PIR_DEVICE pThisDev ) { NTSTATUS ntStatus; PUSB_DEVICE_DESCRIPTOR pDeviceDescriptor = NULL; PURB pUrb; ULONG DescriptorSize;
DEBUGMSG( DBG_FUNC, ("+IrUsb_StartDevice()\n"));
pUrb = MyMemAlloc( sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
DEBUGCOND( DBG_ERR,!pUrb, (" IrUsb_StartDevice() FAILED MyMemAlloc() for URB\n"));
if( pUrb ) { DescriptorSize = sizeof( USB_DEVICE_DESCRIPTOR );
pDeviceDescriptor = MyMemAlloc( DescriptorSize );
DEBUGCOND( DBG_ERR, !pDeviceDescriptor, (" IrUsb_StartDevice() FAILED MyMemAlloc() for deviceDescriptor\n"));
if( pDeviceDescriptor ) { //
// Get all the USB descriptor data
//
UsbBuildGetDescriptorRequest( pUrb, (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, pDeviceDescriptor, NULL, DescriptorSize, NULL );
ntStatus = IrUsb_CallUSBD( pThisDev, pUrb ); // build get descripttor req; main thread
DEBUGCOND( DBG_ERR, !NT_SUCCESS(ntStatus), (" IrUsb_StartDevice() FAILED IrUsb_CallUSBD (pThisDev, pUrb)\n"));
if( NT_SUCCESS(ntStatus) ) { DEBUGMSG( DBG_FUNC,("Device Descriptor = %x, len %x\n", pDeviceDescriptor, pUrb->UrbControlDescriptorRequest.TransferBufferLength));
DEBUGMSG( DBG_FUNC,("IR Dongle Device Descriptor:\n")); DEBUGMSG( DBG_FUNC,("-------------------------\n")); DEBUGMSG( DBG_FUNC,("bLength %d\n", pDeviceDescriptor->bLength)); DEBUGMSG( DBG_FUNC,("bDescriptorType 0x%x\n", pDeviceDescriptor->bDescriptorType)); DEBUGMSG( DBG_FUNC,("bcdUSB 0x%x\n", pDeviceDescriptor->bcdUSB)); DEBUGMSG( DBG_FUNC,("bDeviceClass 0x%x\n", pDeviceDescriptor->bDeviceClass)); DEBUGMSG( DBG_FUNC,("bDeviceSubClass 0x%x\n", pDeviceDescriptor->bDeviceSubClass)); DEBUGMSG( DBG_FUNC,("bDeviceProtocol 0x%x\n", pDeviceDescriptor->bDeviceProtocol)); DEBUGMSG( DBG_FUNC,("bMaxPacketSize0 0x%x\n", pDeviceDescriptor->bMaxPacketSize0)); DEBUGMSG( DBG_FUNC,("idVendor 0x%x\n", pDeviceDescriptor->idVendor)); DEBUGMSG( DBG_FUNC,("idProduct 0x%x\n", pDeviceDescriptor->idProduct)); DEBUGMSG( DBG_FUNC,("bcdDevice 0x%x\n", pDeviceDescriptor->bcdDevice)); DEBUGMSG( DBG_FUNC,("iManufacturer 0x%x\n", pDeviceDescriptor->iManufacturer)); DEBUGMSG( DBG_FUNC,("iProduct 0x%x\n", pDeviceDescriptor->iProduct)); DEBUGMSG( DBG_FUNC,("iSerialNumber 0x%x\n", pDeviceDescriptor->iSerialNumber)); DEBUGMSG( DBG_FUNC,("bNumConfigurations 0x%x\n", pDeviceDescriptor->bNumConfigurations)); } } else { // if we got here we failed to allocate deviceDescriptor
ntStatus = STATUS_INSUFFICIENT_RESOURCES; }
if( NT_SUCCESS(ntStatus) ) { ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbDeviceDescriptor = pDeviceDescriptor; pThisDev->IdVendor = ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbDeviceDescriptor->idVendor; }
MyMemFree( pUrb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST) );
} else { //
// if we got here we failed to allocate the urb
//
ntStatus = STATUS_INSUFFICIENT_RESOURCES; }
//
// Now that we have the descriptors, we can configure the device
//
if( NT_SUCCESS(ntStatus) ) { ntStatus = IrUsb_ConfigureDevice( pThisDev );
DEBUGCOND( DBG_ERR,!NT_SUCCESS(ntStatus),(" IrUsb_StartDevice IrUsb_ConfigureDevice() FAILURE (%x)\n", ntStatus)); }
//
// Read all the initial registers
//
if( NT_SUCCESS(ntStatus) ) { ntStatus = St4200ReadRegisters( pThisDev, 0, STIR4200_MAX_REG ); DEBUGCOND( DBG_ERR,!NT_SUCCESS(ntStatus),(" IrUsb_StartDevice St4200ReadRegisters() FAILURE (%x)\n", ntStatus)); }
//
// Get the current chip revision
//
if( NT_SUCCESS(ntStatus) ) { pThisDev->ChipRevision = pThisDev->StIrTranceiver.SensitivityReg & STIR4200_SENS_IDMASK; } //
// Next we must get the Class-Specific Descriptor
// Get the IR USB dongle's Class-Specific descriptor; this has many
// characterisitics we must tell Ndis about, such as supported speeds,
// BOFS required, rate sniff-supported flag, turnaround time, window size,
// data size.
//
if( NT_SUCCESS(ntStatus) ) { ntStatus = IrUsb_GetDongleCaps( pThisDev ); if( !NT_SUCCESS( ntStatus ) ) { DEBUGMSG( DBG_ERR,(" IrUsb_ConfigureDevice() IrUsb_GetClassDescriptor() FAILURE (%x)\n", ntStatus)); } else { // fill out dongleCaps struct from class-specific descriptor info
IrUsb_SetDongleCaps( pThisDev ); } }
//
// Read customer data block.
//
if( NT_SUCCESS(ntStatus) && !pThisDev->CustomerDataRead) { ntStatus = ReadCustomerData(pThisDev); DEBUGCOND( DBG_ERR,!NT_SUCCESS(ntStatus),(" IrUsb_StartDevice ReadCustomerData() FAILURE (%x)\n", ntStatus)); pThisDev->CustomerDataRead = TRUE; // one chance only
}
//
// Set the initial speed
//
if( NT_SUCCESS(ntStatus) ) { ntStatus = St4200SetSpeed( pThisDev ); DEBUGCOND( DBG_ERR,!NT_SUCCESS(ntStatus),(" IrUsb_StartDevice St4200SetSpeed() FAILURE (%x)\n", ntStatus)); }
//
// All set and ready to roll
//
if( NT_SUCCESS(ntStatus) ) { pThisDev->fDeviceStarted = TRUE; }
DEBUGMSG( DBG_FUNC, ("-IrUsb_StartDevice (%x)\n", ntStatus)); return ntStatus; }
/*****************************************************************************
* * Function: IrUsb_StopDevice * * Synopsis: Stops a given instance of a ST4200 device on the USB. * We basically just tell USB this device is now 'unconfigured' * * Arguments: pThisDev - pointer to IR device * * Returns: NT status code * * Notes: * *****************************************************************************/ NTSTATUS IrUsb_StopDevice( IN PIR_DEVICE pThisDev ) { NTSTATUS ntStatus = STATUS_SUCCESS; PURB pUrb; ULONG DescriptorSize;
DEBUGMSG( DBG_FUNC,("+IrUsb_StopDevice\n"));
//
// Send the select configuration urb with a NULL pointer for the configuration
// handle. This closes the configuration and puts the device in the 'unconfigured'
// state.
//
DescriptorSize = sizeof( struct _URB_SELECT_CONFIGURATION ); pUrb = MyMemAlloc( DescriptorSize );
if( pUrb ) { UsbBuildSelectConfigurationRequest( pUrb, (USHORT)DescriptorSize, NULL );
ntStatus = IrUsb_CallUSBD( pThisDev, pUrb ); // build select config req; main thread
DEBUGCOND( DBG_ERR, !NT_SUCCESS(ntStatus),(" IrUsb_StopDevice() FAILURE Configuration Closed status = %x usb status = %x.\n", ntStatus, pUrb->UrbHeader.Status)); DEBUGCOND( DBG_WARN, NT_SUCCESS(ntStatus),(" IrUsb_StopDevice() SUCCESS Configuration Closed status = %x usb status = %x.\n", ntStatus, pUrb->UrbHeader.Status));
MyMemFree( pUrb, sizeof(struct _URB_SELECT_CONFIGURATION) ); } else { ntStatus = STATUS_INSUFFICIENT_RESOURCES; }
DEBUGMSG( DBG_FUNC,("-IrUsb_StopDevice (%x) \n ", ntStatus)); return ntStatus; }
/*****************************************************************************
* * Function: ResetPipeCallback * * Synopsis: Callback for resetting a pipe * * Arguments: pWorkItem - pointer to the reset work item * * Returns: NTSTATUS * * Notes: * *****************************************************************************/ NTSTATUS ResetPipeCallback ( IN PIR_WORK_ITEM pWorkItem ) { PIR_DEVICE pThisDev; HANDLE Pipe; NTSTATUS Status = STATUS_SUCCESS;
pThisDev = (PIR_DEVICE)pWorkItem->pIrDevice; Pipe = (HANDLE)pWorkItem->pInfoBuf;
if( Pipe == pThisDev->BulkInPipeHandle ) { IRUSB_ASSERT( TRUE == pThisDev->fPendingReadClearStall ); // MS Security recommendation - not safe to cancel pending IRPs
Status = IrUsb_ResetPipe( pThisDev, Pipe );
InterlockedExchange( &pThisDev->fPendingReadClearStall, FALSE ); } else if( Pipe == pThisDev->BulkOutPipeHandle ) { IRUSB_ASSERT( TRUE == pThisDev->fPendingWriteClearStall );
// MS Security recommendation - not safe to cancel pending IRPs
Status = IrUsb_ResetPipe( pThisDev, Pipe );
InterlockedExchange( &pThisDev->fPendingWriteClearStall, FALSE ); } #if DBG
else { IRUSB_ASSERT( 0 ); } #endif
FreeWorkItem( pWorkItem );
return Status; }
/*****************************************************************************
* * Function: IrUsb_ResetPipe * * Synopsis: This will reset the host pipe to Data0 and should also reset the device * endpoint to Data0 for Bulk and Interrupt pipes by issuing a Clear_Feature * Endpoint_Stall to the device endpoint. * * Arguments: pThisDev - pointer to IR device * Pipe - handle to the pipe to reset * * Returns: NTSTATUS * * Notes: Must be called at IRQL PASSIVE_LEVEL * *****************************************************************************/ NTSTATUS IrUsb_ResetPipe ( IN PIR_DEVICE pThisDev, IN HANDLE Pipe ) { PURB pUrb; NTSTATUS ntStatus;
DEBUGMSG(DBG_ERR, ("+IrUsb_ResetPipe()\n")); //
// Allocate URB for RESET_PIPE request
//
pUrb = MyMemAlloc( sizeof(struct _URB_PIPE_REQUEST) );
if( pUrb != NULL ) { NdisZeroMemory( pUrb, sizeof (struct _URB_PIPE_REQUEST) ); //
// Initialize RESET_PIPE request URB
//
pUrb->UrbHeader.Length = sizeof (struct _URB_PIPE_REQUEST); pUrb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE; pUrb->UrbPipeRequest.PipeHandle = (USBD_PIPE_HANDLE)Pipe; //
// Submit RESET_PIPE request URB
//
ntStatus = IrUsb_CallUSBD( pThisDev, pUrb );
DEBUGCOND(DBG_ERR, !NT_SUCCESS(ntStatus), (" IrUsb_ResetPipe RESET PIPE FAILED \n")); DEBUGCOND(DBG_ERR, NT_SUCCESS(ntStatus), (" IrUsb_ResetPipe RESET PIPE SUCCEEDED \n")); //
// Done with URB for RESET_PIPE request, free urb
//
MyMemFree( pUrb, sizeof(struct _URB_PIPE_REQUEST) ); } else { ntStatus = STATUS_INSUFFICIENT_RESOURCES; }
DEBUGMSG(DBG_ERR, ("-IrUsb_ResetPipe %08X\n", ntStatus)); return ntStatus; }
/*****************************************************************************
* * Function: MyKeWaitForSingleObject * * Synopsis: Wait with a timeout in a loop * so we will never hang if we are asked to halt/reset the driver while * pollingthread is waiting for something. * * Arguments: pThisDev - pointer to IR device * pEventWaitingFor - pointer to event to wait for * timeout100ns - timeout * * Returns: NT status code * * Notes: THIS FUNCTION MUST BE RE-ENTERABLE! * *****************************************************************************/ NTSTATUS MyKeWaitForSingleObject( IN PIR_DEVICE pThisDev, IN PVOID pEventWaitingFor, LONGLONG timeout100ns ) { NTSTATUS status = STATUS_SUCCESS; LARGE_INTEGER Timeout;
DEBUGMSG( DBG_FUNC,("+MyKeWaitForSingleObject\n ")); if( timeout100ns ) { //
//if a non-zero timeout was passed in, use it
//
Timeout.QuadPart = - ( timeout100ns );
} else { // MS Security recommendation - changed back to 3 seconds because
// timeout now for sure disables all processing.
Timeout.QuadPart = -10000 * 1000 * 3; // default to 3 second relative delay
//Timeout.QuadPart = -10000 * 1000; // default to 1 second relative delay
}
status = KeWaitForSingleObject( //keep this as standard wait
pEventWaitingFor, Suspended, KernelMode, FALSE, &Timeout );
DEBUGCOND( DBG_OUT,( STATUS_TIMEOUT == status ),(" MyKeWaitForSingleObject TIMED OUT\n")); DEBUGCOND( DBG_OUT,( STATUS_ALERTED == status ),(" MyKeWaitForSingleObject ALERTED\n")); DEBUGCOND( DBG_OUT,( STATUS_USER_APC == status ),(" MyKeWaitForSingleObject USER APC\n"));
DEBUGMSG( DBG_FUNC,("-MyKeWaitForSingleObject (%x)\n", status)); return status; }
/*****************************************************************************
* * Function: PassiveLevelThread * * Synopsis: Thread running at IRQL PASSIVE_LEVEL. * * Arguments: Context - pointer to IR device * * Returns: None * * Notes: * * Any work item that can be called must be serialized. * i.e. when IrUsbReset is called, NDIS will not make any other * requests of the miniport until NdisMResetComplete is called. * *****************************************************************************/ VOID PassiveLevelThread( IN OUT PVOID Context ) { LARGE_INTEGER Timeout; int i; PIR_WORK_ITEM pWorkItem; PIR_DEVICE pThisDev = (PIR_DEVICE)Context; NTSTATUS Status=STATUS_SUCCESS;
DEBUGMSG(DBG_WARN, ("+PassiveLevelThread\n")); // change to FUNC later?
DEBUGMSG(DBG_ERR, (" PassiveLevelThread: Starting\n"));
KeSetPriorityThread( KeGetCurrentThread(), LOW_REALTIME_PRIORITY+1 ); Timeout.QuadPart = -10000 * 1000 * 3; // 3 second relative delay
while ( !pThisDev->fKillPassiveLevelThread ) { Status=STATUS_SUCCESS;
//
// The eventPassiveThread is an auto-clearing event, so
// we don't need to reset the event.
//
KeWaitForSingleObject( //keep this as standard wait
&pThisDev->EventPassiveThread, Suspended, KernelMode, FALSE, &Timeout );
for( i = 0; i < NUM_WORK_ITEMS; i++ ) { if( pThisDev->WorkItems[i].fInUse ) { Status = pThisDev->WorkItems[i].Callback( &(pThisDev->WorkItems[i]) );
if (Status == STATUS_TIMEOUT) break; } } } // while !fKill
// MS Security recommendation - cannot cancel IRP on timeout, so we must exit
if (Status == STATUS_TIMEOUT) { DEBUGMSG(DBG_ERR, (" PassiveLevelThread exits on TIMEOUT error\n")); IRUSB_ASSERT(0); }
DEBUGMSG(DBG_ERR, (" PassiveLevelThread: HALT\n"));
ZwClose(pThisDev->hPassiveThread); pThisDev->hPassiveThread = NULL;
DEBUGMSG(DBG_WARN, ("-PassiveLevelThread\n")); // change to FUNC later?
PsTerminateSystemThread( STATUS_SUCCESS ); }
/*****************************************************************************
* * Function: PollingThread * * Synopsis: Thread running at IRQL PASSIVE_LEVEL. * * Arguments: Context - Pointer to IR device * * Returns: None * * Algorithm: * 1) Call USBD for input data; * 2) Call USBD for output data or sets a new speed; * * Notes: * *****************************************************************************/ VOID PollingThread( IN OUT PVOID Context ) { PIR_DEVICE pThisDev = (PIR_DEVICE)Context; NTSTATUS Status = STATUS_SUCCESS; PLIST_ENTRY pListEntry;
DEBUGMSG(DBG_WARN, ("+PollingThread\n")); // change to FUNC later?
DEBUGMSG(DBG_ERR, (" PollingThread: Starting\n"));
#ifdef LOW_PRIORITY_POLL
//KeSetPriorityThread( KeGetCurrentThread(), LOW_REALTIME_PRIORITY );
#else
KeSetPriorityThread( KeGetCurrentThread(), HIGH_PRIORITY ); #endif
DEBUGMSG(DBG_ERR, (" PollingThread priority=%d\n", KeQueryPriorityThread(KeGetCurrentThread())));
//
// MS Security bug #539259
// Note: all requests that end up sending URBs either called at init time only
// or serialized through this thread. Therefore, it is safe to reuse the
// EventSyncUrb event.
//
while( !pThisDev->fKillPollingThread ) { if( pThisDev->fProcessing ) { ULONG FifoCount; PIRUSB_CONTEXT pThisContext; BOOLEAN SentPackets;
//
// First process the receive
//
Status = ReceivePreprocessFifo( pThisDev, &FifoCount ); if( Status != STATUS_SUCCESS ) { //
// There is a USB error, stop banging on the chip for a while
//
NdisMSleep( 1000 ); } else if( FifoCount ) { //
// Indicate that we are now receiving
//
InterlockedExchange( (PLONG)&pThisDev->fCurrentlyReceiving, TRUE );
//
// Tell the protocol that the media is now busy
//
if( pThisDev->fIndicatedMediaBusy == FALSE ) { InterlockedExchange( &pThisDev->fMediaBusy, TRUE ); InterlockedExchange( &pThisDev->fIndicatedMediaBusy, TRUE ); IndicateMediaBusy( pThisDev ); }
ReceiveProcessFifoData( pThisDev ); } else if( pThisDev->currentSpeed == SPEED_9600 ) { NdisMSleep( 10*1000 ); }
if (Status == STATUS_TIMEOUT) break;
//
// Then process the contexts that are ready
//
SentPackets = FALSE; do { Status = STATUS_SUCCESS; pListEntry = ExInterlockedRemoveHeadList( &pThisDev->SendBuiltQueue, &pThisDev->SendLock ); if( pListEntry ) { InterlockedDecrement( &pThisDev->SendBuiltCount ); pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry ); switch( pThisContext->ContextType ) { //
// Packet to send
//
case CONTEXT_NDIS_PACKET: //
// make sure the receive is cleaned
//
ReceiveResetPointers( pThisDev );
//
// Send
//
Status = SendPreprocessedPacketSend( pThisDev, pThisContext ); if (Status != STATUS_TIMEOUT) { if( (pThisDev->ChipRevision >= CHIP_REVISION_7) && (pThisDev->currentSpeed > MAX_MIR_SPEED) ) { SentPackets = TRUE; Status = SendCheckForOverflow( pThisDev ); } else { Status = SendWaitCompletion( pThisDev ); } } break; //
// Set the new speed
//
case CONTEXT_SET_SPEED: //
// make sure the receive is cleaned
//
ReceiveResetPointers( pThisDev );
//
// Force completion and set
//
if( SentPackets ) { SentPackets = TRUE; Status = SendWaitCompletion( pThisDev ); }
if (Status == STATUS_TIMEOUT) break;
if( !pThisDev->fPendingHalt && !pThisDev->fPendingReset ) { DEBUGMSG( DBG_ERR, (" Changing speed to: %d\n", pThisDev->linkSpeedInfo->BitsPerSec)); Status = St4200SetSpeed( pThisDev ); InterlockedExchange( (PLONG)&pThisDev->currentSpeed, pThisDev->linkSpeedInfo->BitsPerSec ); #if defined(DIAGS)
if( !pThisDev->DiagsActive ) #endif
MyNdisMSetInformationComplete( pThisDev, STATUS_SUCCESS ); } else { DEBUGMSG( DBG_ERR , (" St4200SetSpeed DUMPING OUT on TIMEOUT,HALT OR RESET\n")); #if defined(DIAGS)
if( !pThisDev->DiagsActive ) #endif
MyNdisMSetInformationComplete( pThisDev, STATUS_UNSUCCESSFUL ); } ExInterlockedInsertTailList( &pThisDev->SendAvailableQueue, &pThisContext->ListEntry, &pThisDev->SendLock ); InterlockedIncrement( &pThisDev->SendAvailableCount ); break; #if defined(DIAGS)
//
// Diagnostic state is enabled
//
case CONTEXT_DIAGS_ENABLE: Diags_CompleteEnable( pThisDev, pThisContext ); break; //
// Diagnostic read of the registers
//
case CONTEXT_DIAGS_READ_REGISTERS: Status = Diags_CompleteReadRegisters( pThisDev, pThisContext ); break; //
// Diagnostic write of the registers
//
case CONTEXT_DIAGS_WRITE_REGISTER: Status = Diags_CompleteWriteRegister( pThisDev, pThisContext ); break; //
// Diagnostic bulk out
//
case CONTEXT_DIAGS_BULK_OUT: Status = Diags_Bulk( pThisDev, pThisContext, TRUE ); break; //
// Diagnostic bulk in
//
case CONTEXT_DIAGS_BULK_IN: Status = Diags_Bulk( pThisDev, pThisContext, FALSE ); break; //
// Diagnostic bulk out
//
case CONTEXT_DIAGS_SEND: Status = Diags_Send( pThisDev, pThisContext ); break; #endif
} } if (Status == STATUS_TIMEOUT) break;
} while( pListEntry ); if (Status == STATUS_TIMEOUT) break;
//
// Force to wait
//
if( SentPackets ) { Status = SendWaitCompletion( pThisDev ); if (Status == STATUS_TIMEOUT) break; }
} // end if
else { NdisMSleep( 10*1000 ); } } // end while
// MS Security recommendation - cannot cancel IRP on timeout, so we must exit
if (Status == STATUS_TIMEOUT) { DEBUGMSG(DBG_ERR, (" PollingThread exits on TIMEOUT error\n")); IRUSB_ASSERT(0); }
DEBUGMSG(DBG_ERR, (" PollingThread: HALT\n"));
ZwClose(pThisDev->hPollingThread); pThisDev->hPollingThread = NULL; pThisDev->fProcessing = FALSE;
//
// this thread will finish here
// if the terminate flag is TRUE
//
DEBUGMSG(DBG_WARN, ("-PollingThread\n")); // change to FUNC later?
PsTerminateSystemThread( STATUS_SUCCESS ); }
/*****************************************************************************
* * Function: AllocUsbInfo * * Synopsis: Allocates the USB portion of the device context. * * Arguments: pThisDev - pointer to current ir device object * * Returns: TRUE - Success * FALSE - Failure * * Notes: * *****************************************************************************/ BOOLEAN AllocUsbInfo( IN OUT PIR_DEVICE pThisDev ) { UINT Size = sizeof( IRUSB_USB_INFO );
pThisDev->pUsbInfo = MyMemAlloc( Size );
if( NULL == pThisDev->pUsbInfo ) { return FALSE; }
NdisZeroMemory( (PVOID)pThisDev->pUsbInfo, Size ); return TRUE; }
/*****************************************************************************
* * Function: AllocUsbInfo * * Synopsis: Deallocates the USB portion of the device context. * * Arguments: pThisDev - pointer to current ir device object * * Returns: None * * Notes: * *****************************************************************************/ VOID FreeUsbInfo( IN OUT PIR_DEVICE pThisDev ) { if( NULL != pThisDev->pUsbInfo ) { //
// Free device descriptor structure
//
if ( ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbDeviceDescriptor ) { MyMemFree( ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbDeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR) ); }
//
// Free up the Usb Interface structure
//
if( ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbInterface ) { MyMemFree( ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbInterface, ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbInterface->Length ); }
//
// free up the USB config discriptor
//
if( ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbConfigurationDescriptor ) { MyMemFree( ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor, sizeof(USB_CONFIGURATION_DESCRIPTOR) + 512 ); }
MyMemFree( (PVOID)pThisDev->pUsbInfo, sizeof(IRUSB_USB_INFO) ); } }
/*****************************************************************************
* * Function: IrUsb_InitSendStructures * * Synopsis: Allocates the send stuff * * Arguments: pThisDev - pointer to IR device * * Returns: TRUE if successful * FALSE otherwise * * Notes: * *****************************************************************************/ BOOLEAN IrUsb_InitSendStructures( IN OUT PIR_DEVICE pThisDev ) {
BOOLEAN InitResult = TRUE; PUCHAR pThisContext; PIRUSB_CONTEXT pCont; int i;
DEBUGMSG(DBG_FUNC, ("+IrUsb_InitSendStructures\n")); //
// Initialize a notification event for signalling PassiveLevelThread.
//
KeInitializeEvent( &pThisDev->EventPassiveThread, SynchronizationEvent, // auto-clearing event
FALSE // event initially non-signalled
);
#if defined(DIAGS)
KeInitializeEvent( &pThisDev->EventDiags, NotificationEvent, // non-auto-clearing event
FALSE // event initially non-signalled
); #endif
((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb = NULL;
//
// allocate our send context structs
//
pThisDev->pSendContexts = MyMemAlloc( NUM_SEND_CONTEXTS * sizeof(IRUSB_CONTEXT) );
if( NULL == pThisDev->pSendContexts ) { InitResult = FALSE; goto done; }
NdisZeroMemory( pThisDev->pSendContexts, NUM_SEND_CONTEXTS * sizeof(IRUSB_CONTEXT) );
//
// Initialize list for holding pending read requests
//
InitializeListHead( &pThisDev->SendAvailableQueue ); InitializeListHead( &pThisDev->SendBuiltQueue ); InitializeListHead( &pThisDev->SendPendingQueue ); KeInitializeSpinLock( &pThisDev->SendLock );
//
// Prepare the read/write specific queue
//
InitializeListHead( &pThisDev->ReadWritePendingQueue );
pThisContext = pThisDev->pSendContexts; for ( i= 0; i < NUM_SEND_CONTEXTS; i++ ) { pCont = (PIRUSB_CONTEXT)pThisContext;
pCont->pThisDev = pThisDev;
// Also put in the available queue
ExInterlockedInsertTailList( &pThisDev->SendAvailableQueue, &pCont->ListEntry, &pThisDev->SendLock );
pThisContext += sizeof( IRUSB_CONTEXT );
} // for
// MS Security issue - don't reuse urb
// Single URB allocate removed.
//
// Send buffers
//
pThisDev->pBuffer = MyMemAlloc( MAX_IRDA_DATA_SIZE ); if( NULL == pThisDev->pBuffer ) { DEBUGMSG(DBG_ERR, (" IrUsb_InitSendStructures failed to alloc info buf\n"));
InitResult = FALSE; goto done; }
pThisDev->pStagingBuffer = MyMemAlloc( MAX_TOTAL_SIZE_WITH_ALL_HEADERS + FAST_IR_FCS_SIZE ); if( NULL == pThisDev->pStagingBuffer ) { DEBUGMSG(DBG_ERR, (" IrUsb_InitSendStructures failed to alloc staging buf\n"));
InitResult = FALSE; goto done; }
//
// and send counts
//
pThisDev->SendAvailableCount = NUM_SEND_CONTEXTS; pThisDev->SendBuiltCount = 0; pThisDev->SendPendingCount = 0; pThisDev->ReadWritePendingCount = 0; pThisDev->SendFifoCount = 0;
done: DEBUGMSG(DBG_FUNC, ("-IrUsb_InitSendStructures\n")); return InitResult; }
/*****************************************************************************
* * Function: IrUsb_FreeSendStructures * * Synopsis: Deallocates the send stuff * * Arguments: pThisDev - pointer to IR device * * Returns: None * * Notes: * *****************************************************************************/ VOID IrUsb_FreeSendStructures( IN OUT PIR_DEVICE pThisDev ) { DEBUGMSG(DBG_FUNC, ("+IrUsb_FreeSendStructures\n"));
if( NULL != pThisDev->pSendContexts ) { MyMemFree( pThisDev->pSendContexts, NUM_SEND_CONTEXTS * sizeof(IRUSB_CONTEXT) ); pThisDev->pSendContexts = NULL;
}
if( NULL != pThisDev->pBuffer ) { MyMemFree( pThisDev->pBuffer, MAX_IRDA_DATA_SIZE ); pThisDev->pBuffer = NULL; }
if( NULL != pThisDev->pStagingBuffer ) { MyMemFree( pThisDev->pStagingBuffer, MAX_TOTAL_SIZE_WITH_ALL_HEADERS + FAST_IR_FCS_SIZE ); pThisDev->pStagingBuffer = NULL; }
DEBUGMSG(DBG_FUNC, ("-IrUsb_FreeSendStructures\n")); }
/*****************************************************************************
* * Function: IrUsb_PrepareSetSpeed * * Synopsis: Prepares a context to set the new speed * * Arguments: pThisDev - pointer to IR device * * Returns: None * * Notes: * *****************************************************************************/ VOID IrUsb_PrepareSetSpeed( IN OUT PIR_DEVICE pThisDev ) { PIRUSB_CONTEXT pThisContext; PLIST_ENTRY pListEntry;
DEBUGMSG( DBG_FUNC, ("+IrUsb_PrepareSetSpeed()\n"));
//
// Get a context to queue
//
pListEntry = ExInterlockedRemoveHeadList( &pThisDev->SendAvailableQueue, &pThisDev->SendLock );
if( NULL == pListEntry ) { //
// This must not happen
//
DEBUGMSG(DBG_ERR, (" IrUsb_PrepareSetSpeed failed to find a free context struct\n")); IRUSB_ASSERT( 0 ); goto done; } InterlockedDecrement( &pThisDev->SendAvailableCount );
pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry ); pThisContext->ContextType = CONTEXT_SET_SPEED; //
// Queue the context and nothing else has to be done
//
ExInterlockedInsertTailList( &pThisDev->SendBuiltQueue, &pThisContext->ListEntry, &pThisDev->SendLock ); InterlockedIncrement( &pThisDev->SendBuiltCount );
done: DEBUGMSG( DBG_FUNC, ("-IrUsb_PrepareSetSpeed()\n")); }
/*****************************************************************************
* * Function: IrUsb_IncIoCount * * Synopsis: Tracks count of pending irps * * Arguments: pThisDev - pointer to IR device * * Returns: None * * Notes: * *****************************************************************************/ VOID IrUsb_IncIoCount( IN OUT PIR_DEVICE pThisDev ) { InterlockedIncrement( &pThisDev->PendingIrpCount ); }
/*****************************************************************************
* * Function: IrUsb_DecIoCount * * Synopsis: Tracks count of pending irps * * Arguments: pThisDev - pointer to IR device * * Returns: None * * Notes: * *****************************************************************************/ VOID IrUsb_DecIoCount( IN OUT PIR_DEVICE pThisDev ) { InterlockedDecrement( &pThisDev->PendingIrpCount ); }
/*****************************************************************************
* * Function: AllocXferUrb * * Synopsis: Allocates the transfer Urb for a USB transaction * * Arguments: None * * Returns: Pointer to Urb * * Notes: * *****************************************************************************/ PVOID AllocXferUrb( VOID ) { return MyMemAlloc( sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER) ); }
/*****************************************************************************
* * Function: FreeXferUrb * * Synopsis: Deallocates the transfer Urb for a USB transaction * * Arguments: pUrb - pointer to Urb * * Returns: Pointer to Urb * * Notes: * *****************************************************************************/ VOID FreeXferUrb( IN OUT PVOID pUrb ) { MyMemFree( pUrb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER) ); }
/*****************************************************************************
* * Function: ReadCustomerData * * Synopsis: Read customer data block from chip. * * Arguments: Pointer to device. * * Returns: STATUS_SUCCESS if any data is read. * * Notes: * *****************************************************************************/ NTSTATUS ReadCustomerData( IN OUT PIR_DEVICE pThisDev ) { #define SIZE_FAKE_SEND 6
UCHAR pDataSend[SIZE_FAKE_SEND]={0x55,0xaa,SIZE_FAKE_SEND-4,0x00,0xff,0xff}; BAUDRATE_INFO *SavedLinkSpeedInfo; UCHAR SavedSensitivity; UCHAR SavedControlReg; NTSTATUS ntStatus;
//
// Set the speed to 9600.
//
SavedLinkSpeedInfo = pThisDev->linkSpeedInfo; pThisDev->linkSpeedInfo = &supportedBaudRateTable[BAUDRATE_9600]; ntStatus = St4200SetSpeed( pThisDev ); DEBUGCOND( DBG_ERR,!NT_SUCCESS(ntStatus),(" ReadCustomerData set speed FAILURE (%x)\n", ntStatus)); pThisDev->linkSpeedInfo = SavedLinkSpeedInfo; //
// Set the sensitivity.
//
SavedSensitivity = pThisDev->StIrTranceiver.SensitivityReg; pThisDev->StIrTranceiver.SensitivityReg = 0x0f; ntStatus = St4200WriteRegister(pThisDev, STIR4200_SENSITIVITY_REG); DEBUGCOND( DBG_ERR,!NT_SUCCESS(ntStatus),(" ReadCustomerData set sensitivity FAILURE (%x)\n", ntStatus)); pThisDev->StIrTranceiver.SensitivityReg = SavedSensitivity;
//
// Select RXSLOW.
//
SavedControlReg = pThisDev->StIrTranceiver.ControlReg; pThisDev->StIrTranceiver.ControlReg |= STIR4200_CTRL_RXSLOW; ntStatus = St4200WriteRegister(pThisDev, STIR4200_CONTROL_REG); DEBUGCOND( DBG_ERR,!NT_SUCCESS(ntStatus),(" ReadCustomerData set rxslow FAILURE (%x)\n", ntStatus)); pThisDev->StIrTranceiver.ControlReg = SavedControlReg;
//
// Send a bulk-out transfer to trigger the device to make the customer data available.
//
ntStatus = St4200FakeSend( pThisDev, pDataSend, SIZE_FAKE_SEND ); if (!NT_SUCCESS(ntStatus)) return ntStatus; //
// Wait until uP fills up usb pipe with customer data, about 1 millisecond per byte.
//
NdisMSleep( 1000*STIR4200_CUST_DATA_SIZE );
//
// Issue bulk read to get all the customer data.
//
ntStatus = St4200FakeReceive( pThisDev, pThisDev->pCustomerData, STIR4200_CUST_DATA_SIZE ); if (!NT_SUCCESS(ntStatus)) return ntStatus;
#if 0
#if DBG
{ int i; for (i = 0; i < STIR4200_CUST_DATA_SIZE; i++) { DbgPrint("%02x ", pThisDev->pCustomerData[i]); if (((i+1) % 16) == 0) DbgPrint("\n"); } DbgPrint("\n\n"); } #endif
#endif
//
// If data starts with 7e7e then it is valid customer data and we will
// send it to the app when requested. Otherwise clear the customer data
// buffer.
//
if (!(pThisDev->pCustomerData[0] == 0x7e && pThisDev->pCustomerData[1] == 0x7e)) NdisZeroMemory(pThisDev->pCustomerData, STIR4200_CUST_DATA_SIZE);
return STATUS_SUCCESS; }
|