mirror of
https://github.com/reactos/reactos.git
synced 2025-01-11 08:38:17 +00:00
c424146e2c
svn path=/branches/cmake-bringup/; revision=48236
2229 lines
72 KiB
C
2229 lines
72 KiB
C
/**
|
|
* umss.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 "usbdriver.h"
|
|
|
|
#include <srb.h>
|
|
#include <ntddscsi.h>
|
|
#include <scsi.h>
|
|
|
|
#define UMSS_EXIT_DISPATCH( dev_OBJ, staTUS, iRp ) \
|
|
{\
|
|
iRp->IoStatus.Status = staTUS;\
|
|
if( staTUS != STATUS_PENDING)\
|
|
{\
|
|
IoCompleteRequest( iRp, IO_NO_INCREMENT);\
|
|
return staTUS;\
|
|
}\
|
|
IoMarkIrpPending( iRp );\
|
|
IoStartPacket( dev_OBJ, iRp, NULL, NULL ); \
|
|
return STATUS_PENDING;\
|
|
}
|
|
|
|
#define UMSS_COMPLETE_START_IO( dev_OBJ, staTUS, iRP ) \
|
|
{\
|
|
iRP->IoStatus.Status = staTUS;\
|
|
if( staTUS != STATUS_PENDING )\
|
|
{\
|
|
IoStartNextPacket( dev_OBJ, FALSE );\
|
|
IoCompleteRequest( iRP, IO_NO_INCREMENT );\
|
|
}\
|
|
return;\
|
|
}
|
|
|
|
extern VOID gendrv_startio(IN PDEVICE_OBJECT dev_obj, IN PIRP irp);
|
|
|
|
NTSYSAPI NTSTATUS NTAPI ZwLoadDriver(IN PUNICODE_STRING DriverServiceName);
|
|
|
|
NTSYSAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes,
|
|
IN POBJECT_TYPE ObjectType OPTIONAL,
|
|
IN KPROCESSOR_MODE AccessMode,
|
|
IN OUT PACCESS_STATE AccessState OPTIONAL,
|
|
IN ACCESS_MASK DesiredAccess OPTIONAL,
|
|
IN OUT PVOID ParseContext OPTIONAL, OUT PHANDLE Handle);
|
|
|
|
VOID NTAPI umss_start_io(IN PDEVICE_OBJECT dev_obj, IN PIRP irp);
|
|
NTSTATUS umss_port_dispatch_routine(PDEVICE_OBJECT pdev_obj, PIRP irp);
|
|
BOOLEAN umss_connect(PDEV_CONNECT_DATA dev_mgr, DEV_HANDLE dev_handle);
|
|
BOOLEAN umss_disconnect(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle);
|
|
BOOLEAN umss_stop(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle);
|
|
NTSTATUS umss_dispatch_routine(PDEVICE_OBJECT pdev_obj, PIRP irp);
|
|
VOID umss_set_cfg_completion(PURB purb, PVOID pcontext);
|
|
VOID NTAPI umss_start_create_device(IN PVOID Parameter);
|
|
BOOLEAN umss_delete_device(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdrvr, PDEVICE_OBJECT dev_obj, BOOLEAN is_if);
|
|
BOOLEAN umss_stop(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle);
|
|
NTSTATUS umss_process_srb(PDEVICE_OBJECT dev_obj, PIRP irp);
|
|
VOID umss_load_class_driver(PVOID context);
|
|
BOOLEAN umss_tsc_to_sff(PIO_PACKET io_packet);
|
|
VOID umss_fix_sff_result(PIO_PACKET io_packet, SCSI_REQUEST_BLOCK * srb);
|
|
|
|
PDEVICE_OBJECT
|
|
umss_create_port_device(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver)
|
|
{
|
|
|
|
// currently a port device is a connection point
|
|
// and upper driver use this to register itself
|
|
// with umss driver for future notification of
|
|
// pnp event. 2004-03-22 23:12:41
|
|
CHAR dev_name[64];
|
|
STRING string;
|
|
NTSTATUS status;
|
|
PDEVICE_OBJECT pdev;
|
|
UNICODE_STRING name_string, symb_link;
|
|
PUMSS_PORT_DEV_EXT pdev_ext;
|
|
|
|
sprintf(dev_name, "\\Device\\usbPort_%d", (int)0);
|
|
|
|
RtlInitString(&string, dev_name);
|
|
RtlAnsiStringToUnicodeString(&name_string, &string, TRUE);
|
|
pdev = NULL;
|
|
|
|
status = IoCreateDevice(dev_mgr->usb_driver_obj,
|
|
sizeof(UMSS_PORT_DEV_EXT), &name_string, FILE_USB_DEV_TYPE, 0, TRUE, &pdev);
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// We do buffered io
|
|
//
|
|
pdev->Flags |= DO_BUFFERED_IO;
|
|
|
|
pdev->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
pdev->StackSize = 2; //one for fdo, one for file device obj
|
|
|
|
pdev_ext = (PUMSS_PORT_DEV_EXT) pdev->DeviceExtension;
|
|
|
|
pdev_ext->dev_ext_hdr.type = NTDEV_TYPE_CLIENT_DEV;
|
|
pdev_ext->dev_ext_hdr.dispatch = umss_port_dispatch_routine;
|
|
pdev_ext->dev_ext_hdr.start_io = NULL;
|
|
pdev_ext->dev_ext_hdr.dev_mgr = dev_mgr;
|
|
pdev_ext->pdriver = pdriver;
|
|
|
|
sprintf(dev_name, "\\DosDevices\\usbPort%d", (int)0);
|
|
|
|
RtlInitString(&string, dev_name);
|
|
RtlAnsiStringToUnicodeString(&symb_link, &string, TRUE);
|
|
IoCreateSymbolicLink(&symb_link, &name_string);
|
|
RtlFreeUnicodeString(&symb_link);
|
|
|
|
}
|
|
|
|
RtlFreeUnicodeString(&name_string);
|
|
return pdev;
|
|
}
|
|
|
|
BOOLEAN
|
|
umss_delete_port_device(PDEVICE_OBJECT dev_obj)
|
|
{
|
|
CHAR dev_name[64];
|
|
STRING string;
|
|
UNICODE_STRING symb_link;
|
|
|
|
if (dev_obj == NULL)
|
|
return FALSE;
|
|
|
|
// remove the symbolic link
|
|
sprintf(dev_name, "\\DosDevices\\usbPort%d", (int)0);
|
|
RtlInitString(&string, dev_name);
|
|
RtlAnsiStringToUnicodeString(&symb_link, &string, TRUE);
|
|
IoDeleteSymbolicLink(&symb_link);
|
|
RtlFreeUnicodeString(&symb_link);
|
|
|
|
if (dev_obj->ReferenceCount == 0)
|
|
{
|
|
IoDeleteDevice(dev_obj);
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("umss_delete_port_device(): port device object is removed\n"));
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// FIXME!!! there can not be sent IOCTL_SUBMIT_URB_XXX while
|
|
// the IOCTL_SUBMIT_CDB_XXX are active. may confuse the device.
|
|
// not resolved yet.
|
|
// 2004-03-22 23:12:26
|
|
NTSTATUS
|
|
umss_port_dispatch_routine(PDEVICE_OBJECT pdev_obj, PIRP irp)
|
|
{
|
|
ULONG ctrl_code;
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irp_stack;
|
|
PUMSS_PORT_DEV_EXT pdev_ext;
|
|
PUMSS_DRVR_EXTENSION pdrvr_ext;
|
|
|
|
if (pdev_obj == NULL || irp == NULL)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
status = STATUS_SUCCESS;
|
|
irp_stack = IoGetCurrentIrpStackLocation(irp);
|
|
ctrl_code = irp_stack->Parameters.DeviceIoControl.IoControlCode;
|
|
|
|
pdev_ext = (PUMSS_PORT_DEV_EXT) pdev_obj->DeviceExtension;
|
|
|
|
switch (irp_stack->MajorFunction)
|
|
{
|
|
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
|
|
{
|
|
switch (ctrl_code)
|
|
{
|
|
case IOCTL_REGISTER_DRIVER:
|
|
{
|
|
PCLASS_DRV_REG_INFO pcdri;
|
|
if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(CLASS_DRV_REG_INFO))
|
|
{
|
|
EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
|
|
}
|
|
|
|
pcdri = irp->AssociatedIrp.SystemBuffer;
|
|
if (pcdri->fdo_driver == NULL || pcdri->add_device == NULL || pcdri->pnp_dispatch == NULL)
|
|
{
|
|
EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
|
|
}
|
|
pdrvr_ext = (PUMSS_DRVR_EXTENSION) pdev_ext->pdriver->driver_ext;
|
|
pdrvr_ext->class_driver_info.fdo_driver = pcdri->fdo_driver;
|
|
pdrvr_ext->class_driver_info.add_device = pcdri->add_device;
|
|
pdrvr_ext->class_driver_info.pnp_dispatch = pcdri->pnp_dispatch;
|
|
EXIT_DISPATCH(STATUS_SUCCESS, irp);
|
|
}
|
|
case IOCTL_REVOKE_DRIVER:
|
|
{
|
|
pdrvr_ext = (PUMSS_DRVR_EXTENSION) pdev_ext->pdriver->driver_ext;
|
|
pdrvr_ext->class_driver_info.fdo_driver = NULL;
|
|
pdrvr_ext->class_driver_info.add_device = NULL;
|
|
pdrvr_ext->class_driver_info.pnp_dispatch = NULL;
|
|
EXIT_DISPATCH(STATUS_SUCCESS, irp);
|
|
}
|
|
}
|
|
}
|
|
case IRP_MJ_CREATE:
|
|
case IRP_MJ_CLOSE:
|
|
{
|
|
EXIT_DISPATCH(STATUS_SUCCESS, irp);
|
|
}
|
|
}
|
|
EXIT_DISPATCH(STATUS_INVALID_DEVICE_REQUEST, irp);
|
|
}
|
|
|
|
BOOLEAN
|
|
umss_driver_init(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver)
|
|
{
|
|
PUMSS_DRVR_EXTENSION pdrvr_ext;
|
|
|
|
if (dev_mgr == NULL || pdriver == NULL)
|
|
return FALSE;
|
|
|
|
//init driver structure, no PNP table functions
|
|
pdriver->driver_desc.flags = USB_DRIVER_FLAG_DEV_CAPABLE;
|
|
pdriver->driver_desc.vendor_id = 0x0dd8; // USB Vendor ID
|
|
pdriver->driver_desc.product_id = 0x0003; // USB Product ID.
|
|
pdriver->driver_desc.release_num = 0x100; // Release Number of Device
|
|
|
|
pdriver->driver_desc.config_val = 1; // Configuration Value
|
|
pdriver->driver_desc.if_num = 1; // Interface Number
|
|
pdriver->driver_desc.if_class = USB_CLASS_MASS_STORAGE; // 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 Mass Storage driver"; // Driver name for Name Registry
|
|
pdriver->driver_desc.dev_class = USB_CLASS_MASS_STORAGE;
|
|
pdriver->driver_desc.dev_sub_class = 0; // Device Subclass
|
|
pdriver->driver_desc.dev_protocol = 0; // Protocol Info.
|
|
|
|
pdriver->driver_ext = usb_alloc_mem(NonPagedPool, sizeof(UMSS_DRVR_EXTENSION));
|
|
if (!pdriver->driver_ext) return FALSE;
|
|
pdriver->driver_ext_size = sizeof(UMSS_DRVR_EXTENSION);
|
|
|
|
RtlZeroMemory(pdriver->driver_ext, sizeof(UMSS_DRVR_EXTENSION));
|
|
pdrvr_ext = (PUMSS_DRVR_EXTENSION) pdriver->driver_ext;
|
|
pdrvr_ext->dev_count = 0;
|
|
InitializeListHead(&pdrvr_ext->dev_list);
|
|
ExInitializeFastMutex(&pdrvr_ext->dev_list_mutex);
|
|
|
|
pdriver->disp_tbl.version = 1;
|
|
pdriver->disp_tbl.dev_connect = umss_connect;
|
|
pdriver->disp_tbl.dev_disconnect = umss_disconnect;
|
|
pdriver->disp_tbl.dev_stop = umss_stop;
|
|
pdriver->disp_tbl.dev_reserved = NULL;
|
|
|
|
if ((pdrvr_ext->port_dev_obj = umss_create_port_device(dev_mgr, pdriver)) == NULL)
|
|
{
|
|
usb_free_mem(pdriver->driver_ext);
|
|
pdriver->driver_ext = NULL;
|
|
pdriver->driver_ext_size = 0;
|
|
pdriver->disp_tbl.dev_connect = NULL;
|
|
pdriver->disp_tbl.dev_stop = NULL;
|
|
pdriver->disp_tbl.dev_disconnect = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
umss_load_class_driver(NULL);
|
|
|
|
// umss_schedule_workitem( NULL, umss_load_class_driver, NULL, 0 );
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("umss_driver_init(): umss driver is initialized\n"));
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
umss_driver_destroy(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver)
|
|
{
|
|
PUMSS_DRVR_EXTENSION pdrvr_ext;
|
|
if (dev_mgr == NULL || pdriver == NULL)
|
|
return FALSE;
|
|
|
|
pdrvr_ext = (PUMSS_DRVR_EXTENSION) pdriver->driver_ext;
|
|
umss_delete_port_device(pdrvr_ext->port_dev_obj);
|
|
pdrvr_ext->port_dev_obj = NULL;
|
|
|
|
ASSERT(IsListEmpty(&pdrvr_ext->dev_list) == TRUE);
|
|
usb_free_mem(pdriver->driver_ext);
|
|
pdriver->driver_ext = NULL;
|
|
pdriver->driver_ext_size = 0;
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("umss_driver_destroy(): umss driver is destroyed\n"));
|
|
return TRUE;
|
|
}
|
|
|
|
PDEVICE_OBJECT
|
|
umss_create_device(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER umss_drvr, DEV_HANDLE dev_handle, BOOLEAN is_if)
|
|
{
|
|
|
|
CHAR dev_name[64], dev_id;
|
|
STRING string;
|
|
NTSTATUS status;
|
|
PDEVICE_OBJECT pdev;
|
|
UNICODE_STRING name_string, symb_link;
|
|
PUMSS_DRVR_EXTENSION pdrvr_ext;
|
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
|
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("umss_create_device(): entering...\n"));
|
|
pdrvr_ext = (PUMSS_DRVR_EXTENSION) umss_drvr->driver_ext;
|
|
dev_id = (UCHAR) dev_id_from_handle(dev_handle); // pdrvr_ext->dev_count;
|
|
|
|
if (is_if == FALSE)
|
|
sprintf(dev_name, "\\Device\\umssdev_%d", (int)dev_id);
|
|
else
|
|
sprintf(dev_name, "\\Device\\umssifdev_%d", (int)dev_id);
|
|
|
|
RtlInitString(&string, dev_name);
|
|
RtlAnsiStringToUnicodeString(&name_string, &string, TRUE);
|
|
pdev = NULL;
|
|
|
|
status = IoCreateDevice(dev_mgr->usb_driver_obj,
|
|
sizeof(UMSS_DEVICE_EXTENSION),
|
|
&name_string,
|
|
FILE_USB_DEV_TYPE,
|
|
0,
|
|
TRUE,
|
|
&pdev);
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// We do direct io
|
|
//
|
|
pdev->Flags |= DO_DIRECT_IO;
|
|
|
|
pdev->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
pdev->StackSize = 2; //one for fdo, one for file device obj
|
|
|
|
pdev_ext = (PUMSS_DEVICE_EXTENSION) pdev->DeviceExtension;
|
|
|
|
//may be accessed by other thread
|
|
ExAcquireFastMutex(&pdrvr_ext->dev_list_mutex);
|
|
InsertTailList(&pdrvr_ext->dev_list, &pdev_ext->dev_obj_link);
|
|
pdrvr_ext->dev_count++;
|
|
ExReleaseFastMutex(&pdrvr_ext->dev_list_mutex);
|
|
|
|
if (is_if)
|
|
pdev_ext->flags |= UMSS_DEV_FLAG_IF_DEV;
|
|
|
|
pdev_ext->umss_dev_id = dev_id;
|
|
pdev_ext->pdo = pdev;
|
|
pdev_ext->dev_handle = dev_handle;
|
|
pdev_ext->dev_mgr = dev_mgr;
|
|
pdev_ext->pdriver = umss_drvr;
|
|
|
|
pdev_ext->dev_ext_hdr.type = NTDEV_TYPE_CLIENT_DEV;
|
|
pdev_ext->dev_ext_hdr.dispatch = umss_dispatch_routine;
|
|
pdev_ext->dev_ext_hdr.start_io = umss_start_io;
|
|
pdev_ext->dev_ext_hdr.dev_mgr = dev_mgr;
|
|
|
|
if (is_if == FALSE)
|
|
sprintf(dev_name, "\\DosDevices\\umssdev%d", (int)dev_id);
|
|
else
|
|
sprintf(dev_name, "\\DosDevices\\umssifdev%d", (int)dev_id);
|
|
|
|
RtlInitString(&string, dev_name);
|
|
RtlAnsiStringToUnicodeString(&symb_link, &string, TRUE);
|
|
IoCreateSymbolicLink(&symb_link, &name_string);
|
|
RtlFreeUnicodeString(&symb_link);
|
|
KeInitializeEvent(&pdev_ext->sync_event, SynchronizationEvent, FALSE);
|
|
KeInitializeSpinLock(&pdev_ext->dev_lock);
|
|
|
|
}
|
|
RtlFreeUnicodeString(&name_string);
|
|
return pdev;
|
|
}
|
|
|
|
BOOLEAN
|
|
umss_connect(PDEV_CONNECT_DATA param, DEV_HANDLE dev_handle)
|
|
{
|
|
PURB purb;
|
|
NTSTATUS status;
|
|
PUSB_CTRL_SETUP_PACKET psetup;
|
|
PUSB_DEV_MANAGER dev_mgr;
|
|
PUSB_DRIVER pdrvr;
|
|
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("umss_connect(): entering...\n"));
|
|
|
|
dev_mgr = param->dev_mgr;
|
|
pdrvr = param->pdriver;
|
|
|
|
//directly set the configuration
|
|
purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
|
|
if (purb == NULL)
|
|
return FALSE;
|
|
|
|
psetup = (PUSB_CTRL_SETUP_PACKET) (purb)->setup_packet;
|
|
urb_init((purb));
|
|
|
|
purb->endp_handle = dev_handle | 0xffff;
|
|
purb->data_buffer = NULL;
|
|
purb->data_length = 0;
|
|
purb->completion = umss_set_cfg_completion;
|
|
purb->context = dev_mgr;
|
|
purb->reference = (LONG) pdrvr;
|
|
psetup->bmRequestType = 0;
|
|
psetup->bRequest = USB_REQ_SET_CONFIGURATION;
|
|
psetup->wValue = 1;
|
|
psetup->wIndex = 0;
|
|
psetup->wLength = 0;
|
|
|
|
status = usb_submit_urb(dev_mgr, purb);
|
|
if (status != STATUS_PENDING)
|
|
{
|
|
usb_free_mem(purb);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
umss_set_cfg_completion(PURB purb, PVOID pcontext)
|
|
{
|
|
PUSB_CTRL_SETUP_PACKET psetup;
|
|
PUCHAR buf;
|
|
PWORK_QUEUE_ITEM pwork_item;
|
|
PUMSS_CREATE_DATA pcd;
|
|
DEV_HANDLE dev_handle;
|
|
NTSTATUS status;
|
|
PUSB_DEV_MANAGER dev_mgr;
|
|
PUSB_DRIVER pdrvr;
|
|
|
|
if (purb == NULL || pcontext == NULL)
|
|
return;
|
|
|
|
dev_mgr = (PUSB_DEV_MANAGER) pcontext;
|
|
pdrvr = (PUSB_DRIVER) purb->reference;
|
|
dev_handle = purb->endp_handle & ~0xffff;
|
|
|
|
|
|
if (purb->status != STATUS_SUCCESS)
|
|
{
|
|
usb_free_mem(purb);
|
|
return;
|
|
}
|
|
|
|
buf = usb_alloc_mem(NonPagedPool, 512);
|
|
if (buf == NULL)
|
|
{
|
|
usb_free_mem(purb);
|
|
return;
|
|
}
|
|
|
|
//now let's get the descs, one configuration, one interface and two endpoint
|
|
psetup = (PUSB_CTRL_SETUP_PACKET) (purb)->setup_packet;
|
|
purb->data_buffer = buf;
|
|
purb->data_length = 512;
|
|
purb->completion = NULL; //this is an immediate request, no needs completion
|
|
purb->context = dev_mgr;
|
|
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(purb);
|
|
purb = NULL;
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
usb_free_mem(buf);
|
|
buf = NULL;
|
|
return;
|
|
}
|
|
|
|
pcd = usb_alloc_mem(NonPagedPool, sizeof(WORK_QUEUE_ITEM) + sizeof(UMSS_CREATE_DATA));
|
|
if (pcd == NULL)
|
|
{
|
|
usb_free_mem(buf);
|
|
buf = NULL;
|
|
return;
|
|
}
|
|
|
|
pcd->desc_buf = buf;
|
|
pcd->dev_handle = dev_handle;
|
|
pcd->dev_mgr = dev_mgr;
|
|
pcd->pdriver = pdrvr;
|
|
pwork_item = (PWORK_QUEUE_ITEM) (&pcd[1]);
|
|
|
|
ExInitializeWorkItem(pwork_item, umss_start_create_device, (PVOID) pcd);
|
|
ExQueueWorkItem(pwork_item, DelayedWorkQueue);
|
|
}
|
|
|
|
VOID NTAPI
|
|
umss_start_create_device(IN PVOID Parameter)
|
|
{
|
|
LONG i;
|
|
PUCHAR desc_buf;
|
|
NTSTATUS status;
|
|
PUSB_DEV pdev;
|
|
DEV_HANDLE dev_handle;
|
|
PUSB_DRIVER pdrvr;
|
|
PDEVICE_OBJECT pdev_obj;
|
|
PUSB_DEV_MANAGER dev_mgr;
|
|
PUMSS_CREATE_DATA pcd;
|
|
PUSB_INTERFACE_DESC pif_desc;
|
|
PUSB_ENDPOINT_DESC pendp_desc;
|
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
|
PUSB_CONFIGURATION_DESC pconfig_desc;
|
|
|
|
USE_BASIC_NON_PENDING_IRQL;
|
|
|
|
if (Parameter == NULL)
|
|
return;
|
|
|
|
pcd = (PUMSS_CREATE_DATA) Parameter;
|
|
desc_buf = pcd->desc_buf;
|
|
dev_mgr = pcd->dev_mgr;
|
|
dev_handle = pcd->dev_handle;
|
|
pdrvr = pcd->pdriver;
|
|
usb_free_mem(pcd);
|
|
pcd = NULL;
|
|
|
|
status = usb_query_and_lock_dev(dev_mgr, dev_handle, &pdev);
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
usb_free_mem(desc_buf);
|
|
return;
|
|
}
|
|
|
|
pdev_obj = umss_create_device(dev_mgr, pdrvr, dev_handle, FALSE);
|
|
|
|
lock_dev(pdev, FALSE);
|
|
if (pdev_obj == NULL ||
|
|
dev_state(pdev) == USB_DEV_STATE_ZOMB ||
|
|
dev_mgr_set_driver(dev_mgr, dev_handle, pdrvr, pdev) == FALSE)
|
|
{
|
|
usb_free_mem(desc_buf);
|
|
unlock_dev(pdev, FALSE);
|
|
|
|
if (pdev_obj)
|
|
umss_delete_device(dev_mgr, pdrvr, pdev_obj, FALSE);
|
|
|
|
usb_unlock_dev(pdev);
|
|
return;
|
|
}
|
|
unlock_dev(pdev, FALSE);
|
|
|
|
pdev_ext = (PUMSS_DEVICE_EXTENSION) pdev_obj->DeviceExtension;
|
|
|
|
pdev_ext->desc_buf = desc_buf;
|
|
pdev_ext->pif_desc = NULL;
|
|
pdev_ext->pin_endp_desc = pdev_ext->pout_endp_desc = NULL;
|
|
|
|
pconfig_desc = (PUSB_CONFIGURATION_DESC) desc_buf;
|
|
pif_desc = (PUSB_INTERFACE_DESC) (&pconfig_desc[1]);
|
|
//search for our if
|
|
for(i = 0; ((UCHAR) i) < pconfig_desc->bNumInterfaces; i++)
|
|
{
|
|
if (pif_desc->bLength == sizeof(USB_INTERFACE_DESC) && pif_desc->bDescriptorType == USB_DT_INTERFACE)
|
|
{
|
|
if (pif_desc->bInterfaceClass == USB_CLASS_MASS_STORAGE)
|
|
{
|
|
pdev_ext->pif_desc = pif_desc;
|
|
pdev_ext->if_idx = (UCHAR) i;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (usb_skip_if_and_altif((PUCHAR *) & pif_desc) == FALSE)
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pdev_ext->pif_desc)
|
|
{
|
|
pendp_desc = (PUSB_ENDPOINT_DESC) & pif_desc[1];
|
|
for(i = 0; ((UCHAR) i) < pif_desc->bNumEndpoints; i++)
|
|
{
|
|
if (pendp_desc->bDescriptorType == USB_DT_ENDPOINT
|
|
&& pendp_desc->bLength == sizeof(USB_ENDPOINT_DESC))
|
|
{
|
|
if ((pendp_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
|
|
{
|
|
pdev_ext->pint_endp_desc = pendp_desc;
|
|
pdev_ext->int_endp_idx = (UCHAR) i;
|
|
}
|
|
else if ((pendp_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)
|
|
{
|
|
if (pendp_desc->bEndpointAddress & USB_DIR_IN)
|
|
{
|
|
pdev_ext->pin_endp_desc = pendp_desc;
|
|
pdev_ext->in_endp_idx = (UCHAR) i;
|
|
}
|
|
else
|
|
{
|
|
pdev_ext->pout_endp_desc = pendp_desc;
|
|
pdev_ext->out_endp_idx = (UCHAR) i;
|
|
}
|
|
}
|
|
pendp_desc = &pendp_desc[1];
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
usb_unlock_dev(pdev);
|
|
return;
|
|
}
|
|
|
|
BOOLEAN
|
|
umss_stop(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle)
|
|
{
|
|
UNREFERENCED_PARAMETER(dev_handle);
|
|
UNREFERENCED_PARAMETER(dev_mgr);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
umss_disconnect(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle)
|
|
{
|
|
PDEVICE_OBJECT dev_obj;
|
|
NTSTATUS status;
|
|
PUSB_DEV pdev;
|
|
PUSB_DRIVER pdrvr;
|
|
|
|
if (dev_mgr == NULL || dev_handle == 0)
|
|
return FALSE;
|
|
|
|
pdev = NULL;
|
|
//special use of the lock dev, simply use this routine to get the dev
|
|
status = usb_query_and_lock_dev(dev_mgr, dev_handle, &pdev);
|
|
if (pdev == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
// must be a bug
|
|
TRAP();
|
|
usb_unlock_dev(pdev);
|
|
}
|
|
pdrvr = pdev->dev_driver;
|
|
dev_obj = pdev->dev_obj;
|
|
pdev = NULL;
|
|
|
|
return umss_delete_device(dev_mgr, pdrvr, dev_obj, FALSE);
|
|
}
|
|
|
|
VOID
|
|
umss_deferred_delete_device(PVOID context)
|
|
{
|
|
PDEVICE_OBJECT dev_obj;
|
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
|
PUMSS_DRVR_EXTENSION pdrvr_ext;
|
|
LARGE_INTEGER interval;
|
|
|
|
if (context == NULL)
|
|
return;
|
|
|
|
dev_obj = (PDEVICE_OBJECT) context;
|
|
pdev_ext = dev_obj->DeviceExtension;
|
|
pdrvr_ext = (PUMSS_DRVR_EXTENSION) pdev_ext->pdriver->driver_ext;
|
|
|
|
interval.QuadPart = -20000; //two ms
|
|
|
|
for(;;)
|
|
{
|
|
if (dev_obj->ReferenceCount)
|
|
KeDelayExecutionThread(KernelMode, TRUE, &interval);
|
|
else
|
|
{
|
|
KeDelayExecutionThread(KernelMode, TRUE, &interval);
|
|
if (dev_obj->ReferenceCount == 0)
|
|
break;
|
|
}
|
|
}
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("umss_deferred_delete_device(): delete device, 0x%x\n", dev_obj));
|
|
|
|
ExAcquireFastMutex(&pdrvr_ext->dev_list_mutex);
|
|
RemoveEntryList(&pdev_ext->dev_obj_link);
|
|
pdrvr_ext->dev_count--;
|
|
ExReleaseFastMutex(&pdrvr_ext->dev_list_mutex);
|
|
|
|
IoDeleteDevice(dev_obj);
|
|
return;
|
|
}
|
|
|
|
BOOLEAN
|
|
umss_delete_device(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdrvr, PDEVICE_OBJECT dev_obj, BOOLEAN is_if)
|
|
{
|
|
CHAR dev_name[64];
|
|
STRING string;
|
|
UNICODE_STRING symb_link;
|
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
|
PUMSS_DRVR_EXTENSION pdrvr_ext;
|
|
|
|
if (dev_obj == NULL)
|
|
return FALSE;
|
|
|
|
if (pdrvr == NULL || dev_mgr == NULL)
|
|
return FALSE;
|
|
|
|
pdev_ext = (PUMSS_DEVICE_EXTENSION) dev_obj->DeviceExtension;
|
|
pdrvr_ext = (PUMSS_DRVR_EXTENSION) pdrvr->driver_ext;
|
|
if (is_if == FALSE)
|
|
sprintf(dev_name, "\\DosDevices\\umssdev%d", (int)pdev_ext->umss_dev_id);
|
|
else
|
|
sprintf(dev_name, "\\DosDevices\\umssifdev%d", (int)pdev_ext->umss_dev_id);
|
|
|
|
RtlInitString(&string, dev_name);
|
|
RtlAnsiStringToUnicodeString(&symb_link, &string, TRUE);
|
|
IoDeleteSymbolicLink(&symb_link);
|
|
RtlFreeUnicodeString(&symb_link);
|
|
|
|
if (pdev_ext->desc_buf)
|
|
{
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("umss_delete_device(): delete desc_buf\n"));
|
|
usb_free_mem(pdev_ext->desc_buf);
|
|
pdev_ext->desc_buf = NULL;
|
|
|
|
}
|
|
|
|
if (dev_obj->ReferenceCount == 0)
|
|
{
|
|
ExAcquireFastMutex(&pdrvr_ext->dev_list_mutex);
|
|
RemoveEntryList(&pdev_ext->dev_obj_link);
|
|
pdrvr_ext->dev_count--;
|
|
ExReleaseFastMutex(&pdrvr_ext->dev_list_mutex);
|
|
|
|
IoDeleteDevice(dev_obj);
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// FIXME: how if the driver unloading happens
|
|
// since this is called in dev_mgr_disconnect_dev, umss_schedule_workitem
|
|
// can not protect the USB_DEV object from be deleted. so the workitem
|
|
// can not access anything relative to the USB_DEV object. In this case
|
|
// we will tollerate the usb_query_and_lock_dev failure since it will
|
|
// never success when come to this point, and we won't pass dev_mgr
|
|
// and pdev to the function. But other scenarios, usb_query_and_lock_dev
|
|
// can not fail if dev_mgr and pdev are passed valid.
|
|
// When driver is unloading, don't know. Wish NT will unload the driver
|
|
// only when all the devices to the driver are deleted.
|
|
//
|
|
umss_schedule_workitem(dev_obj, umss_deferred_delete_device, NULL, 0);
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
umss_submit_io_packet(PDEVICE_OBJECT dev_obj, PIO_PACKET io_packet)
|
|
{
|
|
NTSTATUS status;
|
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
|
PUSB_DEV pdev;
|
|
|
|
pdev_ext = dev_obj->DeviceExtension;
|
|
|
|
// lock the dev, the pdev_ext->pif_desc won't go away.
|
|
if ((status = usb_query_and_lock_dev(pdev_ext->dev_mgr, pdev_ext->dev_handle, &pdev)) != STATUS_SUCCESS)
|
|
{
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("umss_start_io(): error, device is not valid\n"));
|
|
UMSS_COMPLETE_START_IO(dev_obj, status, io_packet->pirp);
|
|
return;
|
|
}
|
|
|
|
if (pdev_ext->pif_desc->bInterfaceProtocol == PROTOCOL_BULKONLY)
|
|
{
|
|
status = umss_bulkonly_startio(pdev_ext, io_packet);
|
|
}
|
|
else if (pdev_ext->pif_desc->bInterfaceProtocol == PROTOCOL_CB
|
|
|| pdev_ext->pif_desc->bInterfaceProtocol == PROTOCOL_CBI)
|
|
{
|
|
status = umss_cbi_startio(pdev_ext, io_packet);
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_DEVICE_PROTOCOL_ERROR;
|
|
}
|
|
usb_unlock_dev(pdev);
|
|
UMSS_COMPLETE_START_IO(dev_obj, status, io_packet->pirp);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
umss_start_io(IN PDEVICE_OBJECT dev_obj, IN PIRP irp)
|
|
{
|
|
ULONG ctrl_code;
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irp_stack;
|
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
|
IO_PACKET io_packet;
|
|
PUSER_IO_PACKET user_io_packet;
|
|
|
|
if (dev_obj == NULL || irp == NULL)
|
|
return;
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
irp_stack = IoGetCurrentIrpStackLocation(irp);
|
|
ctrl_code = irp_stack->Parameters.DeviceIoControl.IoControlCode;
|
|
pdev_ext = (PUMSS_DEVICE_EXTENSION) dev_obj->DeviceExtension;
|
|
|
|
if (irp_stack->MajorFunction == IRP_MJ_SCSI)
|
|
{
|
|
umss_process_srb(dev_obj, irp);
|
|
return;
|
|
}
|
|
|
|
if (irp_stack->MajorFunction != IRP_MJ_DEVICE_CONTROL)
|
|
{
|
|
UMSS_COMPLETE_START_IO(dev_obj, STATUS_INVALID_DEVICE_REQUEST, irp);
|
|
}
|
|
|
|
switch (ctrl_code)
|
|
{
|
|
case IOCTL_UMSS_SUBMIT_CDB_IN:
|
|
case IOCTL_UMSS_SUBMIT_CDB_OUT:
|
|
case IOCTL_UMSS_SUBMIT_CDB:
|
|
{
|
|
if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(USER_IO_PACKET))
|
|
{
|
|
UMSS_COMPLETE_START_IO(dev_obj, STATUS_INVALID_PARAMETER, irp);
|
|
}
|
|
|
|
user_io_packet = (PUSER_IO_PACKET) irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if (user_io_packet->sub_class != pdev_ext->pif_desc->bInterfaceSubClass)
|
|
{
|
|
// not agree with the dev's subclass
|
|
UMSS_COMPLETE_START_IO(dev_obj, STATUS_DEVICE_PROTOCOL_ERROR, irp);
|
|
}
|
|
|
|
RtlZeroMemory(&io_packet, sizeof(io_packet));
|
|
io_packet.cdb_length = user_io_packet->cdb_length;
|
|
io_packet.lun = user_io_packet->lun;
|
|
|
|
RtlCopyMemory(io_packet.cdb, user_io_packet->cdb, MAX_CDB_LENGTH);
|
|
|
|
if (ctrl_code == IOCTL_UMSS_SUBMIT_CDB_IN)
|
|
io_packet.flags |= USB_DIR_IN;
|
|
|
|
if (ctrl_code != IOCTL_UMSS_SUBMIT_CDB)
|
|
{
|
|
if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength == 0)
|
|
UMSS_COMPLETE_START_IO(dev_obj, STATUS_BUFFER_TOO_SMALL, irp);
|
|
|
|
io_packet.data_buffer = MmGetSystemAddressForMdl(irp->MdlAddress);
|
|
io_packet.data_length = irp_stack->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
if (io_packet.data_length > MAX_BULK_TRANSFER_LENGTH)
|
|
UMSS_COMPLETE_START_IO(dev_obj, STATUS_BUFFER_TOO_SMALL, irp);
|
|
|
|
//synchronize the buffer
|
|
if (io_packet.flags & USB_DIR_IN)
|
|
KeFlushIoBuffers(irp->MdlAddress, TRUE, TRUE);
|
|
else
|
|
KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE);
|
|
}
|
|
|
|
io_packet.pirp = irp;
|
|
umss_submit_io_packet(dev_obj, &io_packet);
|
|
return;
|
|
}
|
|
case IOCTL_SCSI_PASS_THROUGH:
|
|
{
|
|
PSCSI_PASS_THROUGH pass_through;
|
|
IO_PACKET io_packet;
|
|
|
|
pass_through = irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if (pass_through->DataTransferLength &&
|
|
pass_through->DataBufferOffset != sizeof(SCSI_PASS_THROUGH))
|
|
UMSS_COMPLETE_START_IO(dev_obj, STATUS_INVALID_PARAMETER, irp);
|
|
|
|
if (pass_through->SenseInfoLength &&
|
|
(pass_through->SenseInfoOffset !=
|
|
pass_through->DataBufferOffset + pass_through->DataTransferLength))
|
|
UMSS_COMPLETE_START_IO(dev_obj, STATUS_INVALID_PARAMETER, irp);
|
|
|
|
if (irp_stack->Parameters.DeviceIoControl.InputBufferLength <
|
|
(sizeof(SCSI_PASS_THROUGH) +
|
|
pass_through->SenseInfoLength + pass_through->DataTransferLength))
|
|
UMSS_COMPLETE_START_IO(dev_obj, STATUS_BUFFER_TOO_SMALL, irp);
|
|
|
|
RtlZeroMemory(&io_packet, sizeof(io_packet));
|
|
|
|
io_packet.flags |= IOP_FLAG_SCSI_CTRL_TRANSFER;
|
|
if (pass_through->DataIn)
|
|
io_packet.flags |= IOP_FLAG_DIR_IN;
|
|
|
|
io_packet.data_buffer = (PVOID) & pass_through[1];
|
|
io_packet.data_length = pass_through->DataTransferLength;
|
|
|
|
if (pass_through->SenseInfoLength)
|
|
{
|
|
io_packet.sense_data = ((PUCHAR) pass_through) + pass_through->SenseInfoOffset;
|
|
io_packet.sense_data_length = pass_through->SenseInfoLength;
|
|
io_packet.flags |= IOP_FLAG_REQ_SENSE;
|
|
}
|
|
|
|
io_packet.cdb_length = pass_through->CdbLength;
|
|
RtlCopyMemory(io_packet.cdb, pass_through->Cdb, sizeof(io_packet.cdb));
|
|
io_packet.lun = 0;
|
|
io_packet.pirp = irp;
|
|
umss_submit_io_packet(dev_obj, &io_packet);
|
|
return;
|
|
}
|
|
case IOCTL_SCSI_PASS_THROUGH_DIRECT:
|
|
{
|
|
PSCSI_PASS_THROUGH_DIRECT pass_through_direct;
|
|
IO_PACKET io_packet;
|
|
|
|
pass_through_direct = irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if (pass_through_direct->SenseInfoLength &&
|
|
pass_through_direct->SenseInfoOffset != sizeof(SCSI_PASS_THROUGH_DIRECT))
|
|
UMSS_COMPLETE_START_IO(dev_obj, STATUS_INVALID_PARAMETER, irp);
|
|
|
|
if (irp_stack->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(SCSI_PASS_THROUGH_DIRECT) + pass_through_direct->SenseInfoLength)
|
|
UMSS_COMPLETE_START_IO(dev_obj, STATUS_BUFFER_TOO_SMALL, irp);
|
|
|
|
RtlZeroMemory(&io_packet, sizeof(io_packet));
|
|
|
|
io_packet.flags |= IOP_FLAG_SCSI_CTRL_TRANSFER;
|
|
if (pass_through_direct->DataIn)
|
|
io_packet.flags |= IOP_FLAG_DIR_IN;
|
|
|
|
io_packet.data_buffer = pass_through_direct->DataBuffer;
|
|
io_packet.data_length = pass_through_direct->DataTransferLength;
|
|
|
|
if (pass_through_direct->SenseInfoLength)
|
|
{
|
|
io_packet.sense_data = ((PUCHAR) pass_through_direct) + pass_through_direct->SenseInfoOffset;
|
|
io_packet.sense_data_length = pass_through_direct->SenseInfoLength;
|
|
io_packet.flags |= IOP_FLAG_REQ_SENSE;
|
|
}
|
|
|
|
io_packet.cdb_length = pass_through_direct->CdbLength;
|
|
RtlCopyMemory(io_packet.cdb, pass_through_direct->Cdb, sizeof(io_packet.cdb));
|
|
io_packet.lun = 0;
|
|
io_packet.pirp = irp;
|
|
umss_submit_io_packet(dev_obj, &io_packet);
|
|
return;
|
|
}
|
|
case IOCTL_SUBMIT_URB_RD:
|
|
case IOCTL_SUBMIT_URB_NOIO:
|
|
case IOCTL_SUBMIT_URB_WR:
|
|
{
|
|
gendrv_startio(dev_obj, irp);
|
|
return;
|
|
}
|
|
default:
|
|
UMSS_COMPLETE_START_IO(dev_obj, STATUS_INVALID_DEVICE_REQUEST, irp);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// bugbug!!! there can not be sent IOCTL_SUBMIT_URB_XXX while
|
|
// the IOCTL_SUBMIT_CDB_XXX are active. may confuse the device.
|
|
// not resolved yet.
|
|
NTSTATUS
|
|
umss_dispatch_routine(PDEVICE_OBJECT pdev_obj, PIRP irp)
|
|
{
|
|
ULONG ctrl_code;
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irp_stack;
|
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
|
USE_BASIC_NON_PENDING_IRQL;
|
|
|
|
if (pdev_obj == NULL || irp == NULL)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
status = STATUS_SUCCESS;
|
|
irp_stack = IoGetCurrentIrpStackLocation(irp);
|
|
ctrl_code = irp_stack->Parameters.DeviceIoControl.IoControlCode;
|
|
|
|
pdev_ext = (PUMSS_DEVICE_EXTENSION) pdev_obj->DeviceExtension;
|
|
|
|
switch (irp_stack->MajorFunction)
|
|
{
|
|
case IRP_MJ_CREATE:
|
|
case IRP_MJ_CLOSE:
|
|
{
|
|
return dev_mgr_dispatch(pdev_ext->dev_mgr, irp);
|
|
}
|
|
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
|
|
{
|
|
// function code to receive scsi request
|
|
UMSS_EXIT_DISPATCH(pdev_obj, STATUS_PENDING, irp);
|
|
}
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
{
|
|
switch (ctrl_code)
|
|
{
|
|
case IOCTL_UMSS_SET_FDO:
|
|
{
|
|
PDEVICE_OBJECT fdo;
|
|
PUSB_DEV pdev;
|
|
|
|
if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(PDEVICE_OBJECT))
|
|
{
|
|
EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
|
|
}
|
|
|
|
fdo = (PDEVICE_OBJECT) ((PULONG) irp->AssociatedIrp.SystemBuffer)[0];
|
|
if (fdo == NULL)
|
|
EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
|
|
//
|
|
// we have to test the usb dev's state to determine whether set or not the fdo
|
|
//
|
|
|
|
if (usb_query_and_lock_dev(pdev_ext->dev_mgr, pdev_ext->dev_handle, &pdev) !=
|
|
STATUS_SUCCESS)
|
|
EXIT_DISPATCH(STATUS_DEVICE_DOES_NOT_EXIST, irp);
|
|
|
|
lock_dev(pdev, FALSE);
|
|
|
|
if (dev_state(pdev) >= USB_DEV_STATE_BEFORE_ZOMB || dev_state(pdev) == USB_DEV_STATE_ZOMB)
|
|
{
|
|
unlock_dev(pdev, FALSE);
|
|
usb_unlock_dev(pdev);
|
|
EXIT_DISPATCH(STATUS_DEVICE_DOES_NOT_EXIST, irp);
|
|
}
|
|
|
|
pdev_ext->fdo = fdo;
|
|
unlock_dev(pdev, FALSE);
|
|
usb_unlock_dev(pdev);
|
|
irp->IoStatus.Information = 0;
|
|
EXIT_DISPATCH(STATUS_SUCCESS, irp);
|
|
}
|
|
|
|
case IOCTL_GET_DEV_DESC:
|
|
{
|
|
PGET_DEV_DESC_REQ pgddr;
|
|
if (irp_stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(GET_DEV_DESC_REQ))
|
|
{
|
|
EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
|
|
}
|
|
pgddr = irp->AssociatedIrp.SystemBuffer;
|
|
if (pgddr->dev_handle != (pdev_ext->dev_handle & 0xffff0000))
|
|
{
|
|
EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
|
|
}
|
|
// an immediate request
|
|
return dev_mgr_dispatch(pdev_ext->dev_mgr, irp);
|
|
}
|
|
case IOCTL_SUBMIT_URB_RD:
|
|
case IOCTL_SUBMIT_URB_NOIO:
|
|
case IOCTL_SUBMIT_URB_WR:
|
|
{
|
|
PURB purb;
|
|
DEV_HANDLE endp_handle;
|
|
|
|
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 (!default_endp_handle(endp_handle))
|
|
{
|
|
//no permit to other interface if interface dev
|
|
if ((pdev_ext->flags & UMSS_DEV_FLAG_IF_DEV)
|
|
&& if_idx_from_handle(endp_handle) != pdev_ext->if_idx)
|
|
EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
|
|
}
|
|
// FIXME: this is dangeous
|
|
// return dev_mgr_dispatch( pdev_ext->dev_mgr, irp );
|
|
UMSS_EXIT_DISPATCH(pdev_obj, STATUS_PENDING, irp);
|
|
}
|
|
case IOCTL_GET_DEV_HANDLE:
|
|
{
|
|
if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(LONG))
|
|
EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
|
|
|
|
*((PLONG) irp->AssociatedIrp.SystemBuffer) = pdev_ext->dev_handle;
|
|
irp->IoStatus.Information = sizeof(LONG);
|
|
EXIT_DISPATCH(STATUS_SUCCESS, irp);
|
|
}
|
|
|
|
//
|
|
// request from scsi class driver
|
|
//
|
|
case IOCTL_SCSI_PASS_THROUGH:
|
|
case IOCTL_SCSI_PASS_THROUGH_DIRECT:
|
|
//
|
|
// direct cdb request
|
|
//
|
|
case IOCTL_UMSS_SUBMIT_CDB:
|
|
case IOCTL_UMSS_SUBMIT_CDB_OUT:
|
|
case IOCTL_UMSS_SUBMIT_CDB_IN:
|
|
{
|
|
UMSS_EXIT_DISPATCH(pdev_obj, STATUS_PENDING, irp);
|
|
}
|
|
case IOCTL_SCSI_GET_INQUIRY_DATA:
|
|
{
|
|
PSCSI_ADAPTER_BUS_INFO adapter_info;
|
|
PSCSI_BUS_DATA bus_data;
|
|
PSCSI_INQUIRY_DATA inq_dat;
|
|
PINQUIRYDATA inq;
|
|
IO_PACKET io_packet;
|
|
ULONG required_size;
|
|
|
|
required_size = sizeof(SCSI_ADAPTER_BUS_INFO)
|
|
+ sizeof(SCSI_BUS_DATA) + sizeof(SCSI_INQUIRY_DATA) + INQUIRYDATABUFFERSIZE;
|
|
|
|
if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength < required_size)
|
|
UMSS_EXIT_DISPATCH(pdev_obj, STATUS_BUFFER_TOO_SMALL, irp);
|
|
|
|
RtlZeroMemory(&io_packet, sizeof(io_packet));
|
|
|
|
adapter_info = irp->AssociatedIrp.SystemBuffer;
|
|
adapter_info->NumberOfBuses = 1;
|
|
bus_data = &adapter_info->BusData[0];
|
|
bus_data->NumberOfLogicalUnits = 1;
|
|
bus_data->InitiatorBusId = 0;
|
|
bus_data->InquiryDataOffset = sizeof(SCSI_ADAPTER_BUS_INFO);
|
|
inq_dat = (PVOID) & bus_data[1];
|
|
inq_dat->PathId = 0;
|
|
inq_dat->TargetId = pdev_ext->umss_dev_id;
|
|
//
|
|
// this is the dev_id for usb dev_manager
|
|
//
|
|
inq_dat->Lun = (UCHAR) (pdev_ext->dev_handle >> 16);
|
|
inq_dat->DeviceClaimed = FALSE;
|
|
inq_dat->InquiryDataLength = 36;
|
|
inq_dat->NextInquiryDataOffset = 0;
|
|
inq = (PINQUIRYDATA) inq_dat->InquiryData;
|
|
|
|
RtlZeroMemory(inq, sizeof(INQUIRYDATA));
|
|
inq->DeviceType = DIRECT_ACCESS_DEVICE;
|
|
inq->DeviceTypeQualifier = 0;
|
|
inq->RemovableMedia = 1;
|
|
|
|
//
|
|
// pretend to comply scsi primary 2 command set
|
|
//
|
|
|
|
inq->Versions = 0x04;
|
|
|
|
//
|
|
// the format is in scsi-2 format
|
|
//
|
|
|
|
inq->ResponseDataFormat = 0x02;
|
|
|
|
//
|
|
// we are the poor scsi device
|
|
//
|
|
|
|
inq->AdditionalLength = 31;
|
|
inq->SoftReset = 0;
|
|
inq->CommandQueue = 0;
|
|
inq->LinkedCommands = 0;
|
|
inq->RelativeAddressing = 0;
|
|
RtlCopyMemory(&inq->VendorId, "Unknown", 7);
|
|
RtlCopyMemory(&inq->ProductId, "USB Mass Storage", 16);
|
|
irp->IoStatus.Information = required_size;
|
|
EXIT_DISPATCH(STATUS_SUCCESS, irp);
|
|
}
|
|
case IOCTL_SCSI_GET_CAPABILITIES:
|
|
{
|
|
PIO_SCSI_CAPABILITIES port_cap;
|
|
|
|
if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(IO_SCSI_CAPABILITIES))
|
|
EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
|
|
|
|
port_cap = (PIO_SCSI_CAPABILITIES) irp->AssociatedIrp.SystemBuffer;
|
|
port_cap->Length = sizeof(IO_SCSI_CAPABILITIES);
|
|
port_cap->MaximumTransferLength = 65536;
|
|
port_cap->MaximumPhysicalPages = 65536 / PAGE_SIZE;
|
|
port_cap->SupportedAsynchronousEvents = 0;
|
|
port_cap->AlignmentMask = 0x10;
|
|
port_cap->TaggedQueuing = FALSE;
|
|
port_cap->AdapterScansDown = FALSE;
|
|
port_cap->AdapterUsesPio = FALSE;
|
|
irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
|
|
EXIT_DISPATCH(STATUS_SUCCESS, irp);
|
|
}
|
|
case IOCTL_SCSI_GET_ADDRESS:
|
|
{
|
|
PSCSI_ADDRESS paddr;
|
|
if (irp_stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SCSI_ADDRESS))
|
|
EXIT_DISPATCH(STATUS_INVALID_PARAMETER, irp);
|
|
|
|
paddr = (PSCSI_ADDRESS) irp->AssociatedIrp.SystemBuffer;
|
|
|
|
paddr->Length = sizeof(SCSI_ADDRESS);
|
|
paddr->PortNumber = 0;
|
|
paddr->PathId = 0;
|
|
paddr->TargetId = pdev_ext->umss_dev_id;
|
|
paddr->Lun = (UCHAR) (pdev_ext->dev_handle >> 16);
|
|
irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
|
|
EXIT_DISPATCH(STATUS_SUCCESS, irp);
|
|
}
|
|
case IOCTL_SCSI_RESCAN_BUS:
|
|
{
|
|
irp->IoStatus.Information = 0;
|
|
EXIT_DISPATCH(STATUS_SUCCESS, irp);
|
|
}
|
|
default:
|
|
{
|
|
EXIT_DISPATCH(STATUS_INVALID_DEVICE_REQUEST, irp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
EXIT_DISPATCH(STATUS_NOT_SUPPORTED, irp);
|
|
}
|
|
|
|
VOID
|
|
umss_reset_pipe_completion(PURB purb, PVOID context)
|
|
{
|
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
|
if (context == NULL)
|
|
return;
|
|
|
|
pdev_ext = (PUMSS_DEVICE_EXTENSION) context;
|
|
pdev_ext->reset_pipe_status = purb->status;
|
|
KeSetEvent(&pdev_ext->sync_event, 0, FALSE);
|
|
return;
|
|
}
|
|
|
|
//can only be called at passive level
|
|
NTSTATUS
|
|
umss_reset_pipe(PUMSS_DEVICE_EXTENSION pdev_ext, DEV_HANDLE endp_handle)
|
|
{
|
|
NTSTATUS status;
|
|
PUSB_DEV pdev;
|
|
|
|
if (pdev_ext == NULL)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
status = usb_query_and_lock_dev(pdev_ext->dev_mgr, pdev_ext->dev_handle, &pdev);
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
status = usb_reset_pipe_ex(pdev_ext->dev_mgr, endp_handle, umss_reset_pipe_completion, pdev_ext);
|
|
|
|
if (status == STATUS_PENDING)
|
|
{
|
|
KeWaitForSingleObject(&pdev_ext->sync_event, Executive, KernelMode, TRUE, NULL);
|
|
status = pdev_ext->reset_pipe_status;
|
|
}
|
|
usb_unlock_dev(pdev);
|
|
return status;
|
|
}
|
|
|
|
BOOLEAN
|
|
umss_gen_result_srb(PIO_PACKET io_packet, PSCSI_REQUEST_BLOCK srb, NTSTATUS status)
|
|
{
|
|
|
|
if (srb == NULL || io_packet == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
PULONG dest_buf, src_buf;
|
|
ULONG i;
|
|
|
|
srb->SrbStatus = SRB_STATUS_SUCCESS;
|
|
|
|
io_packet->pirp->IoStatus.Information = srb->DataTransferLength;
|
|
if ((io_packet->pirp->Flags & IRP_READ_OPERATION) && !(io_packet->pirp->Flags & IRP_PAGING_IO))
|
|
{
|
|
src_buf = (PULONG) io_packet->data_buffer;
|
|
dest_buf = (PULONG) srb->DataBuffer;
|
|
if (src_buf && dest_buf)
|
|
{
|
|
for(i = 0; i < (srb->DataTransferLength >> 2); i++)
|
|
{
|
|
dest_buf[i] = src_buf[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (status == STATUS_DEVICE_DOES_NOT_EXIST)
|
|
{
|
|
PSENSE_DATA sense_buf;
|
|
srb->SrbStatus = SRB_STATUS_NO_DEVICE;
|
|
srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
|
|
|
|
//
|
|
// let's build the srb status for class driver
|
|
//
|
|
|
|
srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
|
|
sense_buf = (PSENSE_DATA) srb->SenseInfoBuffer;
|
|
|
|
if (!(srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE))
|
|
{
|
|
RtlZeroMemory(srb->SenseInfoBuffer, srb->SenseInfoBufferLength);
|
|
sense_buf->ErrorCode = 0x70;
|
|
sense_buf->Valid = 1;
|
|
sense_buf->SenseKey = SCSI_SENSE_NOT_READY;
|
|
sense_buf->AdditionalSenseCode = SCSI_ADSENSE_NO_MEDIA_IN_DEVICE;
|
|
sense_buf->AdditionalSenseLength = 10;
|
|
}
|
|
}
|
|
else if (status == USB_STATUS_STALL_PID || status == USB_STATUS_CRC ||
|
|
status == USB_STATUS_BTSTUFF || status == USB_STATUS_DATA_OVERRUN)
|
|
{
|
|
PSENSE_DATA sense_buf;
|
|
srb->SrbStatus = SRB_STATUS_ERROR;
|
|
srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
|
|
|
|
srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
|
|
sense_buf = (PSENSE_DATA) srb->SenseInfoBuffer;
|
|
|
|
if (!(srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE))
|
|
{
|
|
RtlZeroMemory(srb->SenseInfoBuffer, srb->SenseInfoBufferLength);
|
|
sense_buf->ErrorCode = 0x70;
|
|
sense_buf->Valid = 1;
|
|
sense_buf->SenseKey = SCSI_SENSE_HARDWARE_ERROR;
|
|
sense_buf->AdditionalSenseCode = 0;
|
|
sense_buf->AdditionalSenseLength = 10;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
srb->SrbStatus = SRB_STATUS_ERROR;
|
|
}
|
|
|
|
if ((io_packet->pirp->Flags & (IRP_READ_OPERATION | IRP_WRITE_OPERATION))
|
|
&& !(io_packet->pirp->Flags & IRP_PAGING_IO))
|
|
{
|
|
if (io_packet->data_buffer)
|
|
{
|
|
usb_free_mem(io_packet->data_buffer);
|
|
io_packet->data_buffer = NULL;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
umss_gen_result_ctrl(PDEVICE_OBJECT dev_obj, PIRP irp, NTSTATUS status)
|
|
{
|
|
PIO_STACK_LOCATION irp_stack;
|
|
ULONG ctrl_code;
|
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
|
|
|
if (irp == NULL)
|
|
return FALSE;
|
|
|
|
irp->IoStatus.Information = 0;
|
|
irp_stack = IoGetCurrentIrpStackLocation(irp);
|
|
ctrl_code = irp_stack->Parameters.DeviceIoControl.IoControlCode;
|
|
pdev_ext = dev_obj->DeviceExtension;
|
|
|
|
switch (ctrl_code)
|
|
{
|
|
case IOCTL_SCSI_PASS_THROUGH:
|
|
{
|
|
PSCSI_PASS_THROUGH pass_through;
|
|
pass_through = irp->AssociatedIrp.SystemBuffer;
|
|
irp->IoStatus.Status = status;
|
|
|
|
// we have set these two value in bulkonly.c when data transfer complete
|
|
// pass_through_direct->DataTransferLength = pdev_ext->io_packet.data_length;
|
|
// pass_through_direct->SenseInfoLength = pdev_ext->io_packet.sense_data_length;
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
irp->IoStatus.Information = pass_through->SenseInfoOffset + pass_through->SenseInfoLength;
|
|
else
|
|
pass_through->ScsiStatus = SCSISTAT_CHECK_CONDITION;
|
|
return TRUE;
|
|
}
|
|
case IOCTL_SCSI_PASS_THROUGH_DIRECT:
|
|
{
|
|
PSCSI_PASS_THROUGH_DIRECT pass_through_direct;
|
|
|
|
pass_through_direct = irp->AssociatedIrp.SystemBuffer;
|
|
pass_through_direct->ScsiStatus = 0;
|
|
irp->IoStatus.Status = status;
|
|
|
|
// we have set these two value in bulkonly.c when data transfer complete
|
|
// pass_through_direct->DataTransferLength = pdev_ext->io_packet.data_length;
|
|
// pass_through_direct->SenseInfoLength = pdev_ext->io_packet.sense_data_length;
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
irp->IoStatus.Information =
|
|
pass_through_direct->SenseInfoOffset + pass_through_direct->SenseInfoLength;
|
|
else
|
|
pass_through_direct->ScsiStatus = SCSISTAT_CHECK_CONDITION;
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
umss_complete_request(PUMSS_DEVICE_EXTENSION pdev_ext, NTSTATUS status)
|
|
{
|
|
PIRP pirp;
|
|
KIRQL old_irql;
|
|
|
|
PDEVICE_OBJECT dev_obj;
|
|
PIO_STACK_LOCATION irp_stack;
|
|
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("umss_complete_request(): entering...\n"));
|
|
|
|
pirp = pdev_ext->io_packet.pirp;
|
|
dev_obj = pdev_ext->pdo;
|
|
|
|
irp_stack = IoGetCurrentIrpStackLocation(pirp);
|
|
|
|
if (pdev_ext->io_packet.flags & IOP_FLAG_SRB_TRANSFER)
|
|
{
|
|
if (pdev_ext->pif_desc->bInterfaceSubClass == UMSS_SUBCLASS_SFF8070I)
|
|
{
|
|
umss_fix_sff_result(&pdev_ext->io_packet, irp_stack->Parameters.Scsi.Srb);
|
|
}
|
|
umss_gen_result_srb(&pdev_ext->io_packet, irp_stack->Parameters.Scsi.Srb, status);
|
|
}
|
|
else if (pdev_ext->io_packet.flags & IOP_FLAG_SCSI_CTRL_TRANSFER)
|
|
umss_gen_result_ctrl(dev_obj, pirp, status);
|
|
|
|
//this device has its irp queued
|
|
if (status == STATUS_CANCELLED)
|
|
{
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("umss_complete_request(): status of irp is cancelled\n"));
|
|
IoAcquireCancelSpinLock(&old_irql);
|
|
if (dev_obj->CurrentIrp == pirp)
|
|
{
|
|
IoReleaseCancelSpinLock(old_irql);
|
|
IoStartNextPacket(dev_obj, FALSE);
|
|
}
|
|
else
|
|
{
|
|
KeRemoveEntryDeviceQueue(&dev_obj->DeviceQueue, &pirp->Tail.Overlay.DeviceQueueEntry);
|
|
IoReleaseCancelSpinLock(old_irql);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// all requests come to this point from the irp queue
|
|
IoStartNextPacket(dev_obj, FALSE);
|
|
|
|
// we are going to complete the request, so set it's cancel routine to NULL
|
|
IoAcquireCancelSpinLock(&old_irql);
|
|
(void)IoSetCancelRoutine(pirp, NULL);
|
|
IoReleaseCancelSpinLock(old_irql);
|
|
}
|
|
|
|
pirp->IoStatus.Status = status;
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
pirp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(pirp, IO_NO_INCREMENT);
|
|
return;
|
|
}
|
|
|
|
BOOLEAN
|
|
umss_if_connect(PDEV_CONNECT_DATA params, DEV_HANDLE if_handle)
|
|
{
|
|
PURB purb;
|
|
LONG if_idx, i;
|
|
PUCHAR desc_buf;
|
|
NTSTATUS status;
|
|
PUSB_DEV pdev;
|
|
PUSB_DRIVER pdrvr;
|
|
PUSB_INTERFACE_DESC pif_desc;
|
|
PUSB_CTRL_SETUP_PACKET psetup;
|
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
|
PUSB_CONFIGURATION_DESC pconfig_desc;
|
|
PUSB_DEV_MANAGER dev_mgr;
|
|
PUSB_ENDPOINT_DESC pendp_desc;
|
|
PUMSS_DRVR_EXTENSION pdrvr_ext;
|
|
PDEVICE_OBJECT pdev_obj;
|
|
USE_BASIC_NON_PENDING_IRQL;
|
|
|
|
//configuration is already set
|
|
purb = NULL;
|
|
desc_buf = NULL;
|
|
pdev = NULL;
|
|
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("umss_if_connect(): entering...\n"));
|
|
|
|
if (params == NULL)
|
|
return FALSE;
|
|
|
|
dev_mgr = params->dev_mgr;
|
|
pdrvr = params->pdriver;
|
|
|
|
if_idx = if_idx_from_handle(if_handle);
|
|
|
|
purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
|
|
if (purb == NULL)
|
|
goto ERROR_OUT;
|
|
|
|
desc_buf = usb_alloc_mem(NonPagedPool, 512);
|
|
if (desc_buf == NULL)
|
|
goto ERROR_OUT;
|
|
|
|
psetup = (PUSB_CTRL_SETUP_PACKET) (purb)->setup_packet;
|
|
urb_init((purb));
|
|
|
|
// now let's get the descs, one configuration, one interface and two endpoint
|
|
psetup = (PUSB_CTRL_SETUP_PACKET) (purb)->setup_packet;
|
|
purb->endp_handle = if_handle | 0xffff;
|
|
purb->data_buffer = desc_buf;
|
|
purb->data_length = 512;
|
|
purb->completion = NULL; // this is an immediate request, no needs completion
|
|
purb->context = dev_mgr;
|
|
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(purb);
|
|
purb = NULL;
|
|
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
goto ERROR_OUT;
|
|
}
|
|
|
|
status = usb_query_and_lock_dev(dev_mgr, if_handle, &pdev);
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
goto ERROR_OUT;
|
|
}
|
|
|
|
#ifdef _TIANSHENG_DRIVER
|
|
if (!((pdev->pusb_dev_desc->idVendor == 0x03eb && pdev->pusb_dev_desc->idProduct == 0x2002)
|
|
|| (pdev->pusb_dev_desc->idVendor == 0x0ea0 && pdev->pusb_dev_desc->idProduct == 0x6803)
|
|
|| (pdev->pusb_dev_desc->idVendor == 0x0ef5 && pdev->pusb_dev_desc->idProduct == 0x2202)))
|
|
{
|
|
// check TianSheng's product
|
|
goto ERROR_OUT;
|
|
}
|
|
#endif
|
|
|
|
pdev_obj = umss_create_device(dev_mgr, pdrvr, if_handle, TRUE);
|
|
if (pdev_obj == NULL)
|
|
{
|
|
goto ERROR_OUT;
|
|
}
|
|
|
|
lock_dev(pdev, FALSE);
|
|
if (dev_state(pdev) == USB_DEV_STATE_ZOMB ||
|
|
dev_mgr_set_if_driver(dev_mgr, if_handle, pdrvr, pdev) == FALSE)
|
|
{
|
|
unlock_dev(pdev, FALSE);
|
|
if (pdev_obj)
|
|
{
|
|
umss_delete_device(dev_mgr, pdrvr, pdev_obj, TRUE);
|
|
}
|
|
goto ERROR_OUT;
|
|
}
|
|
|
|
if (pdev->usb_config)
|
|
{
|
|
pdev->usb_config->interf[if_idx].if_ext = pdev_obj;
|
|
pdev->usb_config->interf[if_idx].if_ext_size = 0;
|
|
}
|
|
// olympus dev needs special care
|
|
if (UMSS_OLYMPUS_VENDOR_ID == pdev->pusb_dev_desc->idVendor)
|
|
status = TRUE;
|
|
else
|
|
status = FALSE;
|
|
|
|
unlock_dev(pdev, FALSE);
|
|
|
|
pdev_ext = (PUMSS_DEVICE_EXTENSION) pdev_obj->DeviceExtension;
|
|
|
|
pdev_ext->desc_buf = desc_buf;
|
|
pdev_ext->pif_desc = NULL;
|
|
pdev_ext->pin_endp_desc = pdev_ext->pout_endp_desc = NULL;
|
|
pconfig_desc = (PUSB_CONFIGURATION_DESC) desc_buf;
|
|
pif_desc = (PUSB_INTERFACE_DESC) (&pconfig_desc[1]);
|
|
|
|
if (status)
|
|
pdev_ext->flags |= UMSS_DEV_FLAG_OLYMPUS_DEV;
|
|
|
|
//search for our if
|
|
for(i = 0; ((UCHAR) i) < if_idx; i++)
|
|
{
|
|
if (usb_skip_if_and_altif((PUCHAR *) & pif_desc) == FALSE)
|
|
break;
|
|
}
|
|
pdev_ext->pif_desc = pif_desc;
|
|
|
|
if (pdev_ext->pif_desc)
|
|
{
|
|
pendp_desc = (PUSB_ENDPOINT_DESC) & pif_desc[1];
|
|
for(i = 0; ((UCHAR) i) < pif_desc->bNumEndpoints; i++)
|
|
{
|
|
if (pendp_desc->bDescriptorType == USB_DT_ENDPOINT
|
|
&& pendp_desc->bLength == sizeof(USB_ENDPOINT_DESC))
|
|
{
|
|
if ((pendp_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
|
|
{
|
|
pdev_ext->pint_endp_desc = pendp_desc;
|
|
pdev_ext->int_endp_idx = (UCHAR) i;
|
|
}
|
|
else if ((pendp_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)
|
|
{
|
|
if (pendp_desc->bEndpointAddress & USB_DIR_IN)
|
|
{
|
|
pdev_ext->pin_endp_desc = pendp_desc;
|
|
pdev_ext->in_endp_idx = (UCHAR) i;
|
|
}
|
|
else
|
|
{
|
|
pdev_ext->pout_endp_desc = pendp_desc;
|
|
pdev_ext->out_endp_idx = (UCHAR) i;
|
|
}
|
|
}
|
|
pendp_desc = &pendp_desc[1];
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
// notify the class driver, some device comes
|
|
pdrvr_ext = (PUMSS_DRVR_EXTENSION) pdrvr->driver_ext;
|
|
if (pdrvr_ext && pdrvr_ext->class_driver_info.add_device && pdrvr_ext->class_driver_info.fdo_driver)
|
|
pdrvr_ext->class_driver_info.add_device(pdrvr_ext->class_driver_info.fdo_driver, pdev_obj);
|
|
|
|
usb_unlock_dev(pdev);
|
|
return TRUE;
|
|
|
|
ERROR_OUT:
|
|
if (desc_buf)
|
|
usb_free_mem(desc_buf);
|
|
|
|
if (purb)
|
|
usb_free_mem(purb);
|
|
|
|
usb_unlock_dev(pdev);
|
|
|
|
desc_buf = NULL;
|
|
purb = NULL;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN
|
|
umss_if_disconnect(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE if_handle)
|
|
{
|
|
LONG if_idx;
|
|
NTSTATUS status;
|
|
PUSB_DEV pdev;
|
|
PUSB_DRIVER pdrvr = NULL;
|
|
PDEVICE_OBJECT dev_obj = NULL;
|
|
PUMSS_DRVR_EXTENSION pdrvr_ext;
|
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
|
|
|
if (dev_mgr == NULL || if_handle == 0)
|
|
return FALSE;
|
|
|
|
pdev = NULL;
|
|
if_idx = if_idx_from_handle(if_handle);
|
|
//
|
|
// special use of the lock dev, simply use this routine to get the dev
|
|
//
|
|
status = usb_query_and_lock_dev(dev_mgr, if_handle, &pdev);
|
|
if (pdev == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
// must be a bug
|
|
TRAP();
|
|
}
|
|
if (pdev->usb_config)
|
|
{
|
|
pdrvr = pdev->usb_config->interf[if_idx].pif_drv;
|
|
dev_obj = (PDEVICE_OBJECT) pdev->usb_config->interf[if_idx].if_ext;
|
|
}
|
|
pdev = NULL;
|
|
|
|
// notify the class driver, some device gone
|
|
pdrvr_ext = (PUMSS_DRVR_EXTENSION) pdrvr->driver_ext;
|
|
pdev_ext = dev_obj->DeviceExtension;
|
|
if (pdrvr_ext && pdrvr_ext->class_driver_info.pnp_dispatch)
|
|
pdrvr_ext->class_driver_info.pnp_dispatch(dev_obj, UMSS_PNPMSG_DISCONNECT, NULL);
|
|
|
|
// no need to unlock the dev
|
|
return umss_delete_device(dev_mgr, pdrvr, dev_obj, TRUE);
|
|
}
|
|
|
|
BOOLEAN
|
|
umss_if_stop(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE if_handle)
|
|
{
|
|
LONG if_idx;
|
|
NTSTATUS status;
|
|
PUSB_DEV pdev;
|
|
PUSB_DRIVER pdrvr = NULL;
|
|
PDEVICE_OBJECT dev_obj = NULL;
|
|
PUMSS_DRVR_EXTENSION pdrvr_ext;
|
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
|
USE_BASIC_NON_PENDING_IRQL;
|
|
|
|
if (dev_mgr == NULL || if_handle == 0)
|
|
return FALSE;
|
|
|
|
pdev = NULL;
|
|
if_idx = if_idx_from_handle(if_handle);
|
|
|
|
// special use of the lock dev, simply use this routine to get the dev
|
|
status = usb_query_and_lock_dev(dev_mgr, if_handle, &pdev);
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
lock_dev(pdev, FALSE);
|
|
if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (pdev->usb_config)
|
|
{
|
|
pdrvr = pdev->usb_config->interf[if_idx].pif_drv;
|
|
dev_obj = (PDEVICE_OBJECT) pdev->usb_config->interf[if_idx].if_ext;
|
|
}
|
|
unlock_dev(pdev, FALSE);
|
|
|
|
// notify the class driver, some device stops
|
|
pdev_ext = dev_obj->DeviceExtension;
|
|
pdrvr_ext = (PUMSS_DRVR_EXTENSION) pdrvr->driver_ext;
|
|
if (pdrvr_ext && pdrvr_ext->class_driver_info.pnp_dispatch)
|
|
pdrvr_ext->class_driver_info.pnp_dispatch(dev_obj, UMSS_PNPMSG_STOP, NULL);
|
|
|
|
usb_unlock_dev(pdev);
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
umss_load_class_driver(PVOID context)
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING unicode_string;
|
|
|
|
UNREFERENCED_PARAMETER(context);
|
|
|
|
//
|
|
// let's load the class driver
|
|
//
|
|
RtlInitUnicodeString(&unicode_string,
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\usbstor");
|
|
status = ZwLoadDriver(&unicode_string);
|
|
usb_dbg_print(DBGLVL_MAXIMUM,
|
|
("umss_load_class_driver(): try to load class driver, status=0x%x\n", status));
|
|
}
|
|
|
|
BOOLEAN
|
|
umss_if_driver_init(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver)
|
|
{
|
|
PUMSS_DRVR_EXTENSION pdrvr_ext;
|
|
|
|
if (dev_mgr == NULL || pdriver == NULL)
|
|
return FALSE;
|
|
|
|
//init driver structure, no PNP table functions
|
|
|
|
pdriver->driver_desc.flags = USB_DRIVER_FLAG_IF_CAPABLE;
|
|
pdriver->driver_desc.vendor_id = 0x0000; // USB Vendor ID
|
|
pdriver->driver_desc.product_id = 0x0000; // USB Product ID.
|
|
pdriver->driver_desc.release_num = 0x100; // Release Number of Device
|
|
|
|
pdriver->driver_desc.config_val = 1; // Configuration Value
|
|
pdriver->driver_desc.if_num = 1; // Interface Number
|
|
pdriver->driver_desc.if_class = USB_CLASS_MASS_STORAGE; // 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 Mass Storage interface 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.
|
|
|
|
pdriver->driver_ext = usb_alloc_mem(NonPagedPool, sizeof(UMSS_DRVR_EXTENSION));
|
|
if (!pdriver->driver_ext) return FALSE;
|
|
|
|
pdriver->driver_ext_size = sizeof(UMSS_DRVR_EXTENSION);
|
|
|
|
RtlZeroMemory(pdriver->driver_ext, sizeof(UMSS_DRVR_EXTENSION));
|
|
|
|
pdrvr_ext = (PUMSS_DRVR_EXTENSION) pdriver->driver_ext;
|
|
pdrvr_ext->dev_count = 0;
|
|
InitializeListHead(&pdrvr_ext->dev_list);
|
|
ExInitializeFastMutex(&pdrvr_ext->dev_list_mutex);
|
|
|
|
pdriver->disp_tbl.version = 1;
|
|
pdriver->disp_tbl.dev_connect = umss_if_connect;
|
|
pdriver->disp_tbl.dev_disconnect = umss_if_disconnect;
|
|
pdriver->disp_tbl.dev_stop = umss_if_stop;
|
|
pdriver->disp_tbl.dev_reserved = NULL;
|
|
|
|
if ((pdrvr_ext->port_dev_obj = umss_create_port_device(dev_mgr, pdriver)) == NULL)
|
|
{
|
|
usb_free_mem(pdriver->driver_ext);
|
|
pdriver->driver_ext = NULL;
|
|
pdriver->driver_ext_size = 0;
|
|
pdriver->disp_tbl.dev_connect = NULL;
|
|
pdriver->disp_tbl.dev_stop = NULL;
|
|
pdriver->disp_tbl.dev_disconnect = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// let's load the class driver
|
|
//
|
|
umss_load_class_driver(NULL);
|
|
|
|
// umss_schedule_workitem( NULL, umss_load_class_driver, NULL, 0 );
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("umss_if_driver_init(): umss driver is initialized\n"));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// get the driver reg information for pnp notification to class
|
|
// driver.
|
|
// bug??? how if the driver info is returned while the driver
|
|
// is being unloaded.
|
|
// So the routine must be called when usb_query_and_lock_dev is
|
|
// called.
|
|
PCLASS_DRV_REG_INFO
|
|
umss_get_if_driver_info(PUSB_DEV_MANAGER dev_mgr, PUSB_DEV pdev, DEV_HANDLE if_handle)
|
|
{
|
|
PUMSS_DRVR_EXTENSION drvr_ext;
|
|
ULONG if_idx;
|
|
USE_BASIC_NON_PENDING_IRQL;
|
|
|
|
UNREFERENCED_PARAMETER(dev_mgr);
|
|
|
|
if_idx = if_idx_from_handle(if_handle);
|
|
if (if_idx >= 4) // max interfaces per config supports. defined in td.h
|
|
return NULL;
|
|
|
|
ASSERT(pdev != NULL);
|
|
|
|
lock_dev(pdev, FALSE);
|
|
if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
|
|
{
|
|
unlock_dev(pdev, FALSE);
|
|
usb_unlock_dev(pdev);
|
|
return NULL;
|
|
}
|
|
|
|
drvr_ext = NULL;
|
|
|
|
if (pdev->usb_config->interf[if_idx].pif_drv)
|
|
drvr_ext = (PUMSS_DRVR_EXTENSION) pdev->usb_config->interf[if_idx].pif_drv->driver_ext;
|
|
else
|
|
TRAP();
|
|
|
|
unlock_dev(pdev, FALSE);
|
|
|
|
if (drvr_ext == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return &drvr_ext->class_driver_info;
|
|
}
|
|
|
|
VOID NTAPI
|
|
umss_worker(IN PVOID reference)
|
|
{
|
|
PUMSS_WORKER_PACKET worker_packet;
|
|
PUSB_DEV pdev;
|
|
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("umss_worker(): entering...\n"));
|
|
worker_packet = (PUMSS_WORKER_PACKET) reference;
|
|
worker_packet->completion(worker_packet->context);
|
|
if (worker_packet->dev_mgr && worker_packet->pdev)
|
|
{
|
|
pdev = (PUSB_DEV) worker_packet->pdev;
|
|
usb_unlock_dev(pdev);
|
|
pdev = NULL;
|
|
}
|
|
usb_free_mem(worker_packet);
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("umss_worker(): exit\n"));
|
|
}
|
|
|
|
/*++
|
|
Routine Description:
|
|
|
|
Wrapper for handling worker thread callbacks, it is importent to
|
|
lock the dev from being deleted by calling usb_query_and_lock_dev
|
|
and in umss_worker, call the usb_unlock_dev to release the ref
|
|
count. One exception is that the umss_if_disconnect call this
|
|
function to delete the device object that is still held by some
|
|
others, and deferred deletion is required.
|
|
|
|
Arguments:
|
|
|
|
Routine - Routine to be called when this work-item is processed
|
|
Context - Value to be passed to worker routine
|
|
|
|
Return Value:
|
|
TRUE if work item queued
|
|
FALSE if work item not queued
|
|
|
|
--*/
|
|
BOOLEAN
|
|
umss_schedule_workitem(PVOID context,
|
|
UMSS_WORKER_ROUTINE completion, PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle)
|
|
{
|
|
BOOLEAN ret_val = TRUE;
|
|
PWORK_QUEUE_ITEM workitem;
|
|
PUMSS_WORKER_PACKET worker_packet;
|
|
|
|
worker_packet = usb_alloc_mem(NonPagedPool, sizeof(WORK_QUEUE_ITEM) + sizeof(UMSS_WORKER_PACKET));
|
|
|
|
if (worker_packet)
|
|
{
|
|
RtlZeroMemory(worker_packet, sizeof(WORK_QUEUE_ITEM) + sizeof(UMSS_WORKER_PACKET));
|
|
|
|
workitem = (PWORK_QUEUE_ITEM) & worker_packet[1];
|
|
worker_packet->completion = completion;
|
|
worker_packet->context = context;
|
|
|
|
if (dev_mgr != NULL && dev_handle != 0)
|
|
{
|
|
PUSB_DEV pdev;
|
|
// lock the device until the workitem is executed.
|
|
if (usb_query_and_lock_dev(dev_mgr, dev_handle, &pdev) == STATUS_SUCCESS)
|
|
{
|
|
worker_packet->dev_mgr = dev_mgr;
|
|
worker_packet->pdev = pdev;
|
|
}
|
|
else
|
|
{
|
|
usb_free_mem(worker_packet);
|
|
return FALSE;
|
|
}
|
|
}
|
|
// Initialize the work-item
|
|
ExInitializeWorkItem(workitem, umss_worker, worker_packet);
|
|
|
|
// Schedule the work-item
|
|
ExQueueWorkItem(workitem, DelayedWorkQueue);
|
|
|
|
usb_dbg_print(DBGLVL_MINIMUM, ("umss_schedule_workitem(): work-item queued\n"));
|
|
}
|
|
else
|
|
{
|
|
usb_dbg_print(DBGLVL_MINIMUM, ("umss_schedule_workitem(): Failed to allocate work-item\n"));
|
|
ret_val = FALSE;
|
|
}
|
|
|
|
return ret_val;
|
|
}
|
|
|
|
NTSTATUS
|
|
umss_process_srb(PDEVICE_OBJECT dev_obj, PIRP irp)
|
|
{
|
|
NTSTATUS status;
|
|
PUSB_DEV pdev;
|
|
PIO_STACK_LOCATION cur_stack;
|
|
PUMSS_DEVICE_EXTENSION pdev_ext;
|
|
PSCSI_REQUEST_BLOCK srb;
|
|
|
|
if (dev_obj == NULL || irp == NULL)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
pdev = NULL;
|
|
cur_stack = IoGetCurrentIrpStackLocation(irp);
|
|
srb = cur_stack->Parameters.Scsi.Srb;
|
|
|
|
if (srb == NULL || srb->DataTransferLength > 65536)
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto ERROR_OUT;
|
|
}
|
|
|
|
irp->IoStatus.Status = STATUS_SUCCESS;
|
|
irp->IoStatus.Information = 0;
|
|
|
|
pdev_ext = (PUMSS_DEVICE_EXTENSION) dev_obj->DeviceExtension;
|
|
if ((status = usb_query_and_lock_dev(pdev_ext->dev_mgr, pdev_ext->dev_handle, &pdev)) != STATUS_SUCCESS)
|
|
{
|
|
PSENSE_DATA sense_buf;
|
|
srb->SrbStatus = SRB_STATUS_NO_DEVICE;
|
|
|
|
//
|
|
// let's build the srb status for class driver
|
|
//
|
|
srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
|
|
RtlZeroMemory(srb->SenseInfoBuffer, srb->SenseInfoBufferLength);
|
|
if (!(srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE))
|
|
{
|
|
sense_buf = (PSENSE_DATA) srb->SenseInfoBuffer;
|
|
sense_buf->ErrorCode = 0x70;
|
|
sense_buf->Valid = 1;
|
|
sense_buf->SenseKey = SCSI_SENSE_NOT_READY;
|
|
sense_buf->AdditionalSenseCode = SCSI_ADSENSE_NO_MEDIA_IN_DEVICE;
|
|
sense_buf->AdditionalSenseLength = 10;
|
|
}
|
|
goto ERROR_OUT;
|
|
}
|
|
|
|
switch (srb->Function)
|
|
{
|
|
case SRB_FUNCTION_EXECUTE_SCSI:
|
|
{
|
|
IO_PACKET io_packet;
|
|
RtlZeroMemory(&io_packet, sizeof(io_packet));
|
|
|
|
io_packet.flags |= IOP_FLAG_SRB_TRANSFER;
|
|
if (srb->SrbFlags & SRB_FLAGS_DATA_IN)
|
|
io_packet.flags |= IOP_FLAG_DIR_IN;
|
|
if (!(srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE))
|
|
io_packet.flags |= IOP_FLAG_REQ_SENSE;
|
|
|
|
io_packet.cdb_length = srb->CdbLength;
|
|
RtlCopyMemory(io_packet.cdb, srb->Cdb, sizeof(io_packet.cdb));
|
|
io_packet.lun = 0;
|
|
|
|
if (srb->SrbFlags & SRB_FLAGS_NO_DATA_TRANSFER)
|
|
{
|
|
io_packet.data_buffer = NULL;
|
|
io_packet.data_length = 0;
|
|
}
|
|
else
|
|
{
|
|
if ((irp->Flags & (IRP_READ_OPERATION | IRP_WRITE_OPERATION))
|
|
&& !(irp->Flags & IRP_PAGING_IO))
|
|
{
|
|
//
|
|
// since these operations does not allign the buffer on page boundary
|
|
// and some unknown traps in window NT, we have to copy to a buffer
|
|
// we allocated
|
|
io_packet.data_buffer = usb_alloc_mem(NonPagedPool, srb->DataTransferLength);
|
|
if (irp->Flags & IRP_WRITE_OPERATION)
|
|
{
|
|
PULONG dest_buf, src_buf;
|
|
ULONG i;
|
|
|
|
dest_buf = (PULONG) io_packet.data_buffer;
|
|
src_buf = (PULONG) srb->DataBuffer;
|
|
|
|
if (src_buf && dest_buf)
|
|
{
|
|
for(i = 0; i < (srb->DataTransferLength >> 2); i++)
|
|
{
|
|
dest_buf[i] = src_buf[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
io_packet.data_buffer = srb->DataBuffer;
|
|
|
|
io_packet.data_length = srb->DataTransferLength;
|
|
}
|
|
|
|
if (io_packet.flags & IOP_FLAG_REQ_SENSE)
|
|
{
|
|
io_packet.sense_data = srb->SenseInfoBuffer;
|
|
io_packet.sense_data_length = srb->SenseInfoBufferLength;
|
|
}
|
|
|
|
io_packet.pirp = irp;
|
|
|
|
// do some conversions
|
|
if (pdev_ext->pif_desc->bInterfaceSubClass == UMSS_SUBCLASS_SFF8070I)
|
|
{
|
|
if (umss_tsc_to_sff(&io_packet) == FALSE)
|
|
{
|
|
status = STATUS_DEVICE_PROTOCOL_ERROR;
|
|
|
|
usb_dbg_print(DBGLVL_MAXIMUM,
|
|
("umss_process_srb(): error converting to sff proto, 0x%x\n", status));
|
|
srb->SrbStatus = SRB_STATUS_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pdev_ext->pif_desc->bInterfaceProtocol == PROTOCOL_BULKONLY)
|
|
{
|
|
//
|
|
// currently we support only transparent scsi command set
|
|
//
|
|
if (pdev_ext->pif_desc->bInterfaceSubClass == UMSS_SUBCLASS_SCSI_TCS ||
|
|
pdev_ext->pif_desc->bInterfaceSubClass == UMSS_SUBCLASS_SFF8070I)
|
|
status = umss_bulkonly_startio(pdev_ext, &io_packet);
|
|
else
|
|
status = STATUS_DEVICE_PROTOCOL_ERROR;
|
|
}
|
|
else if (pdev_ext->pif_desc->bInterfaceProtocol == PROTOCOL_CB
|
|
|| pdev_ext->pif_desc->bInterfaceProtocol == PROTOCOL_CBI)
|
|
{
|
|
status = umss_cbi_startio(pdev_ext, &io_packet);
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_DEVICE_PROTOCOL_ERROR;
|
|
}
|
|
|
|
if (status != STATUS_PENDING && status != STATUS_SUCCESS)
|
|
{
|
|
// error occured
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("umss_process_srb(): error sending request, 0x%x\n", status));
|
|
srb->SrbStatus = SRB_STATUS_ERROR;
|
|
}
|
|
break;
|
|
}
|
|
case SRB_FUNCTION_CLAIM_DEVICE:
|
|
{
|
|
srb->DataBuffer = (PVOID) dev_obj;
|
|
}
|
|
case SRB_FUNCTION_SHUTDOWN:
|
|
case SRB_FUNCTION_FLUSH:
|
|
case SRB_FUNCTION_RESET_BUS:
|
|
case SRB_FUNCTION_FLUSH_QUEUE:
|
|
case SRB_FUNCTION_RELEASE_QUEUE:
|
|
case SRB_FUNCTION_RELEASE_DEVICE:
|
|
default:
|
|
{
|
|
// for usb flash disk, they are luxurious
|
|
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("umss_process_srb(): current srb->Function=0x%x\n",
|
|
srb->Function));
|
|
|
|
status = STATUS_SUCCESS;
|
|
srb->SrbStatus = SRB_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
usb_unlock_dev(pdev);
|
|
pdev = NULL;
|
|
|
|
ERROR_OUT:
|
|
irp->IoStatus.Status = status;
|
|
if (status != STATUS_PENDING)
|
|
{
|
|
IoStartNextPacket(dev_obj, FALSE);
|
|
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
//
|
|
// UMSS_COMPLETE_START_IO( dev_obj, status, irp );
|
|
//
|
|
return status;
|
|
}
|
|
|
|
BOOLEAN
|
|
umss_tsc_to_sff(PIO_PACKET io_packet)
|
|
{
|
|
if (io_packet == NULL)
|
|
return FALSE;
|
|
|
|
io_packet->cdb_length = 12;
|
|
if (io_packet->cdb[0] == SCSIOP_MODE_SENSE)
|
|
{
|
|
io_packet->cdb[0] = 0x5a; // mode sense( 10 )
|
|
io_packet->cdb[8] = io_packet->cdb[4];
|
|
io_packet->cdb[4] = 0;
|
|
if (io_packet->cdb[8] < 8)
|
|
io_packet->cdb[8] = 8;
|
|
|
|
io_packet->data_length = 8;
|
|
return TRUE;
|
|
}
|
|
if (io_packet->cdb[0] == SCSIOP_REASSIGN_BLOCKS ||
|
|
io_packet->cdb[0] == SCSIOP_RESERVE_UNIT || io_packet->cdb[0] == SCSIOP_RELEASE_UNIT)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
umss_fix_sff_result(PIO_PACKET io_packet, SCSI_REQUEST_BLOCK *srb)
|
|
{
|
|
PBYTE buf;
|
|
if (io_packet->cdb[0] != 0x5a)
|
|
return;
|
|
// the following is not right since it has to be 0x3f, return all pages
|
|
// if( io_packet->cdb[ 2 ] != 0 )
|
|
// return;
|
|
srb->DataTransferLength = 4;
|
|
buf = io_packet->data_buffer;
|
|
// convert the mode param to scsi II
|
|
buf[0] = buf[1];
|
|
buf[1] = buf[2];
|
|
buf[2] = buf[3];
|
|
buf[3] = 0;
|
|
return;
|
|
}
|