📄 cusbintf.cpp
字号:
/*+++ *******************************************************************\
*
* Copyright and Disclaimer:
*
* ---------------------------------------------------------------
* This software is provided "AS IS" without warranty of any kind,
* either expressed or implied, including but not limited to the
* implied warranties of noninfringement, merchantability and/or
* fitness for a particular purpose.
* ---------------------------------------------------------------
*
* Copyright (c) 2008 Conexant Systems, Inc.
* All rights reserved.
*
\******************************************************************* ---*/
extern "C"
{
#include <wdm.h>
#include <usb.h>
#include <usbdrivr.h>
}
#include <windef.h>
#include "cusbintf.h"
#include "debug.h"
#include "device.h"
/////////////////////////////////////////////////////////////////////////////
//
//
CUsbInterface::CUsbInterface(PDEVICE_OBJECT pdo):
_pdo(pdo),
_p_configs(NULL),
_config_index(0),
_p_interfaces(NULL),
_config_handle(NULL),
_error_occured(FALSE),
_is_initialized(FALSE),
_is_descriptor_available(FALSE),
_bSurpriseRemoval(FALSE),
_p_irp(NULL),
_p_cmd_urb(NULL)
{
KeInitializeEvent(&_event, NotificationEvent, 0);
KeInitializeMutex(&_mutex, 1);
KeInitializeEvent(&_usb_config_event, NotificationEvent, TRUE);
KeClearEvent(&_usb_config_event);
#if DBG
USBD_VERSION_INFORMATION version_info;
RtlZeroMemory(&version_info, sizeof(USBD_VERSION_INFORMATION));
USBD_GetUSBDIVersion(&version_info);
DbgLogInfo(("CUsbInterface::CUsbInterface() USBDI_Version(0x%x) Supported_USB_Version(0x%x)\n",
version_info.USBDI_Version,
version_info.Supported_USB_Version));
#endif
}
/////////////////////////////////////////////////////////////////////////////////////////
CUsbInterface::~CUsbInterface()
{
if (_is_initialized)
{
Release();
}
UnConfigDevice();
if(_p_cmd_urb)
{
delete _p_cmd_urb;
_p_cmd_urb = NULL;
}
if (_p_irp)
{
IoFreeIrp(_p_irp);
_p_irp = NULL;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
//CUsbInterface::InitDevice()
//
// Note that actual initialization occurs in ConfigDevice(), called from the constructor
//
NTSTATUS CUsbInterface::InitDevice()
{
if (_is_initialized)
{
DbgLogError(("CUsbInterface::InitDevice() Already Initialized. Skipping...\n"));
return STATUS_SUCCESS;
}
if (!_p_irp)
{
_p_irp = IoAllocateIrp(_pdo->StackSize, FALSE);
if (!_p_irp)
{
DbgLogError(("CUsbInterface::InitDevice() Unable to allocate IRP\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
}
if(!_p_cmd_urb)
{
//Allocate a URB
_p_cmd_urb = (PURB) new _URB_BULK_OR_INTERRUPT_TRANSFER;
if(!_p_cmd_urb)
{
DbgLogError(("CUsbInterface::InitDevice() Unable to allocate command URB\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
}
NTSTATUS status = ConfigDevice();
DbgLogInfo(("CUsbInterface::ConfigDevice() Status(0x%x)\n", status));
if (!NT_SUCCESS(status))
{
DbgLogError(("CUsbInterface::InitDevice() Unable to ConfigDevice\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
if(!_p_configs || !_p_interfaces)
{
DbgLogError((
"CUsbInterface::InitDevice() Failed _p_configs(0x%p) _p_interfaces(0x%p)\n",
_p_configs,
_p_interfaces));
return STATUS_UNSUCCESSFUL;
}
// clear error condition
_error_occured = FALSE;
_is_initialized = TRUE;
return STATUS_SUCCESS;
}
/////////////////////////////////////////////////////////////////////////////////////////
//CUsbInterface::waitForConfigDevice
//
NTSTATUS CUsbInterface::waitForConfigDevice()
{
//Wait for the acknowledge interrupt
LARGE_INTEGER timeout;
timeout.QuadPart = -10000*10000; //10000 ms timeout
DbgLogInfo(("CUsbInterface: waitForConfigDevice: Starting Usb Config Device wait Event\n"));
NTSTATUS status = KeWaitForSingleObject(
&_usb_config_event,
Executive,
KernelMode,
TRUE,
&timeout);
return status;
}
/////////////////////////////////////////////////////////////////////////////////////////
//CUsbInterface::setUsbConfigEvent
//
void CUsbInterface::setUsbConfigEvent()
{
DbgLogInfo(("CUsbInterface: setUsbConfigEvent: Clearing Usb Config Device wait Event\n"));
//Set the event to notify the waiting thread that the command is compelte
KeSetEvent(
&_usb_config_event,
IO_NO_INCREMENT,
FALSE);
}
/////////////////////////////////////////////////////////////////////////////////////////
//CUsbInterface::Release
//
// This performs the opposite task of InitDevice
//
NTSTATUS CUsbInterface::Release(void)
{
_is_initialized = FALSE;
_is_descriptor_available = FALSE;
KeClearEvent(&_usb_config_event);
return (STATUS_SUCCESS);
}
/////////////////////////////////////////////////////////////////////////////////////////
// CUsbInterface::UsbCall_GSPN
//
// Send a URB to the USB bus driver and wait for it to complete. The function name
// is not very descriptive.
//
NTSTATUS CUsbInterface::UsbCall_GSPN(URB* p_urb)
{
NTSTATUS status = STATUS_SUCCESS;
DWORD function_id = p_urb->UrbHeader.Function;
// if device is surprise removed then we should not allow any call further below
if(_bSurpriseRemoval)
{
DbgLogError(("CUsbInterface::UsbCall_GSPN() : Device Surprise Removal!!\n"));
return (STATUS_DEVICE_DATA_ERROR);
}
//Exit early if an error occured in an earlier transfer.
if (_error_occured)
{
if ((URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER == function_id) ||
(URB_FUNCTION_ISOCH_TRANSFER == function_id) ||
(URB_FUNCTION_CONTROL_TRANSFER == function_id) ||
(URB_FUNCTION_RESET_PIPE == function_id)
)
{
DbgLogError(( "CUsbInterface::UsbCall_GSPN() : Func(%d) Rejecting, device IO error occured before!!\n", function_id ));
switch(function_id)
{
case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
if(UsbGetStatusPipe(0, 0) != STATUS_SUCCESS)
{
// abort command pipe in
status = UsbAbortPipe(0,0); //PIPE_CMD_IN
if (!NT_SUCCESS(status))
{
DbgLogError(("CUsbInterface::UsbCall_GSPN, Failed to abort cmd IN pipe %x\n", status));
}
// reset command pipe in
status = UsbResetPipe(0,0); //PIPE_CMD_IN
if (!NT_SUCCESS(status))
{
DbgLogError(("CUsbInterface::UsbCall_GSPN, Failed to reset cmd IN pipe %x\n", status));
}
}
if(UsbGetStatusPipe(1, 0) != STATUS_SUCCESS)
{
// abort command pipe OUT
status = UsbAbortPipe(1,0); //PIPE_CMD_OUT
if (!NT_SUCCESS(status))
{
DbgLogError(("CUsbInterface::UsbCall_GSPN, Failed to abort cmd OUT pipe %x\n", status));
}
// reset command pipe OUT
status = UsbResetPipe(1,0); //PIPE_CMD_OUT
if (!NT_SUCCESS(status))
{
DbgLogError(("CUsbInterface::UsbCall_GSPN, Failed to reset cmd OUT pipe %x\n", status));
}
}
break;
case URB_FUNCTION_ISOCH_TRANSFER:
if(UsbGetStatusPipe(2, 0) != STATUS_SUCCESS)
{
// abort MPEG data pipe
status = UsbAbortPipe(2,0); //PIPE_STREAMING
if (!NT_SUCCESS(status))
{
DbgLogError(("CUsbInterface::UsbCall_GSPN, Failed to abort firmware download pipe %x\n", status));
}
// reset MPEG data pipe
status = UsbResetPipe(2,0); //PIPE_STREAMING
if (!NT_SUCCESS(status))
{
DbgLogError(("CUsbInterface::UsbCall_GSPN, Failed to reset firmware download pipe %x\n", status));
}
}
break;
case URB_FUNCTION_CONTROL_TRANSFER:
case URB_FUNCTION_RESET_PIPE:
default:
status = ResetDevice();
}
if (!NT_SUCCESS(status))
{
if( (status == STATUS_DEVICE_NOT_CONNECTED) || (status == STATUS_NO_SUCH_DEVICE) )
{
// if the device status is not connected, set removal flag
DbgLogError(("CUsbInterface::UsbCall_GSPN, Setting surprise removal flag\n"));
_bSurpriseRemoval = TRUE;
}
status = ResetDevice();
if (!NT_SUCCESS(status))
{
DbgLogError(("CUsbInterface::UsbCall_GSPN, Failed to reset Device %x\n", status));
return (STATUS_DEVICE_DATA_ERROR);
}
DbgLogInfo(("CUsbInterface::UsbCall_GSPN, Successfully reset the pipes and Device\n"));
_error_occured = FALSE;
}
else
{
DbgLogInfo(("CUsbInterface::UsbCall_GSPN, Successfully reset the pipes\n"));
_error_occured = FALSE;
}
}
else
{
DbgLogError(("CUsbInterface::UsbCall_GSPN() : Func(%d) Allowed, device IO error occured before!!\n", function_id));
}
}
// send command and wait until it completes
status = SendCmdAndWait(p_urb);
return (status);
}
/////////////////////////////////////////////////////////////////////////////////////////
//CUsbInterface::EzUsb_VendorRequest
//
// Send a vendor-specific request to an EZ-USB device (FX2 is an EZ-USB device)
//
NTSTATUS CUsbInterface::Ezusb_VendorRequest(PVENDOR_REQUEST_IN p_request)
{
// if device is surprise removed then we should not allow any call further below
if(_bSurpriseRemoval)
{
DbgLogError(("CUsbInterface::UsbCall_GSPN() : Device Surprise Removal!!\n"));
return (STATUS_DEVICE_DATA_ERROR);
}
//Allocate a URB for the transfer
PURB p_urb = (PURB) new _URB_CONTROL_VENDOR_OR_CLASS_REQUEST;
if(!p_urb)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
//Zero the URB and the buffer
RtlZeroMemory(p_urb, sizeof(_URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
//Fill in the URB
p_urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
p_urb->UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
p_urb->UrbControlVendorClassRequest.TransferBufferLength = p_request->wLength;
p_urb->UrbControlVendorClassRequest.TransferBufferMDL = NULL;
p_urb->UrbControlVendorClassRequest.Request = p_request->bRequest;
p_urb->UrbControlVendorClassRequest.Value = p_request->wValue;
p_urb->UrbControlVendorClassRequest.Index = p_request->wIndex;
p_urb->UrbControlVendorClassRequest.TransferBuffer = p_request->pBuff;
if(p_request->direction)
{
p_urb->UrbControlVendorClassRequest.TransferFlags = USBD_TRANSFER_DIRECTION_IN;
}
//Send the URB
NTSTATUS status = UsbCall_GSPN(p_urb);
delete p_urb;
return status;
}
/////////////////////////////////////////////////////////////////////////////////////////
//CUsbInterface::UsbSendMcCmd
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -