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.
2269 lines
64 KiB
2269 lines
64 KiB
/**************************************************************************************************************************
|
|
* 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;
|
|
}
|