gendrv.c

来自「这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统」· C语言 代码 · 共 1,827 行 · 第 1/4 页

C
1,827
字号
/**
 * gendrv.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 non-driver device
#include "usbdriver.h"
#include "gendrv.h"

#define if_dev( dev_obj ) \
( ( ( ( PGENDRV_DEVICE_EXTENSION)dev_obj->DeviceExtension )->pdriver->driver_desc.flags & USB_DRIVER_FLAG_IF_CAPABLE ) != 0 )

#define GENDRV_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, gendrv_cancel_queued_irp ); \
    return STATUS_PENDING;\
}

#define GENDRV_COMPLETE_START_IO( dev_OBJ, staTUS, iRP ) \
{\
	iRP->IoStatus.Status = staTUS;\
	if( staTUS != STATUS_PENDING )\
	{\
		IoStartNextPacket( dev_OBJ, TRUE );\
		IoCompleteRequest( iRP, IO_NO_INCREMENT );\
	}\
	return;\
}

extern POBJECT_TYPE NTSYSAPI IoDriverObjectType;

extern VOID disp_urb_completion(PURB purb, PVOID context);


VOID disp_noio_urb_completion(PURB purb, PVOID context);

NTSYSAPI NTSTATUS NTAPI ZwLoadDriver(IN PUNICODE_STRING DriverServiceName);

NTSYSAPI NTSTATUS NTAPI ZwClose(IN HANDLE Handle);

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);

BOOLEAN gendrv_if_driver_destroy(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver);

VOID gendrv_set_cfg_completion(PURB purb, PVOID context);

BOOLEAN gendrv_connect(PDEV_CONNECT_DATA param, DEV_HANDLE dev_handle);

BOOLEAN gendrv_stop(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle);

BOOLEAN gendrv_disconnect(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle);

VOID gendrv_startio(IN PDEVICE_OBJECT dev_obj, IN PIRP irp);

VOID NTAPI gendrv_cancel_queued_irp(PDEVICE_OBJECT pdev_obj, PIRP pirp);

VOID gendrv_release_ext_drvr_entry(PGENDRV_DRVR_EXTENSION pdrvr_ext, PGENDRV_EXT_DRVR_ENTRY pentry);

VOID gendrv_clean_up_queued_irps(PDEVICE_OBJECT dev_obj);

PGENDRV_EXT_DRVR_ENTRY gendrv_alloc_ext_drvr_entry(PGENDRV_DRVR_EXTENSION pdrvr_ext);

PDRIVER_OBJECT gendrv_open_ext_driver(PUNICODE_STRING unicode_string);

NTSTATUS
gendrv_get_key_value(IN HANDLE KeyHandle, IN PWSTR ValueName, OUT PKEY_VALUE_FULL_INFORMATION * Information);

NTSTATUS
gendrv_open_reg_key(OUT PHANDLE handle,
                    IN HANDLE base_handle OPTIONAL,
                    IN PUNICODE_STRING keyname, IN ACCESS_MASK desired_access, IN BOOLEAN create);

BOOLEAN gendrv_do_disconnect(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE if_handle, BOOLEAN is_if);

BOOLEAN gendrv_do_stop(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle, BOOLEAN is_if);

NTSTATUS gendrv_send_pnp_msg(ULONG msg, PDEVICE_OBJECT pdev_obj, PVOID pctx);

BOOLEAN gendrv_delete_device(PUSB_DEV_MANAGER dev_mgr, PDEVICE_OBJECT dev_obj);

PDEVICE_OBJECT gendrv_create_device(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER gen_drvr, DEV_HANDLE dev_handle);

PDRIVER_OBJECT gendrv_load_ext_drvr(PGENDRV_DRVR_EXTENSION pdrvr_ext, PUSB_DESC_HEADER pdesc);

PDRIVER_OBJECT gendrv_find_drvr_by_key(PGENDRV_DRVR_EXTENSION pdrvr_ext, ULONG key);

ULONG gendrv_make_key(PUSB_DESC_HEADER pdesc);

BOOLEAN
gendrv_driver_init(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver)
{
    PGENDRV_DRVR_EXTENSION pdrvr_ext;

    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 = 0xff;       // Interface Class
    pdriver->driver_desc.if_sub_class = 0xff;   // Interface SubClass
    pdriver->driver_desc.if_protocol = 0xff;    // Interface Protocol

    pdriver->driver_desc.driver_name = "USB generic dev driver";        // Driver name for Name Registry
    pdriver->driver_desc.dev_class = USB_CLASS_VENDOR_SPEC;
    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(GENDRV_DRVR_EXTENSION));
    pdriver->driver_ext_size = sizeof(GENDRV_DRVR_EXTENSION);

    RtlZeroMemory(pdriver->driver_ext, pdriver->driver_ext_size);
    pdrvr_ext = (PGENDRV_DRVR_EXTENSION) pdriver->driver_ext;

    // InitializeListHead( &pdrvr_ext->dev_list );
    InitializeListHead(&pdrvr_ext->ext_drvr_list);
    pdrvr_ext->ext_drvr_count = 0;
    ExInitializeFastMutex(&pdrvr_ext->drvr_ext_mutex);

    pdriver->disp_tbl.version = 1;
    pdriver->disp_tbl.dev_connect = gendrv_connect;
    pdriver->disp_tbl.dev_disconnect = gendrv_disconnect;
    pdriver->disp_tbl.dev_stop = gendrv_stop;
    pdriver->disp_tbl.dev_reserved = NULL;

    return TRUE;
}

BOOLEAN
gendrv_driver_destroy(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver)
{
    return gendrv_if_driver_destroy(dev_mgr, pdriver);
}

BOOLEAN
gendrv_connect(PDEV_CONNECT_DATA param, DEV_HANDLE dev_handle)
{
    PURB purb;
    PUSB_CTRL_SETUP_PACKET psetup;
    NTSTATUS status;
    PUCHAR buf;
    LONG i;
    PUSB_CONFIGURATION_DESC pconfig_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, ("gendrv_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;
    }

    // check the config desc valid
    pconfig_desc = (PUSB_CONFIGURATION_DESC) buf;
    if (pconfig_desc->wTotalLength > 512)
    {
        usb_free_mem(buf);
        usb_free_mem(purb);
        usb_dbg_print(DBGLVL_MAXIMUM, ("gendrv_connect(): error, bad configuration desc\n"));
        return FALSE;
    }

    i = pconfig_desc->bConfigurationValue;
    usb_free_mem(buf);
    buf = NULL;

    //set the configuration
    urb_init(purb);
    purb->endp_handle = dev_handle | 0xffff;
    purb->data_buffer = NULL;
    purb->data_length = 0;
    purb->completion = gendrv_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, ("gendrv_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;
}

BOOLEAN
gendrv_event_select_driver(PUSB_DEV pdev,       //always null. we do not use this param
                           ULONG event, ULONG context, ULONG param)
{
    //
    // try to search the registry to find one driver.
    // if found, create the PDO, load the driver. 
    // and call its AddDevice.
    //
    LONG i;
    PUSB_DRIVER pdrvr;
    PGENDRV_DRVR_EXTENSION pdrvr_ext;
    PGENDRV_EXT_DRVR_ENTRY pentry;
    PGENDRV_DEVICE_EXTENSION pdev_ext;
    PUSB_CONFIGURATION_DESC pconfig_desc;
    PUSB_DEV_MANAGER dev_mgr;

    PDEVICE_OBJECT pdev_obj;
    PDRIVER_OBJECT pdrvr_obj;
    PLIST_ENTRY pthis, pnext;

    USE_BASIC_NON_PENDING_IRQL;

    UNREFERENCED_PARAMETER(context);
    UNREFERENCED_PARAMETER(event);

    if (pdev == NULL)
        return FALSE;

    usb_dbg_print(DBGLVL_MAXIMUM, ("gendrv_event_select_driver(): entering...\n"));

    pdrvr = (PUSB_DRIVER) param;
    //original code: pconfig_desc = (PUSB_CONFIGURATION_DESC) pdev->desc_buf[sizeof(USB_DEVICE_DESC)];
    pconfig_desc = (PUSB_CONFIGURATION_DESC) &pdev->desc_buf[sizeof(USB_DEVICE_DESC)];
    pdrvr_ext = (PGENDRV_DRVR_EXTENSION) pdrvr->driver_ext;

    //
    // well, let's do the hard work to see if there is a class driver 
    // for this device.
    // in the event routine, we have no need to check if the device is zomb or
    // not, it must be alive there.
    //
    i = gendrv_make_key((PUSB_DESC_HEADER) pdev->pusb_dev_desc);
    if (i == -1)
    {
        return FALSE;
    }

    pdrvr_obj = gendrv_find_drvr_by_key(pdrvr_ext, (ULONG) i);
    if (!pdrvr_obj)
    {
        if ((pdrvr_obj = gendrv_load_ext_drvr(pdrvr_ext, (PUSB_DESC_HEADER) pdev->pusb_dev_desc)) == NULL)
            return FALSE;
    }

    dev_mgr = dev_mgr_from_dev(pdev);
    pdev_obj = gendrv_create_device(dev_mgr, pdrvr, usb_make_handle(pdev->dev_id, 0, 0));
    if (pdev_obj == NULL)
    {
        goto ERROR_OUT;
    }

    lock_dev(pdev, FALSE);
    if (dev_state(pdev) == USB_DEV_STATE_ZOMB ||
        dev_mgr_set_driver(dev_mgr, usb_make_handle(pdev->dev_id, 0, 0), pdrvr, pdev) == FALSE)
    {
        unlock_dev(pdev, FALSE);
        gendrv_delete_device(dev_mgr, pdev_obj);
        goto ERROR_OUT;
    }

    if (pdev->usb_config)
    {
        pdev->dev_obj = pdev_obj;
    }

    unlock_dev(pdev, FALSE);

    pdev_ext = (PGENDRV_DEVICE_EXTENSION) pdev_obj->DeviceExtension;
    pdev_ext->desc_buf = usb_alloc_mem(NonPagedPool, 512);
    RtlCopyMemory(pdev_ext->desc_buf, pconfig_desc, 512);

    // insert the device to the dev_list
    ExAcquireFastMutex(&pdrvr_ext->drvr_ext_mutex);
    ListFirst(&pdrvr_ext->ext_drvr_list, pthis);
    pentry = NULL;
    while (pthis)
    {
        pentry = (PGENDRV_EXT_DRVR_ENTRY) pthis;
        if (pentry->pext_drvr == pdrvr_obj)
            break;
        ListNext(&pdrvr_ext->ext_drvr_list, pthis, pnext);
        pthis = pnext;
        pentry = NULL;
    }
    ASSERT(pentry);
    InsertTailList(&pentry->dev_list, &pdev_ext->dev_obj_link);
    pdev_ext->ext_drvr_entry = pentry;
    pentry->ref_count++;
    ExReleaseFastMutex(&pdrvr_ext->drvr_ext_mutex);

    // notify the class driver, some device comes
    gendrv_send_pnp_msg(GENDRV_MSG_ADDDEVICE, pdev_obj, pdrvr_obj);
    usb_unlock_dev(pdev);
    return TRUE;

  ERROR_OUT:

    usb_unlock_dev(pdev);
    return FALSE;
}

VOID
gendrv_set_cfg_completion(PURB purb, PVOID context)
{
    DEV_HANDLE dev_handle;
    PUSB_DEV_MANAGER dev_mgr;
    PUSB_DRIVER pdriver;
    NTSTATUS status;
    PUSB_DEV pdev;
    PUSB_EVENT pevent;
    USE_BASIC_NON_PENDING_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;
    }
    usb_unlock_dev(pdev);       // safe to release the pdev ref since we are in urb completion


    KeAcquireSpinLockAtDpcLevel(&dev_mgr->event_list_lock);
    lock_dev(pdev, TRUE);

    if (dev_state(pdev) >= USB_DEV_STATE_BEFORE_ZOMB)
    {
        unlock_dev(pdev, TRUE);
        KeReleaseSpinLockFromDpcLevel(&dev_mgr->event_list_lock);
        return;
    }

    if (dev_mgr_set_driver(dev_mgr, dev_handle, pdriver, pdev) == FALSE)
    {
        unlock_dev(pdev, TRUE);
        KeReleaseSpinLockFromDpcLevel(&dev_mgr->event_list_lock);
        return;
    }

    //transit the state to configured
    pdev->flags &= ~USB_DEV_STATE_MASK;
    pdev->flags |= USB_DEV_STATE_CONFIGURED;

    pevent = alloc_event(&dev_mgr->event_pool, 1);
    if (pevent == NULL)
    {
        unlock_dev(pdev, TRUE);
        KeReleaseSpinLockFromDpcLevel(&dev_mgr->event_list_lock);
    }

    pevent->flags = USB_EVENT_FLAG_ACTIVE;
    pevent->event = USB_EVENT_DEFAULT;
    pevent->pdev = pdev;
    pevent->context = 0;
    pevent->param = (ULONG) pdriver;
    pevent->pnext = 0;          //vertical queue for serialized operation
    pevent->process_event = (PROCESS_EVENT) gendrv_event_select_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);
    unlock_dev(pdev, TRUE);
    KeReleaseSpinLockFromDpcLevel(&dev_mgr->event_list_lock);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?