umss.c

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

C
1,933
字号
{
    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;

⌨️ 快捷键说明

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