?? rwusb.c
字號:
/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
rwusb.c
Abstract:
USB device driver .
This module contains code pertaining to IRPS and URBS and USB, but no
ndis-specific code
Environment:
kernel mode only
Notes:
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
PURPOSE.
Copyright (c) 1999 Microsoft Corporation. All Rights Reserved.
Revision History:
--*/
#include <ndis.h>
#include <ntdef.h>
#include <windef.h>
#include "usbdi.h"
#include "usbdlib.h"
#include "debug.h"
#include "common.h"
#include "HPNA_2k.h"
/*****************************************************************************
*
* Function: InitializeReceive
*
* Synopsis: Initialize the receive functionality.
*
* Arguments: Deviceice - pointer to current usb device object
*
* 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
*
* Algorithm:
* 1) Set the receive timeout to READ_INTERVAL_TIMEOUT_MSEC.
* 2) Initialize our rcvInfo and associate info for our
* receive state machine.
* 3) Build an IRP_MJ_READ irp to send to the USB device
* object, and set the completion(or timeout) routine
* to UsbIoCompleteRead.
* Notes:
*
* This routine must be called in IRQL PASSIVE_LEVEL.
*
*****************************************************************************/
NTSTATUS
InitializeReceive(
IN PUSB_DEVICE Device
)
{
NTSTATUS status = STATUS_SUCCESS;
DEBUGMSG(DBG_FUNC, ("+InitializeReceive\n"));
//
// Create a thread to run at IRQL PASSIVE_LEVEL.
//
status = PsCreateSystemThread(
&Device->hPassiveThread,
(ACCESS_MASK) 0L,
NULL,
NULL,
NULL,
PassiveLevelThread,
Device
);
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(
&Device->hPollingThread,
(ACCESS_MASK) 0L,
NULL,
NULL,
NULL,
PollingThread,
Device
);
if (status != STATUS_SUCCESS)
{
DEBUGMSG(DBG_ERROR, ("PsCreateSystemThread PollingThread failed. Returned 0x%.8x\n", status));
status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
Device->fReceiving = TRUE;
done:
return status;
}
NTSTATUS StartUsbRead(IN PUSB_DEVICE Device)
/*++
Routine Description:
Allocates an irp and calls USBD.
Arguments:
Device - Current usb device.
Return Value:
STATUS_INSUFFICIENT_RESOURCES or result of IoCallDriver
--*/
{
ULONG siz;
ULONG length;
PURB urb = NULL;
PDEVICE_OBJECT urbTargetDev;
PIO_STACK_LOCATION nextStack;
NTSTATUS timeStat = STATUS_UNSUCCESSFUL;
PMDL mdl;
PRCV_BUFFER pRecBuf;
UINT Index;
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
siz = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
length = MAX_PACKET_SIZE;
// Find a free buffer and set the state to PENDING;
pRecBuf = GetRcvBuf( Device, &Index, STATE_PENDING );
if ( !pRecBuf)
{
//
// no buffers available; drop it
//
timeStat = STATUS_UNSUCCESSFUL;
goto done;
}
if( TRUE == Device->fPendingReadClearStall ) {
timeStat = STATUS_UNSUCCESSFUL;
goto done;
}
urb = ((PURB) pRecBuf->Urb);
// Build our URB for USBD
NdisZeroMemory(urb, siz);
ASSERT(Device->BulkInPipeHandle);
//
// Now that we have created the urb, we will send a
// request to the USB device object.
//
KeClearEvent(&pRecBuf->Event);
urbTargetDev = Device->pUsbDevObj;
ASSERT(urbTargetDev);
//
// Now that we have created the urb, we will send a
// request to the USB device object.
//
urbTargetDev = Device->pUsbDevObj;
// make an irp sending to usbhub
pRecBuf->Irp = IoAllocateIrp( (CCHAR)(Device->pUsbDevObj->StackSize +1), FALSE );
if ( NULL == pRecBuf->Irp )
{
timeStat = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
((PIRP) pRecBuf->Irp)->IoStatus.Status = STATUS_NOT_SUPPORTED;
((PIRP) pRecBuf->Irp)->IoStatus.Information = 0;
// Build our URB for USBD
urb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT) siz;
urb->UrbBulkOrInterruptTransfer.Hdr.Function =
URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
urb->UrbBulkOrInterruptTransfer.PipeHandle =
Device->BulkInPipeHandle;
urb->UrbBulkOrInterruptTransfer.TransferFlags =
USBD_TRANSFER_DIRECTION_IN ;
// short packet is not treated as an error.
urb->UrbBulkOrInterruptTransfer.TransferFlags |=
USBD_SHORT_TRANSFER_OK;
//
// not using linked urb's
//
urb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
urb->UrbBulkOrInterruptTransfer.TransferBuffer = pRecBuf->dataBuf;
urb->UrbBulkOrInterruptTransfer.TransferBufferLength =length;
//
// Call the class driver to perform the operation.
nextStack = IoGetNextIrpStackLocation( (PIRP) pRecBuf->Irp );
ASSERT(nextStack != NULL);
//
// pass the URB to the USB driver stack
//
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = urb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine(
((PIRP) pRecBuf->Irp), // irp to use
UsbIoCompleteRead, // routine to call when irp is done
pRecBuf, // context to pass routine is the RCV_BUFFER
TRUE, // call on success
TRUE, // call on error
TRUE); // call on cancel
//
// Call IoCallDriver to send the irp to the usb port.
//
UsbIncIoCount( Device ) ;
timeStat = IoCallDriver(urbTargetDev, (PIRP) pRecBuf->Irp ); // Start UsbRead()
DEBUGMSG(DBG_FUNC, (" StartUsbRead() after IoCallDriver () status = 0x%x\n", timeStat));
ASSERT( STATUS_SUCCESS != timeStat );
while ( timeStat != STATUS_SUCCESS ) { //we will always get to our completion routine, even if cancelled
timeStat = MyKeWaitForSingleObject(
Device,
&pRecBuf->Event, //event to wait on
NULL, //irp to cancel on halt/reset or timeout
10000 * 1000 * 1 );//1秒
}
ASSERT( NULL == pRecBuf->Irp ); // WIll be nulled by completion routine
done:
if ( !pRecBuf || ( Device->RcvBuffersInUse >= (NUM_RCV_BUFS -2) ) )
{
/*if ( FALSE == Device->fIndicatedMediaBusy )
{
InterlockedExchange( &Device->fMediaBusy, TRUE );
InterlockedExchange( &Device->fIndicatedMediaBusy, TRUE );
IndicateMediaBusy( Device ); // indicate to Ndis BUGBUG? NOT NEEDED HERE?
}*/
IndicateMediaBusy( Device ); // indicate to Ndis BUGBUG? NOT NEEDED HERE?
}
return timeStat;
}
/*****************************************************************************
*
* Function: UsbIoCompleteRead
*
* Synopsis:
*
* 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.
*
* Algorithm:
* This is the completion routine for all pending IRP_MJ_READ irps
* sent to the device object.
*
* If there is a pending halt or reset, we exit the completion
* routine without sending another irp to the USBl device object.
*
*
* If the IRP_MJ_READ irp returned either STATUS_SUCCESS or
* STATUS_TIMEOUT, we must process any data (stripping BOFs, ESC
* sequences, and EOF) into an NDIS_BUFFER and NDIS_PACKET.
*
* Another irp is then built (we just re-use the incoming irp) and
* sent to the USB object with another IRP_MJ_READ
* request.
* Notes:
*
* This routine is called (by the io manager) in IRQL DISPATCH_LEVEL.
*
*****************************************************************************/
NTSTATUS
UsbIoCompleteRead(
IN PDEVICE_OBJECT pUsbDevObj,
IN PIRP pIrp,
IN PVOID Context
)
{
PUSB_DEVICE device;
NTSTATUS status;
ULONG_PTR BytesRead;
PRCV_BUFFER pRecBuf;
LARGE_INTEGER tat;
DEBUGMSG(DBG_FUNC, ("+UsbIoCompleteRead\n"));
//
// The context given to IoSetCompletionRoutine is the receive buffer object
//
pRecBuf = (PRCV_BUFFER) Context;
device = (PUSB_DEVICE) pRecBuf->device;
ASSERT( pRecBuf->Irp == pIrp );
ASSERT( NULL != device );
if ((device->fPendingHalt == TRUE) ||
(device->fPendingReset == TRUE))
{
//
// Set the fReceiving boolean so that the halt and reset routines
// know when it is okay to continue.
//
// change the below back to DBG_FUNC later?
DEBUGMSG(DBG_FUNC, ("UsbIoCompleteRead halt or reset pending setting fReceiving FALSE\n"));
device->fReceiving = FALSE;
}
//
// We have a number of cases:
// 1) The USB read timed out and we received no data.
// 2) The USB read timed out and we received some data.
// 3) The USB read was successful and fully filled our irp buffer.
// 4) The irp was cancelled.
// 5) Some other failure from the USB device object.
//
status = pIrp->IoStatus.Status;
//
// IoCallDriver has been called on this Irp;
// Set the length based on the TransferBufferLength
// value in the URB
//
pIrp->IoStatus.Information =
((PURB) pRecBuf->Urb)->UrbBulkOrInterruptTransfer.TransferBufferLength;
BytesRead = pIrp->IoStatus.Information;
device->pCurrentRcvBuf = NULL;
switch (status)
{
case STATUS_SUCCESS:
if (BytesRead > 0)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -