mirror of
https://github.com/reactos/reactos.git
synced 2025-07-23 11:03:49 +00:00
Import "USB Driver stack project for Windows NT 4.0" by Zhiming/Woodhead (mypublic99@yahoo.com).
It supports UHCI/EHCI controllers. Don't expect it to compile with ReactOS build environment. I intend to do some work on it, and use this place to keep my changes, before it's suitable for ReactOS. "I would like to see it useful for ReactOS" (c) woodhead svn path=/trunk/; revision=23602
This commit is contained in:
parent
4fec2ff8db
commit
430d3e90b8
26 changed files with 30369 additions and 0 deletions
|
@ -1,6 +1,9 @@
|
||||||
<directory name="miniport">
|
<directory name="miniport">
|
||||||
<xi:include href="miniport/directory.rbuild" />
|
<xi:include href="miniport/directory.rbuild" />
|
||||||
</directory>
|
</directory>
|
||||||
|
<directory name="nt4compat">
|
||||||
|
<xi:include href="nt4compat/directory.rbuild" />
|
||||||
|
</directory>
|
||||||
<!--directory name="usbd">
|
<!--directory name="usbd">
|
||||||
<xi:include href="usbd/usbd.rbuild" />
|
<xi:include href="usbd/usbd.rbuild" />
|
||||||
</directory-->
|
</directory-->
|
||||||
|
|
3
reactos/drivers/usb/nt4compat/directory.rbuild
Normal file
3
reactos/drivers/usb/nt4compat/directory.rbuild
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<!--<directory name="usbdriver">
|
||||||
|
<xi:include href="usbdriver/usbdriver.rbuild" />
|
||||||
|
</directory>-->
|
909
reactos/drivers/usb/nt4compat/usbdriver/bulkonly.c
Normal file
909
reactos/drivers/usb/nt4compat/usbdriver/bulkonly.c
Normal file
|
@ -0,0 +1,909 @@
|
||||||
|
/**
|
||||||
|
* bulkonly.c - USB driver stack project for Windows NT 4.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
|
||||||
|
*
|
||||||
|
* This program/include file is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as published
|
||||||
|
* by the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program/include file is distributed in the hope that it will be
|
||||||
|
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||||
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program (in the main directory of the distribution, the file
|
||||||
|
* COPYING); if not, write to the Free Software Foundation,Inc., 59 Temple
|
||||||
|
* Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ntddk.h>
|
||||||
|
#include "debug.h"
|
||||||
|
#include "usb.h"
|
||||||
|
#include "umss.h"
|
||||||
|
#include <ntddscsi.h>
|
||||||
|
|
||||||
|
#define OLYMPUS_CSW( pdev_EXT, staTUS ) \
|
||||||
|
( ( ( pdev_EXT )->flags & UMSS_DEV_FLAG_OLYMPUS_DEV ) ? ( ( staTUS ) == CSW_OLYMPUS_SIGNATURE ) : FALSE )
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
umss_clear_pass_through_length(
|
||||||
|
PIO_PACKET io_packet
|
||||||
|
);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
umss_bulkonly_send_sense_req(
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_bulkonly_send_cbw_completion(
|
||||||
|
IN PURB purb,
|
||||||
|
IN PVOID context
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_bulkonly_transfer_data(
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_sync_submit_urb_completion(
|
||||||
|
PURB purb,
|
||||||
|
PVOID context
|
||||||
|
);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
umss_sync_submit_urb(
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext,
|
||||||
|
PURB purb
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_bulkonly_get_status(
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_bulkonly_transfer_data_complete(
|
||||||
|
PURB purb,
|
||||||
|
PVOID reference
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_bulkonly_reset_pipe_and_get_status(
|
||||||
|
IN PVOID reference
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_bulkonly_reset_recovery(
|
||||||
|
IN PVOID reference
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_bulkonly_get_status_complete(
|
||||||
|
IN PURB purb,
|
||||||
|
IN PVOID context
|
||||||
|
);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
umss_bulkonly_startio(
|
||||||
|
IN PUMSS_DEVICE_EXTENSION pdev_ext,
|
||||||
|
IN PIO_PACKET io_packet
|
||||||
|
)
|
||||||
|
/*++
|
||||||
|
Routine Description:
|
||||||
|
|
||||||
|
Handler for all I/O requests using bulk-only protocol.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
|
||||||
|
DeviceExtension - Device extension for our FDO.
|
||||||
|
|
||||||
|
Return Value:
|
||||||
|
|
||||||
|
NONE
|
||||||
|
|
||||||
|
--*/
|
||||||
|
|
||||||
|
{
|
||||||
|
PCOMMAND_BLOCK_WRAPPER cbw;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
if( pdev_ext == NULL || io_packet == NULL || io_packet->pirp == NULL )
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
pdev_ext->retry = TRUE;
|
||||||
|
RtlCopyMemory( &pdev_ext->io_packet, io_packet, sizeof( pdev_ext->io_packet ) );
|
||||||
|
|
||||||
|
// Setup the command block wrapper for this request
|
||||||
|
cbw = &pdev_ext->cbw;
|
||||||
|
cbw->dCBWSignature = CBW_SIGNATURE;
|
||||||
|
cbw->dCBWTag = 0;
|
||||||
|
cbw->dCBWDataTransferLength = io_packet->data_length;
|
||||||
|
cbw->bmCBWFlags = ( io_packet->flags & USB_DIR_IN ) ? 0x80 : 0;
|
||||||
|
cbw->bCBWLun = io_packet->lun;
|
||||||
|
cbw->bCBWLength = io_packet->cdb_length;
|
||||||
|
RtlCopyMemory( cbw->CBWCB, io_packet->cdb, sizeof( cbw->CBWCB ) );
|
||||||
|
|
||||||
|
RtlZeroMemory( &pdev_ext->csw, sizeof( pdev_ext->csw ) );
|
||||||
|
// Send the command block wrapper to the device.
|
||||||
|
// Calls UMSS_BulkOnlySendCBWComplete when transfer completes.
|
||||||
|
status = umss_bulk_transfer(
|
||||||
|
pdev_ext,
|
||||||
|
USB_DIR_OUT,
|
||||||
|
cbw,
|
||||||
|
sizeof( COMMAND_BLOCK_WRAPPER ),
|
||||||
|
umss_bulkonly_send_cbw_completion
|
||||||
|
);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
umss_bulk_transfer(
|
||||||
|
IN PUMSS_DEVICE_EXTENSION pdev_ext,
|
||||||
|
IN UCHAR trans_dir,
|
||||||
|
IN PVOID buf,
|
||||||
|
IN ULONG buf_length,
|
||||||
|
IN PURBCOMPLETION completion
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PURB purb;
|
||||||
|
NTSTATUS status;
|
||||||
|
DEV_HANDLE endp_handle;
|
||||||
|
|
||||||
|
if( pdev_ext == NULL || buf == NULL || completion == NULL )
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if( buf_length > ( ULONG )MAX_BULK_TRANSFER_LENGTH )
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
purb = usb_alloc_mem( NonPagedPool, sizeof( URB ) );
|
||||||
|
|
||||||
|
if( purb == NULL )
|
||||||
|
return STATUS_NO_MEMORY;
|
||||||
|
|
||||||
|
if( trans_dir == USB_DIR_OUT )
|
||||||
|
{
|
||||||
|
endp_handle = usb_make_handle( ( pdev_ext->dev_handle >> 16 ), pdev_ext->if_idx, pdev_ext->out_endp_idx );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
endp_handle = usb_make_handle( ( pdev_ext->dev_handle >> 16 ), pdev_ext->if_idx, pdev_ext->in_endp_idx );
|
||||||
|
}
|
||||||
|
|
||||||
|
UsbBuildInterruptOrBulkTransferRequest( purb,
|
||||||
|
endp_handle,
|
||||||
|
buf,
|
||||||
|
buf_length,
|
||||||
|
completion,
|
||||||
|
pdev_ext,
|
||||||
|
0 );
|
||||||
|
dev_mgr_register_irp( pdev_ext->dev_mgr, pdev_ext->io_packet.pirp, purb );
|
||||||
|
status = usb_submit_urb( pdev_ext->dev_mgr, purb );
|
||||||
|
if( status == STATUS_PENDING )
|
||||||
|
{
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_mgr_remove_irp( pdev_ext->dev_mgr, pdev_ext->io_packet.pirp );
|
||||||
|
if( purb )
|
||||||
|
{
|
||||||
|
usb_free_mem( purb );
|
||||||
|
purb = NULL;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_bulkonly_send_cbw_completion(
|
||||||
|
IN PURB purb,
|
||||||
|
IN PVOID context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
||||||
|
|
||||||
|
pdev_ext = ( PUMSS_DEVICE_EXTENSION )context;
|
||||||
|
|
||||||
|
status = purb->status;
|
||||||
|
dev_mgr_remove_irp( pdev_ext->dev_mgr, pdev_ext->io_packet.pirp );
|
||||||
|
|
||||||
|
if( ( pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK ) == IOP_FLAG_STAGE_SENSE )
|
||||||
|
{
|
||||||
|
usb_free_mem( purb->data_buffer );
|
||||||
|
purb->data_buffer = NULL;
|
||||||
|
purb->data_length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( status != STATUS_SUCCESS )
|
||||||
|
{
|
||||||
|
if ( usb_halted( status ) )
|
||||||
|
{
|
||||||
|
//Schedule a work-item to do a reset recovery
|
||||||
|
if( !umss_schedule_workitem( (PVOID)pdev_ext, umss_bulkonly_reset_recovery, pdev_ext->dev_mgr, pdev_ext->dev_handle ) )
|
||||||
|
{
|
||||||
|
umss_complete_request( pdev_ext, STATUS_IO_DEVICE_ERROR );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Device failed CBW without stalling, so complete with error
|
||||||
|
umss_complete_request( pdev_ext, status );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// CBW was accepted by device, so start data phase of I/O operation
|
||||||
|
umss_bulkonly_transfer_data( pdev_ext );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( purb )
|
||||||
|
usb_free_mem( purb );
|
||||||
|
|
||||||
|
purb = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
umss_sync_submit_urb(
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext,
|
||||||
|
PURB purb
|
||||||
|
)
|
||||||
|
//can only be called at passive level
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
if( pdev_ext == NULL || purb == NULL )
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
purb->completion = umss_sync_submit_urb_completion;
|
||||||
|
purb->context = ( PVOID )pdev_ext;
|
||||||
|
|
||||||
|
dev_mgr_register_irp( pdev_ext->dev_mgr, pdev_ext->io_packet.pirp, purb );
|
||||||
|
status = usb_submit_urb( pdev_ext->dev_mgr, purb );
|
||||||
|
if( status == STATUS_PENDING )
|
||||||
|
{
|
||||||
|
KeWaitForSingleObject(
|
||||||
|
&pdev_ext->sync_event,
|
||||||
|
Executive,
|
||||||
|
KernelMode,
|
||||||
|
TRUE,
|
||||||
|
NULL );
|
||||||
|
status = purb->status;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dev_mgr_remove_irp( pdev_ext->dev_mgr, pdev_ext->io_packet.pirp );
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_sync_submit_urb_completion(
|
||||||
|
PURB purb,
|
||||||
|
PVOID context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
||||||
|
|
||||||
|
if( purb == NULL || context == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
pdev_ext = ( PUMSS_DEVICE_EXTENSION )context;
|
||||||
|
dev_mgr_remove_irp( pdev_ext->dev_mgr, pdev_ext->io_packet.pirp );
|
||||||
|
KeSetEvent( &pdev_ext->sync_event, 0, FALSE );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_bulkonly_reset_recovery(
|
||||||
|
IN PVOID reference
|
||||||
|
)
|
||||||
|
/*++
|
||||||
|
Routine Description:
|
||||||
|
|
||||||
|
Worker function used to execute a reset recovery after a stall.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
|
||||||
|
Reference - Our device extension.
|
||||||
|
|
||||||
|
Return Value:
|
||||||
|
|
||||||
|
NONE
|
||||||
|
|
||||||
|
--*/
|
||||||
|
|
||||||
|
{
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
||||||
|
URB urb;
|
||||||
|
NTSTATUS status;
|
||||||
|
DEV_HANDLE endp_handle;
|
||||||
|
|
||||||
|
pdev_ext = (PUMSS_DEVICE_EXTENSION)reference;
|
||||||
|
usb_dbg_print( DBGLVL_MAXIMUM, ( "umss_bulkonly_reset_recovery(): entering...\n" ) );
|
||||||
|
// Steps for reset recovery:
|
||||||
|
// 1. Send device a mass storage reset command on the default endpoint.
|
||||||
|
// 2. Reset the bulk-in endpoint.
|
||||||
|
// 3. Reset the bulk-out endpoint.
|
||||||
|
// 4. Complete the original I/O request with error.
|
||||||
|
|
||||||
|
|
||||||
|
// Build the mass storage reset command
|
||||||
|
UsbBuildVendorRequest(
|
||||||
|
&urb,
|
||||||
|
pdev_ext->dev_handle | 0xffff, //default pipe
|
||||||
|
NULL, //no extra data
|
||||||
|
0, //no size
|
||||||
|
0x21, //class, interface
|
||||||
|
BULK_ONLY_MASS_STORAGE_RESET,
|
||||||
|
0,
|
||||||
|
pdev_ext->pif_desc->bInterfaceNumber,
|
||||||
|
NULL, //completion
|
||||||
|
NULL, //context
|
||||||
|
0 ); //reference
|
||||||
|
|
||||||
|
// Send mass storage reset command to device
|
||||||
|
status = umss_sync_submit_urb( pdev_ext, &urb);
|
||||||
|
|
||||||
|
if ( status != STATUS_SUCCESS )
|
||||||
|
{
|
||||||
|
usb_dbg_print( DBGLVL_MINIMUM,("umss_bulkonly_reset_recovery(): Reset Recovery failed!\n"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Reset Bulk-in endpoint
|
||||||
|
endp_handle = usb_make_handle( ( pdev_ext->dev_handle >> 16 ), pdev_ext->if_idx, pdev_ext->in_endp_idx );
|
||||||
|
status = umss_reset_pipe(
|
||||||
|
pdev_ext,
|
||||||
|
endp_handle
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(status))
|
||||||
|
{
|
||||||
|
usb_dbg_print( DBGLVL_MINIMUM,("umss_bulkonly_reset_recovery(): Unable to clear Bulk-in endpoint\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Reset Bulk-out endpoint
|
||||||
|
endp_handle = usb_make_handle( ( pdev_ext->dev_handle >> 16 ), pdev_ext->if_idx, pdev_ext->out_endp_idx );
|
||||||
|
status = umss_reset_pipe(
|
||||||
|
pdev_ext,
|
||||||
|
endp_handle
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(status))
|
||||||
|
{
|
||||||
|
usb_dbg_print( DBGLVL_MINIMUM,("umss_bulkonly_reset_recovery(): Unable to clear Bulk-out endpoint\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
umss_complete_request( pdev_ext, status );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_bulkonly_transfer_data(
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext
|
||||||
|
)
|
||||||
|
/*++
|
||||||
|
Routine Description:
|
||||||
|
|
||||||
|
Schedules a bulk data transfer to/from the device.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
|
||||||
|
DeviceExtension - Our FDO's device extension.
|
||||||
|
|
||||||
|
Return Value:
|
||||||
|
|
||||||
|
NONE
|
||||||
|
|
||||||
|
--*/
|
||||||
|
|
||||||
|
{
|
||||||
|
PVOID data_buf;
|
||||||
|
ULONG data_buf_length;
|
||||||
|
NTSTATUS status;
|
||||||
|
UCHAR trans_dir;
|
||||||
|
|
||||||
|
// Steps for data phase
|
||||||
|
// 1. Get data buffer fragment (either SGD list, flat buffer, or none).
|
||||||
|
// 2. Schedule data transfer if neccessary.
|
||||||
|
// 3. Repeat 1-2 until all data transferred, or endpoint stalls.
|
||||||
|
// 4. Move to status phase.
|
||||||
|
|
||||||
|
// Get next data buffer element, if any
|
||||||
|
data_buf = umss_get_buffer( pdev_ext, &data_buf_length);
|
||||||
|
|
||||||
|
if (NULL == data_buf)
|
||||||
|
{
|
||||||
|
//No data to transfer, so move to status phase
|
||||||
|
umss_bulkonly_get_status( pdev_ext );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Schedule the data transfer.
|
||||||
|
// Calls umss_bulkonly_transfer_data_complete when transfer completes.
|
||||||
|
|
||||||
|
if( ( pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK ) == IOP_FLAG_STAGE_NORMAL )
|
||||||
|
trans_dir = ( UCHAR )( ( pdev_ext->cbw.bmCBWFlags & USB_DIR_IN ) ? USB_DIR_IN : USB_DIR_OUT );
|
||||||
|
else if( ( pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK ) == IOP_FLAG_STAGE_SENSE )
|
||||||
|
trans_dir = USB_DIR_IN;
|
||||||
|
|
||||||
|
if( ( status = umss_bulk_transfer(
|
||||||
|
pdev_ext,
|
||||||
|
trans_dir,
|
||||||
|
data_buf,
|
||||||
|
data_buf_length,
|
||||||
|
umss_bulkonly_transfer_data_complete )
|
||||||
|
) != STATUS_PENDING )
|
||||||
|
{
|
||||||
|
umss_complete_request( pdev_ext, status );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_bulkonly_transfer_data_complete(
|
||||||
|
PURB purb,
|
||||||
|
PVOID reference
|
||||||
|
)
|
||||||
|
/*++
|
||||||
|
Routine Description:
|
||||||
|
Completion handler for bulk data transfer requests.
|
||||||
|
--*/
|
||||||
|
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
||||||
|
pdev_ext = ( PUMSS_DEVICE_EXTENSION )reference;
|
||||||
|
|
||||||
|
status = purb->status;
|
||||||
|
|
||||||
|
dev_mgr_remove_irp( pdev_ext->dev_mgr, pdev_ext->io_packet.pirp );
|
||||||
|
|
||||||
|
if ( status != STATUS_SUCCESS )
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// clear the data length if this is a scsi pass through request
|
||||||
|
//
|
||||||
|
umss_clear_pass_through_length( &pdev_ext->io_packet );
|
||||||
|
|
||||||
|
// Device failed data phase
|
||||||
|
// Check if we need to clear stalled pipe
|
||||||
|
if ( usb_halted( status ) )
|
||||||
|
{
|
||||||
|
PULONG buf;
|
||||||
|
buf = usb_alloc_mem( NonPagedPool, 32 );
|
||||||
|
buf[ 0 ] = ( ULONG )pdev_ext;
|
||||||
|
buf[ 1 ] = ( ULONG )purb->endp_handle;
|
||||||
|
|
||||||
|
usb_dbg_print( DBGLVL_MINIMUM,("umss_transfer_data_complete(): transfer data error!\n"));
|
||||||
|
if (!umss_schedule_workitem( ( PVOID )buf, umss_bulkonly_reset_pipe_and_get_status, pdev_ext->dev_mgr, pdev_ext->dev_handle ) )
|
||||||
|
{
|
||||||
|
usb_free_mem( buf ), buf = NULL;
|
||||||
|
usb_dbg_print( DBGLVL_MINIMUM,("umss_transfer_data_complete(): Failed to allocate work-item to reset pipe!\n"));
|
||||||
|
TRAP();
|
||||||
|
umss_complete_request( pdev_ext, status );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//finish our request
|
||||||
|
umss_complete_request( pdev_ext, status );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Start next part of data phase
|
||||||
|
//umss_bulkonly_transfer_data( pdev_ext );
|
||||||
|
umss_bulkonly_get_status( pdev_ext );
|
||||||
|
//umss_complete_request( pdev_ext, status );
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_free_mem( purb );
|
||||||
|
purb = NULL;
|
||||||
|
|
||||||
|
return; // STATUS_MORE_PROCESSING_REQUIRED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_bulkonly_reset_pipe_and_get_status(
|
||||||
|
IN PVOID reference
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
||||||
|
DEV_HANDLE endp_handle;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
usb_dbg_print( DBGLVL_MINIMUM,("umss_bulkonly_reset_pipe_and_get_status(): entering...\n") );
|
||||||
|
|
||||||
|
pdev_ext = ( PUMSS_DEVICE_EXTENSION )( ( ( PULONG )reference )[ 0 ] );
|
||||||
|
endp_handle = ( DEV_HANDLE )( ( PULONG )reference )[ 1 ];
|
||||||
|
usb_free_mem( reference );
|
||||||
|
reference = NULL;
|
||||||
|
|
||||||
|
// Reset the endpoint
|
||||||
|
if( ( status = umss_reset_pipe( pdev_ext, endp_handle ) ) != STATUS_SUCCESS )
|
||||||
|
{
|
||||||
|
usb_dbg_print( DBGLVL_MINIMUM,("umss_bulkonly_reset_pipe_and_get_status(): reset pipe failed\n") );
|
||||||
|
umss_complete_request( pdev_ext, status );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Data phase is finished since the endpoint stalled, so go to status phase
|
||||||
|
usb_dbg_print( DBGLVL_MINIMUM,("umss_bulkonly_reset_pipe_and_get_status(): reset pipe succeeds, continue to get status\n") );
|
||||||
|
umss_bulkonly_get_status( pdev_ext );
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_bulkonly_get_status(
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext
|
||||||
|
)
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
// Schedule bulk transfer to get command status wrapper from device
|
||||||
|
status = umss_bulk_transfer(
|
||||||
|
pdev_ext,
|
||||||
|
USB_DIR_IN,
|
||||||
|
&( pdev_ext->csw ),
|
||||||
|
sizeof( COMMAND_STATUS_WRAPPER ),
|
||||||
|
umss_bulkonly_get_status_complete
|
||||||
|
);
|
||||||
|
if( status != STATUS_PENDING )
|
||||||
|
{
|
||||||
|
umss_complete_request( pdev_ext, status );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_bulkonly_get_status_complete(
|
||||||
|
IN PURB purb,
|
||||||
|
IN PVOID context
|
||||||
|
)
|
||||||
|
/*++
|
||||||
|
Routine Description:
|
||||||
|
|
||||||
|
Completion handler for bulk data transfer request.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
|
||||||
|
DeviceObject - Previous device object.
|
||||||
|
Irp - Irp used for sending command.
|
||||||
|
Reference - Our FDO.
|
||||||
|
|
||||||
|
Return Value:
|
||||||
|
|
||||||
|
Driver-originated IRPs always return STATUS_MORE_PROCESSING_REQUIRED.
|
||||||
|
|
||||||
|
--*/
|
||||||
|
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
||||||
|
PCOMMAND_STATUS_WRAPPER csw;
|
||||||
|
|
||||||
|
pdev_ext = ( PUMSS_DEVICE_EXTENSION ) context;
|
||||||
|
status = purb->status;
|
||||||
|
|
||||||
|
dev_mgr_remove_irp( pdev_ext->dev_mgr, pdev_ext->io_packet.pirp );
|
||||||
|
|
||||||
|
csw = &( pdev_ext->csw );
|
||||||
|
if ( status == STATUS_SUCCESS &&
|
||||||
|
( ( csw->dCSWSignature == CSW_SIGNATURE ) || OLYMPUS_CSW( pdev_ext, csw->dCSWSignature ) ) )
|
||||||
|
{
|
||||||
|
if ( csw->bCSWStatus == CSW_STATUS_PASSED )
|
||||||
|
{
|
||||||
|
// Received valid CSW with good status
|
||||||
|
|
||||||
|
if( ( pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK ) == IOP_FLAG_STAGE_NORMAL &&
|
||||||
|
( pdev_ext->io_packet.flags & IOP_FLAG_REQ_SENSE ) &&
|
||||||
|
pdev_ext->io_packet.sense_data != NULL )
|
||||||
|
UMSS_FORGE_GOOD_SENSE( pdev_ext->io_packet.sense_data )
|
||||||
|
|
||||||
|
umss_complete_request( pdev_ext, STATUS_SUCCESS );
|
||||||
|
}
|
||||||
|
else if ( csw->bCSWStatus == CSW_STATUS_FAILED )
|
||||||
|
{
|
||||||
|
// start a request sense if necessary
|
||||||
|
if( ( pdev_ext->io_packet.flags & IOP_FLAG_REQ_SENSE ) &&
|
||||||
|
( pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK ) == IOP_FLAG_STAGE_NORMAL )
|
||||||
|
{
|
||||||
|
if( umss_bulkonly_send_sense_req( pdev_ext ) != STATUS_PENDING )
|
||||||
|
{
|
||||||
|
// don't know how to handle.
|
||||||
|
umss_complete_request( pdev_ext, STATUS_IO_DEVICE_ERROR );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// fall through to free the urb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// error occurred, reset device
|
||||||
|
if( !umss_schedule_workitem( (PVOID)pdev_ext, umss_bulkonly_reset_recovery, pdev_ext->dev_mgr, pdev_ext->dev_handle ) )
|
||||||
|
{
|
||||||
|
umss_complete_request( pdev_ext, STATUS_IO_DEVICE_ERROR );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// error occurred, reset device
|
||||||
|
if( !umss_schedule_workitem( (PVOID)pdev_ext, umss_bulkonly_reset_recovery, pdev_ext->dev_mgr, pdev_ext->dev_handle ) )
|
||||||
|
{
|
||||||
|
umss_complete_request( pdev_ext, STATUS_IO_DEVICE_ERROR );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( ( status != STATUS_SUCCESS ) && ( usb_halted( status ) ) && ( pdev_ext->retry ) )
|
||||||
|
{
|
||||||
|
// Device stalled CSW transfer, retry once before failing
|
||||||
|
PULONG buf;
|
||||||
|
pdev_ext->retry = FALSE;
|
||||||
|
|
||||||
|
buf = usb_alloc_mem( NonPagedPool, 32 );
|
||||||
|
buf[ 0 ] = ( ULONG )pdev_ext;
|
||||||
|
buf[ 1 ] = ( ULONG )purb->endp_handle;
|
||||||
|
|
||||||
|
if ( !umss_schedule_workitem( ( PVOID )buf, umss_bulkonly_reset_pipe_and_get_status, pdev_ext->dev_mgr, pdev_ext->dev_handle ) )
|
||||||
|
{
|
||||||
|
usb_free_mem( buf ), buf = NULL;
|
||||||
|
usb_dbg_print( DBGLVL_MINIMUM,("umss_bulkonly_get_status_complete(): Failed to allocate work-item to reset pipe!\n"));
|
||||||
|
TRAP();
|
||||||
|
umss_complete_request( pdev_ext, status );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( status != STATUS_CANCELLED )
|
||||||
|
{
|
||||||
|
// An error has occured. Reset the device.
|
||||||
|
if ( !umss_schedule_workitem( ( PVOID )pdev_ext, umss_bulkonly_reset_recovery, pdev_ext->dev_mgr, pdev_ext->dev_handle ) )
|
||||||
|
{
|
||||||
|
usb_dbg_print( DBGLVL_MINIMUM,("umss_bulkonly_get_status_complete(): Failed to schedule work-item to reset pipe!\n"));
|
||||||
|
TRAP();
|
||||||
|
umss_complete_request( pdev_ext, status );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// the request is canceled
|
||||||
|
usb_dbg_print( DBGLVL_MINIMUM,("umss_bulkonly_get_status_complete(): the request is canceled\n"));
|
||||||
|
umss_complete_request( pdev_ext, STATUS_CANCELLED );
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_free_mem( purb );
|
||||||
|
purb = NULL;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CHAR
|
||||||
|
umss_bulkonly_get_maxlun(
|
||||||
|
IN PUMSS_DEVICE_EXTENSION pdev_ext
|
||||||
|
)
|
||||||
|
/*++
|
||||||
|
Routine Description:
|
||||||
|
|
||||||
|
Queries Bulk-Only device for maximum LUN number
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
|
||||||
|
DeviceExtension - Our device extension.
|
||||||
|
|
||||||
|
Return Value:
|
||||||
|
|
||||||
|
Maximum LUN number for device, or 0 if error occurred.
|
||||||
|
|
||||||
|
--*/
|
||||||
|
|
||||||
|
{
|
||||||
|
PURB purb=NULL;
|
||||||
|
CHAR max_lun;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
purb = usb_alloc_mem( NonPagedPool, sizeof( URB ) );
|
||||||
|
|
||||||
|
if (!purb)
|
||||||
|
{
|
||||||
|
usb_dbg_print( DBGLVL_MINIMUM,("umss_bulkonly_get_maxlun(): Failed to allocate URB, setting max LUN to 0\n"));
|
||||||
|
max_lun = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Build the get max lun command
|
||||||
|
UsbBuildVendorRequest(
|
||||||
|
purb,
|
||||||
|
( pdev_ext->dev_handle | 0xffff ),
|
||||||
|
&max_lun,
|
||||||
|
sizeof( max_lun ),
|
||||||
|
0xb1, //class, interface, in
|
||||||
|
BULK_ONLY_GET_MAX_LUN,
|
||||||
|
0,
|
||||||
|
pdev_ext->pif_desc->bInterfaceNumber,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
|
||||||
|
// Send get max lun command to device
|
||||||
|
status = umss_sync_submit_urb( pdev_ext, purb);
|
||||||
|
|
||||||
|
if ( status != STATUS_PENDING )
|
||||||
|
{
|
||||||
|
usb_dbg_print( DBGLVL_MINIMUM,("umss_bulkonly_get_maxlun(): Get Max LUN command failed, setting max LUN to 0!\n"));
|
||||||
|
max_lun = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( purb )
|
||||||
|
usb_free_mem( purb );
|
||||||
|
|
||||||
|
usb_dbg_print( DBGLVL_MINIMUM,("umss_bulkonly_get_maxlun(): Max LUN = %x\n", max_lun));
|
||||||
|
|
||||||
|
return max_lun;
|
||||||
|
}
|
||||||
|
|
||||||
|
PVOID
|
||||||
|
umss_get_buffer(
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext,
|
||||||
|
ULONG* buf_length
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PVOID buffer;
|
||||||
|
|
||||||
|
if( ( pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK ) == IOP_FLAG_STAGE_NORMAL )
|
||||||
|
{
|
||||||
|
buffer = (PVOID)pdev_ext->io_packet.data_buffer;
|
||||||
|
*buf_length = pdev_ext->io_packet.data_length;
|
||||||
|
}
|
||||||
|
else if( ( pdev_ext->io_packet.flags & IOP_FLAG_STAGE_MASK ) == IOP_FLAG_STAGE_SENSE )
|
||||||
|
{
|
||||||
|
buffer = (PVOID)pdev_ext->io_packet.sense_data;
|
||||||
|
*buf_length = pdev_ext->io_packet.sense_data_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
umss_bulkonly_build_sense_cdb(
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext,
|
||||||
|
PCOMMAND_BLOCK_WRAPPER cbw
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UCHAR sub_class;
|
||||||
|
PUCHAR cdb;
|
||||||
|
|
||||||
|
if( pdev_ext == NULL || cbw == NULL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
cdb = cbw->CBWCB;
|
||||||
|
RtlZeroMemory( cdb, MAX_CDB_LENGTH );
|
||||||
|
sub_class = pdev_ext->pif_desc->bInterfaceSubClass;
|
||||||
|
|
||||||
|
cdb[ 0 ] = SFF_REQUEST_SENSEE;
|
||||||
|
cdb[ 1 ] = pdev_ext->io_packet.lun << 5;
|
||||||
|
cdb[ 4 ] = 18;
|
||||||
|
|
||||||
|
switch( sub_class )
|
||||||
|
{
|
||||||
|
case UMSS_SUBCLASS_SFF8070I:
|
||||||
|
case UMSS_SUBCLASS_UFI:
|
||||||
|
{
|
||||||
|
cbw->bCBWLength = 12;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UMSS_SUBCLASS_RBC:
|
||||||
|
case UMSS_SUBCLASS_SCSI_TCS:
|
||||||
|
{
|
||||||
|
cbw->bCBWLength = 6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
umss_bulkonly_send_sense_req(
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PCOMMAND_BLOCK_WRAPPER cbw;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
if( pdev_ext == NULL || pdev_ext->io_packet.sense_data == NULL || pdev_ext->io_packet.sense_data_length < 18 )
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
pdev_ext->retry = TRUE;
|
||||||
|
|
||||||
|
cbw = usb_alloc_mem( NonPagedPool, sizeof( COMMAND_BLOCK_WRAPPER ) );
|
||||||
|
RtlZeroMemory( cbw, sizeof( COMMAND_BLOCK_WRAPPER ) );
|
||||||
|
pdev_ext->io_packet.flags &= ~IOP_FLAG_STAGE_MASK;
|
||||||
|
pdev_ext->io_packet.flags |= IOP_FLAG_STAGE_SENSE;
|
||||||
|
|
||||||
|
cbw->dCBWSignature = CBW_SIGNATURE;
|
||||||
|
cbw->dCBWTag = 0;
|
||||||
|
cbw->dCBWDataTransferLength = pdev_ext->io_packet.sense_data_length;
|
||||||
|
cbw->bmCBWFlags = USB_DIR_IN;
|
||||||
|
cbw->bCBWLun = 0;
|
||||||
|
|
||||||
|
if( umss_bulkonly_build_sense_cdb( pdev_ext, cbw ) == FALSE )
|
||||||
|
{
|
||||||
|
usb_free_mem( cbw );
|
||||||
|
cbw = NULL;
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = umss_bulk_transfer(
|
||||||
|
pdev_ext,
|
||||||
|
USB_DIR_OUT,
|
||||||
|
cbw,
|
||||||
|
sizeof( COMMAND_BLOCK_WRAPPER ),
|
||||||
|
umss_bulkonly_send_cbw_completion
|
||||||
|
);
|
||||||
|
|
||||||
|
if( status != STATUS_PENDING )
|
||||||
|
{
|
||||||
|
usb_free_mem( cbw );
|
||||||
|
cbw = NULL;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
umss_clear_pass_through_length(
|
||||||
|
PIO_PACKET io_packet
|
||||||
|
)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// clear the respective data length to meet request of scsi pass through requirement.
|
||||||
|
//
|
||||||
|
|
||||||
|
BOOL sense_stage;
|
||||||
|
ULONG ctrl_code;
|
||||||
|
PIO_STACK_LOCATION cur_stack;
|
||||||
|
PSCSI_PASS_THROUGH pass_through;
|
||||||
|
PSCSI_PASS_THROUGH_DIRECT pass_through_direct;
|
||||||
|
|
||||||
|
if( io_packet == NULL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if( ( io_packet->flags & IOP_FLAG_SCSI_CTRL_TRANSFER ) == 0 )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
sense_stage = FALSE;
|
||||||
|
if( io_packet->flags & IOP_FLAG_STAGE_SENSE )
|
||||||
|
sense_stage = TRUE;
|
||||||
|
|
||||||
|
cur_stack = IoGetCurrentIrpStackLocation( io_packet->pirp );
|
||||||
|
ctrl_code = cur_stack->Parameters.DeviceIoControl.IoControlCode;
|
||||||
|
if( ctrl_code == IOCTL_SCSI_PASS_THROUGH_DIRECT )
|
||||||
|
{
|
||||||
|
pass_through_direct = io_packet->pirp->AssociatedIrp.SystemBuffer;
|
||||||
|
if( sense_stage )
|
||||||
|
pass_through_direct->SenseInfoLength = 0;
|
||||||
|
else
|
||||||
|
pass_through_direct->DataTransferLength = 0;
|
||||||
|
}
|
||||||
|
else if( ctrl_code == IOCTL_SCSI_PASS_THROUGH )
|
||||||
|
{
|
||||||
|
pass_through= io_packet->pirp->AssociatedIrp.SystemBuffer;
|
||||||
|
if( sense_stage )
|
||||||
|
pass_through->SenseInfoLength = 0;
|
||||||
|
else
|
||||||
|
pass_through->DataTransferLength = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
363
reactos/drivers/usb/nt4compat/usbdriver/cbi.c
Normal file
363
reactos/drivers/usb/nt4compat/usbdriver/cbi.c
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
/**
|
||||||
|
* cbi.c - USB driver stack project for Windows NT 4.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
|
||||||
|
*
|
||||||
|
* This program/include file is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as published
|
||||||
|
* by the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program/include file is distributed in the hope that it will be
|
||||||
|
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||||
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program (in the main directory of the distribution, the file
|
||||||
|
* COPYING); if not, write to the Free Software Foundation,Inc., 59 Temple
|
||||||
|
* Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ntddk.h>
|
||||||
|
#include "debug.h"
|
||||||
|
#include "umss.h"
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_cbi_send_adsc_complete(
|
||||||
|
PURB purb,
|
||||||
|
PVOID context
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_cbi_transfer_data(
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_cbi_get_status(
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_cbi_transfer_data_complete(
|
||||||
|
PURB purb,
|
||||||
|
PVOID context
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_cbi_get_status_complete(
|
||||||
|
PURB purb,
|
||||||
|
PVOID context
|
||||||
|
);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
umss_class_specific_request(
|
||||||
|
IN PUMSS_DEVICE_EXTENSION pdev_ext,
|
||||||
|
IN UCHAR request,
|
||||||
|
IN UCHAR dir,
|
||||||
|
IN PVOID buffer,
|
||||||
|
IN ULONG buffer_length,
|
||||||
|
IN PURBCOMPLETION completion
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PURB purb;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
purb = usb_alloc_mem( NonPagedPool, sizeof( URB ) );
|
||||||
|
// Build URB for the ADSC command
|
||||||
|
UsbBuildVendorRequest(
|
||||||
|
purb,
|
||||||
|
pdev_ext->dev_handle | 0xffff,
|
||||||
|
buffer,
|
||||||
|
buffer_length,
|
||||||
|
0x21,
|
||||||
|
request,
|
||||||
|
0,
|
||||||
|
pdev_ext->pif_desc->bInterfaceNumber,
|
||||||
|
completion,
|
||||||
|
pdev_ext,
|
||||||
|
0 );
|
||||||
|
|
||||||
|
status = usb_submit_urb( pdev_ext->dev_mgr, purb );
|
||||||
|
if( status != STATUS_PENDING )
|
||||||
|
{
|
||||||
|
usb_free_mem( purb );
|
||||||
|
purb = NULL;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
dev_mgr_register_irp( pdev_ext->dev_mgr, pdev_ext->io_packet.pirp, purb );
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
umss_cbi_startio(
|
||||||
|
IN PUMSS_DEVICE_EXTENSION pdev_ext,
|
||||||
|
IN PIO_PACKET io_packet
|
||||||
|
)
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
status = STATUS_NOT_SUPPORTED;
|
||||||
|
return status;
|
||||||
|
|
||||||
|
RtlCopyMemory( &pdev_ext->io_packet, io_packet, sizeof( pdev_ext->io_packet ) );
|
||||||
|
|
||||||
|
// Send the ADSC request to the device
|
||||||
|
// Calls UMSS_CbiSendADSCComplete when transfer completes
|
||||||
|
status = umss_class_specific_request(
|
||||||
|
pdev_ext,
|
||||||
|
ACCEPT_DEVICE_SPECIFIC_COMMAND,
|
||||||
|
USB_DIR_OUT ,
|
||||||
|
io_packet->cdb,
|
||||||
|
io_packet->cdb_length,
|
||||||
|
umss_cbi_send_adsc_complete
|
||||||
|
);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_cbi_send_adsc_complete(
|
||||||
|
PURB purb,
|
||||||
|
PVOID context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
PIO_STACK_LOCATION irpStack;
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
||||||
|
PIO_PACKET io_packet;
|
||||||
|
ULONG bytes_to_transfer;
|
||||||
|
PUCHAR buf;
|
||||||
|
|
||||||
|
pdev_ext = (PUMSS_DEVICE_EXTENSION) context;
|
||||||
|
io_packet = &pdev_ext->io_packet;
|
||||||
|
|
||||||
|
status = purb->status;
|
||||||
|
|
||||||
|
dev_mgr_remove_irp( pdev_ext->dev_mgr, pdev_ext->io_packet.pirp );
|
||||||
|
|
||||||
|
if (!usb_success( status ) )
|
||||||
|
{
|
||||||
|
usb_dbg_print( DBGLVL_MINIMUM,("umss_cbi_send_adsc_complete(): Command Block Failure!!!\n"));
|
||||||
|
|
||||||
|
// BUGBUG - Should reset device here?
|
||||||
|
// Device failed Command Block, complete with error
|
||||||
|
umss_complete_request( pdev_ext, STATUS_IO_DEVICE_ERROR );
|
||||||
|
|
||||||
|
}
|
||||||
|
else if ( io_packet->data_length )
|
||||||
|
{
|
||||||
|
|
||||||
|
usb_dbg_print( DBGLVL_HIGH,("umss_cbi_send_adsc_complete(): Queuing Data Transfer DPC\n"));
|
||||||
|
umss_cbi_transfer_data( pdev_ext );
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (pdev_ext->pif_desc->bInterfaceProtocol == PROTOCOL_CBI)
|
||||||
|
{
|
||||||
|
// Device supports interrupt pipe, so get status
|
||||||
|
umss_cbi_get_status( pdev_ext );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Device does not report status, so complete request
|
||||||
|
umss_complete_request( pdev_ext, STATUS_SUCCESS );
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_free_mem( purb );
|
||||||
|
purb = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_cbi_reset_pipe(
|
||||||
|
IN PVOID reference
|
||||||
|
)
|
||||||
|
|
||||||
|
{
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
||||||
|
pdev_ext = (PUMSS_DEVICE_EXTENSION) reference;
|
||||||
|
|
||||||
|
// Reset the appropriate pipe, based on data direction
|
||||||
|
umss_reset_pipe(
|
||||||
|
pdev_ext,
|
||||||
|
( pdev_ext->io_packet.flags & USB_DIR_IN ) ?
|
||||||
|
usb_make_handle( ( pdev_ext->dev_handle >> 16 ), pdev_ext->if_idx, pdev_ext->in_endp_idx ):
|
||||||
|
usb_make_handle( ( pdev_ext->dev_handle >> 16 ), pdev_ext->if_idx, pdev_ext->out_endp_idx )
|
||||||
|
);
|
||||||
|
|
||||||
|
// Device stalled endpoint, so complete I/O operation with error.
|
||||||
|
// BUGBUG is this correct? Check spec...
|
||||||
|
umss_complete_request( pdev_ext, USB_STATUS_STALL_PID );
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_cbi_transfer_data(
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PVOID buffer;
|
||||||
|
ULONG buffer_length;
|
||||||
|
|
||||||
|
// Get next data buffer element, if any.
|
||||||
|
buffer = umss_get_buffer( pdev_ext, &buffer_length );
|
||||||
|
if (NULL == buffer)
|
||||||
|
{
|
||||||
|
//Done with data phase, so move to status phase if (supported)
|
||||||
|
|
||||||
|
if (pdev_ext->pif_desc->bInterfaceProtocol == PROTOCOL_CBI)
|
||||||
|
{
|
||||||
|
// Device supports interrupt pipe, so get status
|
||||||
|
umss_cbi_get_status(pdev_ext);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No interrupt pipe, so just complete the request
|
||||||
|
umss_complete_request(pdev_ext, STATUS_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Transfer next element of the data phase
|
||||||
|
umss_bulk_transfer(
|
||||||
|
pdev_ext,
|
||||||
|
(UCHAR)((pdev_ext->io_packet.flags & USB_DIR_IN ) ? USB_DIR_IN : USB_DIR_OUT ),
|
||||||
|
buffer,
|
||||||
|
buffer_length,
|
||||||
|
umss_cbi_transfer_data_complete
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_cbi_transfer_data_complete(
|
||||||
|
PURB purb,
|
||||||
|
PVOID context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
||||||
|
|
||||||
|
pdev_ext = (PUMSS_DEVICE_EXTENSION) context;
|
||||||
|
status = purb->status;
|
||||||
|
|
||||||
|
usb_free_mem( purb );
|
||||||
|
purb = NULL;
|
||||||
|
|
||||||
|
if ( !usb_success( status ) )
|
||||||
|
{
|
||||||
|
// Device failed Data Transfer
|
||||||
|
// Check if we need to clear stalled pipe
|
||||||
|
if ( usb_halted( status ) )
|
||||||
|
{
|
||||||
|
// Reset pipe can only be done at passive level, so we need
|
||||||
|
// to schedule a work item to do it.
|
||||||
|
if ( !umss_schedule_workitem( ( PVOID )pdev_ext, umss_cbi_reset_pipe, pdev_ext->dev_mgr, pdev_ext->dev_handle ) )
|
||||||
|
{
|
||||||
|
usb_dbg_print( DBGLVL_MINIMUM,("umss_cbi_transfer_data_complete(): Failed to allocate work-item to reset pipe!\n"));
|
||||||
|
TRAP();
|
||||||
|
umss_complete_request( pdev_ext, STATUS_IO_DEVICE_ERROR );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
umss_complete_request( pdev_ext, STATUS_IO_DEVICE_ERROR );
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Transfer succeeded
|
||||||
|
// umss_cbi_transfer_data( pdev_ext );
|
||||||
|
umss_complete_request( pdev_ext, STATUS_SUCCESS );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_cbi_get_status(
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PURB purb;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
purb = usb_alloc_mem( NonPagedPool, sizeof( URB ) );
|
||||||
|
if( purb == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Build a URB for our interrupt transfer
|
||||||
|
UsbBuildInterruptOrBulkTransferRequest(
|
||||||
|
purb,
|
||||||
|
usb_make_handle( ( pdev_ext->dev_handle >> 16 ), pdev_ext->if_idx, pdev_ext->int_endp_idx ),
|
||||||
|
( PUCHAR )&pdev_ext->idb,
|
||||||
|
sizeof( INTERRUPT_DATA_BLOCK ),
|
||||||
|
umss_cbi_get_status_complete,
|
||||||
|
pdev_ext,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
// Call USB driver stack
|
||||||
|
status = usb_submit_urb( pdev_ext->dev_mgr, purb );
|
||||||
|
if( status != STATUS_PENDING )
|
||||||
|
{
|
||||||
|
usb_free_mem( purb );
|
||||||
|
purb = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dev_mgr_register_irp( pdev_ext->dev_mgr, pdev_ext->io_packet.pirp, purb );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_cbi_get_status_complete(
|
||||||
|
PURB purb,
|
||||||
|
PVOID context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
||||||
|
PINTERRUPT_DATA_BLOCK idb;
|
||||||
|
|
||||||
|
pdev_ext = (PUMSS_DEVICE_EXTENSION) context;
|
||||||
|
|
||||||
|
status = purb->status;
|
||||||
|
dev_mgr_remove_irp( pdev_ext->dev_mgr, pdev_ext->io_packet.pirp );
|
||||||
|
|
||||||
|
usb_free_mem( purb );
|
||||||
|
purb = NULL;
|
||||||
|
|
||||||
|
if ( !usb_success( status ) )
|
||||||
|
{
|
||||||
|
// Device failed Data Transfer
|
||||||
|
// Check if we need to clear stalled pipe
|
||||||
|
if ( usb_halted( status ) )
|
||||||
|
{
|
||||||
|
if ( !umss_schedule_workitem( (PVOID)pdev_ext, umss_cbi_reset_pipe, pdev_ext->dev_mgr, pdev_ext->dev_handle ) )
|
||||||
|
{
|
||||||
|
usb_dbg_print( DBGLVL_MINIMUM,("umss_cbi_get_status_complete(): Failed to allocate work-item to reset pipe!\n"));
|
||||||
|
TRAP();
|
||||||
|
umss_complete_request( pdev_ext, STATUS_IO_DEVICE_ERROR );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
umss_complete_request( pdev_ext, STATUS_IO_DEVICE_ERROR );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interrupt transfer succeeded
|
||||||
|
idb = &(pdev_ext->idb);
|
||||||
|
|
||||||
|
// Check for an error in the status block
|
||||||
|
if ( ( 0 != idb->bType ) || ( 0 != ( idb->bValue & 0x3 ) ) )
|
||||||
|
{
|
||||||
|
umss_complete_request( pdev_ext, STATUS_IO_DEVICE_ERROR );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
umss_complete_request( pdev_ext, STATUS_SUCCESS );
|
||||||
|
}
|
||||||
|
}
|
566
reactos/drivers/usb/nt4compat/usbdriver/compdrv.c
Normal file
566
reactos/drivers/usb/nt4compat/usbdriver/compdrv.c
Normal file
|
@ -0,0 +1,566 @@
|
||||||
|
/**
|
||||||
|
* compdrv.c - USB driver stack project for Windows NT 4.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
|
||||||
|
*
|
||||||
|
* This program/include file is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as published
|
||||||
|
* by the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program/include file is distributed in the hope that it will be
|
||||||
|
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||||
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program (in the main directory of the distribution, the file
|
||||||
|
* COPYING); if not, write to the Free Software Foundation,Inc., 59 Temple
|
||||||
|
* Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
//this driver is part of the dev manager responsible to manage if device
|
||||||
|
|
||||||
|
#include "td.h"
|
||||||
|
#include "ntddk.h"
|
||||||
|
#include "umss.h"
|
||||||
|
#include "usb.h"
|
||||||
|
#include "hub.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
VOID
|
||||||
|
compdev_set_cfg_completion(
|
||||||
|
PURB purb,
|
||||||
|
PVOID context
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
compdev_select_driver(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
DEV_HANDLE dev_handle
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
compdev_connect(
|
||||||
|
PCONNECT_DATA param,
|
||||||
|
DEV_HANDLE dev_handle
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
compdev_stop(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
DEV_HANDLE dev_handle
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
compdev_disconnect(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
DEV_HANDLE dev_handle
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
compdev_driver_init(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DRIVER pdriver
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if( dev_mgr == NULL || pdriver == NULL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
pdriver->driver_desc.flags = USB_DRIVER_FLAG_DEV_CAPABLE;
|
||||||
|
pdriver->driver_desc.vendor_id = 0xffff; // USB Vendor ID
|
||||||
|
pdriver->driver_desc.product_id = 0xffff; // USB Product ID.
|
||||||
|
pdriver->driver_desc.release_num = 0x100; // Release Number of Device
|
||||||
|
|
||||||
|
pdriver->driver_desc.config_val = 0; // Configuration Value
|
||||||
|
pdriver->driver_desc.if_num = 0; // Interface Number
|
||||||
|
pdriver->driver_desc.if_class = 0; // Interface Class
|
||||||
|
pdriver->driver_desc.if_sub_class = 0; // Interface SubClass
|
||||||
|
pdriver->driver_desc.if_protocol = 0; // Interface Protocol
|
||||||
|
|
||||||
|
pdriver->driver_desc.driver_name = "USB composit dev driver"; // Driver name for Name Registry
|
||||||
|
pdriver->driver_desc.dev_class = USB_CLASS_PER_INTERFACE;
|
||||||
|
pdriver->driver_desc.dev_sub_class = 0; // Device Subclass
|
||||||
|
pdriver->driver_desc.dev_protocol = 0; // Protocol Info.
|
||||||
|
|
||||||
|
//we have no extra data sturcture currently
|
||||||
|
pdriver->driver_ext = NULL;
|
||||||
|
pdriver->driver_ext_size = 0;
|
||||||
|
|
||||||
|
pdriver->disp_tbl.version = 1;
|
||||||
|
pdriver->disp_tbl.dev_connect = compdev_connect;
|
||||||
|
pdriver->disp_tbl.dev_disconnect = compdev_disconnect;
|
||||||
|
pdriver->disp_tbl.dev_stop = compdev_stop;
|
||||||
|
pdriver->disp_tbl.dev_reserved = NULL;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
compdev_driver_destroy(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DRIVER pdriver
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
compdev_connect(
|
||||||
|
PCONNECT_DATA param,
|
||||||
|
DEV_HANDLE dev_handle
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PURB purb;
|
||||||
|
PUSB_CTRL_SETUP_PACKET psetup;
|
||||||
|
NTSTATUS status;
|
||||||
|
PUCHAR buf;
|
||||||
|
LONG credit, i, j, match;
|
||||||
|
PUSB_CONFIGURATION_DESC pconfig_desc;
|
||||||
|
PUSB_INTERFACE_DESC pif_desc;
|
||||||
|
PUSB_DEV_MANAGER dev_mgr;
|
||||||
|
|
||||||
|
if( param == NULL || dev_handle == 0 )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
dev_mgr = param->dev_mgr;
|
||||||
|
|
||||||
|
// let's set the configuration
|
||||||
|
purb = usb_alloc_mem( NonPagedPool, sizeof( URB ) );
|
||||||
|
if( purb == NULL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
buf = usb_alloc_mem( NonPagedPool, 512 );
|
||||||
|
if( buf == NULL )
|
||||||
|
{
|
||||||
|
usb_dbg_print( DBGLVL_MAXIMUM, ( "compdev_connect(): can not alloc buf\n" ) );
|
||||||
|
usb_free_mem( purb );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// before we set the configuration, let's search to find if there
|
||||||
|
// exist interfaces we supported
|
||||||
|
psetup = ( PUSB_CTRL_SETUP_PACKET )( purb )->setup_packet;
|
||||||
|
urb_init( ( purb ) );
|
||||||
|
purb->endp_handle = dev_handle | 0xffff;
|
||||||
|
purb->data_buffer = buf;
|
||||||
|
purb->data_length = 512;
|
||||||
|
purb->completion = NULL; // this is an immediate request, no completion required
|
||||||
|
purb->context = NULL;
|
||||||
|
purb->reference = 0;
|
||||||
|
psetup->bmRequestType = 0x80;
|
||||||
|
psetup->bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||||
|
psetup->wValue = USB_DT_CONFIG << 8;
|
||||||
|
psetup->wIndex = 0;
|
||||||
|
psetup->wLength = 512;
|
||||||
|
|
||||||
|
status = usb_submit_urb( dev_mgr, purb );
|
||||||
|
if( status == STATUS_PENDING )
|
||||||
|
{
|
||||||
|
TRAP();
|
||||||
|
usb_free_mem( buf );
|
||||||
|
usb_free_mem( purb );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// let's scan the interfacs for those we recognize
|
||||||
|
pconfig_desc = ( PUSB_CONFIGURATION_DESC )buf;
|
||||||
|
if( pconfig_desc->wTotalLength > 512 )
|
||||||
|
{
|
||||||
|
usb_free_mem( buf );
|
||||||
|
usb_free_mem( purb );
|
||||||
|
usb_dbg_print( DBGLVL_MAXIMUM, ( "compdev_connect(): error, bad configuration desc\n" ) );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pif_desc = ( PUSB_INTERFACE_DESC )&pconfig_desc[ 1 ];
|
||||||
|
for( i = 0, credit = 0; i < ( LONG )pconfig_desc->bNumInterfaces; i++ )
|
||||||
|
{
|
||||||
|
for( j = 0; j < DEVMGR_MAX_DRIVERS; j++ )
|
||||||
|
{
|
||||||
|
credit = dev_mgr_score_driver_for_if( dev_mgr, &dev_mgr->driver_list[ j ], pif_desc );
|
||||||
|
if( credit )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( credit )
|
||||||
|
break;
|
||||||
|
|
||||||
|
if( usb_skip_if_and_altif( ( PUCHAR* )&pif_desc ) )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = pconfig_desc->bConfigurationValue;
|
||||||
|
usb_free_mem( buf );
|
||||||
|
buf = NULL;
|
||||||
|
if( credit == 0 )
|
||||||
|
{
|
||||||
|
usb_free_mem( purb );
|
||||||
|
usb_dbg_print( DBGLVL_MAXIMUM, ( "compdev_connect(): oops..., no supported interface found\n" ) );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//set the configuration
|
||||||
|
urb_init( purb );
|
||||||
|
purb->endp_handle = dev_handle | 0xffff;
|
||||||
|
purb->data_buffer = NULL;
|
||||||
|
purb->data_length = 0;
|
||||||
|
purb->completion = compdev_set_cfg_completion;
|
||||||
|
purb->context = dev_mgr;
|
||||||
|
purb->reference = ( ULONG )param->pdriver;
|
||||||
|
psetup->bmRequestType = 0;
|
||||||
|
psetup->bRequest = USB_REQ_SET_CONFIGURATION;
|
||||||
|
psetup->wValue = ( USHORT ) i;
|
||||||
|
psetup->wIndex = 0;
|
||||||
|
psetup->wLength = 0;
|
||||||
|
|
||||||
|
usb_dbg_print( DBGLVL_MAXIMUM, ( "compdev_connect(): start config the device, cfgval=%d\n", i ) );
|
||||||
|
status = usb_submit_urb( dev_mgr, purb );
|
||||||
|
|
||||||
|
if( status != STATUS_PENDING )
|
||||||
|
{
|
||||||
|
usb_free_mem( purb );
|
||||||
|
|
||||||
|
if( status == STATUS_SUCCESS )
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
compdev_event_select_if_driver(
|
||||||
|
PUSB_DEV pdev,
|
||||||
|
ULONG event,
|
||||||
|
ULONG context,
|
||||||
|
ULONG param
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PUSB_DEV_MANAGER dev_mgr;
|
||||||
|
DEV_HANDLE dev_handle;
|
||||||
|
PUMSS_CREATE_DATA cd;
|
||||||
|
|
||||||
|
if( pdev == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
//
|
||||||
|
// RtlZeroMemory( &cd, sizeof( cd ) );
|
||||||
|
//
|
||||||
|
dev_mgr = dev_mgr_from_dev( pdev );
|
||||||
|
dev_handle = usb_make_handle( pdev->dev_id, 0, 0 );
|
||||||
|
compdev_select_driver( dev_mgr, dev_handle );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
compdev_post_event_select_driver(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
DEV_HANDLE dev_handle
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PUSB_EVENT pevent;
|
||||||
|
BOOL bret;
|
||||||
|
PUSB_DEV pdev;
|
||||||
|
|
||||||
|
USE_IRQL;
|
||||||
|
|
||||||
|
if( dev_mgr == NULL || dev_handle == 0 )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if( usb_query_and_lock_dev( dev_mgr, dev_handle, &pdev ) != STATUS_SUCCESS )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
KeAcquireSpinLockAtDpcLevel( &dev_mgr->event_list_lock );
|
||||||
|
lock_dev( pdev, TRUE );
|
||||||
|
|
||||||
|
if( dev_state( pdev ) == USB_DEV_STATE_ZOMB )
|
||||||
|
{
|
||||||
|
bret = FALSE;
|
||||||
|
goto LBL_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
pevent = alloc_event( &dev_mgr->event_pool, 1 );
|
||||||
|
if( pevent == NULL )
|
||||||
|
{
|
||||||
|
bret = FALSE;
|
||||||
|
goto LBL_OUT;
|
||||||
|
}
|
||||||
|
pevent->flags = USB_EVENT_FLAG_ACTIVE;
|
||||||
|
pevent->event = USB_EVENT_DEFAULT;
|
||||||
|
pevent->pdev = pdev;
|
||||||
|
pevent->context = 0;
|
||||||
|
pevent->param = 0;
|
||||||
|
pevent->pnext = 0; //vertical queue for serialized operation
|
||||||
|
pevent->process_event = compdev_event_select_if_driver;
|
||||||
|
pevent->process_queue = event_list_default_process_queue;
|
||||||
|
|
||||||
|
InsertTailList( &dev_mgr->event_list, &pevent->event_link );
|
||||||
|
KeSetEvent( &dev_mgr->wake_up_event, 0, FALSE ); // wake up the dev_mgr_thread
|
||||||
|
bret = TRUE;
|
||||||
|
|
||||||
|
LBL_OUT:
|
||||||
|
|
||||||
|
unlock_dev( pdev, TRUE );
|
||||||
|
KeReleaseSpinLockFromDpcLevel( &dev_mgr->event_list_lock );
|
||||||
|
usb_unlock_dev( pdev );
|
||||||
|
return bret;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
compdev_set_cfg_completion(
|
||||||
|
PURB purb,
|
||||||
|
PVOID context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DEV_HANDLE dev_handle;
|
||||||
|
PUSB_DEV_MANAGER dev_mgr;
|
||||||
|
PWORK_QUEUE_ITEM pwork_item;
|
||||||
|
PUSB_DRIVER pdriver;
|
||||||
|
NTSTATUS status;
|
||||||
|
PUSB_DEV pdev;
|
||||||
|
|
||||||
|
USE_IRQL;
|
||||||
|
|
||||||
|
if( purb == NULL || context == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
dev_handle = purb->endp_handle & ~0xffff;
|
||||||
|
dev_mgr = ( PUSB_DEV_MANAGER ) context;
|
||||||
|
pdriver = ( PUSB_DRIVER )purb->reference;
|
||||||
|
|
||||||
|
if( purb->status != STATUS_SUCCESS )
|
||||||
|
{
|
||||||
|
usb_free_mem( purb );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_free_mem( purb );
|
||||||
|
purb = NULL;
|
||||||
|
|
||||||
|
// set the dev state
|
||||||
|
status = usb_query_and_lock_dev( dev_mgr, dev_handle, &pdev );
|
||||||
|
if( status != STATUS_SUCCESS )
|
||||||
|
{
|
||||||
|
usb_unlock_dev( pdev );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// safe to release the pdev ref since we are in urb completion
|
||||||
|
usb_unlock_dev( pdev );
|
||||||
|
|
||||||
|
lock_dev( pdev, TRUE );
|
||||||
|
if( dev_state( pdev ) >= USB_DEV_STATE_BEFORE_ZOMB )
|
||||||
|
{
|
||||||
|
unlock_dev( pdev, TRUE );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( dev_mgr_set_driver( dev_mgr, dev_handle, pdriver, pdev ) == FALSE )
|
||||||
|
return;
|
||||||
|
|
||||||
|
//transit the state to configured
|
||||||
|
pdev->flags &= ~USB_DEV_STATE_MASK;
|
||||||
|
pdev->flags |= USB_DEV_STATE_CONFIGURED;
|
||||||
|
unlock_dev( pdev, TRUE );
|
||||||
|
|
||||||
|
//
|
||||||
|
// we change to use our thread for driver choosing. it will reduce
|
||||||
|
// the race condition when different pnp event comes simultaneously
|
||||||
|
//
|
||||||
|
usb_dbg_print( DBGLVL_MAXIMUM, ( "compdev_set_cfg_completion(): start select driver for the dev\n" ) );
|
||||||
|
compdev_post_event_select_driver( dev_mgr, dev_handle );
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
compdev_select_driver(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
DEV_HANDLE dev_handle
|
||||||
|
)
|
||||||
|
{
|
||||||
|
URB urb;
|
||||||
|
LONG i, j, k, credit;
|
||||||
|
ULONG dev_id;
|
||||||
|
PUCHAR buf;
|
||||||
|
NTSTATUS status;
|
||||||
|
PUSB_DRIVER pcand, ptemp_drv;
|
||||||
|
|
||||||
|
PUSB_CTRL_SETUP_PACKET psetup;
|
||||||
|
PUSB_INTERFACE_DESC pif_desc;
|
||||||
|
PUSB_CONFIGURATION_DESC pconfig_desc;
|
||||||
|
PUSB_DEV pdev;
|
||||||
|
|
||||||
|
USE_IRQL;
|
||||||
|
|
||||||
|
usb_dbg_print( DBGLVL_MAXIMUM, ( "compdev_select_driver(): entering...\n" ) );
|
||||||
|
|
||||||
|
dev_id = dev_handle >> 16;
|
||||||
|
|
||||||
|
buf = usb_alloc_mem( NonPagedPool, 512 );
|
||||||
|
|
||||||
|
if( buf == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// now let's get the descs, one configuration
|
||||||
|
urb_init( &urb );
|
||||||
|
psetup = ( PUSB_CTRL_SETUP_PACKET )urb.setup_packet;
|
||||||
|
urb.endp_handle = dev_handle | 0xffff;
|
||||||
|
urb.data_buffer = buf;
|
||||||
|
urb.data_length = 512;
|
||||||
|
urb.completion = NULL; // this is an immediate request, no completion required
|
||||||
|
urb.context = NULL;
|
||||||
|
urb.reference = 0;
|
||||||
|
psetup->bmRequestType = 0x80;
|
||||||
|
psetup->bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||||
|
psetup->wValue = USB_DT_CONFIG << 8;
|
||||||
|
psetup->wIndex = 0;
|
||||||
|
psetup->wLength = 512;
|
||||||
|
|
||||||
|
status = usb_submit_urb( dev_mgr, &urb );
|
||||||
|
if( status == STATUS_PENDING )
|
||||||
|
{
|
||||||
|
TRAP();
|
||||||
|
}
|
||||||
|
|
||||||
|
// let's scan the interfacs for those we recognize
|
||||||
|
pconfig_desc = ( PUSB_CONFIGURATION_DESC )buf;
|
||||||
|
if( pconfig_desc->wTotalLength > 512 )
|
||||||
|
{
|
||||||
|
usb_free_mem( buf );
|
||||||
|
usb_dbg_print( DBGLVL_MAXIMUM, ( "compdev_select_driver(): error, bad configuration desc\n" ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pif_desc = ( PUSB_INTERFACE_DESC )&pconfig_desc[ 1 ];
|
||||||
|
|
||||||
|
if( usb_query_and_lock_dev( dev_mgr, dev_handle, &pdev ) != STATUS_SUCCESS )
|
||||||
|
{
|
||||||
|
usb_free_mem( buf );
|
||||||
|
usb_dbg_print( DBGLVL_MAXIMUM, ( "compdev_select_driver(): error, dev does not exist\n" ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( i = 0; i < ( LONG )pconfig_desc->bNumInterfaces; i++ )
|
||||||
|
{
|
||||||
|
for( j = 0, credit = 0, pcand = NULL; j < DEVMGR_MAX_DRIVERS; j++ )
|
||||||
|
{
|
||||||
|
ptemp_drv = &dev_mgr->driver_list[ j ];
|
||||||
|
k = dev_mgr_score_driver_for_if( dev_mgr, ptemp_drv, pif_desc );
|
||||||
|
if( k > credit )
|
||||||
|
credit = k, pcand = ptemp_drv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( credit )
|
||||||
|
{
|
||||||
|
// ok, we find one
|
||||||
|
CONNECT_DATA param;
|
||||||
|
|
||||||
|
if( pcand->disp_tbl.dev_connect )
|
||||||
|
{
|
||||||
|
param.dev_mgr = dev_mgr;
|
||||||
|
param.pdriver = pcand;
|
||||||
|
param.dev_handle = 0;
|
||||||
|
pcand->disp_tbl.dev_connect( ¶m, usb_make_handle( dev_id, i, 0 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( usb_skip_if_and_altif( ( PUCHAR* )&pif_desc ) == FALSE )
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
usb_unlock_dev( pdev );
|
||||||
|
|
||||||
|
if( buf )
|
||||||
|
{
|
||||||
|
usb_free_mem( buf );
|
||||||
|
buf = NULL;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
compdev_stop(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
DEV_HANDLE dev_handle
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PUSB_DEV pdev;
|
||||||
|
LONG i;
|
||||||
|
ULONG dev_id;
|
||||||
|
PUSB_DRIVER pdrv;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
if( dev_mgr == NULL || dev_handle == 0 )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
pdev = NULL;
|
||||||
|
dev_id = dev_handle >> 16;
|
||||||
|
status = usb_query_and_lock_dev( dev_mgr, dev_handle, &pdev );
|
||||||
|
if( pdev )
|
||||||
|
{
|
||||||
|
if( pdev->usb_config )
|
||||||
|
{
|
||||||
|
for( i = 0; i < pdev->usb_config->if_count; i++ )
|
||||||
|
{
|
||||||
|
if( pdrv = pdev->usb_config->interf[ i ].pif_drv )
|
||||||
|
{
|
||||||
|
pdrv->disp_tbl.dev_stop( dev_mgr, usb_make_handle( dev_id, i, 0 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( status == STATUS_SUCCESS )
|
||||||
|
{
|
||||||
|
usb_unlock_dev( pdev );
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
compdev_disconnect(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
DEV_HANDLE dev_handle
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PUSB_DEV pdev;
|
||||||
|
LONG i;
|
||||||
|
ULONG dev_id;
|
||||||
|
PUSB_DRIVER pdrv;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
if( dev_mgr == NULL || dev_handle == 0 )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
pdev = NULL;
|
||||||
|
dev_id = dev_handle >> 16;
|
||||||
|
status = usb_query_and_lock_dev( dev_mgr, dev_handle, &pdev );
|
||||||
|
if( pdev )
|
||||||
|
{
|
||||||
|
if( pdev->usb_config )
|
||||||
|
{
|
||||||
|
for( i = 0; i < pdev->usb_config->if_count; i++ )
|
||||||
|
{
|
||||||
|
if( pdrv = pdev->usb_config->interf[ i ].pif_drv )
|
||||||
|
{
|
||||||
|
pdrv->disp_tbl.dev_disconnect( dev_mgr, usb_make_handle( dev_id, i, 0 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( status == STATUS_SUCCESS )
|
||||||
|
{
|
||||||
|
usb_unlock_dev( pdev );
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// note:
|
||||||
|
// dev_mgr_set_driver seems to be dangeous since compdev, gendrv and hub and
|
||||||
|
// umss use it to set the driver while there may exist race condition when the
|
||||||
|
// dev_mgr_disconnect_dev is called. If the driver is set and the
|
||||||
|
// disconnect_dev cut in immediately, the stop or disconnect may not function
|
||||||
|
// well. Now hub and compdev's set dev_mgr_set_driver are ok.
|
||||||
|
//
|
||||||
|
// another danger comes from umss's dev irp processing. This may confuse the device
|
||||||
|
// when the disk is being read or written, and at the same time dmgrdisp's dispatch
|
||||||
|
// route irp request to the device a control request.
|
70
reactos/drivers/usb/nt4compat/usbdriver/debug.h
Normal file
70
reactos/drivers/usb/nt4compat/usbdriver/debug.h
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#ifndef _UHCIDBG_H_
|
||||||
|
#define _UHCIDBG_H_
|
||||||
|
|
||||||
|
#define DBGLVL_OFF 0 // if gDebugLevel set to this, there is NO debug output
|
||||||
|
#define DBGLVL_MINIMUM 1 // minimum verbosity
|
||||||
|
#define DBGLVL_DEFAULT 2 // default verbosity level if no registry override
|
||||||
|
#define DBGLVL_MEDIUM 3 // medium verbosity
|
||||||
|
#define DBGLVL_HIGH 4 // highest 'safe' level (without severely affecting timing )
|
||||||
|
#define DBGLVL_MAXIMUM 5 // maximum level, may be dangerous
|
||||||
|
|
||||||
|
#ifndef DBGSTR_PREFIX
|
||||||
|
#define DBGSTR_PREFIX "wood_uhci: "
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEBUG_UHCI TRUE
|
||||||
|
#define DEBUG_HUB TRUE
|
||||||
|
#define DEBUG_DEV_MGR TRUE
|
||||||
|
|
||||||
|
#define DPRINT DbgPrint
|
||||||
|
|
||||||
|
|
||||||
|
#define UHCI_DBGOUTSIZE 512
|
||||||
|
|
||||||
|
#define hcd_dbg_print_cond( ilev, cond, _x_) \
|
||||||
|
if( debug_level && ( ilev <= debug_level ) && ( cond )) { \
|
||||||
|
DPRINT( DBGSTR_PREFIX ); \
|
||||||
|
DPRINT _x_ ; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define hcd_dbg_print( ilev, _x_) hcd_dbg_print_cond( ilev, TRUE, _x_ )
|
||||||
|
|
||||||
|
extern ULONG debug_level;
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
|
||||||
|
#define uhci_dbg_print_cond( ilev, cond, _x_ ) hcd_dbg_print_cond( ilev, cond, _x_ )
|
||||||
|
#define uhci_dbg_print( ilev, _x_) hcd_dbg_print_cond( ilev, TRUE, _x_ )
|
||||||
|
|
||||||
|
#define uhci_trap_cond( ilev, cond ) if ( debug_level && ( ilev <= debug_level ) && (cond) ) TRAP()
|
||||||
|
#define uhci_trap( ilev ) uhci_trap_cond( ilev, TRUE )
|
||||||
|
|
||||||
|
|
||||||
|
#define uhci_assert( cond ) ASSERT( cond )
|
||||||
|
#define dbg_count_list( _x_ ) usb_count_list( _x_ )
|
||||||
|
|
||||||
|
#define TRAP() DbgBreakPoint()
|
||||||
|
|
||||||
|
#else // if not DBG
|
||||||
|
|
||||||
|
// dummy definitions that go away in the retail build
|
||||||
|
|
||||||
|
#define uhci_dbg_print_cond( ilev, cond, _x_ )
|
||||||
|
#define uhci_dbg_print( ilev, _x_)
|
||||||
|
#define uhci_trap_cont( ilev, cond )
|
||||||
|
#define uhci_trap( ilev )
|
||||||
|
#define uhci_assert( cond )
|
||||||
|
#define TRAP()
|
||||||
|
#define dbg_count_list( _x_ ) 0
|
||||||
|
|
||||||
|
#endif //DBG
|
||||||
|
|
||||||
|
#define usb_dbg_print( ilev, _x_ ) uhci_dbg_print( ilev, _x_ )
|
||||||
|
#define ehci_dbg_print( ilev, _x_ ) uhci_dbg_print( ilev, _x_ )
|
||||||
|
#define ohci_dbg_print( ilev, _x_ ) uhci_dbg_print( ilev, _x_ )
|
||||||
|
#define ehci_dbg_print_cond( ilev, cond, _x_ ) uhci_dbg_print_cond( ilev, cond, _x_ )
|
||||||
|
|
||||||
|
#define DO_NOTHING
|
||||||
|
|
||||||
|
LONG usb_count_list( struct _LIST_ENTRY* list_head );
|
||||||
|
#endif // included
|
551
reactos/drivers/usb/nt4compat/usbdriver/dmgrdisp.c
Normal file
551
reactos/drivers/usb/nt4compat/usbdriver/dmgrdisp.c
Normal file
|
@ -0,0 +1,551 @@
|
||||||
|
/**
|
||||||
|
* dmgrdisp.c - USB driver stack project for Windows NT 4.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
|
||||||
|
*
|
||||||
|
* This program/include file is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as published
|
||||||
|
* by the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program/include file is distributed in the hope that it will be
|
||||||
|
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||||
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program (in the main directory of the distribution, the file
|
||||||
|
* COPYING); if not, write to the Free Software Foundation,Inc., 59 Temple
|
||||||
|
* Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ntddk.h>
|
||||||
|
#include "usb.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "td.h"
|
||||||
|
#include "hub.h"
|
||||||
|
|
||||||
|
VOID
|
||||||
|
disp_urb_completion(
|
||||||
|
PURB purb,
|
||||||
|
PVOID context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PUSB_CTRL_SETUP_PACKET psetup;
|
||||||
|
PUSB_DEV_MANAGER dev_mgr;
|
||||||
|
ULONG ctrl_code;
|
||||||
|
NTSTATUS status;
|
||||||
|
PDEVEXT_HEADER dev_hdr;
|
||||||
|
|
||||||
|
if( purb == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
ctrl_code = ( ULONG )purb->reference;
|
||||||
|
dev_mgr = ( PUSB_DEV_MANAGER )purb->context;
|
||||||
|
|
||||||
|
// at this stage, the irp can not be canceled since the urb
|
||||||
|
// won't be found in any queue and the irp is not in any queue.
|
||||||
|
// see line 4685 in hub.c
|
||||||
|
// Sometimes, it may be very fast to enter this routine before
|
||||||
|
// the dev_mgr_register_irp to be called in dispatch routine in
|
||||||
|
// usb2.0 environment as
|
||||||
|
// we did in usb1.1 driver. We can not simply add a loop to wait
|
||||||
|
// for the dispatch thread to add the irp to the list, because
|
||||||
|
// here we are at DPC level higher than the dispatch thread
|
||||||
|
// running level. And the solution is to register the irp
|
||||||
|
// before the urb is scheduled instead of registering it after
|
||||||
|
// urb is scheduled.
|
||||||
|
if( purb->pirp )
|
||||||
|
{
|
||||||
|
PIO_STACK_LOCATION irp_stack;
|
||||||
|
dev_mgr_remove_irp( dev_mgr, purb->pirp );
|
||||||
|
|
||||||
|
status = purb->status;
|
||||||
|
irp_stack = IoGetCurrentIrpStackLocation( purb->pirp );
|
||||||
|
|
||||||
|
if( purb->status != STATUS_SUCCESS )
|
||||||
|
{
|
||||||
|
purb->pirp->IoStatus.Information = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// currently only IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL
|
||||||
|
// are allowed. And we do not need to set information
|
||||||
|
// for IRP_MJ_INTERNAL_DEVICE_CONTROL
|
||||||
|
if( irp_stack->MajorFunction == IRP_MJ_DEVICE_CONTROL )
|
||||||
|
purb->pirp->IoStatus.Information = purb->data_length;
|
||||||
|
}
|
||||||
|
purb->pirp->IoStatus.Status = status;
|
||||||
|
if( irp_stack )
|
||||||
|
{
|
||||||
|
dev_hdr = irp_stack->DeviceObject->DeviceExtension;
|
||||||
|
if( dev_hdr->start_io )
|
||||||
|
{
|
||||||
|
IoStartNextPacket( irp_stack->DeviceObject, TRUE );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IoCompleteRequest( purb->pirp, IO_NO_INCREMENT );
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
disp_noio_urb_completion(
|
||||||
|
PURB purb,
|
||||||
|
PVOID context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PUSB_CTRL_SETUP_PACKET psetup;
|
||||||
|
PURB purb2;
|
||||||
|
PUSB_DEV_MANAGER dev_mgr;
|
||||||
|
NTSTATUS status;
|
||||||
|
PIO_STACK_LOCATION irp_stack;
|
||||||
|
PDEVEXT_HEADER dev_hdr;
|
||||||
|
|
||||||
|
if( purb == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
psetup = ( PUSB_CTRL_SETUP_PACKET )purb->setup_packet;
|
||||||
|
|
||||||
|
if( psetup->bmRequestType == 0x2
|
||||||
|
&& psetup->bRequest == USB_REQ_CLEAR_FEATURE
|
||||||
|
&& psetup->wIndex == 0 ) //reset pipe
|
||||||
|
purb2 = ( PURB )context;
|
||||||
|
else
|
||||||
|
purb2 = purb;
|
||||||
|
|
||||||
|
if( purb2->pirp == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
dev_mgr = ( PUSB_DEV_MANAGER )purb2->context;
|
||||||
|
|
||||||
|
dev_mgr_remove_irp( dev_mgr, purb2->pirp );
|
||||||
|
|
||||||
|
if( purb->status != STATUS_SUCCESS )
|
||||||
|
status = STATUS_IO_DEVICE_ERROR;
|
||||||
|
|
||||||
|
purb2->pirp->IoStatus.Information = 0;
|
||||||
|
purb2->pirp->IoStatus.Status = status;
|
||||||
|
irp_stack = IoGetCurrentIrpStackLocation( purb->pirp );
|
||||||
|
if( irp_stack )
|
||||||
|
{
|
||||||
|
dev_hdr = irp_stack->DeviceObject->DeviceExtension;
|
||||||
|
if( dev_hdr->start_io )
|
||||||
|
{
|
||||||
|
IoStartNextPacket( irp_stack->DeviceObject, TRUE );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IoCompleteRequest( purb2->pirp, IO_NO_INCREMENT );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
dev_mgr_dispatch(
|
||||||
|
IN PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
IN PIRP irp
|
||||||
|
)
|
||||||
|
//this function is called by the hcd's
|
||||||
|
//dispatch when they have done their job.
|
||||||
|
{
|
||||||
|
PIO_STACK_LOCATION irp_stack;
|
||||||
|
NTSTATUS status;
|
||||||
|
ULONG ctrl_code;
|
||||||
|
USE_IRQL;
|
||||||
|
|
||||||
|
if( dev_mgr == NULL || irp == NULL )
|
||||||
|
{
|
||||||
|
EXIT_DISPATCH( STATUS_INVALID_PARAMETER, irp );
|
||||||
|
}
|
||||||
|
|
||||||
|
status = STATUS_SUCCESS;
|
||||||
|
irp_stack = IoGetCurrentIrpStackLocation (irp);
|
||||||
|
ctrl_code = irp_stack->Parameters.DeviceIoControl.IoControlCode;
|
||||||
|
|
||||||
|
switch ( irp_stack->MajorFunction )
|
||||||
|
{
|
||||||
|
case IRP_MJ_CREATE:
|
||||||
|
{
|
||||||
|
InterlockedIncrement( &dev_mgr->open_count );
|
||||||
|
EXIT_DISPATCH( STATUS_SUCCESS, irp );
|
||||||
|
}
|
||||||
|
case IRP_MJ_CLOSE:
|
||||||
|
{
|
||||||
|
InterlockedDecrement( &dev_mgr->open_count );
|
||||||
|
EXIT_DISPATCH( STATUS_SUCCESS, irp );
|
||||||
|
}
|
||||||
|
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
|
||||||
|
case IRP_MJ_DEVICE_CONTROL:
|
||||||
|
{
|
||||||
|
switch( ctrl_code )
|
||||||
|
{
|
||||||
|
case IOCTL_GET_DEV_COUNT:
|
||||||
|
{
|
||||||
|
LONG dev_count;
|
||||||
|
|
||||||
|
irp->IoStatus.Information = 0;
|
||||||
|
if( irp_stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof( LONG ) )
|
||||||
|
{
|
||||||
|
EXIT_DISPATCH( STATUS_INVALID_PARAMETER, irp );
|
||||||
|
}
|
||||||
|
|
||||||
|
KeAcquireSpinLock( &dev_mgr->dev_list_lock, &old_irql );
|
||||||
|
dev_count = usb_count_list( &dev_mgr->dev_list );
|
||||||
|
KeReleaseSpinLock( &dev_mgr->dev_list_lock, old_irql );
|
||||||
|
|
||||||
|
*( ( PLONG )irp->AssociatedIrp.SystemBuffer ) = dev_count;
|
||||||
|
irp->IoStatus.Information = sizeof( LONG );
|
||||||
|
EXIT_DISPATCH( STATUS_SUCCESS, irp );
|
||||||
|
}
|
||||||
|
case IOCTL_ENUM_DEVICES:
|
||||||
|
{
|
||||||
|
PLIST_ENTRY pthis, pnext;
|
||||||
|
LONG dev_count, array_size, i, j;
|
||||||
|
PUSB_DEV pdev;
|
||||||
|
PENUM_DEV_ARRAY peda;
|
||||||
|
|
||||||
|
irp->IoStatus.Information = 0;
|
||||||
|
if( irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof( LONG ) )
|
||||||
|
{
|
||||||
|
EXIT_DISPATCH( STATUS_INVALID_PARAMETER, irp );
|
||||||
|
}
|
||||||
|
if( irp_stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof( ENUM_DEV_ARRAY ) )
|
||||||
|
{
|
||||||
|
EXIT_DISPATCH( STATUS_INVALID_PARAMETER, irp );
|
||||||
|
}
|
||||||
|
array_size = *( ( PULONG )irp->AssociatedIrp.SystemBuffer );
|
||||||
|
|
||||||
|
KeAcquireSpinLock( &dev_mgr->dev_list_lock, &old_irql );
|
||||||
|
dev_count = usb_count_list( &dev_mgr->dev_list );
|
||||||
|
dev_count = dev_count > array_size ? array_size : dev_count;
|
||||||
|
peda = ( PENUM_DEV_ARRAY )irp->AssociatedIrp.SystemBuffer;
|
||||||
|
RtlZeroMemory( peda, sizeof( ENUM_DEV_ARRAY ) + ( dev_count - 1 ) * sizeof( ENUM_DEV_ELEMENT ) );
|
||||||
|
|
||||||
|
if( dev_count )
|
||||||
|
{
|
||||||
|
ListFirst( &dev_mgr->dev_list, pthis );
|
||||||
|
for( i = 0, j = 0; i < dev_count; i++ )
|
||||||
|
{
|
||||||
|
pdev = struct_ptr( pthis, USB_DEV, dev_link );
|
||||||
|
ListNext( &dev_mgr->dev_list, pthis, pnext );
|
||||||
|
pthis = pnext;
|
||||||
|
|
||||||
|
lock_dev( pdev, FALSE );
|
||||||
|
if( dev_state( pdev ) == USB_DEV_STATE_ZOMB )
|
||||||
|
{
|
||||||
|
unlock_dev( pdev, FALSE );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( dev_state( pdev ) < USB_DEV_STATE_ADDRESSED )
|
||||||
|
{
|
||||||
|
unlock_dev( pdev, FALSE );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
peda->dev_arr[ i ].dev_handle = ( pdev->dev_id << 16 );
|
||||||
|
//may not get the desc yet
|
||||||
|
if( pdev->pusb_dev_desc )
|
||||||
|
{
|
||||||
|
peda->dev_arr[ i ].product_id = pdev->pusb_dev_desc->idProduct;
|
||||||
|
peda->dev_arr[ i ].vendor_id = pdev->pusb_dev_desc->idVendor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
peda->dev_arr[ i ].product_id = 0xffff;
|
||||||
|
peda->dev_arr[ i ].vendor_id = 0xffff;
|
||||||
|
}
|
||||||
|
peda->dev_arr[ i ].dev_addr = pdev->dev_addr;
|
||||||
|
unlock_dev( pdev, FALSE );
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
peda->dev_count = dev_count ? j : 0;
|
||||||
|
KeReleaseSpinLock( &dev_mgr->dev_list_lock, old_irql );
|
||||||
|
|
||||||
|
irp->IoStatus.Information = sizeof( ENUM_DEV_ARRAY ) + ( dev_count - 1 ) * sizeof( ENUM_DEV_ELEMENT );
|
||||||
|
EXIT_DISPATCH( STATUS_SUCCESS, irp );
|
||||||
|
}
|
||||||
|
case IOCTL_GET_DEV_DESC:
|
||||||
|
{
|
||||||
|
GET_DEV_DESC_REQ gddr;
|
||||||
|
PUSB_DESC_HEADER pusb_desc_header;
|
||||||
|
KIRQL old_irql;
|
||||||
|
PUSB_DEV pdev;
|
||||||
|
LONG buf_size;
|
||||||
|
|
||||||
|
if( irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof( GET_DEV_DESC_REQ ) )
|
||||||
|
{
|
||||||
|
EXIT_DISPATCH( STATUS_INVALID_PARAMETER, irp );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( irp_stack->Parameters.DeviceIoControl.OutputBufferLength < 8 )
|
||||||
|
{
|
||||||
|
EXIT_DISPATCH( STATUS_INVALID_PARAMETER, irp );
|
||||||
|
}
|
||||||
|
|
||||||
|
status = STATUS_SUCCESS;
|
||||||
|
buf_size = irp_stack->Parameters.DeviceIoControl.OutputBufferLength;
|
||||||
|
RtlCopyMemory( &gddr, irp->AssociatedIrp.SystemBuffer, sizeof( GET_DEV_DESC_REQ ) );
|
||||||
|
pusb_desc_header = irp->AssociatedIrp.SystemBuffer;
|
||||||
|
|
||||||
|
if( gddr.desc_type != USB_DT_CONFIG && gddr.desc_type != USB_DT_DEVICE )
|
||||||
|
{
|
||||||
|
EXIT_DISPATCH( STATUS_INVALID_DEVICE_REQUEST, irp );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( usb_query_and_lock_dev( dev_mgr, gddr.dev_handle, &pdev ) != STATUS_SUCCESS )
|
||||||
|
{
|
||||||
|
EXIT_DISPATCH( STATUS_IO_DEVICE_ERROR, irp );
|
||||||
|
}
|
||||||
|
|
||||||
|
lock_dev( pdev, FALSE );
|
||||||
|
if( dev_state( pdev ) == USB_DEV_STATE_ZOMB )
|
||||||
|
{
|
||||||
|
status = STATUS_INVALID_DEVICE_STATE;
|
||||||
|
goto ERROR_OUT;
|
||||||
|
}
|
||||||
|
if( dev_state( pdev ) != USB_DEV_STATE_ADDRESSED && \
|
||||||
|
dev_state( pdev ) != USB_DEV_STATE_CONFIGURED )
|
||||||
|
{
|
||||||
|
status = STATUS_DEVICE_NOT_READY;
|
||||||
|
goto ERROR_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( pdev->pusb_dev_desc == NULL )
|
||||||
|
{
|
||||||
|
status = STATUS_DEVICE_NOT_READY;
|
||||||
|
goto ERROR_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( gddr.desc_type == USB_DT_DEVICE )
|
||||||
|
{
|
||||||
|
RtlCopyMemory(
|
||||||
|
pusb_desc_header,
|
||||||
|
pdev->pusb_dev_desc,
|
||||||
|
buf_size > sizeof( USB_DEVICE_DESC )
|
||||||
|
? sizeof( USB_DEVICE_DESC ) : buf_size );
|
||||||
|
|
||||||
|
irp->IoStatus.Information =
|
||||||
|
buf_size >= sizeof( USB_DEVICE_DESC )
|
||||||
|
? sizeof( USB_DEVICE_DESC ): buf_size ;
|
||||||
|
}
|
||||||
|
else if( gddr.desc_type == USB_DT_CONFIG )
|
||||||
|
{
|
||||||
|
PUSB_CONFIGURATION_DESC pusb_config_desc;
|
||||||
|
if( pdev->pusb_dev_desc->bNumConfigurations <= gddr.desc_idx )
|
||||||
|
{
|
||||||
|
status = STATUS_INVALID_PARAMETER;
|
||||||
|
goto ERROR_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
pusb_config_desc = usb_find_config_desc_by_idx(
|
||||||
|
( PUCHAR )&pdev->pusb_dev_desc[ 1 ],
|
||||||
|
gddr.desc_idx,
|
||||||
|
pdev->pusb_dev_desc->bNumConfigurations );
|
||||||
|
|
||||||
|
if( pusb_config_desc == NULL )
|
||||||
|
{
|
||||||
|
status = STATUS_DEVICE_NOT_READY;
|
||||||
|
goto ERROR_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
RtlCopyMemory(
|
||||||
|
pusb_desc_header,
|
||||||
|
pusb_config_desc,
|
||||||
|
buf_size >= pusb_config_desc->wTotalLength
|
||||||
|
? pusb_config_desc->wTotalLength : buf_size );
|
||||||
|
|
||||||
|
irp->IoStatus.Information =
|
||||||
|
buf_size >= pusb_config_desc->wTotalLength
|
||||||
|
? pusb_config_desc->wTotalLength : buf_size;
|
||||||
|
}
|
||||||
|
ERROR_OUT:
|
||||||
|
unlock_dev( pdev, FALSE );
|
||||||
|
usb_unlock_dev( pdev );
|
||||||
|
EXIT_DISPATCH( status, irp );
|
||||||
|
}
|
||||||
|
case IOCTL_SUBMIT_URB_RD:
|
||||||
|
case IOCTL_SUBMIT_URB_WR:
|
||||||
|
case IOCTL_SUBMIT_URB_NOIO:
|
||||||
|
{
|
||||||
|
LONG buf_size;
|
||||||
|
PURB purb;
|
||||||
|
KIRQL old_irql;
|
||||||
|
ULONG endp_idx, if_idx, user_buffer_length;
|
||||||
|
PUCHAR user_buffer;
|
||||||
|
PUSB_DEV pdev;
|
||||||
|
DEV_HANDLE endp_handle;
|
||||||
|
PUSB_ENDPOINT pendp;
|
||||||
|
|
||||||
|
PUSB_CTRL_SETUP_PACKET psetup;
|
||||||
|
|
||||||
|
if( irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof( URB ) )
|
||||||
|
{
|
||||||
|
EXIT_DISPATCH( STATUS_INVALID_PARAMETER, irp );
|
||||||
|
}
|
||||||
|
|
||||||
|
purb = ( PURB )irp->AssociatedIrp.SystemBuffer;
|
||||||
|
endp_handle = purb->endp_handle;
|
||||||
|
|
||||||
|
if( ctrl_code == IOCTL_SUBMIT_URB_RD || ctrl_code == IOCTL_SUBMIT_URB_WR )
|
||||||
|
{
|
||||||
|
if( irp_stack->MajorFunction == IRP_MJ_DEVICE_CONTROL )
|
||||||
|
{
|
||||||
|
user_buffer_length = irp_stack->Parameters.DeviceIoControl.OutputBufferLength;
|
||||||
|
if( user_buffer_length == 0 )
|
||||||
|
EXIT_DISPATCH( STATUS_INVALID_PARAMETER, irp );
|
||||||
|
user_buffer = MmGetSystemAddressForMdl( irp->MdlAddress );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( purb->data_buffer == NULL || purb->data_length == 0 )
|
||||||
|
EXIT_DISPATCH( STATUS_INVALID_PARAMETER, irp );
|
||||||
|
user_buffer_length = purb->data_length;
|
||||||
|
user_buffer = purb->data_buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( usb_query_and_lock_dev( dev_mgr, endp_handle & ~0xffff, &pdev ) != STATUS_SUCCESS )
|
||||||
|
{
|
||||||
|
EXIT_DISPATCH( STATUS_IO_DEVICE_ERROR, irp );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lock_dev( pdev, FALSE );
|
||||||
|
if( dev_state( pdev ) == USB_DEV_STATE_ZOMB \
|
||||||
|
|| ( dev_state( pdev ) < USB_DEV_STATE_ADDRESSED ) )
|
||||||
|
|
||||||
|
{
|
||||||
|
status = STATUS_INVALID_DEVICE_STATE;
|
||||||
|
goto ERROR_OUT1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( dev_state( pdev ) == USB_DEV_STATE_ADDRESSED
|
||||||
|
&& !default_endp_handle( endp_handle ) )
|
||||||
|
{
|
||||||
|
status = STATUS_DEVICE_NOT_READY;
|
||||||
|
goto ERROR_OUT1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if_idx = if_idx_from_handle( endp_handle );
|
||||||
|
endp_idx = endp_idx_from_handle( endp_handle );
|
||||||
|
|
||||||
|
//if_idx exceeds the upper limit
|
||||||
|
if( pdev->usb_config )
|
||||||
|
{
|
||||||
|
if( if_idx >= pdev->usb_config->if_count
|
||||||
|
|| endp_idx >= pdev->usb_config->interf[ if_idx ].endp_count )
|
||||||
|
{
|
||||||
|
if( !default_endp_handle( endp_handle ) )
|
||||||
|
{
|
||||||
|
status = STATUS_INVALID_DEVICE_STATE;
|
||||||
|
goto ERROR_OUT1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
endp_from_handle( pdev, endp_handle, pendp );
|
||||||
|
// FIXME: don't know what evil will let loose
|
||||||
|
if( endp_type( pendp ) != USB_ENDPOINT_XFER_CONTROL )
|
||||||
|
{
|
||||||
|
if( user_buffer_length > 0x100000 )
|
||||||
|
{
|
||||||
|
status = STATUS_INVALID_PARAMETER;
|
||||||
|
goto ERROR_OUT1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
purb->pirp = irp;
|
||||||
|
purb->context = dev_mgr;
|
||||||
|
purb->reference = ctrl_code;
|
||||||
|
|
||||||
|
if( ctrl_code == IOCTL_SUBMIT_URB_RD || ctrl_code == IOCTL_SUBMIT_URB_WR )
|
||||||
|
{
|
||||||
|
if( ctrl_code == IOCTL_SUBMIT_URB_RD )
|
||||||
|
KeFlushIoBuffers( irp->MdlAddress, TRUE, TRUE );
|
||||||
|
else
|
||||||
|
KeFlushIoBuffers( irp->MdlAddress, FALSE, TRUE );
|
||||||
|
|
||||||
|
purb->data_buffer = user_buffer;
|
||||||
|
purb->data_length = user_buffer_length;
|
||||||
|
purb->completion = disp_urb_completion;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
purb->completion = disp_noio_urb_completion;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock_dev( pdev, FALSE );
|
||||||
|
|
||||||
|
// we have to mark irp before the urb is scheduled to
|
||||||
|
// avoid race condition
|
||||||
|
IoMarkIrpPending( irp );
|
||||||
|
ASSERT( dev_mgr_register_irp( dev_mgr, irp, purb ) );
|
||||||
|
status = usb_submit_urb( dev_mgr, purb );
|
||||||
|
if( status != STATUS_PENDING )
|
||||||
|
{
|
||||||
|
IoGetCurrentIrpStackLocation( (irp) )->Control &= ~SL_PENDING_RETURNED;
|
||||||
|
dev_mgr_remove_irp( dev_mgr, irp );
|
||||||
|
}
|
||||||
|
usb_unlock_dev( pdev );
|
||||||
|
if( status != STATUS_PENDING)
|
||||||
|
{
|
||||||
|
irp->IoStatus.Status = status;
|
||||||
|
IoCompleteRequest( irp, IO_NO_INCREMENT);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
ERROR_OUT1:
|
||||||
|
unlock_dev( pdev, FALSE );
|
||||||
|
usb_unlock_dev( pdev );
|
||||||
|
irp->IoStatus.Information = 0;
|
||||||
|
EXIT_DISPATCH( status, irp );
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
irp->IoStatus.Information = 0;
|
||||||
|
EXIT_DISPATCH( STATUS_NOT_IMPLEMENTED, irp );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
irp->IoStatus.Information = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXIT_DISPATCH( STATUS_INVALID_DEVICE_REQUEST, irp );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*#define IOCTL_GET_DEV_COUNT CTL_CODE( FILE_HCD_DEV_TYPE, 4093, METHOD_BUFFERED, FILE_ANY_ACCESS )
|
||||||
|
//input_buffer and input_buffer_length is zero, output_buffer is to receive a dword value of the
|
||||||
|
//dev count, output_buffer_length must be no less than sizeof( long ).
|
||||||
|
|
||||||
|
#define IOCTL_ENUM_DEVICES CTL_CODE( FILE_HCD_DEV_TYPE, 4094, METHOD_BUFFERED, FILE_ANY_ACCESS )
|
||||||
|
//input_buffer is a dword value to indicate the count of elements in the array
|
||||||
|
//input_buffer_length is sizeof( long ), output_buffer is to receive a
|
||||||
|
//structure ENUM_DEV_ARRAY where dev_count is the elements hold in this array.
|
||||||
|
|
||||||
|
#define IOCTL_GET_DEV_DESC CTL_CODE( FILE_HCD_DEV_TYPE, 4095, METHOD_BUFFERED, FILE_ANY_ACCESS )
|
||||||
|
//input_buffer is a structure GET_DEV_DESC_REQ, and the input_buffer_length is
|
||||||
|
//no less than sizeof( input_buffer ), output_buffer is a buffer to receive the
|
||||||
|
//requested dev's desc, and output_buffer_length specifies the length of the
|
||||||
|
//buffer
|
||||||
|
|
||||||
|
#define IOCTL_SUBMIT_URB_RD CTL_CODE( FILE_HCD_DEV_TYPE, 4096, METHOD_IN_DIRECT, FILE_ANY_ACCESS )
|
||||||
|
#define IOCTL_SUBMIT_URB_WR CTL_CODE( FILE_HCD_DEV_TYPE, 4097, METHOD_OUT_DIRECT, FILE_ANY_ACCESS )
|
||||||
|
// input_buffer is a URB, and input_buffer_length is equal to or greater than
|
||||||
|
// sizeof( URB ); the output_buffer is a buffer to receive data from or send data
|
||||||
|
// to device. only the following urb fields can be accessed, others must be zeroed.
|
||||||
|
// DEV_HANDLE endp_handle;
|
||||||
|
// UCHAR setup_packet[8]; //for control pipe
|
||||||
|
// the choosing of IOCTL_SUBMIT_URB_RD or IOCTL_SUBMIT_URB_WR should be determined
|
||||||
|
// by the current URB, for example, a request string from device will use XXX_RD,
|
||||||
|
// and a write to the bulk endpoint will use XXX_WR
|
||||||
|
|
||||||
|
#define IOCTL_SUBMIT_URB_NOIO CTL_CODE( FILE_HCD_DEV_TYPE, 4098, METHOD_BUFFERED, FILE_ANY_ACCESS )
|
||||||
|
// input_buffer is a URB, and input_buffer_length is equal to or greater than
|
||||||
|
// sizeof( URB ); the output_buffer is null and no output_buffer_length,
|
||||||
|
// only the following fields in urb can be accessed, others must be zeroed.
|
||||||
|
// DEV_HANDLE endp_handle;
|
||||||
|
// UCHAR setup_packet[8]; //for control pipe
|
||||||
|
*/
|
6733
reactos/drivers/usb/nt4compat/usbdriver/ehci.c
Normal file
6733
reactos/drivers/usb/nt4compat/usbdriver/ehci.c
Normal file
File diff suppressed because it is too large
Load diff
810
reactos/drivers/usb/nt4compat/usbdriver/ehci.h
Normal file
810
reactos/drivers/usb/nt4compat/usbdriver/ehci.h
Normal file
|
@ -0,0 +1,810 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001-2002 by David Brownell
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
#include "hcd.h"
|
||||||
|
#include "usb.h"
|
||||||
|
#include "td.h"
|
||||||
|
#ifndef __EHCI_H__
|
||||||
|
#define __EHCI_H__
|
||||||
|
|
||||||
|
#define EHCI_QH_SIZE sizeof( EHCI_QH )
|
||||||
|
#define EHCI_ITD_SIZE sizeof( EHCI_ITD )
|
||||||
|
#define EHCI_SITD_SIZE sizeof( EHCI_SITD )
|
||||||
|
#define EHCI_FSTN_SIZE sizeof( EHCI_FSTN )
|
||||||
|
#define EHCI_QTD_SIZE sizeof( EHCI_QTD )
|
||||||
|
|
||||||
|
#define INIT_LIST_FLAG_TYPE 0x0f
|
||||||
|
#define INIT_LIST_FLAG_ITD 0x00
|
||||||
|
#define INIT_LIST_FLAG_QH 0x01
|
||||||
|
#define INIT_LIST_FLAG_SITD 0x02
|
||||||
|
#define INIT_LIST_FLAG_FSTN 0x03
|
||||||
|
#define INIT_LIST_FLAG_QTD 0x04
|
||||||
|
|
||||||
|
#define EHCI_MAX_SIZE_TRANSFER 0x100000 // 1 MB per transfer
|
||||||
|
#define EHCI_MAX_ELEMS_POOL 1024
|
||||||
|
#define EHCI_MAX_LISTS_POOL 0x08
|
||||||
|
#define EHCI_MAX_QHS_LIST 256 // 4 pages
|
||||||
|
#define EHCI_MAX_ITDS_LIST ( PAGE_SIZE / EHCI_ITD_SIZE * 2 ) // 2 pages
|
||||||
|
#define EHCI_MAX_SITDS_LIST ( PAGE_SIZE / EHCI_SITD_SIZE )// 1 page
|
||||||
|
#define EHCI_MAX_FSTNS_LIST ( PAGE_SIZE / EHCI_FSTN_SIZE )// 1 page
|
||||||
|
#define EHCI_MAX_QTDS_LIST 256 // 4 pages
|
||||||
|
|
||||||
|
#define EHCI_PTR_TERM 0x01
|
||||||
|
#define EHCI_NAK_RL_COUNT 0x04
|
||||||
|
|
||||||
|
#define EHCI_QTD_MAX_TRANS_SIZE 20480
|
||||||
|
#define PHYS_PART_TYPE_MASK 0x01f
|
||||||
|
#define PHYS_PART_ADDR_MASK ( ~PHYS_PART_TYPE_MASK )
|
||||||
|
|
||||||
|
typedef struct _EHCI_ELEM_LINKS
|
||||||
|
{
|
||||||
|
LIST_ENTRY elem_link; // link for one urb request
|
||||||
|
LIST_ENTRY sched_link; // to shadow link of schedule
|
||||||
|
struct _EHCI_ELEM_POOL* pool_link;
|
||||||
|
struct _EHCI_ELEM_LIST* list_link; // opaque to client, which list this td belongs to
|
||||||
|
PVOID phys_part; // point to EHCI_XXX, the lower 5 bits is used to indicate the type of the element
|
||||||
|
PURB purb;
|
||||||
|
|
||||||
|
} EHCI_ELEM_LINKS, *PEHCI_ELEM_LINKS;
|
||||||
|
|
||||||
|
typedef struct _INIT_ELEM_LIST_CONTEXT
|
||||||
|
{
|
||||||
|
PADAPTER_OBJECT padapter;
|
||||||
|
struct _EHCI_ELEM_POOL *pool;
|
||||||
|
|
||||||
|
} INIT_ELEM_LIST_CONTEXT, *PINIT_ELEM_LIST_CONTEXT;
|
||||||
|
|
||||||
|
typedef VOID ( *PDESTROY_ELEM_LIST )( struct _EHCI_ELEM_LIST* plist );
|
||||||
|
typedef PLIST_ENTRY ( *PGET_LIST_HEAD )( struct _EHCI_ELEM_LIST* plist );
|
||||||
|
typedef LONG ( *PGET_TOTAL_COUNT )( struct _EHCI_ELEM_LIST* plist );
|
||||||
|
typedef LONG ( *PGET_ELEM_SIZE )( struct _EHCI_ELEM_LIST* plist );
|
||||||
|
typedef LONG ( *PGET_LINK_OFFSET )( struct _EHCI_ELEM_LIST* plist );
|
||||||
|
typedef LONG ( *PADD_REF )( struct _EHCI_ELEM_LIST* plist );
|
||||||
|
typedef LONG ( *PRELEASE_REF )( struct _EHCI_ELEM_LIST* plist );
|
||||||
|
typedef LONG ( *PGET_REF )( struct _EHCI_ELEM_LIST* plist );
|
||||||
|
|
||||||
|
typedef struct _EHCI_ELEM_LIST
|
||||||
|
{
|
||||||
|
PDESTROY_ELEM_LIST destroy_list;
|
||||||
|
PGET_LIST_HEAD get_list_head;
|
||||||
|
PGET_TOTAL_COUNT get_total_count;
|
||||||
|
PGET_ELEM_SIZE get_elem_size;
|
||||||
|
PGET_LINK_OFFSET get_link_offset;
|
||||||
|
PADD_REF add_ref;
|
||||||
|
PRELEASE_REF release_ref;
|
||||||
|
PGET_REF get_ref;
|
||||||
|
|
||||||
|
// private area
|
||||||
|
LONG flags; // contails element's type info
|
||||||
|
LONG total_count;
|
||||||
|
LONG elem_size;
|
||||||
|
LIST_HEAD free_list; // chains of all the elements
|
||||||
|
struct _EHCI_ELEM_POOL *parent_pool;
|
||||||
|
LONG reference;
|
||||||
|
|
||||||
|
// used to represent the physical memory
|
||||||
|
PPHYSICAL_ADDRESS phys_addrs; // array of non-contigous memory
|
||||||
|
PBYTE *phys_bufs;
|
||||||
|
PEHCI_ELEM_LINKS elem_head_buf;
|
||||||
|
PADAPTER_OBJECT padapter;
|
||||||
|
|
||||||
|
} EHCI_ELEM_LIST, *PEHCI_ELEM_LIST;
|
||||||
|
|
||||||
|
BOOL elem_pool_init_pool( struct _EHCI_ELEM_POOL* pool, LONG flags, PVOID context);
|
||||||
|
VOID elem_pool_destroy_pool ( struct _EHCI_ELEM_POOL* pool );
|
||||||
|
PEHCI_ELEM_LINKS elem_pool_alloc_elem ( struct _EHCI_ELEM_POOL* pool );
|
||||||
|
VOID elem_pool_free_elem ( PEHCI_ELEM_LINKS elem_link );
|
||||||
|
LONG elem_pool_get_total_count ( struct _EHCI_ELEM_POOL* pool );
|
||||||
|
BOOL elem_pool_is_empty ( struct _EHCI_ELEM_POOL* pool );
|
||||||
|
LONG elem_pool_get_free_count ( struct _EHCI_ELEM_POOL* pool );
|
||||||
|
LONG elem_pool_get_link_offset ( struct _EHCI_ELEM_POOL* pool );
|
||||||
|
PEHCI_ELEM_LINKS elem_pool_alloc_elems ( struct _EHCI_ELEM_POOL* pool, LONG count );
|
||||||
|
BOOL elem_pool_free_elems( PEHCI_ELEM_LINKS elem_chains );
|
||||||
|
LONG elem_pool_get_type( struct _EHCI_ELEM_POOL* pool );
|
||||||
|
|
||||||
|
// the following are private functions
|
||||||
|
BOOL elem_pool_expand_pool( struct _EHCI_ELEM_POOL* pool, LONG elem_count );
|
||||||
|
BOOL elem_pool_collect_garbage( struct _EHCI_ELEM_POOL* pool );
|
||||||
|
|
||||||
|
// lock operations
|
||||||
|
BOOL elem_pool_lock( struct _EHCI_ELEM_POOL* pool, BOOL at_dpc );
|
||||||
|
BOOL elem_pool_unlock( struct _EHCI_ELEM_POOL* pool, BOOL at_dpc );
|
||||||
|
|
||||||
|
// helper
|
||||||
|
LONG get_elem_phys_part_size( ULONG type );
|
||||||
|
|
||||||
|
typedef struct _EHCI_ELEM_POOL
|
||||||
|
{
|
||||||
|
LONG flags;
|
||||||
|
LONG free_count; // free count of all the lists currently allocated
|
||||||
|
LONG link_offset; // a cache for elem_list->get_link_offset
|
||||||
|
LONG list_count; // lists currently allocated
|
||||||
|
PEHCI_ELEM_LIST elem_lists[ EHCI_MAX_LISTS_POOL ];
|
||||||
|
|
||||||
|
} EHCI_ELEM_POOL, *PEHCI_ELEM_POOL;
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define QTD_NEXT(dma) cpu_to_le32((u32)dma)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EHCI Specification 0.95 Section 3.5
|
||||||
|
* QTD: describe data transfer components (buffer, direction, ...)
|
||||||
|
* See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
|
||||||
|
*
|
||||||
|
* These are associated only with "QH" (Queue Head) structures,
|
||||||
|
* used with control, bulk, and interrupt transfers.
|
||||||
|
*/
|
||||||
|
#define QTD_TOGGLE (1 << 31) /* data toggle */
|
||||||
|
#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
|
||||||
|
#define QTD_IOC (1 << 15) /* interrupt on complete */
|
||||||
|
#define QTD_CERR(tok) (((tok)>>10) & 0x3)
|
||||||
|
#define QTD_PID(tok) (((tok)>>8) & 0x3)
|
||||||
|
#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */
|
||||||
|
#define QTD_STS_HALT (1 << 6) /* halted on error */
|
||||||
|
#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */
|
||||||
|
#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */
|
||||||
|
#define QTD_STS_XACT (1 << 3) /* device gave illegal response */
|
||||||
|
#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */
|
||||||
|
#define QTD_STS_STS (1 << 1) /* split transaction state */
|
||||||
|
#define QTD_STS_PING (1 << 0) /* issue PING? */
|
||||||
|
#define QTD_ANY_ERROR ( QTD_STS_HALT | QTD_STS_DBE | QTD_STS_XACT | QTD_STS_MMF | QTD_STS_BABBLE )
|
||||||
|
|
||||||
|
#define QTD_PID_SETUP 0x02
|
||||||
|
#define QTD_PID_IN 0x01
|
||||||
|
#define QTD_PID_OUT 0x00
|
||||||
|
|
||||||
|
#pragma pack( push, usb_align, 1 )
|
||||||
|
|
||||||
|
typedef struct _EHCI_QTD_CONTENT
|
||||||
|
{
|
||||||
|
// DWORD 0
|
||||||
|
ULONG terminal : 1;
|
||||||
|
ULONG reserved : 4;
|
||||||
|
ULONG next_qtd : 27;
|
||||||
|
|
||||||
|
// DWORD 1
|
||||||
|
ULONG alt_terminal : 1;
|
||||||
|
ULONG reserved1 : 4;
|
||||||
|
ULONG alt_qtd : 27;
|
||||||
|
|
||||||
|
// DWORD 2
|
||||||
|
ULONG status : 8;
|
||||||
|
ULONG pid : 2;
|
||||||
|
ULONG err_count : 2;
|
||||||
|
ULONG cur_page : 3;
|
||||||
|
ULONG ioc : 1;
|
||||||
|
ULONG bytes_to_transfer : 15;
|
||||||
|
ULONG data_toggle : 1;
|
||||||
|
|
||||||
|
// DWORD 3
|
||||||
|
ULONG cur_offset : 12;
|
||||||
|
ULONG page0 : 20;
|
||||||
|
|
||||||
|
// DWORD 4-
|
||||||
|
ULONG pages[ 4 ];
|
||||||
|
|
||||||
|
} EHCI_QTD_CONTENT, *PEHCI_QTD_CONTENT;
|
||||||
|
|
||||||
|
typedef struct _EHCI_QTD
|
||||||
|
{
|
||||||
|
/* first part defined by EHCI spec */
|
||||||
|
ULONG hw_next; /* see EHCI 3.5.1 */
|
||||||
|
ULONG hw_alt_next; /* see EHCI 3.5.2 */
|
||||||
|
ULONG hw_token; /* see EHCI 3.5.3 */
|
||||||
|
ULONG hw_buf [5]; /* see EHCI 3.5.4 */
|
||||||
|
|
||||||
|
/* the rest is HCD-private */
|
||||||
|
PEHCI_ELEM_LINKS elem_head_link;
|
||||||
|
ULONG phys_addr; /* qtd address */
|
||||||
|
USHORT bytes_to_transfer; /* the bytes_to_transfer in hw_token will drop to zero when completed*/
|
||||||
|
USHORT reserved2;
|
||||||
|
ULONG reserved[ 5 ];
|
||||||
|
|
||||||
|
} EHCI_QTD, *PEHCI_QTD; //__attribute__ ((aligned (32)));
|
||||||
|
|
||||||
|
#define QTD_MASK cpu_to_le32 (~0x1f) /* mask NakCnt+T in qh->hw_alt_next */
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* type tag from {qh,itd,sitd,fstn}->hw_next */
|
||||||
|
#define Q_NEXT_TYPE(dma) ((dma) & __constant_cpu_to_le32 (3 << 1))
|
||||||
|
|
||||||
|
/* values for that type tag */
|
||||||
|
#define Q_TYPE_ITD (0 << 1)
|
||||||
|
#define Q_TYPE_QH (1 << 1)
|
||||||
|
#define Q_TYPE_SITD (2 << 1)
|
||||||
|
#define Q_TYPE_FSTN (3 << 1)
|
||||||
|
|
||||||
|
/* next async queue entry, or pointer to interrupt/periodic QH */
|
||||||
|
#define QH_NEXT(dma) (cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
|
||||||
|
|
||||||
|
/* for periodic/async schedules and qtd lists, mark end of list */
|
||||||
|
#define EHCI_LIST_END __constant_cpu_to_le32(1) /* "null pointer" to hw */
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EHCI Specification 0.95 Section 3.6
|
||||||
|
* QH: describes control/bulk/interrupt endpoints
|
||||||
|
* See Fig 3-7 "Queue Head Structure Layout".
|
||||||
|
*
|
||||||
|
* These appear in both the async and (for interrupt) periodic schedules.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define QH_HEAD 0x00008000
|
||||||
|
#define QH_STATE_LINKED 1 /* HC sees this */
|
||||||
|
#define QH_STATE_UNLINK 2 /* HC may still see this */
|
||||||
|
#define QH_STATE_IDLE 3 /* HC doesn't see this */
|
||||||
|
#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on reclaim q */
|
||||||
|
#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
|
||||||
|
#define NO_FRAME ((unsigned short)~0) /* pick new start */
|
||||||
|
|
||||||
|
typedef struct _EHCI_QH_CONTENT
|
||||||
|
{
|
||||||
|
// DWORD 0
|
||||||
|
ULONG terminal : 1;
|
||||||
|
ULONG ptr_type : 2;
|
||||||
|
ULONG reserved : 2;
|
||||||
|
ULONG next_link : 27;
|
||||||
|
|
||||||
|
// DWORD 1
|
||||||
|
ULONG dev_addr : 7;
|
||||||
|
ULONG inactive : 1;
|
||||||
|
ULONG endp_addr : 4;
|
||||||
|
ULONG endp_spd : 2;
|
||||||
|
ULONG data_toggle : 1;
|
||||||
|
ULONG is_async_head : 1;
|
||||||
|
ULONG max_packet_size : 11;
|
||||||
|
ULONG is_ctrl_endp : 1;
|
||||||
|
ULONG reload_counter : 4;
|
||||||
|
|
||||||
|
// DWORD 2
|
||||||
|
ULONG s_mask : 8;
|
||||||
|
ULONG c_mask : 8;
|
||||||
|
ULONG hub_addr : 7;
|
||||||
|
ULONG port_idx : 7;
|
||||||
|
ULONG mult : 2;
|
||||||
|
|
||||||
|
// DWORD 3
|
||||||
|
ULONG cur_qtd_ptr;
|
||||||
|
|
||||||
|
// overlay
|
||||||
|
EHCI_QTD_CONTENT cur_qtd;
|
||||||
|
|
||||||
|
} EHCI_QH_CONTENT, *PEHCI_QH_CONTENT;
|
||||||
|
|
||||||
|
typedef struct _EHCI_QH
|
||||||
|
{
|
||||||
|
/* first part defined by EHCI spec */
|
||||||
|
ULONG hw_next; /* see EHCI 3.6.1 */
|
||||||
|
ULONG hw_info1; /* see EHCI 3.6.2 */
|
||||||
|
ULONG hw_info2; /* see EHCI 3.6.2 */
|
||||||
|
ULONG hw_current; /* qtd list - see EHCI 3.6.4 */
|
||||||
|
|
||||||
|
/* qtd overlay (hardware parts of a struct ehci_qtd) */
|
||||||
|
ULONG hw_qtd_next;
|
||||||
|
ULONG hw_alt_next;
|
||||||
|
ULONG hw_token;
|
||||||
|
ULONG hw_buf [5];
|
||||||
|
|
||||||
|
/* the rest is HCD-private */
|
||||||
|
PEHCI_ELEM_LINKS elem_head_link;
|
||||||
|
ULONG phys_addr; /* address of qh */
|
||||||
|
ULONG reserved[ 2 ];
|
||||||
|
|
||||||
|
} EHCI_QH, *PEHCI_QH; // __attribute__ ((aligned (32)));
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EHCI Specification 0.95 Section 3.3
|
||||||
|
* Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
|
||||||
|
*
|
||||||
|
* Schedule records for high speed iso xfers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EHCI_ISOC_ACTIVE (1<<31) /* activate transfer this slot */
|
||||||
|
#define EHCI_ISOC_BUF_ERR (1<<30) /* Data buffer error */
|
||||||
|
#define EHCI_ISOC_BABBLE (1<<29) /* babble detected */
|
||||||
|
#define EHCI_ISOC_XACTERR (1<<28) /* XactErr - transaction error */
|
||||||
|
#define EHCI_ITD_LENGTH(tok) (((tok)>>16) & 0x7fff)
|
||||||
|
#define EHCI_ITD_IOC (1 << 15) /* interrupt on complete */
|
||||||
|
|
||||||
|
#define ITD_STS_ACTIVE 8
|
||||||
|
#define ITD_STS_BUFERR 4
|
||||||
|
#define ITD_STS_BABBLE 2
|
||||||
|
#define ITD_STS_XACTERR 1
|
||||||
|
|
||||||
|
#define ITD_ANY_ERROR ( ITD_STS_BUFERR | ITD_STS_BABBLE | ITD_STS_XACTERR )
|
||||||
|
|
||||||
|
typedef struct _EHCI_ITD_STATUS_SLOT
|
||||||
|
{
|
||||||
|
ULONG offset : 12;
|
||||||
|
ULONG page_sel : 3;
|
||||||
|
ULONG ioc : 1;
|
||||||
|
ULONG trans_length : 12;
|
||||||
|
ULONG status : 4;
|
||||||
|
|
||||||
|
} EHCI_ITD_STATUS_SLOT, *PEHCI_ITD_STATUS_SLOT;
|
||||||
|
|
||||||
|
typedef struct _EHCI_ITD_CONTENT
|
||||||
|
{
|
||||||
|
// DWORD 0;
|
||||||
|
ULONG terminal : 1;
|
||||||
|
ULONG ptr_type : 2;
|
||||||
|
ULONG reserved : 2;
|
||||||
|
ULONG next_link : 27;
|
||||||
|
// DWORD 1-8;
|
||||||
|
EHCI_ITD_STATUS_SLOT status_slot[ 8 ];
|
||||||
|
// DWORD 9;
|
||||||
|
ULONG dev_addr : 7;
|
||||||
|
ULONG reserved1 : 1;
|
||||||
|
ULONG endp_num : 4;
|
||||||
|
ULONG page0 : 20;
|
||||||
|
// DWORD 10;
|
||||||
|
ULONG max_packet_size : 11;
|
||||||
|
ULONG io_dir : 1;
|
||||||
|
ULONG page1 : 20;
|
||||||
|
// DWORD 11;
|
||||||
|
ULONG mult : 2;
|
||||||
|
ULONG reserved2 : 10;
|
||||||
|
ULONG page2 : 20;
|
||||||
|
// DWORD 12-;
|
||||||
|
ULONG pages[ 4 ];
|
||||||
|
|
||||||
|
} EHCI_ITD_CONTENT, *PEHCI_ITD_CONTENT;
|
||||||
|
|
||||||
|
typedef struct _EHCI_ITD {
|
||||||
|
|
||||||
|
/* first part defined by EHCI spec */
|
||||||
|
ULONG hw_next; /* see EHCI 3.3.1 */
|
||||||
|
ULONG hw_transaction [8]; /* see EHCI 3.3.2 */
|
||||||
|
ULONG hw_bufp [7]; /* see EHCI 3.3.3 */
|
||||||
|
|
||||||
|
/* the rest is EHCI-private */
|
||||||
|
PEHCI_ELEM_LINKS elem_head_link;
|
||||||
|
ULONG phys_addr; /* for this itd */
|
||||||
|
ULONG buf_phys_addr; /* buffer address */
|
||||||
|
ULONG reserved[ 5 ];
|
||||||
|
|
||||||
|
} EHCI_ITD, *PEHCI_ITD; // __attribute__ ((aligned (32)));
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EHCI Specification 0.95 Section 3.4
|
||||||
|
* siTD, aka split-transaction isochronous Transfer Descriptor
|
||||||
|
* ... describe low/full speed iso xfers through TT in hubs
|
||||||
|
* see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD)
|
||||||
|
*/
|
||||||
|
#define SITD_STS_ACTIVE 0x80
|
||||||
|
#define SITD_STS_ERR 0x40 // error from device
|
||||||
|
#define SITD_STS_DBE 0x20 // data buffer error
|
||||||
|
#define SITD_STS_BABBLE 0x10 // data more than expected
|
||||||
|
#define SITD_STS_XACTERR 0x08 // general error on hc
|
||||||
|
#define SITD_STS_MISSFRM 0x04 // missd micro frames
|
||||||
|
#define SITD_STS_SC 0x02 // state is whether start-split( 0 ) or complete-split( 1 )
|
||||||
|
#define SITD_STS_RESERVED 0x01
|
||||||
|
#define SITD_ANY_ERROR ( SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE | SITD_STS_XACTERR | SITD_STS_MISSFRM )
|
||||||
|
|
||||||
|
typedef struct _EHCI_SITD_CONTENT
|
||||||
|
{
|
||||||
|
// DWORD 0;
|
||||||
|
ULONG terminal : 1;
|
||||||
|
ULONG ptr_type : 2;
|
||||||
|
ULONG reserved : 2;
|
||||||
|
ULONG next_link : 27;
|
||||||
|
// DWORD 1;
|
||||||
|
ULONG dev_addr : 7;
|
||||||
|
ULONG reserved1 : 1;
|
||||||
|
ULONG endp_num : 4;
|
||||||
|
ULONG reserved2 : 4;
|
||||||
|
ULONG hub_addr : 7;
|
||||||
|
ULONG reserved3 : 1;
|
||||||
|
ULONG port_idx : 7;
|
||||||
|
ULONG io_dir : 1;
|
||||||
|
// DWORD 2;
|
||||||
|
ULONG s_mask : 8;
|
||||||
|
ULONG c_mask : 8;
|
||||||
|
ULONG reserved4 : 16;
|
||||||
|
// DWORD 3:
|
||||||
|
ULONG status : 8;
|
||||||
|
ULONG c_prog_mask : 8;
|
||||||
|
ULONG bytes_to_transfer : 10;
|
||||||
|
ULONG reserved5 : 4;
|
||||||
|
ULONG page_sel : 1;
|
||||||
|
ULONG ioc : 1;
|
||||||
|
// DWORD 4;
|
||||||
|
ULONG cur_offset : 12;
|
||||||
|
ULONG page0 : 20;
|
||||||
|
// DWORD 5;
|
||||||
|
ULONG trans_count : 3;
|
||||||
|
ULONG trans_pos : 2;
|
||||||
|
ULONG reserved6 : 7;
|
||||||
|
ULONG page1 : 20;
|
||||||
|
// DWORD 6;
|
||||||
|
ULONG back_terminal : 1;
|
||||||
|
ULONG reserved7 : 4;
|
||||||
|
ULONG back_ptr : 27;
|
||||||
|
|
||||||
|
} EHCI_SITD_CONTENT, *PEHCI_SITD_CONTENT;
|
||||||
|
|
||||||
|
typedef struct _EHCI_SITD
|
||||||
|
{
|
||||||
|
/* first part defined by EHCI spec */
|
||||||
|
ULONG hw_next;
|
||||||
|
/* uses bit field macros above - see EHCI 0.95 Table 3-8 */
|
||||||
|
|
||||||
|
ULONG hw_fullspeed_ep; /* see EHCI table 3-9 */
|
||||||
|
ULONG hw_uframe; /* see EHCI table 3-10 */
|
||||||
|
ULONG hw_tx_results1; /* see EHCI table 3-11 */
|
||||||
|
ULONG hw_tx_results2; /* see EHCI table 3-12 */
|
||||||
|
ULONG hw_tx_results3; /* see EHCI table 3-12 */
|
||||||
|
ULONG hw_backpointer; /* see EHCI table 3-13 */
|
||||||
|
|
||||||
|
/* the rest is HCD-private */
|
||||||
|
PEHCI_ELEM_LINKS elem_head_link;
|
||||||
|
ULONG phys_addr;
|
||||||
|
ULONG buf_phys_addr; /* buffer address */
|
||||||
|
|
||||||
|
USHORT usecs; /* start bandwidth */
|
||||||
|
USHORT c_usecs; /* completion bandwidth */
|
||||||
|
ULONG reserved[ 5 ];
|
||||||
|
|
||||||
|
} EHCI_SITD, *PEHCI_SITD; // __attribute__ ((aligned (32)));
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* EHCI Specification 0.96 Section 3.7
|
||||||
|
* Periodic Frame Span Traversal Node (FSTN)
|
||||||
|
*
|
||||||
|
* Manages split interrupt transactions (using TT) that span frame boundaries
|
||||||
|
* into uframes 0/1; see 4.12.2.2. In those uframes, a "save place" FSTN
|
||||||
|
* makes the HC jump (back) to a QH to scan for fs/ls QH completions until
|
||||||
|
* it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
|
||||||
|
*/
|
||||||
|
typedef struct _EHCI_FSTN
|
||||||
|
{
|
||||||
|
ULONG hw_next; /* any periodic q entry */
|
||||||
|
ULONG hw_prev; /* qh or EHCI_LIST_END */
|
||||||
|
|
||||||
|
/* the rest is HCD-private */
|
||||||
|
PEHCI_ELEM_LINKS elem_head_link;
|
||||||
|
ULONG phys_addr;
|
||||||
|
ULONG reserved[ 4 ];
|
||||||
|
|
||||||
|
} EHCI_FSTN, *PEHCI_FSTN; // __attribute__ ((aligned (32)));
|
||||||
|
|
||||||
|
|
||||||
|
/* NOTE: urb->transfer_flags expected to not use this bit !!! */
|
||||||
|
#define EHCI_STATE_UNLINK 0x8000 /* urb being unlinked */
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
|
||||||
|
|
||||||
|
/* Section 2.2 Host Controller Capability Registers */
|
||||||
|
#define HCS_DEBUG_PORT(p) (((p)>>20)&0xf) /* bits 23:20, debug port? */
|
||||||
|
#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
|
||||||
|
#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
|
||||||
|
#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */
|
||||||
|
#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
|
||||||
|
#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
|
||||||
|
#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
|
||||||
|
|
||||||
|
#define HCC_EXT_CAPS(p) (((p)>>8)&0xff) /* for pci extended caps */
|
||||||
|
#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
|
||||||
|
#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
|
||||||
|
#define HCC_CANPARK(p) ((p)&(1 << 2)) /* true: can park on async qh */
|
||||||
|
#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1)) /* true: periodic_size changes*/
|
||||||
|
#define HCC_64BIT_ADDR(p) ((p)&(1)) /* true: can use 64-bit addr */
|
||||||
|
|
||||||
|
/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
|
||||||
|
#define CMD_PARK (1<<11) /* enable "park" on async qh */
|
||||||
|
#define CMD_PARK_CNT(c) (((c)>>8)&3) /* how many transfers to park for */
|
||||||
|
#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
|
||||||
|
#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
|
||||||
|
#define CMD_ASE (1<<5) /* async schedule enable */
|
||||||
|
#define CMD_PSE (1<<4) /* periodic schedule enable */
|
||||||
|
/* 3:2 is periodic frame list size */
|
||||||
|
#define CMD_RESET (1<<1) /* reset HC not bus */
|
||||||
|
#define CMD_RUN (1<<0) /* start/stop HC */
|
||||||
|
|
||||||
|
/* these STS_* flags are also intr_enable bits (USBINTR) */
|
||||||
|
#define STS_IAA (1<<5) /* Interrupted on async advance */
|
||||||
|
#define STS_FATAL (1<<4) /* such as some PCI access errors */
|
||||||
|
#define STS_FLR (1<<3) /* frame list rolled over */
|
||||||
|
#define STS_PCD (1<<2) /* port change detect */
|
||||||
|
#define STS_ERR (1<<1) /* "error" completion (overflow, ...) */
|
||||||
|
#define STS_INT (1<<0) /* "normal" completion (short, ...) */
|
||||||
|
|
||||||
|
#define STS_ASS (1<<15) /* Async Schedule Status */
|
||||||
|
#define STS_PSS (1<<14) /* Periodic Schedule Status */
|
||||||
|
#define STS_RECL (1<<13) /* Reclamation */
|
||||||
|
#define STS_HALT (1<<12) /* Not running (any reason) */
|
||||||
|
|
||||||
|
/* 31:23 reserved */
|
||||||
|
#define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */
|
||||||
|
#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */
|
||||||
|
#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */
|
||||||
|
/* 19:16 for port testing */
|
||||||
|
/* 15:14 for using port indicator leds (if HCS_INDICATOR allows) */
|
||||||
|
#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
|
||||||
|
#define PORT_POWER (1<<12) /* true: has power (see PPC) */
|
||||||
|
#define PORT_USB11(x) (((x)&(3<<10))==(1<<10)) /* USB 1.1 device */
|
||||||
|
/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
|
||||||
|
/* 9 reserved */
|
||||||
|
#define PORT_PR (1<<8) /* reset port */
|
||||||
|
#define PORT_SUSP (1<<7) /* suspend port */
|
||||||
|
#define PORT_RESUME (1<<6) /* resume it */
|
||||||
|
#define PORT_OCC (1<<5) /* over current change */
|
||||||
|
#define PORT_OC (1<<4) /* over current active */
|
||||||
|
#define PORT_PEC (1<<3) /* port enable change */
|
||||||
|
#define PORT_PE (1<<2) /* port enable */
|
||||||
|
#define PORT_CSC (1<<1) /* connect status change */
|
||||||
|
#define PORT_CCS (1<<0) /* device connected */
|
||||||
|
|
||||||
|
#define FLAG_CF (1<<0) /* true: we'll support "high speed" */
|
||||||
|
|
||||||
|
typedef struct _EHCI_HCS_CONTENT
|
||||||
|
{
|
||||||
|
ULONG port_count : 4;
|
||||||
|
ULONG port_power_control : 1;
|
||||||
|
ULONG reserved : 2;
|
||||||
|
ULONG port_rout_rules : 1;
|
||||||
|
ULONG port_per_chc : 4;
|
||||||
|
ULONG chc_count : 4;
|
||||||
|
ULONG port_indicator : 1;
|
||||||
|
ULONG reserved2 : 3;
|
||||||
|
ULONG dbg_port_num : 4;
|
||||||
|
ULONG reserved3 : 8;
|
||||||
|
|
||||||
|
} EHCI_HCS_CONTENT, *PEHCI_HCS_CONTENT;
|
||||||
|
|
||||||
|
typedef struct _EHCI_HCC_CONTENT
|
||||||
|
{
|
||||||
|
ULONG cur_addr_bits : 1; /* 0: 32 bit addressing 1: 64 bit addressing */
|
||||||
|
ULONG var_frame_list : 1; /* 0: 1024 frames, 1: support other number of frames */
|
||||||
|
ULONG park_mode : 1;
|
||||||
|
ULONG reserved : 1;
|
||||||
|
ULONG iso_sched_threshold : 4;
|
||||||
|
ULONG eecp_capable : 8;
|
||||||
|
ULONG reserved2 : 16;
|
||||||
|
|
||||||
|
} EHCI_HCC_CONTENT, *PEHCI_HCC_CONTENT;
|
||||||
|
|
||||||
|
typedef struct _EHCI_CAPS {
|
||||||
|
UCHAR length; /* CAPLENGTH - size of this struct */
|
||||||
|
UCHAR reserved; /* offset 0x1 */
|
||||||
|
USHORT hci_version; /* HCIVERSION - offset 0x2 */
|
||||||
|
ULONG hcs_params; /* HCSPARAMS - offset 0x4 */
|
||||||
|
|
||||||
|
ULONG hcc_params; /* HCCPARAMS - offset 0x8 */
|
||||||
|
UCHAR portroute [8]; /* nibbles for routing - offset 0xC */
|
||||||
|
|
||||||
|
} EHCI_CAPS, *PEHCI_CAPS;
|
||||||
|
|
||||||
|
/* Section 2.3 Host Controller Operational Registers */
|
||||||
|
|
||||||
|
#define EHCI_USBCMD 0x00
|
||||||
|
#define EHCI_USBSTS 0x04
|
||||||
|
#define EHCI_USBINTR 0x08
|
||||||
|
#define EHCI_FRINDEX 0x0c
|
||||||
|
#define EHCI_CTRLDSSEGMENT 0x10
|
||||||
|
#define EHCI_PERIODICLISTBASE 0x14
|
||||||
|
#define EHCI_ASYNCLISTBASE 0x18
|
||||||
|
#define EHCI_CONFIGFLAG 0x40
|
||||||
|
#define EHCI_PORTSC 0x44
|
||||||
|
|
||||||
|
#define EHCI_USBINTR_INTE 0x01
|
||||||
|
#define EHCI_USBINTR_ERR 0x02
|
||||||
|
#define EHCI_USBINTR_PC 0x04
|
||||||
|
#define EHCI_USBINTR_FLROVR 0x08
|
||||||
|
#define EHCI_USBINTR_HSERR 0x10
|
||||||
|
#define EHCI_USBINTR_ASYNC 0x20
|
||||||
|
|
||||||
|
typedef struct _EHCI_USBCMD_CONTENT
|
||||||
|
{
|
||||||
|
ULONG run_stop : 1;
|
||||||
|
ULONG hcreset : 1;
|
||||||
|
ULONG frame_list_size : 2;
|
||||||
|
ULONG periodic_enable : 1;
|
||||||
|
ULONG async_enable : 1;
|
||||||
|
ULONG door_bell : 1;
|
||||||
|
ULONG light_reset : 1;
|
||||||
|
ULONG async_park_count : 2;
|
||||||
|
ULONG reserved : 1;
|
||||||
|
ULONG async_park_enable : 1;
|
||||||
|
ULONG reserved1 : 4;
|
||||||
|
ULONG int_threshold : 8;
|
||||||
|
ULONG reserved2 : 8;
|
||||||
|
|
||||||
|
} EHCI_USBCMD_CONTENT, *PEHCI_USBCMD_CONTENT;
|
||||||
|
|
||||||
|
typedef struct _EHCI_USBSTS_CONTENT
|
||||||
|
{
|
||||||
|
ULONG ioc : 1;
|
||||||
|
ULONG trasac_error : 1;
|
||||||
|
ULONG port_change : 1;
|
||||||
|
ULONG fl_rollover : 1;
|
||||||
|
ULONG host_system_error : 1;
|
||||||
|
ULONG async_advance : 1;
|
||||||
|
ULONG reserved : 6;
|
||||||
|
ULONG hc_halted : 1;
|
||||||
|
ULONG reclaimation : 1;
|
||||||
|
ULONG periodic_status : 1;
|
||||||
|
ULONG async_status : 1;
|
||||||
|
ULONG reserved1 : 16;
|
||||||
|
|
||||||
|
} EHCI_USBSTS_CONTENT, *PEHCI_USBSTS_CONTENT;
|
||||||
|
|
||||||
|
typedef struct _EHCI_RHPORTSC_CONTENT
|
||||||
|
{
|
||||||
|
ULONG cur_connect : 1;
|
||||||
|
ULONG cur_connect_change : 1;
|
||||||
|
ULONG port_enable : 1;
|
||||||
|
ULONG port_enable_change : 1;
|
||||||
|
ULONG over_current : 1;
|
||||||
|
ULONG over_current_change : 1;
|
||||||
|
ULONG force_port_resume : 1;
|
||||||
|
ULONG suspend : 1;
|
||||||
|
ULONG port_reset : 1;
|
||||||
|
ULONG reserved : 1;
|
||||||
|
ULONG line_status : 2;
|
||||||
|
ULONG port_power : 1;
|
||||||
|
ULONG port_owner : 1;
|
||||||
|
ULONG port_indicator : 2;
|
||||||
|
ULONG port_test : 4;
|
||||||
|
ULONG we_connect : 1;
|
||||||
|
ULONG we_disconnect : 1;
|
||||||
|
ULONG we_over_current : 1;
|
||||||
|
ULONG reserved1 : 9;
|
||||||
|
|
||||||
|
} EHCI_RHPORTSC_CONTENT, *PEHCI_RHPORTSC_CONTENT;
|
||||||
|
|
||||||
|
typedef struct _EHCI_REGS {
|
||||||
|
|
||||||
|
ULONG command;
|
||||||
|
ULONG status;
|
||||||
|
ULONG intr_enable;
|
||||||
|
ULONG frame_index; /* current microframe number */
|
||||||
|
ULONG segment; /* address bits 63:32 if needed */
|
||||||
|
ULONG frame_list; /* points to periodic list */
|
||||||
|
ULONG async_next; /* address of next async queue head */
|
||||||
|
ULONG reserved [9];
|
||||||
|
ULONG configured_flag;
|
||||||
|
ULONG port_status [0]; /* up to N_PORTS */
|
||||||
|
|
||||||
|
} EHCI_REGS, *PEHCI_REGS;
|
||||||
|
|
||||||
|
#pragma pack( pop, usb_align )
|
||||||
|
|
||||||
|
/* ehci_hcd->lock guards shared data against other CPUs:
|
||||||
|
* ehci_hcd: async, reclaim, periodic (and shadow), ...
|
||||||
|
* hcd_dev: ep[]
|
||||||
|
* ehci_qh: qh_next, qtd_list
|
||||||
|
* ehci_qtd: qtd_list
|
||||||
|
*
|
||||||
|
* Also, hold this lock when talking to HC registers or
|
||||||
|
* when updating hw_* fields in shared qh/qtd/... structures.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */
|
||||||
|
|
||||||
|
#define EHCI_DEVICE_NAME "\\Device\\EHCI"
|
||||||
|
|
||||||
|
#define EHCI_DOS_DEVICE_NAME "\\DosDevices\\EHCI"
|
||||||
|
|
||||||
|
#define EHCI_ITD_POOL_IDX INIT_LIST_FLAG_ITD
|
||||||
|
#define EHCI_QH_POOL_IDX INIT_LIST_FLAG_QH
|
||||||
|
#define EHCI_SITD_POOL_IDX INIT_LIST_FLAG_SITD
|
||||||
|
#define EHCI_FSTN_POOL_IDX INIT_LIST_FLAG_FSTN
|
||||||
|
#define EHCI_QTD_POOL_IDX INIT_LIST_FLAG_QTD
|
||||||
|
|
||||||
|
#define EHCI_DEFAULT_FRAMES UHCI_MAX_FRAMES
|
||||||
|
#define EHCI_MAX_SYNC_BUS_TIME 50000 // stands for 100000 ns, only to get wrapped within one word
|
||||||
|
|
||||||
|
#define EHCI_SCHED_INT8_INDEX 0
|
||||||
|
#define EHCI_SCHED_INT4_INDEX 1
|
||||||
|
#define EHCI_SCHED_INT2_INDEX 2
|
||||||
|
#define EHCI_SCHED_FSTN_INDEX 3
|
||||||
|
#define EHCI_SCHED_INT1_INDEX 4
|
||||||
|
|
||||||
|
#define qtd_pool ( &ehci->elem_pools[ EHCI_QTD_POOL_IDX ] )
|
||||||
|
#define qh_pool ( &ehci->elem_pools[ EHCI_QH_POOL_IDX ] )
|
||||||
|
#define fstn_pool ( &ehci->elem_pools[ EHCI_FSTN_POOL_IDX ] )
|
||||||
|
#define itd_pool ( &ehci->elem_pools[ EHCI_ITD_POOL_IDX ] )
|
||||||
|
#define sitd_pool ( &ehci->elem_pools[ EHCI_SITD_POOL_IDX ] )
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _EHCI_DEV
|
||||||
|
{
|
||||||
|
HCD hcd_interf;
|
||||||
|
|
||||||
|
EHCI_CAPS ehci_caps;
|
||||||
|
|
||||||
|
PHYSICAL_ADDRESS ehci_reg_base; // io space
|
||||||
|
BOOL port_mapped;
|
||||||
|
PBYTE port_base; // note: added by ehci_caps.length, operational regs base addr, not the actural base
|
||||||
|
|
||||||
|
ULONG frame_count;
|
||||||
|
PHYSICAL_ADDRESS frame_list_phys_addr;
|
||||||
|
|
||||||
|
KSPIN_LOCK frame_list_lock; // run at DIRQL
|
||||||
|
PULONG frame_list; // periodic schedule
|
||||||
|
|
||||||
|
PFRAME_LIST_CPU_ENTRY frame_list_cpu; // periodic schedule shadow
|
||||||
|
|
||||||
|
LIST_HEAD urb_list; // active urb-list
|
||||||
|
|
||||||
|
LIST_HEAD async_list_cpu;
|
||||||
|
LIST_HEAD periodic_list_cpu[ 8 ]; // each slot for one periodic
|
||||||
|
PEHCI_QH skel_async_qh;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// pools for device specific data
|
||||||
|
//
|
||||||
|
EHCI_ELEM_POOL elem_pools[ 5 ];
|
||||||
|
|
||||||
|
//
|
||||||
|
//for iso and int bandwidth claim, bandwidth schedule
|
||||||
|
//
|
||||||
|
KSPIN_LOCK pending_endp_list_lock; //lock to access the following two
|
||||||
|
LIST_HEAD pending_endp_list;
|
||||||
|
UHCI_PENDING_ENDP_POOL pending_endp_pool;
|
||||||
|
PUSHORT frame_bw; //unit uFrame
|
||||||
|
USHORT min_bw; //the bottle-neck of the bandwidths across frame-list
|
||||||
|
|
||||||
|
KTIMER reset_timer; //used to reset the host controller
|
||||||
|
struct _EHCI_DEVICE_EXTENSION *pdev_ext;
|
||||||
|
PUSB_DEV root_hub; //root hub
|
||||||
|
|
||||||
|
} EHCI_DEV, *PEHCI_DEV;
|
||||||
|
|
||||||
|
typedef UHCI_PORT EHCI_MEMORY;
|
||||||
|
|
||||||
|
typedef struct _EHCI_DEVICE_EXTENSION
|
||||||
|
{
|
||||||
|
//struct _USB_DEV_MANAGER *pdev_mgr;
|
||||||
|
DEVEXT_HEADER dev_ext_hdr;
|
||||||
|
PDEVICE_OBJECT pdev_obj;
|
||||||
|
PDRIVER_OBJECT pdrvr_obj;
|
||||||
|
PEHCI_DEV ehci;
|
||||||
|
|
||||||
|
//device resources
|
||||||
|
PADAPTER_OBJECT padapter;
|
||||||
|
ULONG map_regs;
|
||||||
|
PCM_RESOURCE_LIST res_list;
|
||||||
|
ULONG pci_addr; // bus number | slot number | funciton number
|
||||||
|
UHCI_INTERRUPT res_interrupt;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
UHCI_PORT res_port;
|
||||||
|
EHCI_MEMORY res_memory;
|
||||||
|
};
|
||||||
|
|
||||||
|
PKINTERRUPT ehci_int;
|
||||||
|
KDPC ehci_dpc;
|
||||||
|
|
||||||
|
} EHCI_DEVICE_EXTENSION, *PEHCI_DEVICE_EXTENSION;
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#endif /* __EHCI_H__ */
|
45
reactos/drivers/usb/nt4compat/usbdriver/ehci.rc
Normal file
45
reactos/drivers/usb/nt4compat/usbdriver/ehci.rc
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// Resource script for USBISO driver
|
||||||
|
// Generated by Walt Oney's driver wizard
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
|
||||||
|
|
||||||
|
|
||||||
|
VS_VERSION_INFO VERSIONINFO
|
||||||
|
FILEVERSION 0,0,1,0
|
||||||
|
PRODUCTVERSION 0,0,1,0
|
||||||
|
FILEFLAGSMASK 0x3fL
|
||||||
|
#ifdef _DEBUG
|
||||||
|
FILEFLAGS 0x1L
|
||||||
|
#else
|
||||||
|
FILEFLAGS 0x0L
|
||||||
|
#endif
|
||||||
|
FILEOS 0x40004L
|
||||||
|
FILETYPE 0x1L
|
||||||
|
FILESUBTYPE 0x0L
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904b0"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Comments", "This is a beta version of usb driver stack( ehci ), contact me at mypublic99@yahoo.com\0"
|
||||||
|
VALUE "CompanyName", "Woodhead Software\0"
|
||||||
|
VALUE "FileDescription", "ehci.sys\0"
|
||||||
|
VALUE "FileVersion", "0, 0, 1, 0\0"
|
||||||
|
VALUE "InternalName", "ehci.sys\0"
|
||||||
|
VALUE "LegalCopyright", "Copyright © 2002-2004 Woodhead Software\0"
|
||||||
|
VALUE "LegalTrademarks", "\0"
|
||||||
|
VALUE "OriginalFilename", "ehci.sys\0"
|
||||||
|
VALUE "PrivateBuild", "0.01\0"
|
||||||
|
VALUE "ProductName", "usb driver stack for windows NT\0"
|
||||||
|
VALUE "ProductVersion", "0, 0, 1, 0\0"
|
||||||
|
VALUE "SpecialBuild", "0131.d\0"
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 1200
|
||||||
|
END
|
||||||
|
END
|
||||||
|
|
733
reactos/drivers/usb/nt4compat/usbdriver/etd.c
Normal file
733
reactos/drivers/usb/nt4compat/usbdriver/etd.c
Normal file
|
@ -0,0 +1,733 @@
|
||||||
|
/**
|
||||||
|
* etd.c - USB driver stack project for Windows NT 4.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
|
||||||
|
*
|
||||||
|
* This program/include file is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as published
|
||||||
|
* by the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program/include file is distributed in the hope that it will be
|
||||||
|
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||||
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program (in the main directory of the distribution, the file
|
||||||
|
* COPYING); if not, write to the Free Software Foundation,Inc., 59 Temple
|
||||||
|
* Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ehci.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#define init_elem( ptr, type, ehci_elem_type ) \
|
||||||
|
{\
|
||||||
|
PEHCI_ELEM_LINKS tmp;\
|
||||||
|
ptr = ( type* )( plist->phys_bufs[ i ] + sizeof( type ) * j );\
|
||||||
|
ptr->hw_next = ehci_elem_type << 1;\
|
||||||
|
if( ehci_elem_type == INIT_LIST_FLAG_QTD )\
|
||||||
|
ptr->hw_next = 0;\
|
||||||
|
tmp = ptr->elem_head_link = &plist->elem_head_buf[ i * elms_per_page + j ];\
|
||||||
|
InitializeListHead( &tmp->elem_link );\
|
||||||
|
InitializeListHead( &tmp->sched_link );\
|
||||||
|
InsertTailList( &plist->free_list, &tmp->elem_link );\
|
||||||
|
tmp->list_link = plist;\
|
||||||
|
tmp->pool_link = pinit_ctx->pool;\
|
||||||
|
tmp->phys_part = ( PVOID )( ( ULONG )ptr | ( ehci_elem_type << 1 ) );\
|
||||||
|
if( ehci_elem_type != INIT_LIST_FLAG_QTD )\
|
||||||
|
ptr->phys_addr = ( plist->phys_addrs[ i ].LowPart + sizeof( type ) * j ) | ( ehci_elem_type << 1 );\
|
||||||
|
else \
|
||||||
|
ptr->phys_addr = plist->phys_addrs[ i ].LowPart + sizeof( type ) * j ;\
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the actual max list count of the pool, two limit, max_elem_pool and max_lists_pool
|
||||||
|
#define get_max_lists_count( pOOL, max_liSTS ) \
|
||||||
|
{\
|
||||||
|
LONG ii1;\
|
||||||
|
switch( elem_pool_get_type( pOOL ) )\
|
||||||
|
{\
|
||||||
|
case INIT_LIST_FLAG_QTD:\
|
||||||
|
ii1 = EHCI_MAX_QTDS_LIST;\
|
||||||
|
break;\
|
||||||
|
case INIT_LIST_FLAG_FSTN:\
|
||||||
|
ii1 = EHCI_MAX_QHS_LIST;\
|
||||||
|
break;\
|
||||||
|
case INIT_LIST_FLAG_SITD:\
|
||||||
|
ii1 = EHCI_MAX_ITDS_LIST;\
|
||||||
|
break;\
|
||||||
|
case INIT_LIST_FLAG_QH: \
|
||||||
|
ii1 = EHCI_MAX_SITDS_LIST;\
|
||||||
|
break;\
|
||||||
|
case INIT_LIST_FLAG_ITD: \
|
||||||
|
ii1 = EHCI_MAX_FSTNS_LIST;\
|
||||||
|
break;\
|
||||||
|
}\
|
||||||
|
max_liSTS = ( EHCI_MAX_ELEMS_POOL / ii1 ) > EHCI_MAX_LISTS_POOL ? EHCI_MAX_LISTS_POOL : ( EHCI_MAX_ELEMS_POOL / ii1 );\
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
elem_list_destroy_elem_list(
|
||||||
|
PEHCI_ELEM_LIST plist
|
||||||
|
);
|
||||||
|
|
||||||
|
PLIST_ENTRY
|
||||||
|
elem_list_get_list_head(
|
||||||
|
PEHCI_ELEM_LIST plist
|
||||||
|
);
|
||||||
|
|
||||||
|
LONG
|
||||||
|
elem_list_get_total_count(
|
||||||
|
PEHCI_ELEM_LIST plist
|
||||||
|
);
|
||||||
|
|
||||||
|
LONG
|
||||||
|
elem_list_get_elem_size(
|
||||||
|
PEHCI_ELEM_LIST plist
|
||||||
|
);
|
||||||
|
|
||||||
|
LONG
|
||||||
|
elem_list_get_link_offset(
|
||||||
|
PEHCI_ELEM_LIST plist
|
||||||
|
);
|
||||||
|
|
||||||
|
LONG
|
||||||
|
elem_list_add_ref(
|
||||||
|
PEHCI_ELEM_LIST plist
|
||||||
|
);
|
||||||
|
|
||||||
|
LONG
|
||||||
|
elem_list_release_ref(
|
||||||
|
PEHCI_ELEM_LIST plist
|
||||||
|
);
|
||||||
|
|
||||||
|
LONG
|
||||||
|
elem_list_get_ref(
|
||||||
|
PEHCI_ELEM_LIST plist
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
elem_pool_lock(
|
||||||
|
PEHCI_ELEM_POOL pool,
|
||||||
|
BOOL at_dpc
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
BOOL
|
||||||
|
elem_pool_unlock(
|
||||||
|
PEHCI_ELEM_POOL pool,
|
||||||
|
BOOL at_dpc
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
LONG
|
||||||
|
get_elem_phys_part_size(
|
||||||
|
ULONG type
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// type is INIT_LIST_FLAG_XXX
|
||||||
|
LONG size;
|
||||||
|
|
||||||
|
size = 0;
|
||||||
|
switch( type )
|
||||||
|
{
|
||||||
|
case INIT_LIST_FLAG_ITD:
|
||||||
|
size = 64;
|
||||||
|
break;
|
||||||
|
case INIT_LIST_FLAG_SITD:
|
||||||
|
size = 28;
|
||||||
|
break;
|
||||||
|
case INIT_LIST_FLAG_QTD:
|
||||||
|
size = 32;
|
||||||
|
break;
|
||||||
|
case INIT_LIST_FLAG_QH:
|
||||||
|
size = 48;
|
||||||
|
break;
|
||||||
|
case INIT_LIST_FLAG_FSTN:
|
||||||
|
size = 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
elem_list_init_elem_list(
|
||||||
|
PEHCI_ELEM_LIST plist,
|
||||||
|
LONG init_flags,
|
||||||
|
PVOID context,
|
||||||
|
LONG count
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LONG pages, i, j, elms_per_page;
|
||||||
|
PEHCI_QH pqh;
|
||||||
|
PEHCI_ITD pitd;
|
||||||
|
PEHCI_SITD psitd;
|
||||||
|
PEHCI_QTD pqtd;
|
||||||
|
PEHCI_FSTN pfstn;
|
||||||
|
PINIT_ELEM_LIST_CONTEXT pinit_ctx;
|
||||||
|
|
||||||
|
if( plist == NULL || context == NULL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
RtlZeroMemory( plist, sizeof( EHCI_ELEM_LIST ) );
|
||||||
|
|
||||||
|
pinit_ctx = context;
|
||||||
|
|
||||||
|
plist->destroy_list = elem_list_destroy_elem_list;
|
||||||
|
plist->get_list_head = elem_list_get_list_head;
|
||||||
|
plist->get_total_count = elem_list_get_total_count;
|
||||||
|
plist->get_elem_size = elem_list_get_elem_size;
|
||||||
|
plist->get_link_offset = elem_list_get_link_offset;
|
||||||
|
plist->add_ref = elem_list_add_ref;
|
||||||
|
plist->release_ref = elem_list_release_ref;
|
||||||
|
plist->get_ref = elem_list_get_ref;
|
||||||
|
|
||||||
|
InitializeListHead( &plist->free_list );
|
||||||
|
|
||||||
|
switch( init_flags & 0x0f )
|
||||||
|
{
|
||||||
|
case INIT_LIST_FLAG_ITD:
|
||||||
|
plist->total_count = EHCI_MAX_ITDS_LIST;
|
||||||
|
plist->elem_size = sizeof( EHCI_ITD );
|
||||||
|
break;
|
||||||
|
case INIT_LIST_FLAG_QH:
|
||||||
|
plist->total_count = EHCI_MAX_QHS_LIST;
|
||||||
|
plist->elem_size = sizeof( EHCI_QH );
|
||||||
|
break;
|
||||||
|
case INIT_LIST_FLAG_SITD:
|
||||||
|
plist->total_count = EHCI_MAX_SITDS_LIST;
|
||||||
|
plist->elem_size = sizeof( EHCI_SITD );
|
||||||
|
break;
|
||||||
|
case INIT_LIST_FLAG_FSTN:
|
||||||
|
plist->total_count = EHCI_MAX_FSTNS_LIST;
|
||||||
|
plist->elem_size = sizeof( EHCI_FSTN );
|
||||||
|
break;
|
||||||
|
case INIT_LIST_FLAG_QTD:
|
||||||
|
plist->total_count = EHCI_MAX_QTDS_LIST;
|
||||||
|
plist->elem_size = sizeof( EHCI_QTD );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto ERROR_OUT;
|
||||||
|
}
|
||||||
|
if( plist->elem_size & 0x1f )
|
||||||
|
{
|
||||||
|
plist->total_count = 0;
|
||||||
|
goto ERROR_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
plist->flags = init_flags;
|
||||||
|
plist->parent_pool = pinit_ctx->pool;
|
||||||
|
plist->padapter = pinit_ctx->padapter;
|
||||||
|
pages = ( ( plist->elem_size * plist->total_count ) + ( PAGE_SIZE - 1 ) ) / PAGE_SIZE;
|
||||||
|
elms_per_page = PAGE_SIZE / plist->elem_size;
|
||||||
|
|
||||||
|
plist->phys_addrs = usb_alloc_mem( NonPagedPool,
|
||||||
|
( sizeof( PHYSICAL_ADDRESS ) + sizeof( PBYTE ) ) * pages + \
|
||||||
|
sizeof( EHCI_ELEM_LINKS ) * plist->total_count );
|
||||||
|
|
||||||
|
if( plist->phys_addrs == NULL )
|
||||||
|
{
|
||||||
|
plist->total_count = 0;
|
||||||
|
goto ERROR_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
plist->phys_bufs = ( PBYTE* )&plist->phys_addrs[ pages ];
|
||||||
|
plist->elem_head_buf = ( PEHCI_ELEM_LINKS )&plist->phys_bufs[ pages ];
|
||||||
|
RtlZeroMemory( plist->phys_addrs,
|
||||||
|
( sizeof( PHYSICAL_ADDRESS ) + sizeof( PBYTE ) ) * pages + \
|
||||||
|
sizeof( EHCI_ELEM_LINKS ) * plist->total_count );
|
||||||
|
|
||||||
|
for( i = 0; i < pages; i++ )
|
||||||
|
{
|
||||||
|
plist->phys_bufs[ i ] = HalAllocateCommonBuffer(
|
||||||
|
plist->padapter,
|
||||||
|
PAGE_SIZE,
|
||||||
|
&plist->phys_addrs[ i ],
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
if( plist->phys_bufs[ i ] == NULL )
|
||||||
|
{
|
||||||
|
// failed, roll back
|
||||||
|
for( j = i - 1; j >= 0; j -- )
|
||||||
|
HalFreeCommonBuffer(
|
||||||
|
plist->padapter,
|
||||||
|
PAGE_SIZE,
|
||||||
|
plist->phys_addrs[ j ],
|
||||||
|
plist->phys_bufs[ j ],
|
||||||
|
FALSE );
|
||||||
|
goto ERROR_OUT;
|
||||||
|
}
|
||||||
|
RtlZeroMemory( plist->phys_bufs[ i ], PAGE_SIZE );
|
||||||
|
for( j = 0; j < elms_per_page; j++ )
|
||||||
|
{
|
||||||
|
switch( init_flags & 0xf )
|
||||||
|
{
|
||||||
|
case INIT_LIST_FLAG_QH:
|
||||||
|
{
|
||||||
|
init_elem( pqh, EHCI_QH, INIT_LIST_FLAG_QH );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case INIT_LIST_FLAG_ITD:
|
||||||
|
{
|
||||||
|
init_elem( pitd, EHCI_ITD, INIT_LIST_FLAG_ITD );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case INIT_LIST_FLAG_QTD:
|
||||||
|
{
|
||||||
|
init_elem( pqtd, EHCI_QTD, INIT_LIST_FLAG_QTD );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case INIT_LIST_FLAG_SITD:
|
||||||
|
{
|
||||||
|
init_elem( psitd, EHCI_SITD, INIT_LIST_FLAG_SITD );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case INIT_LIST_FLAG_FSTN:
|
||||||
|
{
|
||||||
|
init_elem( pfstn, EHCI_FSTN, INIT_LIST_FLAG_FSTN );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
TRAP();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
ERROR_OUT:
|
||||||
|
|
||||||
|
if( plist->phys_addrs != NULL )
|
||||||
|
usb_free_mem( plist->phys_addrs );
|
||||||
|
|
||||||
|
RtlZeroMemory( plist, sizeof( EHCI_ELEM_LIST ) );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
elem_list_destroy_elem_list(
|
||||||
|
PEHCI_ELEM_LIST plist
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LONG i, pages;
|
||||||
|
|
||||||
|
if( plist == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
pages = ( plist->total_count * plist->elem_size + PAGE_SIZE - 1 ) / PAGE_SIZE;
|
||||||
|
for( i = 0; i < pages; i++ )
|
||||||
|
HalFreeCommonBuffer(
|
||||||
|
plist->padapter,
|
||||||
|
PAGE_SIZE,
|
||||||
|
plist->phys_addrs[ i ],
|
||||||
|
plist->phys_bufs[ i ],
|
||||||
|
FALSE );
|
||||||
|
|
||||||
|
usb_free_mem( plist->phys_addrs );
|
||||||
|
RtlZeroMemory( plist, sizeof( EHCI_ELEM_LIST ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
PLIST_ENTRY
|
||||||
|
elem_list_get_list_head(
|
||||||
|
PEHCI_ELEM_LIST plist
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if( plist == NULL )
|
||||||
|
return NULL;
|
||||||
|
return &plist->free_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
elem_list_get_total_count(
|
||||||
|
PEHCI_ELEM_LIST plist
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if( plist == NULL )
|
||||||
|
return 0;
|
||||||
|
return plist->total_count;;
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
elem_list_get_elem_size(
|
||||||
|
PEHCI_ELEM_LIST plist
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if( plist == NULL )
|
||||||
|
return 0;
|
||||||
|
return plist->elem_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
elem_list_get_link_offset(
|
||||||
|
PEHCI_ELEM_LIST plist
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if( plist == NULL )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return get_elem_phys_part_size( plist->flags & 0xf );
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
elem_list_add_ref(
|
||||||
|
PEHCI_ELEM_LIST plist
|
||||||
|
)
|
||||||
|
{
|
||||||
|
plist->reference++;
|
||||||
|
return plist->reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
elem_list_release_ref(
|
||||||
|
PEHCI_ELEM_LIST plist
|
||||||
|
)
|
||||||
|
{
|
||||||
|
plist->reference--;
|
||||||
|
return plist->reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
elem_list_get_ref(
|
||||||
|
PEHCI_ELEM_LIST plist
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return plist->reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// pool methods
|
||||||
|
//
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
elem_pool_init_pool(
|
||||||
|
PEHCI_ELEM_POOL pool,
|
||||||
|
LONG flags,
|
||||||
|
PVOID context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PADAPTER_OBJECT padapter;
|
||||||
|
INIT_ELEM_LIST_CONTEXT init_ctx;
|
||||||
|
|
||||||
|
if( pool == NULL || context == NULL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
RtlZeroMemory( pool, sizeof( EHCI_ELEM_POOL ) );
|
||||||
|
|
||||||
|
init_ctx.pool = pool;
|
||||||
|
init_ctx.padapter = context;
|
||||||
|
|
||||||
|
pool->elem_lists[ 0 ] = usb_alloc_mem( NonPagedPool, sizeof( EHCI_ELEM_LIST ) );
|
||||||
|
|
||||||
|
if( pool->elem_lists[ 0 ] == NULL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if( elem_list_init_elem_list( pool->elem_lists[ 0 ], flags, &init_ctx, 0 ) == FALSE )
|
||||||
|
{
|
||||||
|
usb_free_mem( pool->elem_lists[ 0 ] );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
pool->link_offset = pool->elem_lists[ 0 ]->get_link_offset( pool->elem_lists[ 0 ] );
|
||||||
|
pool->free_count = pool->elem_lists[ 0 ]->get_total_count( pool->elem_lists[ 0 ] );
|
||||||
|
pool->list_count = 1;
|
||||||
|
pool->flags = flags;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
elem_pool_get_link_offset(
|
||||||
|
PEHCI_ELEM_POOL elem_pool
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return elem_pool->link_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
elem_pool_get_total_count(
|
||||||
|
PEHCI_ELEM_POOL elem_pool
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return elem_pool->elem_lists[ 0 ]->get_total_count( elem_pool->elem_lists[ 0 ] ) * elem_pool->list_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
elem_pool_destroy_pool(
|
||||||
|
PEHCI_ELEM_POOL pool
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LONG i;
|
||||||
|
if( pool == NULL )
|
||||||
|
return;
|
||||||
|
for( i = pool->list_count - 1; i >= 0; i-- )
|
||||||
|
{
|
||||||
|
pool->elem_lists[ i ]->destroy_list( pool->elem_lists[ i ] );
|
||||||
|
usb_free_mem( pool->elem_lists[ i ] );
|
||||||
|
pool->elem_lists[ i ] = NULL;
|
||||||
|
}
|
||||||
|
RtlZeroMemory( pool, sizeof( EHCI_ELEM_POOL ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PEHCI_ELEM_LINKS
|
||||||
|
elem_pool_alloc_elem(
|
||||||
|
PEHCI_ELEM_POOL pool
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LONG i;
|
||||||
|
PEHCI_ELEM_LIST pel;
|
||||||
|
PLIST_HEAD lh;
|
||||||
|
PEHCI_ELEM_LINKS elnk;
|
||||||
|
|
||||||
|
if( pool == NULL )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for( i = 0; i < pool->list_count; i++ )
|
||||||
|
{
|
||||||
|
pel = pool->elem_lists[ i ];
|
||||||
|
if( pel->get_ref( pel ) == pel->get_total_count( pel ) )
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( i == pool->list_count )
|
||||||
|
{
|
||||||
|
if( elem_pool_expand_pool( pool, pel->get_total_count( pel ) ) == FALSE )
|
||||||
|
return NULL;
|
||||||
|
pel = pool->elem_lists[ i ];
|
||||||
|
}
|
||||||
|
|
||||||
|
lh = pel->get_list_head( pel );
|
||||||
|
elnk = ( PEHCI_ELEM_LINKS )RemoveHeadList( lh );
|
||||||
|
InitializeListHead( &elnk->elem_link );
|
||||||
|
InitializeListHead( &elnk->sched_link );
|
||||||
|
|
||||||
|
pel->add_ref( pel );
|
||||||
|
pool->free_count--;
|
||||||
|
|
||||||
|
return elnk;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
elem_pool_free_elem(
|
||||||
|
PEHCI_ELEM_LINKS elem_link
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PLIST_HEAD lh;
|
||||||
|
LONG ref;
|
||||||
|
PEHCI_ELEM_POOL pool;
|
||||||
|
if( elem_link == NULL )
|
||||||
|
return;
|
||||||
|
pool = elem_link->pool_link;
|
||||||
|
lh = elem_link->list_link->get_list_head( elem_link->list_link );
|
||||||
|
if( lh == NULL )
|
||||||
|
return;
|
||||||
|
InsertHeadList( lh, ( PLIST_ENTRY )elem_link );
|
||||||
|
ref = elem_link->list_link->release_ref( elem_link->list_link );
|
||||||
|
pool->free_count++;
|
||||||
|
if( ref == 0 )
|
||||||
|
elem_pool_collect_garbage( pool );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
elem_pool_is_empty(
|
||||||
|
PEHCI_ELEM_POOL pool
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PEHCI_ELEM_LIST pel;
|
||||||
|
|
||||||
|
if( pool == NULL )
|
||||||
|
return TRUE;
|
||||||
|
pel = pool->elem_lists[ 0 ];
|
||||||
|
return ( pool->list_count == 1 && pool->free_count == pel->get_total_count( pel ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
elem_pool_get_free_count(
|
||||||
|
PEHCI_ELEM_POOL pool
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if( pool == NULL )
|
||||||
|
return 0;
|
||||||
|
return pool->free_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
PEHCI_ELEM_LINKS
|
||||||
|
elem_pool_alloc_elems(
|
||||||
|
PEHCI_ELEM_POOL pool,
|
||||||
|
LONG count
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LIST_HEAD lh;
|
||||||
|
PLIST_ENTRY pthis;
|
||||||
|
LONG i, alloc_count, max_pool_lists;
|
||||||
|
PEHCI_ELEM_LIST pel;
|
||||||
|
PEHCI_ELEM_LINKS elnk;
|
||||||
|
// calculate to see if the count is affordable
|
||||||
|
|
||||||
|
if( pool == NULL || count <= 0 )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
get_max_lists_count( pool, max_pool_lists );
|
||||||
|
InitializeListHead( &lh );
|
||||||
|
pel = pool->elem_lists[ 0 ];
|
||||||
|
if( count <= pool->free_count )
|
||||||
|
alloc_count = 0;
|
||||||
|
else
|
||||||
|
alloc_count = count - pool->free_count;
|
||||||
|
|
||||||
|
if( alloc_count > pel->get_total_count( pel ) * ( max_pool_lists - pool->list_count ) )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for( i = 0; i < count; i++ )
|
||||||
|
{
|
||||||
|
if( ( elnk = elem_pool_alloc_elem( pool ) ) == NULL )
|
||||||
|
{
|
||||||
|
// undo what we have done
|
||||||
|
while( IsListEmpty( &lh ) == FALSE )
|
||||||
|
{
|
||||||
|
pthis = RemoveHeadList( &lh );
|
||||||
|
elnk = struct_ptr( pthis, EHCI_ELEM_LINKS, elem_link );
|
||||||
|
elem_pool_free_elem( elnk );
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
InsertTailList( &lh, &elnk->elem_link );
|
||||||
|
}
|
||||||
|
ListFirst( &lh, pthis );
|
||||||
|
elnk = struct_ptr( pthis, EHCI_ELEM_LINKS, elem_link );
|
||||||
|
RemoveEntryList( &lh );
|
||||||
|
return elnk;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
elem_pool_free_elems(
|
||||||
|
PEHCI_ELEM_LINKS elem_chains
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// note: no list head exists.
|
||||||
|
LIST_HEAD lh;
|
||||||
|
PEHCI_ELEM_LINKS elnk;
|
||||||
|
|
||||||
|
InsertTailList( &elem_chains->elem_link, &lh );
|
||||||
|
while( IsListEmpty( &lh ) == FALSE )
|
||||||
|
{
|
||||||
|
elnk = ( PEHCI_ELEM_LINKS )RemoveHeadList( &lh );
|
||||||
|
elem_pool_free_elem( elnk );
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
LONG
|
||||||
|
elem_pool_get_type(
|
||||||
|
PEHCI_ELEM_POOL pool
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if( pool == NULL )
|
||||||
|
return -1;
|
||||||
|
return ( pool->flags & 0xf );
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
elem_pool_expand_pool(
|
||||||
|
PEHCI_ELEM_POOL pool,
|
||||||
|
LONG elem_count
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LONG elem_cnt_list, list_count, i, j;
|
||||||
|
INIT_ELEM_LIST_CONTEXT init_ctx;
|
||||||
|
|
||||||
|
if( pool == NULL || elem_count <= 0 || elem_count > EHCI_MAX_ELEMS_POOL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
init_ctx.pool = pool;
|
||||||
|
init_ctx.padapter = pool->elem_lists[ 0 ]->padapter;
|
||||||
|
|
||||||
|
elem_cnt_list = pool->elem_lists[ 0 ]->get_total_count( pool->elem_lists[ 0 ] );
|
||||||
|
list_count = ( elem_count + elem_cnt_list - 1 ) / elem_cnt_list;
|
||||||
|
get_max_lists_count( pool, i );
|
||||||
|
|
||||||
|
if( list_count + pool->list_count > i )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
for( i = pool->list_count; i < list_count + pool->list_count; i++ )
|
||||||
|
{
|
||||||
|
pool->elem_lists[ i ] = usb_alloc_mem( NonPagedPool, sizeof( EHCI_ELEM_LIST ) );
|
||||||
|
if( elem_list_init_elem_list( pool->elem_lists[ i ], pool->flags, &init_ctx, 0 ) == FALSE )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( i < list_count + pool->list_count )
|
||||||
|
{
|
||||||
|
// undo all we have done
|
||||||
|
for( j = pool->list_count; j < pool->list_count + i; j++ )
|
||||||
|
{
|
||||||
|
pool->elem_lists[ j ]->destroy_list( pool->elem_lists[ j ] );
|
||||||
|
usb_free_mem( pool->elem_lists[ j ] );
|
||||||
|
pool->elem_lists[ j ] = NULL;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update pool
|
||||||
|
pool->free_count += elem_cnt_list * list_count;
|
||||||
|
pool->list_count += list_count;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
elem_pool_collect_garbage(
|
||||||
|
PEHCI_ELEM_POOL pool
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LONG i, j, k, fl;
|
||||||
|
LONG free_elem_lists[ EHCI_MAX_LISTS_POOL - 1 ];
|
||||||
|
PEHCI_ELEM_LIST pel;
|
||||||
|
|
||||||
|
if( pool == NULL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
for( i = 1, fl = 0; i < pool->list_count; i++ )
|
||||||
|
{
|
||||||
|
if( pool->elem_lists[ i ]->get_ref( pool->elem_lists[ i ] ) == 0 )
|
||||||
|
{
|
||||||
|
free_elem_lists[ fl++ ] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for( j = fl - 1; j >= 0; j-- )
|
||||||
|
{
|
||||||
|
pel = pool->elem_lists[ free_elem_lists[ j ] ];
|
||||||
|
pel->destroy_list( pel );
|
||||||
|
usb_free_mem( pel );
|
||||||
|
|
||||||
|
for( k = free_elem_lists[ j ] + 1; k < pool->list_count; k++ )
|
||||||
|
{
|
||||||
|
// shrink the elem_lists
|
||||||
|
pool->elem_lists[ k - 1 ] = pool->elem_lists[ k ];
|
||||||
|
}
|
||||||
|
pool->elem_lists[ k ] = NULL;
|
||||||
|
pel = pool->elem_lists[ 0 ];
|
||||||
|
pool->free_count -= pel->get_total_count( pel );
|
||||||
|
pool->list_count --;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
elem_pool_can_transfer(
|
||||||
|
PEHCI_ELEM_POOL pool,
|
||||||
|
LONG td_count
|
||||||
|
)
|
||||||
|
{
|
||||||
|
LONG i;
|
||||||
|
if( pool == NULL || td_count <= 0 )
|
||||||
|
return FALSE;
|
||||||
|
get_max_lists_count( pool, i );
|
||||||
|
if( ( i - pool->list_count )
|
||||||
|
* pool->elem_lists[ 0 ]->get_total_count( pool->elem_lists[ 0 ] )
|
||||||
|
+ pool->free_count < td_count )
|
||||||
|
return FALSE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------
|
||||||
|
|
2076
reactos/drivers/usb/nt4compat/usbdriver/gendrv.c
Normal file
2076
reactos/drivers/usb/nt4compat/usbdriver/gendrv.c
Normal file
File diff suppressed because it is too large
Load diff
65
reactos/drivers/usb/nt4compat/usbdriver/gendrv.h
Normal file
65
reactos/drivers/usb/nt4compat/usbdriver/gendrv.h
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#ifndef __GENDRV_H__
|
||||||
|
#define __GENDRV_H__
|
||||||
|
|
||||||
|
#include "td.h"
|
||||||
|
#include "hub.h"
|
||||||
|
|
||||||
|
#define GENDRV_MAX_EXT_DRVR 2
|
||||||
|
#define GENDRV_DRVR_FLAG_IF_DRVR 0x01
|
||||||
|
|
||||||
|
#define GENDRV_MSG_ADDDEVICE 0x01
|
||||||
|
#define GENDRV_MSG_STOPDEVICE 0x02
|
||||||
|
#define GENDRV_MSG_DISCDEVICE 0x03
|
||||||
|
|
||||||
|
typedef struct _GENDRV_EXT_DRVR_ENTRY
|
||||||
|
{
|
||||||
|
LIST_ENTRY drvr_link; // used for dynamic load/unload driver
|
||||||
|
ULONG drvr_key; // used to find the driver loaded, the key
|
||||||
|
// is ( vendor_id << 16 )|( product_id ) or
|
||||||
|
// ( class_id << 16 ) | ( sub_class_id << 8 ) | ( protocol_id ))
|
||||||
|
PDRIVER_OBJECT pext_drvr; // the external driver count
|
||||||
|
ULONG ref_count; // number of devices attached
|
||||||
|
LIST_HEAD dev_list; // link the devices by deviceExtension->dev_obj_link
|
||||||
|
|
||||||
|
} GENDRV_EXT_DRVR_ENTRY, *PGENDRV_EXT_DRVR_ENTRY;
|
||||||
|
|
||||||
|
typedef struct _GENDRV_DRVR_EXTENSION
|
||||||
|
{
|
||||||
|
FAST_MUTEX drvr_ext_mutex;
|
||||||
|
ULONG ext_drvr_count; // loaded driver count
|
||||||
|
LIST_HEAD ext_drvr_list;
|
||||||
|
GENDRV_EXT_DRVR_ENTRY ext_drvr_array[ GENDRV_MAX_EXT_DRVR ];
|
||||||
|
|
||||||
|
}GENDRV_DRVR_EXTENSION, *PGENDRV_DRVR_EXTENSION;
|
||||||
|
|
||||||
|
typedef struct _GENDRV_IF_CTX
|
||||||
|
{
|
||||||
|
UCHAR if_idx; // valid for if device
|
||||||
|
PUSB_INTERFACE_DESC pif_desc;
|
||||||
|
|
||||||
|
} GENDRV_IF_CTX, *PGENDRV_IF_IDX;
|
||||||
|
|
||||||
|
typedef struct _GENDRV_DEVICE_EXTENSION
|
||||||
|
{
|
||||||
|
//this structure is the device extension for dev_obj
|
||||||
|
//created for the device.
|
||||||
|
DEVEXT_HEADER dev_ext_hdr;
|
||||||
|
ULONG flags;
|
||||||
|
LIST_ENTRY dev_obj_link; // this link is used by the driver object to track the existing dev_objs
|
||||||
|
PGENDRV_EXT_DRVR_ENTRY ext_drvr_entry;
|
||||||
|
|
||||||
|
PDEVICE_OBJECT pdo; // Our device object
|
||||||
|
DEV_HANDLE dev_handle; // handle to the usb_dev under
|
||||||
|
PUCHAR desc_buf;
|
||||||
|
UCHAR dev_id; // used to build symbolic link
|
||||||
|
GENDRV_IF_CTX if_ctx;
|
||||||
|
|
||||||
|
KEVENT sync_event;
|
||||||
|
KSPIN_LOCK dev_lock;
|
||||||
|
|
||||||
|
PUSB_DRIVER pdriver;
|
||||||
|
PUSB_DEV_MANAGER dev_mgr;
|
||||||
|
|
||||||
|
} GENDRV_DEVICE_EXTENSION, *PGENDRV_DEVICE_EXTENSION;
|
||||||
|
|
||||||
|
#endif
|
71
reactos/drivers/usb/nt4compat/usbdriver/hcd.h
Normal file
71
reactos/drivers/usb/nt4compat/usbdriver/hcd.h
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#ifndef __HCD_H__
|
||||||
|
#define __HCD_H__
|
||||||
|
|
||||||
|
#include "ntddk.h"
|
||||||
|
|
||||||
|
#define HCD_TYPE_MASK 0xf0
|
||||||
|
#define HCD_TYPE_UHCI 0x10
|
||||||
|
#define HCD_TYPE_OHCI 0x20
|
||||||
|
#define HCD_TYPE_EHCI 0x30
|
||||||
|
|
||||||
|
#define hcd_type( hCD ) ( ( ( hCD )->flags ) & HCD_TYPE_MASK )
|
||||||
|
#define usb2( hCD ) ( hcd_type( hCD ) == HCD_TYPE_EHCI )
|
||||||
|
|
||||||
|
#define HCD_ID_MASK 0xf
|
||||||
|
|
||||||
|
#ifndef BOOL
|
||||||
|
#define BOOL ULONG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HCD_DISP_READ_PORT_COUNT 1 // the param is a pointer to UCHAR
|
||||||
|
#define HCD_DISP_READ_RH_DEV_CHANGE 2 // the param is a buffer to hold conn change on all the port
|
||||||
|
// must have the rh dev_lock acquired
|
||||||
|
|
||||||
|
typedef VOID ( *PHCD_SET_DEV_MGR )( struct _HCD* hcd, struct _USB_DEV_MANAGER *dev_mgr );
|
||||||
|
typedef struct _USB_DEV_MANAGER* ( *PHCD_GET_DEV_MGR )( struct _HCD* hcd );
|
||||||
|
typedef ULONG ( *PHCD_GET_TYPE )( struct _HCD* hcd );
|
||||||
|
typedef VOID ( *PHCD_SET_ID )( struct _HCD* hcd, UCHAR id );
|
||||||
|
typedef UCHAR ( *PHCD_GET_ID )( struct _HCD* hcd );
|
||||||
|
typedef UCHAR ( *PHCD_ALLOC_ADDR )( struct _HCD* hcd );
|
||||||
|
typedef VOID ( *PHCD_FREE_ADDR )( struct _HCD* hcd, UCHAR addr );
|
||||||
|
typedef NTSTATUS ( *PHCD_SUBMIT_URB )( struct _HCD* hcd, struct _USB_DEV *pdev, struct _USB_ENDPOINT *pendp, struct _URB *purb );
|
||||||
|
typedef VOID ( *PHCD_GENERIC_URB_COMPLETION )( struct _URB *purb, PVOID context ); //we can get te hcd from purb
|
||||||
|
typedef struct _USB_DEV* ( *PHCD_GET_ROOT_HUB )( struct _HCD* hcd );
|
||||||
|
typedef VOID ( *PHCD_SET_ROOT_HUB )( struct _HCD* hcd, struct _USB_DEV *root_hub );
|
||||||
|
typedef BOOL ( *PHCD_REMOVE_DEVICE )( struct _HCD* hcd, struct _USB_DEV *pdev );
|
||||||
|
typedef BOOL ( *PHCD_RH_RESET_PORT )( struct _HCD* hcd, UCHAR port_idx ); //must have the rh dev_lock acquired
|
||||||
|
typedef BOOL ( *PHCD_RELEASE )( struct _HCD* hcd ); //must have the rh dev_lock acquired
|
||||||
|
typedef NTSTATUS( *PHCD_CANCEL_URB)( struct _HCD* hcd, struct _USB_DEV *pdev, struct _USB_ENDPOINT* pendp, struct _URB *purb );
|
||||||
|
typedef BOOL ( *PHCD_START )( struct _HCD* hcd ); //must have the rh dev_lock acquired
|
||||||
|
typedef NTSTATUS ( *PHCD_DISPATCH )( struct _HCD* hcd, LONG disp_code, PVOID param ); // locking depends on type of code
|
||||||
|
|
||||||
|
typedef struct _HCD
|
||||||
|
{
|
||||||
|
PHCD_SET_DEV_MGR hcd_set_dev_mgr;
|
||||||
|
PHCD_GET_DEV_MGR hcd_get_dev_mgr;
|
||||||
|
PHCD_GET_TYPE hcd_get_type;
|
||||||
|
PHCD_SET_ID hcd_set_id;
|
||||||
|
PHCD_GET_ID hcd_get_id;
|
||||||
|
PHCD_ALLOC_ADDR hcd_alloc_addr;
|
||||||
|
PHCD_FREE_ADDR hcd_free_addr;
|
||||||
|
PHCD_SUBMIT_URB hcd_submit_urb;
|
||||||
|
PHCD_GENERIC_URB_COMPLETION hcd_generic_urb_completion;
|
||||||
|
PHCD_GET_ROOT_HUB hcd_get_root_hub;
|
||||||
|
PHCD_SET_ROOT_HUB hcd_set_root_hub;
|
||||||
|
PHCD_REMOVE_DEVICE hcd_remove_device;
|
||||||
|
PHCD_RH_RESET_PORT hcd_rh_reset_port;
|
||||||
|
PHCD_RELEASE hcd_release;
|
||||||
|
PHCD_CANCEL_URB hcd_cancel_urb;
|
||||||
|
PHCD_START hcd_start;
|
||||||
|
PHCD_DISPATCH hcd_dispatch;
|
||||||
|
|
||||||
|
//interfaces for all the host controller
|
||||||
|
ULONG flags; //hcd types | hcd id
|
||||||
|
ULONG conn_count; //statics for connection activities
|
||||||
|
struct _USB_DEV_MANAGER *dev_mgr; //pointer manager
|
||||||
|
UCHAR dev_addr_map[ 128 / 8 ]; //bitmap for the device addrs
|
||||||
|
struct _DEVICE_EXTENSION *pdev_ext;
|
||||||
|
|
||||||
|
} HCD, *PHCD;
|
||||||
|
|
||||||
|
#endif
|
5184
reactos/drivers/usb/nt4compat/usbdriver/hub.c
Normal file
5184
reactos/drivers/usb/nt4compat/usbdriver/hub.c
Normal file
File diff suppressed because it is too large
Load diff
794
reactos/drivers/usb/nt4compat/usbdriver/hub.h
Normal file
794
reactos/drivers/usb/nt4compat/usbdriver/hub.h
Normal file
|
@ -0,0 +1,794 @@
|
||||||
|
|
||||||
|
#ifndef __HUB_H__
|
||||||
|
#define __HUB_H__
|
||||||
|
|
||||||
|
#include "td.h"
|
||||||
|
//#include "hcd.h"
|
||||||
|
#include "ntddk.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hub Class feature numbers
|
||||||
|
*/
|
||||||
|
#define C_HUB_LOCAL_POWER 0
|
||||||
|
#define C_HUB_OVER_CURRENT 1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Port feature numbers
|
||||||
|
*/
|
||||||
|
#define USB_PORT_FEAT_CONNECTION 0
|
||||||
|
#define USB_PORT_FEAT_ENABLE 1
|
||||||
|
#define USB_PORT_FEAT_SUSPEND 2
|
||||||
|
#define USB_PORT_FEAT_OVER_CURRENT 3
|
||||||
|
#define USB_PORT_FEAT_RESET 4
|
||||||
|
#define USB_PORT_FEAT_POWER 8
|
||||||
|
#define USB_PORT_FEAT_LOWSPEED 9
|
||||||
|
#define USB_PORT_FEAT_C_CONNECTION 16
|
||||||
|
#define USB_PORT_FEAT_C_ENABLE 17
|
||||||
|
#define USB_PORT_FEAT_C_SUSPEND 18
|
||||||
|
#define USB_PORT_FEAT_C_OVER_CURRENT 19
|
||||||
|
#define USB_PORT_FEAT_C_RESET 20
|
||||||
|
|
||||||
|
/* wPortStatus bits */
|
||||||
|
#define USB_PORT_STAT_CONNECTION 0x0001
|
||||||
|
#define USB_PORT_STAT_ENABLE 0x0002
|
||||||
|
#define USB_PORT_STAT_SUSPEND 0x0004
|
||||||
|
#define USB_PORT_STAT_OVERCURRENT 0x0008
|
||||||
|
#define USB_PORT_STAT_RESET 0x0010
|
||||||
|
#define USB_PORT_STAT_POWER 0x0100
|
||||||
|
#define USB_PORT_STAT_LOW_SPEED 0x0200
|
||||||
|
|
||||||
|
/* usb 2.0 features */
|
||||||
|
#define USB_PORT_STAT_HIGH_SPEED 0x0400
|
||||||
|
#define USB_PORT_STAT_PORT_TEST 0x0800
|
||||||
|
#define USB_PORT_STAT_PORT_INDICATOR 0x1000
|
||||||
|
|
||||||
|
/* wPortChange bits */
|
||||||
|
#define USB_PORT_STAT_C_CONNECTION 0x0001
|
||||||
|
#define USB_PORT_STAT_C_ENABLE 0x0002
|
||||||
|
#define USB_PORT_STAT_C_SUSPEND 0x0004
|
||||||
|
#define USB_PORT_STAT_C_OVERCURRENT 0x0008
|
||||||
|
#define USB_PORT_STAT_C_RESET 0x0010
|
||||||
|
|
||||||
|
/* wHubCharacteristics (masks) */
|
||||||
|
#define HUB_CHAR_LPSM 0x0003
|
||||||
|
#define HUB_CHAR_COMPOUND 0x0004
|
||||||
|
#define HUB_CHAR_OCPM 0x0018
|
||||||
|
|
||||||
|
/*
|
||||||
|
*Hub Status & Hub Change bit masks
|
||||||
|
*/
|
||||||
|
#define HUB_STATUS_LOCAL_POWER 0x0001
|
||||||
|
#define HUB_STATUS_OVERCURRENT 0x0002
|
||||||
|
|
||||||
|
#define HUB_CHANGE_LOCAL_POWER 0x0001
|
||||||
|
#define HUB_CHANGE_OVERCURRENT 0x0002
|
||||||
|
|
||||||
|
#define HUB_DESCRIPTOR_MAX_SIZE 39 /* enough for 127 ports on a hub */
|
||||||
|
|
||||||
|
//event definitions
|
||||||
|
|
||||||
|
#define MAX_EVENTS 128
|
||||||
|
#define MAX_TIMER_SVCS 24
|
||||||
|
|
||||||
|
#define USB_EVENT_FLAG_ACTIVE 0x80000000
|
||||||
|
|
||||||
|
#define USB_EVENT_FLAG_QUE_TYPE 0x000000FF
|
||||||
|
#define USB_EVENT_FLAG_QUE_RESET 0x01
|
||||||
|
#define USB_EVENT_FLAG_NOQUE 0x00
|
||||||
|
|
||||||
|
#define USB_EVENT_DEFAULT 0x00 //as a placeholder
|
||||||
|
#define USB_EVENT_INIT_DEV_MGR 0x01
|
||||||
|
#define USB_EVENT_HUB_POLL 0x02
|
||||||
|
#define USB_EVENT_WAIT_RESET_PORT 0x03
|
||||||
|
#define USB_EVENT_CLEAR_TT_BUFFER 0x04
|
||||||
|
|
||||||
|
typedef VOID ( *PROCESS_QUEUE )(
|
||||||
|
PLIST_HEAD event_list,
|
||||||
|
struct _USB_EVENT_POOL *event_pool,
|
||||||
|
struct _USB_EVENT *usb_event,
|
||||||
|
struct _USB_EVENT *out_event
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef VOID ( *PROCESS_EVENT )(
|
||||||
|
PUSB_DEV dev,
|
||||||
|
ULONG event,
|
||||||
|
ULONG context,
|
||||||
|
ULONG param
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef struct _USB_EVENT
|
||||||
|
{
|
||||||
|
LIST_ENTRY event_link;
|
||||||
|
ULONG flags;
|
||||||
|
ULONG event;
|
||||||
|
PUSB_DEV pdev;
|
||||||
|
ULONG context;
|
||||||
|
ULONG param;
|
||||||
|
struct _USB_EVENT *pnext; //vertical queue for serialized operation
|
||||||
|
PROCESS_EVENT process_event;
|
||||||
|
PROCESS_QUEUE process_queue;
|
||||||
|
|
||||||
|
} USB_EVENT, *PUSB_EVENT;
|
||||||
|
|
||||||
|
typedef struct _USB_EVENT_POOL
|
||||||
|
{
|
||||||
|
PUSB_EVENT event_array;
|
||||||
|
LIST_HEAD free_que;
|
||||||
|
LONG free_count;
|
||||||
|
LONG total_count;
|
||||||
|
KSPIN_LOCK pool_lock;
|
||||||
|
|
||||||
|
} USB_EVENT_POOL, *PUSB_EVENT_POOL;
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
init_event_pool(
|
||||||
|
PUSB_EVENT_POOL pool
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
free_event(
|
||||||
|
PUSB_EVENT_POOL pool,
|
||||||
|
PUSB_EVENT pevent
|
||||||
|
); //add qhs till pnext == NULL
|
||||||
|
|
||||||
|
PUSB_EVENT
|
||||||
|
alloc_event(
|
||||||
|
PUSB_EVENT_POOL pool,
|
||||||
|
LONG count
|
||||||
|
); //null if failed
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
destroy_event_pool(
|
||||||
|
PUSB_EVENT_POOL pool
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
lock_event_pool(
|
||||||
|
PUSB_EVENT_POOL pool
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
unlock_event_pool(
|
||||||
|
PUSB_EVENT_POOL pool
|
||||||
|
);
|
||||||
|
|
||||||
|
#define DEV_MGR_TIMER_INTERVAL_NS ( 10 * 1000 * 10 ) //unit 100 ns
|
||||||
|
#define DEV_MGR_TIMER_INTERVAL_MS 10
|
||||||
|
|
||||||
|
typedef VOID ( *TIMER_SVC_HANDLER )(PUSB_DEV dev, PVOID context);
|
||||||
|
|
||||||
|
typedef struct _TIMER_SVC
|
||||||
|
{
|
||||||
|
LIST_ENTRY timer_svc_link;
|
||||||
|
ULONG counter;
|
||||||
|
ULONG threshold;
|
||||||
|
ULONG context;
|
||||||
|
PUSB_DEV pdev;
|
||||||
|
TIMER_SVC_HANDLER func;
|
||||||
|
|
||||||
|
} TIMER_SVC, *PTIMER_SVC;
|
||||||
|
|
||||||
|
typedef struct _TIMER_SVC_POOL
|
||||||
|
{
|
||||||
|
PTIMER_SVC timer_svc_array;
|
||||||
|
LIST_HEAD free_que;
|
||||||
|
LONG free_count;
|
||||||
|
LONG total_count;
|
||||||
|
KSPIN_LOCK pool_lock;
|
||||||
|
|
||||||
|
} TIMER_SVC_POOL, *PTIMER_SVC_POOL;
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
init_timer_svc_pool(
|
||||||
|
PTIMER_SVC_POOL pool
|
||||||
|
);
|
||||||
|
BOOL
|
||||||
|
free_timer_svc(
|
||||||
|
PTIMER_SVC_POOL pool,
|
||||||
|
PTIMER_SVC ptimer
|
||||||
|
);
|
||||||
|
|
||||||
|
PTIMER_SVC
|
||||||
|
alloc_timer_svc(
|
||||||
|
PTIMER_SVC_POOL pool,
|
||||||
|
LONG count
|
||||||
|
); //null if failed
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
destroy_timer_svc_pool(
|
||||||
|
PTIMER_SVC_POOL pool
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
lock_timer_svc_pool(
|
||||||
|
PTIMER_SVC_POOL pool
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
unlock_timer_svc_pool(
|
||||||
|
PTIMER_SVC_POOL pool
|
||||||
|
);
|
||||||
|
|
||||||
|
#define MAX_IRP_LIST_SIZE 32
|
||||||
|
|
||||||
|
typedef struct _IRP_LIST_ELEMENT
|
||||||
|
{
|
||||||
|
LIST_ENTRY irp_link;
|
||||||
|
PIRP pirp;
|
||||||
|
struct _URB *purb;
|
||||||
|
|
||||||
|
} IRP_LIST_ELEMENT, *PIRP_LIST_ELEMENT;
|
||||||
|
|
||||||
|
typedef struct _IRP_LIST
|
||||||
|
{
|
||||||
|
KSPIN_LOCK irp_list_lock;
|
||||||
|
LIST_HEAD irp_busy_list;
|
||||||
|
LONG irp_free_list_count;
|
||||||
|
LIST_HEAD irp_free_list;
|
||||||
|
PIRP_LIST_ELEMENT irp_list_element_array;
|
||||||
|
|
||||||
|
} IRP_LIST, *PIRP_LIST;
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
init_irp_list(
|
||||||
|
PIRP_LIST irp_list
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
destroy_irp_list(
|
||||||
|
PIRP_LIST irp_list
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
add_irp_to_list(
|
||||||
|
PIRP_LIST irp_list,
|
||||||
|
PIRP pirp,
|
||||||
|
PURB purb
|
||||||
|
);
|
||||||
|
|
||||||
|
PURB
|
||||||
|
remove_irp_from_list(
|
||||||
|
PIRP_LIST irp_list,
|
||||||
|
PIRP pirp,
|
||||||
|
struct _USB_DEV_MANAGER *dev_mgr
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
irp_list_empty(
|
||||||
|
PIRP_LIST irp_list
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
irp_list_full(
|
||||||
|
PIRP_LIST irp_list
|
||||||
|
);
|
||||||
|
|
||||||
|
#define MAX_HUB_PORTS 8
|
||||||
|
#define USB_HUB_INTERVAL 0xff
|
||||||
|
|
||||||
|
#define USB_PORT_FLAG_STATE_MASK ( 0xf << 16 )
|
||||||
|
#define USB_PORT_FLAG_ENABLE ( 0x1 << 16 )
|
||||||
|
#define USB_PORT_FLAG_DISABLE ( 0x2 << 16 )
|
||||||
|
#define USB_PORT_FLAG_DISCONNECT ( 0x3 << 16 )
|
||||||
|
|
||||||
|
#define USB_PORT_QUE_STATE_MASK 0xff // for detail, refer to document.txt
|
||||||
|
#define STATE_IDLE 0x00
|
||||||
|
#define STATE_EXAMINE_STATUS_QUE 0x01 // set when post a event to examine the status queue
|
||||||
|
#define STATE_WAIT_STABLE 0x02 // set when a new connection comes and about to wait some ms
|
||||||
|
#define STATE_WAIT_RESET 0x03 // set when dev stable and about to reset, may pending in the event queue
|
||||||
|
#define STATE_WAIT_RESET_COMPLETE 0x04 // set when reset signal is about to assert on the port
|
||||||
|
#define STATE_WAIT_ADDRESSED 0x05 // set when reset complete and before address is assigned
|
||||||
|
|
||||||
|
#define port_state( port_FLAG ) \
|
||||||
|
( port_FLAG & USB_PORT_QUE_STATE_MASK )
|
||||||
|
|
||||||
|
#define set_port_state( port_FLAG, stATE ) \
|
||||||
|
{ port_FLAG = ( port_FLAG & (~USB_PORT_QUE_STATE_MASK ) ) | ( stATE & USB_PORT_QUE_STATE_MASK ) ;}
|
||||||
|
|
||||||
|
#define default_endp_handle( endp_HANDLE ) \
|
||||||
|
( ( endp_HANDLE & 0xffff ) == 0xffff )
|
||||||
|
|
||||||
|
#define is_if_dev( pdev ) ( pdev->flags & USB_DEV_FLAG_IF_DEV )
|
||||||
|
|
||||||
|
#define is_composite_dev( pdev ) \
|
||||||
|
( is_if_dev( pdev ) == FALSE \
|
||||||
|
&& pdev->pusb_dev_desc->bDeviceClass == 0 \
|
||||||
|
&& pdev->pusb_dev_desc->bDeviceSubClass == 0 )
|
||||||
|
|
||||||
|
#define dev_handle_from_dev( pdev ) ( pdev->dev_id << 16 )
|
||||||
|
|
||||||
|
#pragma pack( push, hub_align, 1 )
|
||||||
|
typedef struct _USB_PORT_STATUS
|
||||||
|
{
|
||||||
|
USHORT wPortStatus;
|
||||||
|
USHORT wPortChange;
|
||||||
|
|
||||||
|
} USB_PORT_STATUS, *PUSB_PORT_STATUS;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _USB_HUB_STATUS
|
||||||
|
{
|
||||||
|
USHORT wHubStatus;
|
||||||
|
USHORT wHubChange;
|
||||||
|
|
||||||
|
} USB_HUB_STATUS, *PUSB_HUB_STATUS;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _USB_HUB_DESCRIPTOR
|
||||||
|
{
|
||||||
|
BYTE bLength;
|
||||||
|
BYTE bDescriptorType;
|
||||||
|
BYTE bNbrPorts;
|
||||||
|
USHORT wHubCharacteristics;
|
||||||
|
BYTE bPwrOn2PwrGood;
|
||||||
|
BYTE bHubContrCurrent;
|
||||||
|
|
||||||
|
/* DeviceRemovable and PortPwrCtrlMask want to be variable-length
|
||||||
|
bitmaps that hold max 256 entries, but for now they're ignored */
|
||||||
|
BYTE bitmap[0];
|
||||||
|
} USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR;
|
||||||
|
#pragma pack( pop, hub_align )
|
||||||
|
|
||||||
|
typedef struct _PORT_STATUS_QUEUE
|
||||||
|
{
|
||||||
|
USB_PORT_STATUS port_status[ 4 ];
|
||||||
|
BYTE status_count;
|
||||||
|
ULONG port_flags;
|
||||||
|
|
||||||
|
} PORT_STATUS_QUEUE, *PPORT_STATUS_QUEUE;
|
||||||
|
|
||||||
|
VOID
|
||||||
|
psq_init(
|
||||||
|
PPORT_STATUS_QUEUE psq
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
psq_enqueue(
|
||||||
|
PPORT_STATUS_QUEUE psq,
|
||||||
|
ULONG status
|
||||||
|
);
|
||||||
|
ULONG
|
||||||
|
psq_outqueue(
|
||||||
|
PPORT_STATUS_QUEUE psq
|
||||||
|
); //return 0xffffffff if no element
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
psq_push(
|
||||||
|
PPORT_STATUS_QUEUE psq,
|
||||||
|
ULONG status
|
||||||
|
);
|
||||||
|
|
||||||
|
#define psq_is_empty( pSQ ) ( ( pSQ )->status_count == 0 )
|
||||||
|
#define psq_is_full( pSQ ) ( ( pSQ )->status_count == 4 )
|
||||||
|
#define psq_count( psq ) ( ( psq )->status_count )
|
||||||
|
#define psq_peek( psq, i ) \
|
||||||
|
( ( ( ULONG )i ) < 3 ? ( psq )->port_status[ i ] : ( psq )->port_status[ 3 ] )
|
||||||
|
|
||||||
|
#define MAX_DEVS 127
|
||||||
|
#define EHCI_MAX_ROOT_PORTS 15
|
||||||
|
|
||||||
|
typedef struct _HUB_EXTENSION
|
||||||
|
{
|
||||||
|
|
||||||
|
LONG port_count;
|
||||||
|
PUSB_DEV child_dev[ MAX_HUB_PORTS + 1 ];
|
||||||
|
|
||||||
|
PORT_STATUS_QUEUE port_status_queue[ MAX_HUB_PORTS + 1];
|
||||||
|
PUSB_DEV pdev;
|
||||||
|
PUSB_INTERFACE pif;
|
||||||
|
BYTE int_data_buf[ 64 ];
|
||||||
|
|
||||||
|
USB_HUB_STATUS hub_status;
|
||||||
|
USB_PORT_STATUS port_status; //working data buf for get port feature
|
||||||
|
|
||||||
|
USB_PORT_STATUS rh_port1_status; //working buf for get rh port1 feature
|
||||||
|
USB_PORT_STATUS rh_port2_status; //working buf for get rh port2 feature
|
||||||
|
|
||||||
|
USB_HUB_DESCRIPTOR hub_desc;
|
||||||
|
|
||||||
|
} HUB_EXTENSION, *PHUB_EXTENSION;
|
||||||
|
|
||||||
|
typedef struct _HUB2_PORT_TT
|
||||||
|
{
|
||||||
|
ULONG tt_busy : 1;
|
||||||
|
|
||||||
|
} HUB2_PORT_TT, *PHUB2_PORT_TT;
|
||||||
|
|
||||||
|
typedef struct _HUB2_EXTENSION
|
||||||
|
{
|
||||||
|
|
||||||
|
LONG port_count;
|
||||||
|
PUSB_DEV child_dev[ MAX_HUB_PORTS + 1 ];
|
||||||
|
|
||||||
|
PORT_STATUS_QUEUE port_status_queue[ MAX_HUB_PORTS + 1];
|
||||||
|
|
||||||
|
PUSB_DEV pdev;
|
||||||
|
PUSB_INTERFACE pif;
|
||||||
|
BYTE int_data_buf[ 32 ]; // for ports up to 127
|
||||||
|
|
||||||
|
USB_HUB_STATUS hub_status;
|
||||||
|
USB_PORT_STATUS port_status; //working data buf for get port feature
|
||||||
|
|
||||||
|
USB_PORT_STATUS rh_port_status[ EHCI_MAX_ROOT_PORTS ]; //working buf for get rh ports feature
|
||||||
|
|
||||||
|
UCHAR multiple_tt; // boolean
|
||||||
|
ULONG tt_status_map[ 4 ]; // bit map to indicate the indexed tt's periodic buffer busy or not
|
||||||
|
ULONG tt_bulk_map[ 4 ]; // bit map to indicate the indexed tt's bulk/control buffer busy or not
|
||||||
|
USB_HUB_DESCRIPTOR hub_desc;
|
||||||
|
|
||||||
|
} HUB2_EXTENSION, *PHUB2_EXTENSION;
|
||||||
|
|
||||||
|
typedef struct _CONNECT_DATA
|
||||||
|
{
|
||||||
|
DEV_HANDLE dev_handle;
|
||||||
|
struct _USB_DRIVER *pdriver;
|
||||||
|
struct _USB_DEV_MANAGER *dev_mgr;
|
||||||
|
|
||||||
|
} CONNECT_DATA, *PCONNECT_DATA;
|
||||||
|
|
||||||
|
typedef BOOL ( *PDEV_CONNECT_EX )( PCONNECT_DATA init_param, DEV_HANDLE dev_handle );
|
||||||
|
typedef BOOL ( *PDEV_CONNECT )( struct _USB_DEV_MANAGER *dev_mgr, DEV_HANDLE dev_handle );
|
||||||
|
typedef BOOL ( *PDRVR_INIT )( struct _USB_DEV_MANAGER *dev_mgr, struct _USB_DRIVER *pdriver );
|
||||||
|
|
||||||
|
typedef struct _PNP_DISPATCH
|
||||||
|
{
|
||||||
|
ULONG version;
|
||||||
|
PDEV_CONNECT_EX dev_connect;
|
||||||
|
PDEV_CONNECT dev_reserved; //currently we do not use this entry
|
||||||
|
PDEV_CONNECT dev_stop;
|
||||||
|
PDEV_CONNECT dev_disconnect;
|
||||||
|
|
||||||
|
}PNP_DISPATCH, *PPNP_DISPATCH;
|
||||||
|
|
||||||
|
#define USB_DRIVER_FLAG_IF_CAPABLE 0x80000000
|
||||||
|
#define USB_DRIVER_FLAG_DEV_CAPABLE 0x40000000
|
||||||
|
|
||||||
|
typedef struct _USB_DRIVER_DESCRIPTION
|
||||||
|
{
|
||||||
|
// Device Info
|
||||||
|
DWORD flags;
|
||||||
|
WORD vendor_id; // USB Vendor ID
|
||||||
|
WORD product_id; // USB Product ID.
|
||||||
|
WORD release_num; // Release Number of Device
|
||||||
|
|
||||||
|
// Interface Info
|
||||||
|
BYTE config_val; // Configuration Value
|
||||||
|
BYTE if_num; // Interface Number
|
||||||
|
BYTE if_class; // Interface Class
|
||||||
|
BYTE if_sub_class; // Interface SubClass
|
||||||
|
BYTE if_protocol; // Interface Protocol
|
||||||
|
|
||||||
|
// Driver Info
|
||||||
|
PBYTE driver_name; // Driver name for Name Registry
|
||||||
|
BYTE dev_class; // Device Class (from SampleStorageDeviceID.h)
|
||||||
|
BYTE dev_sub_class; // Device Subclass
|
||||||
|
BYTE dev_protocol; // Protocol Info.
|
||||||
|
|
||||||
|
} USB_DRIVER_DESCRIPTION,*PUSB_DRIVER_DESCRIPTION;
|
||||||
|
|
||||||
|
#define DEVMGR_MAX_DRIVERS 6
|
||||||
|
#define RH_DRIVER_IDX 0
|
||||||
|
#define HUB_DRIVER_IDX 1
|
||||||
|
#define UMSS_DRIVER_IDX 2
|
||||||
|
#define COMP_DRIVER_IDX 3
|
||||||
|
#define GEN_DRIVER_IDX 4
|
||||||
|
#define GEN_IF_DRIVER_IDX 5
|
||||||
|
|
||||||
|
typedef struct _USB_DRIVER
|
||||||
|
{
|
||||||
|
USB_DRIVER_DESCRIPTION driver_desc;
|
||||||
|
PNP_DISPATCH disp_tbl;
|
||||||
|
|
||||||
|
PBYTE driver_ext;
|
||||||
|
LONG driver_ext_size;
|
||||||
|
|
||||||
|
PDRVR_INIT driver_init;
|
||||||
|
PDRVR_INIT driver_destroy;
|
||||||
|
|
||||||
|
} USB_DRIVER, *PUSB_DRIVER;
|
||||||
|
|
||||||
|
extern USB_DRIVER g_driver_list[ DEVMGR_MAX_DRIVERS ];
|
||||||
|
|
||||||
|
#define MAX_HCDS 8
|
||||||
|
#define dev_mgr_from_hcd( hCD ) ( ( hCD )->hcd_get_dev_mgr( hCD ) )
|
||||||
|
#define dev_mgr_from_dev( pdEV ) ( dev_mgr_from_hcd( pdEV->hcd ) )
|
||||||
|
|
||||||
|
typedef struct _USB_DEV_MANAGER
|
||||||
|
{
|
||||||
|
//BYTE dev_addr_map[ MAX_DEVS / 8 ]; //one bit per dev
|
||||||
|
struct _HCD *hcd_array[ MAX_HCDS ];
|
||||||
|
unsigned char hcd_count;
|
||||||
|
|
||||||
|
KSPIN_LOCK dev_list_lock;
|
||||||
|
LIST_HEAD dev_list;
|
||||||
|
|
||||||
|
//PDEVICE_EXTENSION pdev_ext;
|
||||||
|
|
||||||
|
PVOID pthread;
|
||||||
|
BOOL term_flag;
|
||||||
|
KEVENT wake_up_event;
|
||||||
|
|
||||||
|
KSPIN_LOCK event_list_lock;
|
||||||
|
LIST_HEAD event_list;
|
||||||
|
USB_EVENT_POOL event_pool;
|
||||||
|
|
||||||
|
KTIMER dev_mgr_timer;
|
||||||
|
KDPC dev_mgr_timer_dpc;
|
||||||
|
KSPIN_LOCK timer_svc_list_lock;
|
||||||
|
LIST_HEAD timer_svc_list;
|
||||||
|
TIMER_SVC_POOL timer_svc_pool;
|
||||||
|
LONG timer_click;
|
||||||
|
IRP_LIST irp_list;
|
||||||
|
|
||||||
|
PUSB_DRIVER driver_list;
|
||||||
|
LONG hub_count;
|
||||||
|
LIST_HEAD hub_list; //for reference only
|
||||||
|
|
||||||
|
//statistics
|
||||||
|
LONG conn_count; //will also be used to assign device id
|
||||||
|
PDRIVER_OBJECT usb_driver_obj; //this driver object
|
||||||
|
LONG open_count; //increment when IRP_MJ_CREATE arrives
|
||||||
|
//and decrement when IRP_MJ_CLOSE arrives
|
||||||
|
|
||||||
|
} USB_DEV_MANAGER, *PUSB_DEV_MANAGER;
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
dev_mgr_post_event(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_EVENT event
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
dev_mgr_init(
|
||||||
|
PUSB_DEV dev, //always null. we do not use this param
|
||||||
|
ULONG event,
|
||||||
|
ULONG dev_mgr
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
dev_mgr_destroy(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
dev_mgr_thread(
|
||||||
|
PVOID dev_mgr
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
dev_mgr_timer_dpc_callback(
|
||||||
|
PKDPC Dpc,
|
||||||
|
PVOID DeferredContext,
|
||||||
|
PVOID SystemArgument1,
|
||||||
|
PVOID SystemArgument2
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
dev_mgr_request_timer_svc(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DEV pdev,
|
||||||
|
ULONG context,
|
||||||
|
ULONG due_time,
|
||||||
|
TIMER_SVC_HANDLER handler
|
||||||
|
);
|
||||||
|
|
||||||
|
BYTE
|
||||||
|
dev_mgr_alloc_addr(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PHCD hcd
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
dev_mgr_free_addr(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DEV pdev,
|
||||||
|
BYTE addr
|
||||||
|
);
|
||||||
|
|
||||||
|
PUSB_DEV
|
||||||
|
dev_mgr_alloc_device(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PHCD hcd
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
dev_mgr_free_device(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DEV pdev
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
dev_mgr_disconnect_dev(
|
||||||
|
PUSB_DEV pdev
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
dev_mgr_strobe(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr
|
||||||
|
);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
dev_mgr_build_usb_config(
|
||||||
|
PUSB_DEV pdev,
|
||||||
|
PBYTE pbuf,
|
||||||
|
ULONG config_val,
|
||||||
|
LONG config_count
|
||||||
|
);
|
||||||
|
|
||||||
|
UCHAR
|
||||||
|
dev_mgr_register_hcd(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PHCD hcd
|
||||||
|
);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
dev_mgr_dispatch(
|
||||||
|
IN PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
IN PIRP irp
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
dev_mgr_register_irp(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PIRP pirp,
|
||||||
|
PURB purb
|
||||||
|
);
|
||||||
|
|
||||||
|
PURB
|
||||||
|
dev_mgr_remove_irp(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PIRP pirp
|
||||||
|
);
|
||||||
|
|
||||||
|
LONG
|
||||||
|
dev_mgr_score_driver_for_if(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DRIVER pdriver,
|
||||||
|
PUSB_INTERFACE_DESC pif_desc
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
dev_mgr_set_driver(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
DEV_HANDLE dev_handle,
|
||||||
|
PUSB_DRIVER pdriver,
|
||||||
|
PUSB_DEV pdev //if pdev != NULL, we use pdev instead if_handle
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
dev_mgr_set_if_driver(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
DEV_HANDLE if_handle,
|
||||||
|
PUSB_DRIVER pdriver,
|
||||||
|
PUSB_DEV pdev //if pdev != NULL, we use pdev instead if_handle
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
dev_mgr_release_hcd(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
dev_mgr_start_hcd(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
event_list_default_process_queue(
|
||||||
|
PLIST_HEAD event_list,
|
||||||
|
PUSB_EVENT_POOL event_pool,
|
||||||
|
PUSB_EVENT usb_event,
|
||||||
|
PUSB_EVENT out_event
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
event_list_default_process_event(
|
||||||
|
PUSB_DEV dev,
|
||||||
|
ULONG event,
|
||||||
|
ULONG context,
|
||||||
|
ULONG param
|
||||||
|
);
|
||||||
|
|
||||||
|
// root hub routines and definitions
|
||||||
|
|
||||||
|
#define RH_INTERVAL ( USB_HUB_INTERVAL / DEV_MGR_TIMER_INTERVAL_MS )
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
rh_driver_destroy(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DRIVER pdriver
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
rh_driver_init(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DRIVER pdriver
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
rh_destroy(
|
||||||
|
PUSB_DEV pdev
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
rh_timer_svc(
|
||||||
|
PUSB_DEV dev,
|
||||||
|
PVOID context
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
rh_submit_urb(
|
||||||
|
PUSB_DEV pdev,
|
||||||
|
PURB urb
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
hub_init(
|
||||||
|
PUSB_DEV pdev
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
hub_destroy(
|
||||||
|
PUSB_DEV pdev
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
hub_lock_tt(
|
||||||
|
PUSB_DEV pdev,
|
||||||
|
UCHAR port_idx,
|
||||||
|
UCHAR type // transfer type
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
hub_unlock_tt(
|
||||||
|
PUSB_DEV pdev,
|
||||||
|
UCHAR port_idx,
|
||||||
|
UCHAR type
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
VOID
|
||||||
|
hub_post_clear_tt_event(
|
||||||
|
PUSB_DEV pdev,
|
||||||
|
BYTE port_idx,
|
||||||
|
ULONG pipe
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
compdev_driver_init(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DRIVER pdriver
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
compdev_driver_destroy(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DRIVER pdriver
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
gendrv_driver_init(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DRIVER pdriver
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
gendrv_driver_destroy(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DRIVER pdriver
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
gendrv_if_driver_init(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DRIVER pdriver
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
gendrv_if_driver_destroy(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DRIVER pdriver
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
687
reactos/drivers/usb/nt4compat/usbdriver/td.c
Normal file
687
reactos/drivers/usb/nt4compat/usbdriver/td.c
Normal file
|
@ -0,0 +1,687 @@
|
||||||
|
/**
|
||||||
|
* td.c - USB driver stack project for Windows NT 4.0
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
|
||||||
|
*
|
||||||
|
* This program/include file is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as published
|
||||||
|
* by the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program/include file is distributed in the hope that it will be
|
||||||
|
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||||
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program (in the main directory of the distribution, the file
|
||||||
|
* COPYING); if not, write to the Free Software Foundation,Inc., 59 Temple
|
||||||
|
* Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "td.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#define UHCI_MIN_TD_POOLS 4
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
free_td_to_pool(
|
||||||
|
PUHCI_TD_POOL ptd_pool,
|
||||||
|
PUHCI_TD ptd
|
||||||
|
); //add tds till pnext == NULL
|
||||||
|
|
||||||
|
|
||||||
|
PUHCI_QH
|
||||||
|
alloc_qh(
|
||||||
|
PUHCI_QH_POOL pqh_pool
|
||||||
|
); //null if failed
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
init_td_pool(
|
||||||
|
PUHCI_TD_POOL ptd_pool
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int i, pages;
|
||||||
|
PTD_EXTENSION ptde;
|
||||||
|
PHYSICAL_ADDRESS phys_addr;
|
||||||
|
|
||||||
|
if (ptd_pool == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if( ptd_pool->padapter == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
pages = sizeof( UHCI_TD ) * UHCI_MAX_POOL_TDS / PAGE_SIZE;
|
||||||
|
RtlZeroMemory( ptd_pool->td_array, sizeof( ptd_pool->td_array ) );
|
||||||
|
RtlZeroMemory( ptd_pool->logic_addr, sizeof( ptd_pool->logic_addr ) );
|
||||||
|
|
||||||
|
for( i = 0; i < pages; i++ )
|
||||||
|
{
|
||||||
|
ptd_pool->td_array[ i ] =
|
||||||
|
HalAllocateCommonBuffer(
|
||||||
|
ptd_pool->padapter,
|
||||||
|
PAGE_SIZE,
|
||||||
|
&ptd_pool->logic_addr[ i ],
|
||||||
|
FALSE);
|
||||||
|
if( ptd_pool->td_array[ i ] == NULL )
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptd_pool->tde_array = ( PTD_EXTENSION )usb_alloc_mem(
|
||||||
|
NonPagedPool,
|
||||||
|
sizeof( TD_EXTENSION ) * UHCI_MAX_POOL_TDS );
|
||||||
|
|
||||||
|
if (ptd_pool->tde_array == NULL)
|
||||||
|
goto failed;
|
||||||
|
|
||||||
|
for( i = 0; i < pages; i++ )
|
||||||
|
{
|
||||||
|
RtlZeroMemory( ptd_pool->td_array[ i ], PAGE_SIZE );
|
||||||
|
}
|
||||||
|
|
||||||
|
RtlZeroMemory(
|
||||||
|
ptd_pool->tde_array,
|
||||||
|
sizeof( TD_EXTENSION ) * UHCI_MAX_POOL_TDS );
|
||||||
|
|
||||||
|
ptde = ptd_pool->tde_array;
|
||||||
|
ptd_pool->free_count = 0;
|
||||||
|
ptd_pool->total_count = UHCI_MAX_POOL_TDS;
|
||||||
|
InitializeListHead( &ptd_pool->free_que);
|
||||||
|
|
||||||
|
for( i = 0; i < UHCI_MAX_POOL_TDS; i++ )
|
||||||
|
{
|
||||||
|
//link tde and the td one by one, fixed since this init
|
||||||
|
ptd_pool->td_array[ i >> 7 ][ i & 0x7f ].ptde = &ptde[ i ];
|
||||||
|
ptde[ i ].ptd = &ptd_pool->td_array[ i >> 7 ][ i & 0x7f ];
|
||||||
|
ptde[ i ].flags = UHCI_ITEM_FLAG_TD;
|
||||||
|
ptd_pool->td_array[ i >> 7 ][ i & 0x7f ].phy_addr = ptd_pool->logic_addr[ i >> 7 ].LowPart + ( i & 0x7f ) * sizeof( UHCI_TD );
|
||||||
|
ptd_pool->td_array[ i >> 7 ][ i & 0x7f ].pool = ptd_pool;
|
||||||
|
ptd_pool->td_array[ i >> 7 ][ i & 0x7f ].purb = NULL;
|
||||||
|
free_td_to_pool( ptd_pool, &ptd_pool->td_array[ i >> 7 ][ i & 0x7f ]);
|
||||||
|
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
failed:
|
||||||
|
for( i = 0; i < pages; i++ )
|
||||||
|
{
|
||||||
|
if( ptd_pool->td_array[ i ] )
|
||||||
|
{
|
||||||
|
HalFreeCommonBuffer( ptd_pool->padapter,
|
||||||
|
PAGE_SIZE,
|
||||||
|
ptd_pool->logic_addr[ i ],
|
||||||
|
ptd_pool->td_array[ i ],
|
||||||
|
FALSE);
|
||||||
|
ptd_pool->td_array[ i ] = NULL;
|
||||||
|
ptd_pool->logic_addr[ i ].QuadPart = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ptd_pool->tde_array )
|
||||||
|
usb_free_mem( ptd_pool->tde_array);
|
||||||
|
|
||||||
|
uhci_dbg_print( DBGLVL_MAXIMUM, ( "init_td_pool(): failed to init the td pool\n" ) );
|
||||||
|
TRAP();
|
||||||
|
|
||||||
|
ptd_pool->free_count = ptd_pool->total_count = 0;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
free_td_to_pool(
|
||||||
|
PUHCI_TD_POOL ptd_pool,
|
||||||
|
PUHCI_TD ptd
|
||||||
|
) //add tds till pnext == NULL
|
||||||
|
{
|
||||||
|
if( ptd_pool == NULL || ptd == NULL )
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptd->link = ptd->status = ptd->info = ptd->buffer = 0;
|
||||||
|
ptd->purb = NULL;
|
||||||
|
ptd_pool->free_count++;
|
||||||
|
|
||||||
|
InsertTailList( &ptd_pool->free_que, &ptd->ptde->vert_link);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
}
|
||||||
|
// qh routines
|
||||||
|
PUHCI_TD
|
||||||
|
alloc_td_from_pool(
|
||||||
|
PUHCI_TD_POOL ptd_pool
|
||||||
|
) //null if failed
|
||||||
|
{
|
||||||
|
PTD_EXTENSION ptde;
|
||||||
|
PLIST_ENTRY temp;
|
||||||
|
|
||||||
|
if( ptd_pool == NULL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if( IsListEmpty( &ptd_pool->free_que ) )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
temp = RemoveHeadList( &ptd_pool->free_que );
|
||||||
|
|
||||||
|
if( temp == NULL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
ptde = struct_ptr( temp, TD_EXTENSION, vert_link );
|
||||||
|
|
||||||
|
ptd_pool->free_count--;
|
||||||
|
|
||||||
|
InitializeListHead( &ptde->vert_link );
|
||||||
|
InitializeListHead( &ptde->hori_link );
|
||||||
|
|
||||||
|
return ptde->ptd;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
is_pool_free(
|
||||||
|
PUHCI_TD_POOL pool
|
||||||
|
) //test whether the pool is all free
|
||||||
|
{
|
||||||
|
if( pool == NULL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if( pool->free_count == pool->total_count )
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
is_pool_empty(
|
||||||
|
PUHCI_TD_POOL pool
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if( pool == NULL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return ( pool->free_count == 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
destroy_td_pool(
|
||||||
|
PUHCI_TD_POOL ptd_pool
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int i, pages;
|
||||||
|
PADAPTER_OBJECT padapter; //we need this garbage for allocation
|
||||||
|
|
||||||
|
padapter = ptd_pool->padapter;
|
||||||
|
|
||||||
|
pages = sizeof( UHCI_TD ) * UHCI_MAX_POOL_TDS / PAGE_SIZE;
|
||||||
|
if( ptd_pool && ptd_pool->padapter )
|
||||||
|
{
|
||||||
|
usb_free_mem( ptd_pool->tde_array );
|
||||||
|
ptd_pool->tde_array = NULL;
|
||||||
|
for( i = 0; i < pages; i++ )
|
||||||
|
{
|
||||||
|
if( ptd_pool->td_array[ i ] )
|
||||||
|
{
|
||||||
|
HalFreeCommonBuffer( ptd_pool->padapter,
|
||||||
|
PAGE_SIZE,
|
||||||
|
ptd_pool->logic_addr[ i ],
|
||||||
|
ptd_pool->td_array[ i ],
|
||||||
|
FALSE);
|
||||||
|
ptd_pool->td_array[ i ] = NULL;
|
||||||
|
ptd_pool->logic_addr[ i ].QuadPart = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RtlZeroMemory( ptd_pool, sizeof( UHCI_TD_POOL ) );
|
||||||
|
ptd_pool->padapter = padapter;
|
||||||
|
ptd_pool->free_count = ptd_pool->total_count = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
init_td_pool_list(
|
||||||
|
PUHCI_TD_POOL_LIST pool_list,
|
||||||
|
PADAPTER_OBJECT padapter
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
RtlZeroMemory( pool_list, sizeof( UHCI_TD_POOL_LIST));
|
||||||
|
InitializeListHead( &pool_list->busy_pools );
|
||||||
|
InitializeListHead( &pool_list->free_pools );
|
||||||
|
|
||||||
|
pool_list->free_count = UHCI_MAX_TD_POOLS;
|
||||||
|
pool_list->free_tds = 0;
|
||||||
|
|
||||||
|
for( i = 0; i < UHCI_MAX_TD_POOLS; i++)
|
||||||
|
{
|
||||||
|
pool_list->pool_array[i].padapter = padapter;
|
||||||
|
InsertTailList( &pool_list->free_pools, &pool_list->pool_array[i].pool_link);
|
||||||
|
}
|
||||||
|
|
||||||
|
KeInitializeSpinLock( &pool_list->pool_lock );
|
||||||
|
return expand_pool_list( pool_list, UHCI_MIN_TD_POOLS );
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
destroy_td_pool_list(
|
||||||
|
PUHCI_TD_POOL_LIST pool_list
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PUHCI_TD_POOL pool;
|
||||||
|
while( IsListEmpty( &pool_list->busy_pools) == FALSE )
|
||||||
|
{
|
||||||
|
pool = (PUHCI_TD_POOL) RemoveHeadList( &pool_list->busy_pools);
|
||||||
|
destroy_td_pool( pool );
|
||||||
|
}
|
||||||
|
|
||||||
|
RtlZeroMemory( pool_list, sizeof( UHCI_TD_POOL_LIST ));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
expand_pool_list(
|
||||||
|
PUHCI_TD_POOL_LIST pool_list,
|
||||||
|
LONG pool_count
|
||||||
|
) //private
|
||||||
|
{
|
||||||
|
PUHCI_TD_POOL pool;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if( IsListEmpty( &pool_list->free_pools) == TRUE )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if( pool_list->free_count < pool_count )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
for( i = 0; i < pool_count; i++ )
|
||||||
|
{
|
||||||
|
pool = (PUHCI_TD_POOL) RemoveHeadList( &pool_list->free_pools);
|
||||||
|
|
||||||
|
if( init_td_pool( pool ) == FALSE )
|
||||||
|
{
|
||||||
|
//reverse the allocation
|
||||||
|
InsertHeadList( &pool_list->free_pools, &pool->pool_link );
|
||||||
|
// collect_garbage( pool_list );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
InsertTailList( &pool_list->busy_pools, &pool->pool_link );
|
||||||
|
pool_list->free_tds += UHCI_MAX_POOL_TDS;
|
||||||
|
pool_list->free_count--;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
collect_garbage(
|
||||||
|
PUHCI_TD_POOL_LIST pool_list
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PLIST_ENTRY prev, next;
|
||||||
|
|
||||||
|
// no garbage
|
||||||
|
if( pool_list->free_count >= UHCI_MAX_TD_POOLS - UHCI_MIN_TD_POOLS )
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
ListFirstPrev( &pool_list->busy_pools, prev);
|
||||||
|
ListNext( &pool_list->busy_pools, prev, next);
|
||||||
|
|
||||||
|
while( next && next != &pool_list->busy_pools)
|
||||||
|
{
|
||||||
|
if( is_pool_free( (PUHCI_TD_POOL)next ) )
|
||||||
|
{
|
||||||
|
RemoveEntryList( next );
|
||||||
|
destroy_td_pool( ( PUHCI_TD_POOL )next );
|
||||||
|
InsertTailList( &pool_list->free_pools, next);
|
||||||
|
pool_list->free_count++;
|
||||||
|
pool_list->free_tds -= UHCI_MAX_POOL_TDS;
|
||||||
|
ListNext( &pool_list->busy_pools, prev, next);
|
||||||
|
if( pool_list->free_count >= UHCI_MAX_TD_POOLS - UHCI_MIN_TD_POOLS )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prev = next;
|
||||||
|
ListNext( &pool_list->busy_pools, prev, next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//private
|
||||||
|
LONG
|
||||||
|
get_num_free_tds(
|
||||||
|
PUHCI_TD_POOL_LIST pool_list
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return pool_list->free_tds;
|
||||||
|
}
|
||||||
|
|
||||||
|
//private
|
||||||
|
LONG
|
||||||
|
get_max_free_tds(
|
||||||
|
PUHCI_TD_POOL_LIST pool_list
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return pool_list->free_tds + pool_list->free_count * UHCI_MAX_POOL_TDS;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
free_td(
|
||||||
|
PUHCI_TD_POOL_LIST pool_list,
|
||||||
|
PUHCI_TD ptd
|
||||||
|
) //add tds till pnext == NULL
|
||||||
|
{
|
||||||
|
if( pool_list == NULL || ptd == NULL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if( free_td_to_pool( ptd->pool, ptd ) == FALSE )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
pool_list->free_tds++;
|
||||||
|
|
||||||
|
if( is_pool_free( ptd->pool ) )
|
||||||
|
{
|
||||||
|
collect_garbage( pool_list );
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PUHCI_TD
|
||||||
|
alloc_td(
|
||||||
|
PUHCI_TD_POOL_LIST pool_list
|
||||||
|
) //null if failed
|
||||||
|
{
|
||||||
|
PLIST_ENTRY prev, next;
|
||||||
|
PUHCI_TD new_td;
|
||||||
|
|
||||||
|
if( pool_list == NULL )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if( pool_list->free_tds == 0 )
|
||||||
|
{
|
||||||
|
if( expand_pool_list( pool_list, 1 ) == FALSE )
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListFirst( &pool_list->busy_pools, prev );
|
||||||
|
|
||||||
|
while( prev && prev != &pool_list->busy_pools )
|
||||||
|
{
|
||||||
|
if( is_pool_empty( (PUHCI_TD_POOL) prev ) == FALSE )
|
||||||
|
{
|
||||||
|
new_td = alloc_td_from_pool( (PUHCI_TD_POOL) prev );
|
||||||
|
|
||||||
|
if( new_td == NULL )
|
||||||
|
TRAP();
|
||||||
|
|
||||||
|
pool_list->free_tds--;
|
||||||
|
|
||||||
|
return new_td;
|
||||||
|
}
|
||||||
|
|
||||||
|
ListNext( &pool_list->busy_pools, prev, next);
|
||||||
|
prev = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PUHCI_TD
|
||||||
|
alloc_tds(
|
||||||
|
PUHCI_TD_POOL_LIST pool_list,
|
||||||
|
LONG count
|
||||||
|
)
|
||||||
|
{
|
||||||
|
//return value is a list of tds, vert_link chain.
|
||||||
|
|
||||||
|
LONG i;
|
||||||
|
PUHCI_TD ptd, pnext;
|
||||||
|
|
||||||
|
if( pool_list == NULL || count <= 0 )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if( count >= get_max_free_tds( pool_list ) )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ptd = alloc_td( pool_list );
|
||||||
|
|
||||||
|
for( i = 1; i < count; i ++ )
|
||||||
|
{
|
||||||
|
pnext = alloc_td( pool_list );
|
||||||
|
|
||||||
|
if( pnext )
|
||||||
|
{
|
||||||
|
InsertTailList( &ptd->ptde->vert_link, &pnext->ptde->vert_link );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
TRAP();
|
||||||
|
}
|
||||||
|
|
||||||
|
uhci_dbg_print( DBGLVL_MEDIUM, ("alloc_tds(): td pool-list free_tds=0x%x, free pools=0x%x\n", \
|
||||||
|
pool_list->free_tds,
|
||||||
|
pool_list->free_count ) );
|
||||||
|
|
||||||
|
return ptd;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
free_tds(
|
||||||
|
PUHCI_TD_POOL_LIST pool_list,
|
||||||
|
PUHCI_TD ptd
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PUHCI_TD ptofree;
|
||||||
|
PLIST_ENTRY pthis;
|
||||||
|
|
||||||
|
if( pool_list == NULL || ptd == NULL )
|
||||||
|
return;
|
||||||
|
|
||||||
|
while( IsListEmpty( &ptd->ptde->vert_link ) == FALSE )
|
||||||
|
{
|
||||||
|
pthis = RemoveHeadList( &ptd->ptde->vert_link )
|
||||||
|
ptofree = ( ( PTD_EXTENSION)pthis )->ptd;
|
||||||
|
free_td( pool_list, ptofree );
|
||||||
|
}
|
||||||
|
|
||||||
|
free_td( pool_list, ptd );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
can_transfer(
|
||||||
|
PUHCI_TD_POOL_LIST pool_list,
|
||||||
|
LONG td_count
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if( td_count > get_max_free_tds( pool_list ) )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
lock_td_pool(
|
||||||
|
PUHCI_TD_POOL_LIST pool_list,
|
||||||
|
BOOL at_dpc
|
||||||
|
)
|
||||||
|
{
|
||||||
|
//if( !at_dpc )
|
||||||
|
// KeAcquireSpinLock( &pool_list->pool_lock );
|
||||||
|
//else
|
||||||
|
// KeAcquireSpinLockAtDpcLevel( &pool_list->pool_lock );
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
unlock_td_pool(
|
||||||
|
PUHCI_TD_POOL_LIST pool_list,
|
||||||
|
BOOL at_dpc
|
||||||
|
)
|
||||||
|
{
|
||||||
|
//if( !at_dpc )
|
||||||
|
// KeReleaseSpinLock( &pool_list->pool_lock );
|
||||||
|
//else
|
||||||
|
// KeReleaseSpinLockFromDpcLevel( &pool_list->pool_lock );
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
init_qh_pool(
|
||||||
|
PUHCI_QH_POOL pqh_pool,
|
||||||
|
PADAPTER_OBJECT padapter
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PQH_EXTENSION pqhe;
|
||||||
|
LONG i;
|
||||||
|
|
||||||
|
if( pqh_pool == NULL || padapter == NULL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
pqh_pool->padapter = padapter;
|
||||||
|
|
||||||
|
pqh_pool->qhe_array = (PQH_EXTENSION)usb_alloc_mem(
|
||||||
|
NonPagedPool,
|
||||||
|
sizeof(QH_EXTENSION) * UHCI_MAX_POOL_QHS);
|
||||||
|
|
||||||
|
if (pqh_pool->qhe_array == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
pqh_pool->qh_array = \
|
||||||
|
(PUHCI_QH)HalAllocateCommonBuffer(
|
||||||
|
padapter,
|
||||||
|
sizeof(UHCI_QH) * UHCI_MAX_POOL_QHS,
|
||||||
|
&pqh_pool->logic_addr,
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
if( pqh_pool->qh_array == NULL )
|
||||||
|
{
|
||||||
|
usb_free_mem( pqh_pool->qhe_array );
|
||||||
|
pqh_pool->qhe_array = NULL;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pqhe = pqh_pool->qhe_array;
|
||||||
|
|
||||||
|
pqh_pool->free_count = 0;
|
||||||
|
pqh_pool->total_count = UHCI_MAX_POOL_TDS;
|
||||||
|
|
||||||
|
KeInitializeSpinLock( &pqh_pool->pool_lock);
|
||||||
|
InitializeListHead( &pqh_pool->free_que);
|
||||||
|
|
||||||
|
|
||||||
|
for(i = 0; i < UHCI_MAX_POOL_QHS; i++)
|
||||||
|
{
|
||||||
|
pqh_pool->qh_array[i].pqhe = &pqhe[i];
|
||||||
|
pqhe[i].pqh = &pqh_pool->qh_array[i];
|
||||||
|
|
||||||
|
pqh_pool->qh_array[i].phy_addr = ( pqh_pool->logic_addr.LowPart + ( sizeof( UHCI_QH) * i ) ) | UHCI_PTR_QH;
|
||||||
|
//pqh_pool->qh_array[i].reserved = 0;
|
||||||
|
|
||||||
|
//always breadth first
|
||||||
|
pqhe[i].flags = UHCI_ITEM_FLAG_QH;
|
||||||
|
|
||||||
|
free_qh( pqh_pool, &pqh_pool->qh_array[i] );
|
||||||
|
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
free_qh(
|
||||||
|
PUHCI_QH_POOL pqh_pool,
|
||||||
|
PUHCI_QH pqh
|
||||||
|
) //add qhs till pnext == NULL
|
||||||
|
{
|
||||||
|
if( pqh_pool == NULL || pqh == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
pqh->link = pqh->element = 0;
|
||||||
|
pqh->pqhe->purb = NULL;
|
||||||
|
InsertTailList( &pqh_pool->free_que, &pqh->pqhe->vert_link);
|
||||||
|
pqh_pool->free_count ++;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PUHCI_QH
|
||||||
|
alloc_qh(
|
||||||
|
PUHCI_QH_POOL pqh_pool
|
||||||
|
) //null if failed
|
||||||
|
{
|
||||||
|
PQH_EXTENSION pqhe;
|
||||||
|
|
||||||
|
if( pqh_pool == NULL )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if( IsListEmpty( &pqh_pool->free_que))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
pqhe = ( PQH_EXTENSION )RemoveHeadList( &pqh_pool->free_que );
|
||||||
|
|
||||||
|
if( pqhe )
|
||||||
|
{
|
||||||
|
InitializeListHead( &pqhe->hori_link );
|
||||||
|
InitializeListHead( &pqhe->vert_link );
|
||||||
|
return pqhe->pqh;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
destroy_qh_pool(
|
||||||
|
PUHCI_QH_POOL pqh_pool
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(pqh_pool)
|
||||||
|
{
|
||||||
|
usb_free_mem(pqh_pool->qhe_array);
|
||||||
|
|
||||||
|
HalFreeCommonBuffer( pqh_pool->padapter,
|
||||||
|
sizeof(UHCI_QH) * UHCI_MAX_POOL_QHS,
|
||||||
|
pqh_pool->logic_addr,
|
||||||
|
pqh_pool->qh_array,
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
RtlZeroMemory( pqh_pool, sizeof( UHCI_QH_POOL ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
lock_qh_pool(
|
||||||
|
PUHCI_QH_POOL pool,
|
||||||
|
BOOL at_dpc
|
||||||
|
)
|
||||||
|
{
|
||||||
|
//if( !at_dpc )
|
||||||
|
// KeAcquireSpinLock( &pool->pool_lock );
|
||||||
|
//else
|
||||||
|
// KeAcquireSpinLockAtDpcLevel( &pool->pool_lock );
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
unlock_qh_pool(
|
||||||
|
PUHCI_QH_POOL pool,
|
||||||
|
BOOL at_dpc
|
||||||
|
)
|
||||||
|
{
|
||||||
|
//if( !at_dpc )
|
||||||
|
// KeReleaseSpinLock( &pool->pool_lock );
|
||||||
|
//else
|
||||||
|
// KeReleaseSpinLockFromDpcLevel( &pool->pool_lock );
|
||||||
|
}
|
||||||
|
|
1031
reactos/drivers/usb/nt4compat/usbdriver/td.h
Normal file
1031
reactos/drivers/usb/nt4compat/usbdriver/td.h
Normal file
File diff suppressed because it is too large
Load diff
4222
reactos/drivers/usb/nt4compat/usbdriver/uhci.c
Normal file
4222
reactos/drivers/usb/nt4compat/usbdriver/uhci.c
Normal file
File diff suppressed because it is too large
Load diff
13
reactos/drivers/usb/nt4compat/usbdriver/uhciver.h
Normal file
13
reactos/drivers/usb/nt4compat/usbdriver/uhciver.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef __UHCIVER_H__
|
||||||
|
#define __UHCIVER_H__
|
||||||
|
|
||||||
|
//#define _MULTI_UHCI
|
||||||
|
//#define _TIANSHENG_DRIVER
|
||||||
|
|
||||||
|
#ifdef _MULTI_UHCI
|
||||||
|
#define UHCI_VER_STR "m564.a\0"
|
||||||
|
#else
|
||||||
|
#define UHCI_VER_STR "0564.d\0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
2443
reactos/drivers/usb/nt4compat/usbdriver/umss.c
Normal file
2443
reactos/drivers/usb/nt4compat/usbdriver/umss.c
Normal file
File diff suppressed because it is too large
Load diff
353
reactos/drivers/usb/nt4compat/usbdriver/umss.h
Normal file
353
reactos/drivers/usb/nt4compat/usbdriver/umss.h
Normal file
|
@ -0,0 +1,353 @@
|
||||||
|
#ifndef __UMSS_H__
|
||||||
|
#define __UMSS_H__
|
||||||
|
|
||||||
|
#include "td.h"
|
||||||
|
#include "hub.h"
|
||||||
|
|
||||||
|
#define MAX_BULK_TRANSFER_LENGTH 0x100000
|
||||||
|
|
||||||
|
#define PROTOCOL_CBI 0x00
|
||||||
|
#define PROTOCOL_CB 0x01
|
||||||
|
#define PROTOCOL_BULKONLY 0x50
|
||||||
|
|
||||||
|
#define PROTOCOL_UNDEFINED 0xFF // Not in spec
|
||||||
|
|
||||||
|
#define UMSS_SUBCLASS_RBC 0x01
|
||||||
|
#define UMSS_SUBCLASS_SFF8020I 0X02
|
||||||
|
#define UMSS_SUBCLASS_QIC157 0x03
|
||||||
|
#define UMSS_SUBCLASS_UFI 0x04
|
||||||
|
#define UMSS_SUBCLASS_SFF8070I 0x05
|
||||||
|
#define UMSS_SUBCLASS_SCSI_TCS 0x06
|
||||||
|
|
||||||
|
#define ACCEPT_DEVICE_SPECIFIC_COMMAND 0
|
||||||
|
|
||||||
|
#define BULK_ONLY_MASS_STORAGE_RESET 0xFF
|
||||||
|
#define BULK_ONLY_GET_MAX_LUN 0xFE
|
||||||
|
|
||||||
|
#define CBW_SIGNATURE 0x43425355L
|
||||||
|
#define CSW_SIGNATURE 0x53425355L
|
||||||
|
#define CSW_OLYMPUS_SIGNATURE 0x55425355L
|
||||||
|
|
||||||
|
#define CSW_STATUS_PASSED 0x00
|
||||||
|
#define CSW_STATUS_FAILED 0x01
|
||||||
|
#define CSW_STATUS_PHASE_ERROR 0x02
|
||||||
|
|
||||||
|
#define IOCTL_UMSS_SUBMIT_CDB CTL_CODE( FILE_USB_DEV_TYPE, 4200, METHOD_BUFFERED, FILE_ANY_ACCESS )
|
||||||
|
// for request with no other input and output
|
||||||
|
// input buffer is a _USER_IO_PACKET and input_buffer_length is length of the _USER_IO_PACKET
|
||||||
|
// output_buffer is NULL, and output_buffer_length is zero
|
||||||
|
|
||||||
|
#define IOCTL_UMSS_SUBMIT_CDB_IN CTL_CODE( FILE_USB_DEV_TYPE, 4201, METHOD_IN_DIRECT, FILE_ANY_ACCESS )
|
||||||
|
// for request to read in data
|
||||||
|
// input_buffer is a _USER_IO_PACKET and input_buffer_length is length to the _USER_IO_PACKET
|
||||||
|
// output_buffer is a buffer to receive the data from dev, and
|
||||||
|
// output_buffer_length is the size of the buffer
|
||||||
|
|
||||||
|
#define IOCTL_UMSS_SUBMIT_CDB_OUT CTL_CODE( FILE_USB_DEV_TYPE, 4202, METHOD_OUT_DIRECT, FILE_ANY_ACCESS )
|
||||||
|
// for request to write data to device
|
||||||
|
// input_buffer is a _USER_IO_PACKET and input_buffer_length is length to the _USER_IO_PACKET
|
||||||
|
// output_buffer is data to send to the device, and
|
||||||
|
// output_buffer_length is the size of the buffer
|
||||||
|
|
||||||
|
#define IOCTL_REGISTER_DRIVER CTL_CODE( FILE_USB_DEV_TYPE, 4203, METHOD_BUFFERED, FILE_ANY_ACCESS )
|
||||||
|
// input_buffer is a CLASS_DRV_REG_INFO, and input_buffer_length is equal to or greater than
|
||||||
|
// sizeof( CLASS_DRV_REG_INFO ); the output_buffer is null and no output_buffer_length,
|
||||||
|
// only the following fields in urb can be accessed, others must be zeroed.
|
||||||
|
|
||||||
|
#define IOCTL_REVOKE_DRIVER CTL_CODE( FILE_USB_DEV_TYPE, 4204, METHOD_BUFFERED, FILE_ANY_ACCESS )
|
||||||
|
// tell the umss driver to clear the information in the drivers registry
|
||||||
|
// no other parameters
|
||||||
|
|
||||||
|
#define IOCTL_UMSS_SUBMIT_SRB CTL_CODE( FILE_USB_DEV_TYPE, 4205, METHOD_BUFFERED, FILE_ANY_ACCESS )
|
||||||
|
// irpStack->Parameters.Scsi.Srb points to an Srb structure and all the data buffer and buffer
|
||||||
|
// size are stored in the srb
|
||||||
|
|
||||||
|
|
||||||
|
#define IOCTL_UMSS_SET_FDO CTL_CODE( FILE_USB_DEV_TYPE, 4206, METHOD_BUFFERED, FILE_ANY_ACCESS )
|
||||||
|
// input_buffer is a pointer to PDEVICE_OBJECT, and input_buffer_length should be
|
||||||
|
// no less than sizeof( PDEVICE_OBJECT )
|
||||||
|
// output buffer is NULL, and output_buffer_length is zero
|
||||||
|
// if the deivce is accessable, the fdo is set, else, the fdo is not set and return
|
||||||
|
// STATUS_DEVICE_DOES_NOT_EXIST
|
||||||
|
|
||||||
|
#define SFF_FORMAT_UNIT 0x04
|
||||||
|
#define SFF_INQUIRY 0x12
|
||||||
|
#define SFF_MODE_SELECT 0x55
|
||||||
|
#define SFF_MODE_SENSE 0x5a
|
||||||
|
#define SFF_ALLOW_REMOVE 0x1e
|
||||||
|
#define SFF_READ10 0x28
|
||||||
|
#define SFF_READ12 0xa8
|
||||||
|
#define SFF_READ_CAPACITY 0x25
|
||||||
|
#define SFF_REQUEST_SENSEE 0x03
|
||||||
|
#define SFF_SEEK 0x2b
|
||||||
|
#define SFF_START_STOP 0x1b
|
||||||
|
#define SFF_TUR 0x00
|
||||||
|
#define SFF_VERIFY 0x2f
|
||||||
|
#define SFF_WRITE10 0x2a
|
||||||
|
#define SFF_WRITE12 0xaa
|
||||||
|
#define SFF_READ_FMT_CAPACITY 0x23
|
||||||
|
#define SFF_WRITE_VERIFY 0x2e
|
||||||
|
|
||||||
|
#define MAX_CDB_LENGTH 0x10
|
||||||
|
|
||||||
|
typedef struct _USER_IO_PACKET
|
||||||
|
{
|
||||||
|
UCHAR sub_class;
|
||||||
|
UCHAR lun;
|
||||||
|
UCHAR cdb_length;
|
||||||
|
UCHAR cdb[ MAX_CDB_LENGTH ];
|
||||||
|
|
||||||
|
} USER_IO_PACKET, *PUSER_IO_PACKET;
|
||||||
|
|
||||||
|
//flags for IO_PACKET::flags
|
||||||
|
#define IOP_FLAG_REQ_SENSE 0x80000000 // sense data would be fetched if error occurs
|
||||||
|
#define IOP_FLAG_SRB_TRANSFER 0x40000000 // current tranfer is initiated by an srb request, the srb is held by the irp
|
||||||
|
#define IOP_FLAG_SCSI_CTRL_TRANSFER 0x20000000 // current transfer is initiated by an scsi ioctrl request
|
||||||
|
|
||||||
|
#define IOP_FLAG_DIR_IN USB_DIR_IN
|
||||||
|
#define IOP_FLAG_STAGE_MASK 0x03
|
||||||
|
#define IOP_FLAG_STAGE_NORMAL 0x00
|
||||||
|
#define IOP_FLAG_STAGE_SENSE 0x01
|
||||||
|
|
||||||
|
typedef struct _IO_PACKET
|
||||||
|
{
|
||||||
|
ULONG flags;
|
||||||
|
UCHAR cdb_length;
|
||||||
|
UCHAR cdb[ MAX_CDB_LENGTH ];
|
||||||
|
UCHAR lun;
|
||||||
|
PVOID data_buffer;
|
||||||
|
ULONG data_length;
|
||||||
|
PVOID sense_data;
|
||||||
|
ULONG sense_data_length;
|
||||||
|
PIRP pirp;
|
||||||
|
|
||||||
|
} IO_PACKET, *PIO_PACKET;
|
||||||
|
|
||||||
|
#pragma pack( 1 )
|
||||||
|
|
||||||
|
typedef struct _COMMAND_BLOCK_WRAPPER
|
||||||
|
{
|
||||||
|
ULONG dCBWSignature;
|
||||||
|
ULONG dCBWTag;
|
||||||
|
ULONG dCBWDataTransferLength;
|
||||||
|
UCHAR bmCBWFlags;
|
||||||
|
UCHAR bCBWLun;
|
||||||
|
UCHAR bCBWLength;
|
||||||
|
UCHAR CBWCB[ MAX_CDB_LENGTH ];
|
||||||
|
|
||||||
|
} COMMAND_BLOCK_WRAPPER, *PCOMMAND_BLOCK_WRAPPER;
|
||||||
|
|
||||||
|
typedef struct _COMMAND_STATUS_WRAPPER
|
||||||
|
{
|
||||||
|
ULONG dCSWSignature;
|
||||||
|
ULONG dCSWTag;
|
||||||
|
ULONG dCSWDataResidue;
|
||||||
|
UCHAR bCSWStatus;
|
||||||
|
|
||||||
|
} COMMAND_STATUS_WRAPPER, *PCOMMAND_STATUS_WRAPPER;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _INTERRUPT_DATA_BLOCK
|
||||||
|
{
|
||||||
|
UCHAR bType;
|
||||||
|
UCHAR bValue;
|
||||||
|
|
||||||
|
} INTERRUPT_DATA_BLOCK, *PINTERRUPT_DATA_BLOCK;
|
||||||
|
|
||||||
|
#pragma pack()
|
||||||
|
|
||||||
|
#define UMSS_PNPMSG_STOP 0x01
|
||||||
|
#define UMSS_PNPMSG_DISCONNECT 0x02
|
||||||
|
|
||||||
|
typedef NTSTATUS ( *PCLASS_DRVR_PNP_DISP )( PDEVICE_OBJECT pdo, ULONG ctrl_code, PVOID context );
|
||||||
|
// pdo is the device object umss created
|
||||||
|
|
||||||
|
typedef PDEVICE_OBJECT ( *PCLASS_DRIVER_ADD_DEV )( PDRIVER_OBJECT fdo_drvr, PDEVICE_OBJECT pdo );
|
||||||
|
// if the return value is not zero, it is a pointer to the
|
||||||
|
// fdo sitting over the pdo of this driver. if it is null,
|
||||||
|
// the add_device failed, and initialization process should
|
||||||
|
// stall.
|
||||||
|
|
||||||
|
typedef struct _CLASS_DRV_REGISTRY_INFO
|
||||||
|
{
|
||||||
|
// class driver will pass this structure to umss port
|
||||||
|
// driver after loaded
|
||||||
|
PDRIVER_OBJECT fdo_driver;
|
||||||
|
PCLASS_DRIVER_ADD_DEV add_device;
|
||||||
|
PCLASS_DRVR_PNP_DISP pnp_dispatch;
|
||||||
|
|
||||||
|
} CLASS_DRV_REG_INFO, *PCLASS_DRV_REG_INFO;
|
||||||
|
|
||||||
|
typedef struct _UMSS_PORT_DEVICE_EXTENSION
|
||||||
|
{
|
||||||
|
// this structure is the device extension for port dev_obj
|
||||||
|
// it is used to has class driver pass CLASS_DRV_REG_INFO
|
||||||
|
// to our umss driver.
|
||||||
|
DEVEXT_HEADER dev_ext_hdr;
|
||||||
|
PUSB_DRIVER pdriver;
|
||||||
|
|
||||||
|
} UMSS_PORT_DEV_EXT, *PUMSS_PORT_DEV_EXT;
|
||||||
|
|
||||||
|
typedef struct _UMSS_DRVR_EXTENSION
|
||||||
|
{
|
||||||
|
LIST_HEAD dev_list;
|
||||||
|
FAST_MUTEX dev_list_mutex;
|
||||||
|
UCHAR dev_count;
|
||||||
|
CLASS_DRV_REG_INFO class_driver_info;
|
||||||
|
PDEVICE_OBJECT port_dev_obj; // we use this obj as a connection point for class driver, its name usbPort0
|
||||||
|
|
||||||
|
} UMSS_DRVR_EXTENSION, *PUMSS_DRVR_EXTENSION;
|
||||||
|
|
||||||
|
#define UMSS_DEV_FLAG_IF_DEV 0x01
|
||||||
|
#define UMSS_DEV_FLAG_OLYMPUS_DEV 0x02
|
||||||
|
|
||||||
|
#define UMSS_OLYMPUS_VENDOR_ID 0x07b4
|
||||||
|
|
||||||
|
typedef struct _UMSS_DEVICE_EXTENSION
|
||||||
|
{
|
||||||
|
//this structure is the device extension for dev_obj
|
||||||
|
//created for the device.
|
||||||
|
DEVEXT_HEADER dev_ext_hdr;
|
||||||
|
|
||||||
|
ULONG flags;
|
||||||
|
LIST_ENTRY dev_obj_link; // this link is used by the driver object to track the existing dev_objs
|
||||||
|
|
||||||
|
PDEVICE_OBJECT pdo; // this is the pdo
|
||||||
|
PDEVICE_OBJECT fdo; // driver object for the dev_obj
|
||||||
|
|
||||||
|
DEV_HANDLE dev_handle; // handle to the usb_dev under
|
||||||
|
|
||||||
|
PUCHAR desc_buf;
|
||||||
|
UCHAR umss_dev_id; // used to build symbolic link
|
||||||
|
|
||||||
|
PUSB_INTERFACE_DESC pif_desc;
|
||||||
|
PUSB_ENDPOINT_DESC pout_endp_desc, pin_endp_desc, pint_endp_desc;
|
||||||
|
UCHAR if_idx, out_endp_idx, in_endp_idx, int_endp_idx;
|
||||||
|
|
||||||
|
struct _USB_DEV_MANAGER *dev_mgr;
|
||||||
|
|
||||||
|
//working data
|
||||||
|
COMMAND_BLOCK_WRAPPER cbw;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
INTERRUPT_DATA_BLOCK idb;
|
||||||
|
COMMAND_STATUS_WRAPPER csw;
|
||||||
|
};
|
||||||
|
|
||||||
|
KEVENT sync_event; //for umss_sync_submit_urb
|
||||||
|
KSPIN_LOCK dev_lock;
|
||||||
|
IO_PACKET io_packet;
|
||||||
|
BOOL retry;
|
||||||
|
|
||||||
|
PUSB_DRIVER pdriver; //used by umss_delete_device
|
||||||
|
NTSTATUS reset_pipe_status;
|
||||||
|
} UMSS_DEVICE_EXTENSION, *PUMSS_DEVICE_EXTENSION;
|
||||||
|
|
||||||
|
// for device creation workitem
|
||||||
|
typedef struct _UMSS_CREATE_DATA
|
||||||
|
{
|
||||||
|
DEV_HANDLE dev_handle;
|
||||||
|
PUCHAR desc_buf;
|
||||||
|
PUSB_DEV_MANAGER dev_mgr;
|
||||||
|
PUSB_DRIVER pdriver;
|
||||||
|
|
||||||
|
} UMSS_CREATE_DATA, *PUMSS_CREATE_DATA;
|
||||||
|
|
||||||
|
// for reset pipe item
|
||||||
|
//typedef void ( _stdcall *COMPLETION_HANDLER )( PVOID );
|
||||||
|
typedef void ( *UMSS_WORKER_ROUTINE )( PVOID );
|
||||||
|
|
||||||
|
typedef struct _UMSS_WORKER_PACKET
|
||||||
|
{
|
||||||
|
UMSS_WORKER_ROUTINE completion;
|
||||||
|
PVOID context;
|
||||||
|
PUSB_DEV_MANAGER dev_mgr;
|
||||||
|
PVOID pdev;
|
||||||
|
|
||||||
|
} UMSS_WORKER_PACKET, *PUMSS_WORKER_PACKET;
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
umss_driver_init(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DRIVER pdriver
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
umss_if_driver_init(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DRIVER pdriver
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
umss_driver_destroy(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DRIVER pdriver
|
||||||
|
);
|
||||||
|
|
||||||
|
#define umss_if_driver_destroy umss_driver_destroy
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
umss_if_driver_destroy(
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
PUSB_DRIVER pdriver
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
umss_complete_request(
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext,
|
||||||
|
NTSTATUS status
|
||||||
|
);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
umss_reset_pipe(
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext,
|
||||||
|
DEV_HANDLE endp_handle
|
||||||
|
);
|
||||||
|
|
||||||
|
PVOID
|
||||||
|
umss_get_buffer(
|
||||||
|
PUMSS_DEVICE_EXTENSION pdev_ext,
|
||||||
|
ULONG* buf_length
|
||||||
|
);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
umss_bulk_transfer(
|
||||||
|
IN PUMSS_DEVICE_EXTENSION pdev_ext,
|
||||||
|
IN UCHAR trans_dir,
|
||||||
|
IN PVOID buf,
|
||||||
|
IN ULONG buf_length,
|
||||||
|
IN PURBCOMPLETION completion
|
||||||
|
);
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
umss_schedule_workitem(
|
||||||
|
PVOID context,
|
||||||
|
UMSS_WORKER_ROUTINE completion,
|
||||||
|
PUSB_DEV_MANAGER dev_mgr,
|
||||||
|
DEV_HANDLE dev_handle
|
||||||
|
);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
umss_bulkonly_startio(
|
||||||
|
IN PUMSS_DEVICE_EXTENSION pdev_ext,
|
||||||
|
IN PIO_PACKET io_packet
|
||||||
|
);
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
umss_cbi_startio(
|
||||||
|
IN PUMSS_DEVICE_EXTENSION pdev_ext,
|
||||||
|
IN PIO_PACKET io_packet
|
||||||
|
);
|
||||||
|
|
||||||
|
#define UMSS_FORGE_GOOD_SENSE( sense_BUF ) \
|
||||||
|
{\
|
||||||
|
int i;\
|
||||||
|
PUCHAR buf = ( PUCHAR )( sense_BUF ); \
|
||||||
|
for( i = 0; i < 18; i++)\
|
||||||
|
{\
|
||||||
|
buf[i] = 0;\
|
||||||
|
}\
|
||||||
|
buf[7] = 10;\
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
1518
reactos/drivers/usb/nt4compat/usbdriver/usb.c
Normal file
1518
reactos/drivers/usb/nt4compat/usbdriver/usb.c
Normal file
File diff suppressed because it is too large
Load diff
1062
reactos/drivers/usb/nt4compat/usbdriver/usb.h
Normal file
1062
reactos/drivers/usb/nt4compat/usbdriver/usb.h
Normal file
File diff suppressed because it is too large
Load diff
19
reactos/drivers/usb/nt4compat/usbdriver/usbdriver.rbuild
Normal file
19
reactos/drivers/usb/nt4compat/usbdriver/usbdriver.rbuild
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<module name="usbdriver" type="kernelmodedriver" installbase="system32/drivers" installname="usbdriver.sys" allowwarnings="true">
|
||||||
|
<define name="INCLUDE_EHCI" />
|
||||||
|
<include base="usbdriver">.</include>
|
||||||
|
<library>ntoskrnl</library>
|
||||||
|
<library>hal</library>
|
||||||
|
<file>ehci.c</file>
|
||||||
|
<file>uhci.c</file>
|
||||||
|
<file>hub.c</file>
|
||||||
|
<file>td.c</file>
|
||||||
|
<file>usb.c</file>
|
||||||
|
<file>umss.c</file>
|
||||||
|
<file>bulkonly.c</file>
|
||||||
|
<file>cbi.c</file>
|
||||||
|
<file>dmgrdisp.c</file>
|
||||||
|
<file>compdrv.c</file>
|
||||||
|
<file>etd.c</file>
|
||||||
|
<file>gendrv.c</file>
|
||||||
|
<file>ehci.rc</file>
|
||||||
|
</module>
|
45
reactos/drivers/usb/nt4compat/usbdriver/usbdriver.rc
Normal file
45
reactos/drivers/usb/nt4compat/usbdriver/usbdriver.rc
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// Resource script for USBISO driver
|
||||||
|
// Generated by Walt Oney's driver wizard
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
|
||||||
|
|
||||||
|
|
||||||
|
VS_VERSION_INFO VERSIONINFO
|
||||||
|
FILEVERSION 0,0,1,0
|
||||||
|
PRODUCTVERSION 0,0,1,0
|
||||||
|
FILEFLAGSMASK 0x3fL
|
||||||
|
#ifdef _DEBUG
|
||||||
|
FILEFLAGS 0x1L
|
||||||
|
#else
|
||||||
|
FILEFLAGS 0x0L
|
||||||
|
#endif
|
||||||
|
FILEOS 0x40004L
|
||||||
|
FILETYPE 0x1L
|
||||||
|
FILESUBTYPE 0x0L
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904b0"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Comments", "This is a beta version of usb driver stack( ehci ), contact me at mypublic99@yahoo.com\0"
|
||||||
|
VALUE "CompanyName", "Woodhead Software\0"
|
||||||
|
VALUE "FileDescription", "ehci.sys\0"
|
||||||
|
VALUE "FileVersion", "0, 0, 1, 0\0"
|
||||||
|
VALUE "InternalName", "ehci.sys\0"
|
||||||
|
VALUE "LegalCopyright", "Copyright © 2002-2004 Woodhead Software\0"
|
||||||
|
VALUE "LegalTrademarks", "\0"
|
||||||
|
VALUE "OriginalFilename", "ehci.sys\0"
|
||||||
|
VALUE "PrivateBuild", "0.01\0"
|
||||||
|
VALUE "ProductName", "usb driver stack for windows NT\0"
|
||||||
|
VALUE "ProductVersion", "0, 0, 1, 0\0"
|
||||||
|
VALUE "SpecialBuild", "0131.d\0"
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 1200
|
||||||
|
END
|
||||||
|
END
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue