gendrv.c

来自「ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机」· C语言 代码 · 共 1,827 行 · 第 1/4 页

C
1,827
字号

    return;
}


BOOLEAN
gendrv_stop(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle)
{
    if (dev_mgr == NULL)
        return FALSE;
    return gendrv_do_stop(dev_mgr, dev_handle, FALSE);
}

BOOLEAN
gendrv_disconnect(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle)
{
    if (dev_mgr == NULL)
        return FALSE;
    return gendrv_do_disconnect(dev_mgr, dev_handle, FALSE);
}

BOOLEAN
gendrv_build_reg_string(PUSB_DESC_HEADER pdesc, PUNICODE_STRING pus)
{

    CHAR desc_str[128];
    STRING atemp;

    if (pdesc == NULL || pus == NULL)
        return FALSE;

    if (pdesc->bDescriptorType == USB_DT_DEVICE)
    {
        PUSB_DEVICE_DESC pdev_desc;
        pdev_desc = (PUSB_DEVICE_DESC) pdesc;
        sprintf(desc_str, "%sv_%04x&p_%04x",
                "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\ehci\\device\\",
                pdev_desc->idVendor, pdev_desc->idProduct);
    }
    else if (pdesc->bDescriptorType == USB_DT_INTERFACE)
    {
        PUSB_INTERFACE_DESC pif_desc;
        pif_desc = (PUSB_INTERFACE_DESC) pdesc;
        sprintf(desc_str, "%sc_%04x&s_%04x&p_%04x",
                "\\Registry\\Machine\\System\\CurrentControlSet\\Services\\ehci\\interface\\",
                pif_desc->bInterfaceClass, pif_desc->bInterfaceSubClass, pif_desc->bInterfaceProtocol);
    }
    else
        return FALSE;

    RtlInitString(&atemp, desc_str);
    RtlAnsiStringToUnicodeString(pus, &atemp, TRUE);
    return TRUE;
}

ULONG
gendrv_make_key(PUSB_DESC_HEADER pdesc)
{
    PUSB_DEVICE_DESC pdev_desc;
    PUSB_INTERFACE_DESC pif_desc;

    if (pdesc == NULL)
        return (ULONG) - 1;
    if (pdesc->bDescriptorType == USB_DT_DEVICE)
    {
        pdev_desc = (PUSB_DEVICE_DESC) pdesc;
        return ((((ULONG) pdev_desc->idVendor) << 16) | pdev_desc->idProduct);
    }
    else if (pdesc->bDescriptorType == USB_DT_INTERFACE)
    {
        pif_desc = (PUSB_INTERFACE_DESC) pdesc;
        return ((((ULONG) pif_desc->bInterfaceClass) << 16) |
                (((ULONG) pif_desc->bInterfaceSubClass) << 8) | ((ULONG) pif_desc->bInterfaceProtocol));
    }
    return (ULONG) - 1;
}

PDRIVER_OBJECT
gendrv_find_drvr_by_key(PGENDRV_DRVR_EXTENSION pdrvr_ext, ULONG key)
{
    PGENDRV_EXT_DRVR_ENTRY pentry;
    PLIST_ENTRY pthis, pnext;
    if (pdrvr_ext == NULL || key == (ULONG) - 1)
        return NULL;

    ExAcquireFastMutex(&pdrvr_ext->drvr_ext_mutex);
    ListFirst(&pdrvr_ext->ext_drvr_list, pthis);
    while (pthis)
    {
        pentry = (PGENDRV_EXT_DRVR_ENTRY) pthis;
        if (pentry->drvr_key == key)
        {
            ExReleaseFastMutex(&pdrvr_ext->drvr_ext_mutex);
            return pentry->pext_drvr;
        }
        ListNext(&pdrvr_ext->ext_drvr_list, pthis, pnext);
        pthis = pnext;
    }
    ExReleaseFastMutex(&pdrvr_ext->drvr_ext_mutex);

    return NULL;
}

PDRIVER_OBJECT
gendrv_load_ext_drvr(PGENDRV_DRVR_EXTENSION pdrvr_ext, PUSB_DESC_HEADER pdesc)
{
    PDRIVER_OBJECT pdrvr_obj;
    PGENDRV_EXT_DRVR_ENTRY pentry;
    UNICODE_STRING usz, svc_name, svc_key, utemp;
    PKEY_VALUE_FULL_INFORMATION val_info;
    PWCHAR val_buf;
    HANDLE handle;
    NTSTATUS status;

    if (pdrvr_ext == NULL || pdesc == NULL)
        return NULL;

    // try to search and load driver from outside
    handle = NULL;
    RtlZeroMemory(&svc_key, sizeof(svc_key));
    val_info = NULL;
    RtlInitUnicodeString(&usz, L"");
    gendrv_build_reg_string(pdesc, &usz);
DbgPrint("UHCI: Trying to load driver %wZ\n", &usz);
    if (gendrv_open_reg_key(&handle, NULL, &usz, KEY_READ, FALSE) != STATUS_SUCCESS)
    {
        goto ERROR_OUT;
    }
    if (gendrv_get_key_value(handle, L"service", &val_info) != STATUS_SUCCESS)
    {
        goto ERROR_OUT;
    }

    if (val_info->DataLength > 32)
        goto ERROR_OUT;

    val_buf = (PWCHAR) (((PBYTE) val_info) + val_info->DataOffset);
    svc_key.Length = 0, svc_key.MaximumLength = 255;
    svc_key.Buffer = usb_alloc_mem(NonPagedPool, 256);

    RtlInitUnicodeString(&utemp, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
    RtlAppendUnicodeStringToString(&svc_key, &utemp);
    RtlInitUnicodeString(&svc_name, val_buf);
    RtlAppendUnicodeStringToString(&svc_key, &svc_name);

    status = ZwLoadDriver(&svc_key);
    if (status != STATUS_SUCCESS)
        goto ERROR_OUT;

    svc_key.Length = 0;
    RtlZeroMemory(svc_key.Buffer, 128);
    RtlInitUnicodeString(&svc_key, L"\\Driver\\");
    RtlAppendUnicodeStringToString(&svc_key, &svc_name);
    pdrvr_obj = gendrv_open_ext_driver(&svc_key);
    if (pdrvr_obj == NULL)
        goto ERROR_OUT;

    ExAcquireFastMutex(&pdrvr_ext->drvr_ext_mutex);

    // insert the driver to the drvr list
    pentry = gendrv_alloc_ext_drvr_entry(pdrvr_ext);
    if (pentry == NULL)
    {
        ExReleaseFastMutex(&pdrvr_ext->drvr_ext_mutex);
        ObDereferenceObject(pdrvr_obj);
        goto ERROR_OUT;
    }
    pentry->pext_drvr = pdrvr_obj;
    InsertTailList(&pdrvr_ext->ext_drvr_list, &pentry->drvr_link);
    pdrvr_ext->ext_drvr_count++;
    ExReleaseFastMutex(&pdrvr_ext->drvr_ext_mutex);
    ZwClose(handle);
    return pdrvr_obj;

ERROR_OUT:
    RtlFreeUnicodeString(&usz);
    if (val_info != NULL)
    {
        usb_free_mem(val_info);
        val_info = NULL;
    }
    if (svc_key.Buffer)
        usb_free_mem(svc_key.Buffer);

    if (handle)
        ZwClose(handle);

    return NULL;
}

VOID
gendrv_release_drvr(PGENDRV_DRVR_EXTENSION pdrvr_ext, PDRIVER_OBJECT pdrvr_obj)
{
    PLIST_ENTRY pthis, pnext;
    PGENDRV_EXT_DRVR_ENTRY pentry;

    if (pdrvr_ext == NULL || pdrvr_obj == NULL)
        return;
    ExAcquireFastMutex(&pdrvr_ext->drvr_ext_mutex);
    ListFirst(&pdrvr_ext->ext_drvr_list, pthis);
    while (pthis)
    {
        pentry = (PGENDRV_EXT_DRVR_ENTRY) pthis;
        if (pentry->pext_drvr == pdrvr_obj)
        {
            ASSERT(pentry->ref_count);
            ExReleaseFastMutex(&pdrvr_ext->drvr_ext_mutex);
            return;
        }
        ListNext(&pdrvr_ext->ext_drvr_list, pthis, pnext);
        pthis = pnext;
    }
    ExReleaseFastMutex(&pdrvr_ext->drvr_ext_mutex);
}

NTSTATUS
gendrv_send_pnp_msg(ULONG msg, PDEVICE_OBJECT pdev_obj, PVOID pctx)
{
    if (pdev_obj == NULL)
        return STATUS_INVALID_PARAMETER;

    switch (msg)
    {
        case GENDRV_MSG_ADDDEVICE:
        {
            PDRIVER_OBJECT pdrvr_obj;
            if (pctx == NULL)
                return STATUS_INVALID_PARAMETER;
            pdrvr_obj = (PDRIVER_OBJECT) pctx;
            if (pdrvr_obj->DriverExtension)
            {
                return pdrvr_obj->DriverExtension->AddDevice(pdrvr_obj, pdev_obj);
            }
            return STATUS_IO_DEVICE_ERROR;
        }
        case GENDRV_MSG_STOPDEVICE:
        case GENDRV_MSG_DISCDEVICE:
        {
            NTSTATUS status;
            IO_STACK_LOCATION *irpstack;
            IRP *irp;
            // IRP_MJ_PNP_POWER
            irp = IoAllocateIrp(2, FALSE);
            if (irp == NULL)
                return STATUS_NO_MEMORY;

            irpstack = IoGetNextIrpStackLocation(irp);
            irpstack->MajorFunction = IRP_MJ_PNP_POWER;
            irpstack->MinorFunction =
                (msg == GENDRV_MSG_STOPDEVICE) ? IRP_MN_STOP_DEVICE : IRP_MN_REMOVE_DEVICE;
            status = IoCallDriver(pdev_obj, irp);
            ASSERT(status != STATUS_PENDING);
            status = irp->IoStatus.Status;
            IoFreeIrp(irp);
            return STATUS_MORE_PROCESSING_REQUIRED;
        }
    }
    return STATUS_INVALID_PARAMETER;
}


BOOLEAN
gendrv_if_connect(PDEV_CONNECT_DATA params, DEV_HANDLE if_handle)
{
    //
    // try to search the registry to find one driver.
    // if found, create the PDO, load the driver. 
    // and call its AddDevice.
    //
    LONG if_idx, i;
    NTSTATUS status;
    PUSB_DEV pdev;
    PUSB_DRIVER pdrvr;
    PUSB_INTERFACE_DESC pif_desc;
    PGENDRV_DEVICE_EXTENSION pdev_ext;
    PUSB_CONFIGURATION_DESC pconfig_desc;
    PUSB_DEV_MANAGER dev_mgr;
    PGENDRV_DRVR_EXTENSION pdrvr_ext;
    PGENDRV_EXT_DRVR_ENTRY pentry;

    PDEVICE_OBJECT pdev_obj;
    PDRIVER_OBJECT pdrvr_obj;
    PLIST_ENTRY pthis, pnext;
    USE_BASIC_NON_PENDING_IRQL;

    pdev = NULL;
    usb_dbg_print(DBGLVL_MAXIMUM, ("gendrv_if_connect(): entering...\n"));

    if (params == NULL)
        return FALSE;

    dev_mgr = params->dev_mgr;
    pdrvr = params->pdriver;
    pdrvr_ext = (PGENDRV_DRVR_EXTENSION) pdrvr->driver_ext;

    status = usb_query_and_lock_dev(dev_mgr, if_handle, &pdev);
    if (status != STATUS_SUCCESS)
    {
        goto ERROR_OUT;
    }
    // obtain the pointer to the config desc, the dev won't go away in this routine
    pconfig_desc = pdev->usb_config->pusb_config_desc;  // 
    usb_unlock_dev(pdev);
    pdev = NULL;

    if_idx = if_idx_from_handle(if_handle);
    pif_desc = (PUSB_INTERFACE_DESC) (&pconfig_desc[1]);

    for(i = 0; i < if_idx; i++)
    {
        //search for our if
        if (usb_skip_if_and_altif((PUCHAR *) & pif_desc) == FALSE)
            break;
    }
    if (pif_desc == NULL)
        return FALSE;

    //
    // well, let's do the hard work to see if there is a class driver 
    // for this device.
    //
    i = gendrv_make_key((PUSB_DESC_HEADER) pif_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) pif_desc)) == NULL)
            return FALSE;
    }


    pdev_obj = gendrv_create_device(dev_mgr, pdrvr, if_handle);
    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);
        gendrv_delete_device(dev_mgr, pdev_obj);
        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;
    }

    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);
    pdev_ext->if_ctx.pif_desc =
        (PUSB_INTERFACE_DESC) & pdev_ext->desc_buf[(PBYTE) pif_desc - (PBYTE) pconfig_desc];

    // 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;
}

BOOLEAN
gendrv_do_stop(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle, BOOLEAN is_if)
{
    PUSB_DEV pdev;
    PDEVICE_OBJECT pdev_obj;
    ULONG if_idx;

    if (dev_mgr == NULL)
        return FALSE;

    // clean up the irps
    if_idx = if_idx_from_handle(dev_handle);
    if (usb_query_and_lock_dev(dev_mgr, dev_handle, &pdev) != STATUS_SUCCESS)
    {
        return FALSE;
    }
    if (is_if && pdev->usb_config)
        pdev_obj = (PDEVICE_OBJECT) pdev->usb_config->interf[if_idx].if_ext;
    else
        pdev_obj = pdev->dev_obj;

    gendrv_clean_up_queued_irps(pdev_obj);
    usb_unlock_dev(pdev);

    // send message to class drivers.
    gendrv_send_pnp_msg(GENDRV_MSG_STOPDEVICE, pdev_obj, NULL);

    return TRUE;
}

BOOLEAN
gendrv_if_stop(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle)
{
    if (dev_mgr == NULL)
        return FALSE;

    return gendrv_do_stop(dev_mgr, dev_handle, TRUE);
}

BOOLEAN
gendrv_do_disconnect(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE if_handle, BOOLEAN is_if)
{
    PUSB_DEV pdev;
    PDEVICE_OBJECT dev_obj = NULL;
    NTSTATUS status;
    PUSB_DRIVER pdrvr;
    PGENDRV_DRVR_EXTENSION pdrvr_ext = NULL;
    PGENDRV_DEVICE_EXTENSION pdev_ext = NULL;
    ULONG if_idx;

    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_idx = if_idx_from_handle(if_handle);
    if (pdev->usb_config)
    {

⌨️ 快捷键说明

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