⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 devmgr.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 3 页
字号:

    if ((addr = dev_mgr_alloc_addr(dev_mgr, hcd)) == 0xff)
        return NULL;

    pdev = usb_alloc_mem(NonPagedPool, sizeof(USB_DEV));
    if (pdev == NULL)
        return NULL;

    RtlZeroMemory(pdev, sizeof(USB_DEV));

    KeInitializeSpinLock(&pdev->dev_lock);
    dev_mgr->conn_count++;

    pdev->flags = USB_DEV_STATE_RESET;  //class | cur_state | low speed
    pdev->ref_count = 0;
    pdev->dev_addr = addr;

    pdev->hcd = hcd;

    pdev->dev_id = dev_mgr->conn_count; //will be used to compose dev_handle

    InitializeListHead(&pdev->default_endp.urb_list);
    pdev->default_endp.pusb_if = (PUSB_INTERFACE) pdev;
    pdev->default_endp.flags = USB_ENDP_FLAG_DEFAULT_ENDP;      //toggle | busy-count | stall | default-endp

    return pdev;
}

VOID
dev_mgr_free_device(PUSB_DEV_MANAGER dev_mgr, PUSB_DEV pdev)
{
    if (pdev == NULL || dev_mgr == NULL)
        return;

    dev_mgr_free_addr(dev_mgr, pdev, pdev->dev_addr);
    if (pdev->usb_config && pdev != pdev->hcd->hcd_get_root_hub(pdev->hcd))
    {
        //root hub has its config and desc buf allocated together,
        //so no usb_config allocated seperately
        dev_mgr_destroy_usb_config(pdev->usb_config);
        pdev->usb_config = NULL;
    }
    if (pdev->desc_buf)
    {
        usb_free_mem(pdev->desc_buf);
        pdev->desc_buf = NULL;
    }
    usb_free_mem(pdev);
    pdev = NULL;
    return;
}

//called when a disconnect is detected on the port
VOID
dev_mgr_disconnect_dev(PUSB_DEV pdev)
{
    PLIST_ENTRY pthis, pnext;
    PHUB2_EXTENSION phub_ext = NULL;
    PUSB_CONFIGURATION pconfig;
    PUSB_DEV_MANAGER dev_mgr;
    PHCD hcd;
    BOOLEAN is_hub, found;
    ULONG dev_id;
    int i;

    USE_NON_PENDING_IRQL;

    if (pdev == NULL)
        return;

    found = FALSE;

    usb_dbg_print(DBGLVL_MAXIMUM, ("dev_mgr_disconnect_dev(): entering, pdev=0x%x\n", pdev));
    lock_dev(pdev, FALSE);
    pdev->flags &= ~USB_DEV_STATE_MASK;
    pdev->flags |= USB_DEV_STATE_BEFORE_ZOMB;
    dev_mgr = dev_mgr_from_dev(pdev);
    unlock_dev(pdev, FALSE);

    // notify dev_driver that the dev stops function before any operations
    if (pdev->dev_driver && pdev->dev_driver->disp_tbl.dev_stop)
        pdev->dev_driver->disp_tbl.dev_stop(dev_mgr, dev_handle_from_dev(pdev));

    //safe to use the dev pointer in this function.
    lock_dev(pdev, FALSE);
    pdev->flags &= ~USB_DEV_STATE_MASK;
    pdev->flags |= USB_DEV_STATE_ZOMB;
    hcd = pdev->hcd;
    dev_id = pdev->dev_id;
    unlock_dev(pdev, FALSE);

    if (dev_mgr == NULL)
        return;

    hcd->hcd_remove_device(hcd, pdev);

    //disconnect its children
    if ((pdev->flags & USB_DEV_CLASS_MASK) == USB_DEV_CLASS_HUB ||
        (pdev->flags & USB_DEV_CLASS_MASK) == USB_DEV_CLASS_ROOT_HUB)
    {
        phub_ext = hub_ext_from_dev(pdev);
        if (phub_ext)
        {
            for(i = 1; i <= phub_ext->port_count; i++)
            {
                if (phub_ext->child_dev[i])
                {
                    dev_mgr_disconnect_dev(phub_ext->child_dev[i]);
                    phub_ext->child_dev[i] = NULL;
                }
            }
        }
    }

    pconfig = pdev->usb_config;

    //remove event belong to the dev
    is_hub = ((pdev->flags & USB_DEV_CLASS_MASK) == USB_DEV_CLASS_HUB);

    if (phub_ext && is_hub)
    {
        for(i = 1; i <= phub_ext->port_count; i++)
        {
            found = hub_remove_reset_event(pdev, i, FALSE);
            if (found)
                break;
        }
    }

    //free event of the dev from the event list
    KeAcquireSpinLock(&dev_mgr->event_list_lock, &old_irql);
    ListFirst(&dev_mgr->event_list, pthis);
    while (pthis)
    {
        ListNext(&dev_mgr->event_list, pthis, pnext);
        if (((PUSB_EVENT) pthis)->pdev == pdev)
        {
            PLIST_ENTRY p1;
            RemoveEntryList(pthis);
            if ((((PUSB_EVENT) pthis)->flags & USB_EVENT_FLAG_QUE_TYPE) != USB_EVENT_FLAG_NOQUE)
            {
                //has a queue, re-insert the queue
                if ((p1 = (PLIST_ENTRY) ((PUSB_EVENT) pthis)->pnext))
                {
                    InsertHeadList(&dev_mgr->event_list, p1);
                    free_event(&dev_mgr->event_pool, struct_ptr(pthis, USB_EVENT, event_link));
                    pthis = p1;
                    //note: this queue will be examined again in the next loop
                    //to find the matched dev in the queue
                    continue;
                }
            }
            free_event(&dev_mgr->event_pool, struct_ptr(pthis, USB_EVENT, event_link));
        }
        else if (((((PUSB_EVENT) pthis)->flags & USB_EVENT_FLAG_QUE_TYPE)
                  != USB_EVENT_FLAG_NOQUE) && ((PUSB_EVENT) pthis)->pnext)
        {
            //has a queue, examine the queue
            PUSB_EVENT p1, p2;
            p1 = (PUSB_EVENT) pthis;
            p2 = p1->pnext;
            while (p2)
            {
                if (p2->pdev == pdev)
                {
                    p1->pnext = p2->pnext;
                    p2->pnext = NULL;
                    free_event(&dev_mgr->event_pool, p2);
                    p2 = p1->pnext;
                }
                else
                {
                    p1 = p2;
                    p2 = p2->pnext;
                }
            }
        }
        pthis = pnext;
    }
    KeReleaseSpinLock(&dev_mgr->event_list_lock, old_irql);

    // found indicates the reset event on one of the dev's port in process
    if (found)
        hub_start_next_reset_port(dev_mgr_from_dev(pdev), FALSE);

    // remove timer-svc belonging to the dev
    KeAcquireSpinLock(&dev_mgr->timer_svc_list_lock, &old_irql);
    ListFirst(&dev_mgr->timer_svc_list, pthis);
    i = 0;
    while (pthis)
    {
        ListNext(&dev_mgr->timer_svc_list, pthis, pnext);
        if (((PUSB_EVENT) pthis)->pdev == pdev)
        {
            RemoveEntryList(pthis);
            free_timer_svc(&dev_mgr->timer_svc_pool, struct_ptr(pthis, TIMER_SVC, timer_svc_link));
            i++;
        }
        pthis = pnext;
    }
    KeReleaseSpinLock(&dev_mgr->timer_svc_list_lock, old_irql);

    // release the refcount
    if (i)
    {
        lock_dev(pdev, FALSE);
        pdev->ref_count -= i;
        unlock_dev(pdev, FALSE);
    }

    // wait for all the reference count be released
    for(;;)
    {
        LARGE_INTEGER interval;

        lock_dev(pdev, FALSE);
        if (pdev->ref_count == 0)
        {
            unlock_dev(pdev, FALSE);
            break;
        }
        unlock_dev(pdev, FALSE);
        // Wait two ms.
        interval.QuadPart = -20000;
        KeDelayExecutionThread(KernelMode, FALSE, &interval);
    }

    if (pdev->dev_driver && pdev->dev_driver->disp_tbl.dev_disconnect)
        pdev->dev_driver->disp_tbl.dev_disconnect(dev_mgr, dev_handle_from_dev(pdev));

    // we put it here to let handle valid before disconnect
    KeAcquireSpinLock(&dev_mgr->dev_list_lock, &old_irql);
    ListFirst(&dev_mgr->dev_list, pthis);
    while (pthis)
    {
        if (((PUSB_DEV) pthis) == pdev)
        {
            RemoveEntryList(pthis);
            break;
        }
        ListNext(&dev_mgr->dev_list, pthis, pnext);
        pthis = pnext;
    }
    KeReleaseSpinLock(&dev_mgr->dev_list_lock, old_irql);


    if (pdev != pdev->hcd->hcd_get_root_hub(pdev->hcd))
    {
        dev_mgr_free_device(dev_mgr, pdev);
    }
    else
    {
        //rh_destroy( pdev );
        //TRAP();
        //destroy it in dev_mgr_destroy
    }

    return;
}

//called in hub_set_address_completion
BOOLEAN
dev_mgr_start_config_dev(PUSB_DEV pdev)
{
    PBYTE data_buf;
    PUSB_CTRL_SETUP_PACKET psetup;
    PURB purb;
    PHCD hcd;
    USE_BASIC_NON_PENDING_IRQL;

    hcd_dbg_print(DBGLVL_MAXIMUM, ("dev_mgr_start_config_dev: pdev=%p\n", pdev));

    if (pdev == NULL)
        return FALSE;

    lock_dev(pdev, TRUE);
    if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
    {
        unlock_dev(pdev, TRUE);
        return FALSE;
    }

    hcd = pdev->hcd;

    //first, get device descriptor
    purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
    data_buf = usb_alloc_mem(NonPagedPool, 512);
    if (purb == NULL)
    {
        unlock_dev(pdev, TRUE);
        return FALSE;
    }

    RtlZeroMemory(purb, sizeof(URB));
    RtlZeroMemory(data_buf, 512);

    psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;

    purb->data_buffer = data_buf;       // user data
    purb->data_length = 8;      // get partial desc

    pdev->desc_buf = data_buf;
    pdev->desc_buf_size = 512;

    purb->pdev = pdev;
    purb->pendp = &pdev->default_endp;  //pipe for current transfer

    purb->completion = dev_mgr_get_desc_completion;
    purb->reference = 0;

    InitializeListHead(&purb->trasac_list);

    psetup->bmRequestType = 0x80;
    psetup->bRequest = USB_REQ_GET_DESCRIPTOR;
    psetup->wValue = (USB_DT_DEVICE << 8) | 0;
    psetup->wIndex = 0;
    psetup->wLength = 8;        //sizeof( USB_DEVICE_DESC );
    unlock_dev(pdev, TRUE);

    if (hcd->hcd_submit_urb(hcd, pdev, purb->pendp, purb) != STATUS_PENDING)
    {
        usb_free_mem(purb);
        usb_free_mem(data_buf);
        return FALSE;
    }
    return TRUE;
}

VOID
dev_mgr_get_desc_completion(PURB purb, PVOID context)
{
    PUSB_DEV pdev;
    PUSB_CONFIGURATION_DESC pconfig_desc;
    PUSB_ENDPOINT pendp;
    PUSB_DEV_MANAGER dev_mgr;
    NTSTATUS status;
    PUSB_CTRL_SETUP_PACKET psetup;
    PHCD hcd;

    USE_BASIC_NON_PENDING_IRQL;;

    if (purb == NULL)
        return;

    hcd_dbg_print(DBGLVL_MAXIMUM,
        ("dev_mgr_get_desc_completion: purb->reference=%d\n", purb->reference));

    pdev = purb->pdev;
    pendp = purb->pendp;

    if (pdev == NULL || pendp == NULL)
    {
        usb_free_mem(purb);
        purb = NULL;
        return;
    }

    lock_dev(pdev, TRUE);
    if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
    {
        unlock_dev(pdev, TRUE);
        goto LBL_OUT;
    }

    pendp = &pdev->default_endp;
    dev_mgr = dev_mgr_from_dev(pdev);
    hcd = pdev->hcd;
    psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;

    if (usb_error(purb->status))
    {
        unlock_dev(pdev, TRUE);
        hcd_dbg_print(DBGLVL_MAXIMUM,
                      ("dev_mgr_get_desc_completion: can not get dev desc ref=0x%x, status=0x%x\n",
                       purb->reference, purb->status));
        goto LBL_OUT;
    }

    switch (purb->reference)
    {
        case 0:
        {
            //only partial dev_desc
            //enable the dev specific default endp maxpacketsize
            pdev->pusb_dev_desc = (PUSB_DEVICE_DESC) purb->data_buffer;

            psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
            psetup->wLength = sizeof(USB_DEVICE_DESC);

            //get the complete dev_desc
            purb->reference = 1;
            purb->status = 0;
            purb->data_length = sizeof(USB_DEVICE_DESC);

            unlock_dev(pdev, TRUE);

            status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
            if (status != STATUS_PENDING)
            {
                goto LBL_OUT;
            }
            return;
        }
        case 1:
        {
            //let's begin to get config descriptors.
            if (pdev->pusb_dev_desc->bNumConfigurations == 0)
            {
                unlock_dev(pdev, TRUE);
                goto LBL_OUT;
            }

            purb->data_buffer += sizeof(USB_DEVICE_DESC);
            purb->data_length = 8;
            purb->reference++;
            purb->context = (PVOID) sizeof(USB_DEVICE_DESC);
            purb->status = 0;

            psetup->wValue = (USB_DT_CONFIG << 8) | 0;
            psetup->wLength = 8;
            unlock_dev(pdev, TRUE);

            status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);

            if (status != STATUS_PENDING)
            {
                goto LBL_OUT;
            }
            return;
        }
        default:
        {
            LONG config_idx;
            config_idx = (purb->reference >> 1) - 1;
            if ((purb->reference & 1) == 0)
            {
                //partial config desc is obtained.
                pconfig_desc = (PUSB_CONFIGURATION_DESC) purb->data_buffer;
                if (pconfig_desc->wTotalLength >= 1024)
                {
                    //treat as an error
                    unlock_dev(pdev, TRUE);
                    goto LBL_OUT;

                }

                if (pconfig_desc->wTotalLength > (USHORT) (pdev->desc_buf_size - (LONG) purb->context))
                {
                    //rewind the 8-byte hdr
                    *((PULONG) & context) -= 8;
                    realloc_buf(pdev, purb);
                }
                purb->data_length = pconfig_desc->wTotalLength;
                psetup->wLength = pconfig_desc->wTotalLength;
                purb->reference++;
                unlock_dev(pdev, TRUE);
                status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
                if (status != STATUS_PENDING)
                    goto LBL_OUT;

            }
            else
            {
                //complete desc is returned.
                if (config_idx + 1 < pdev->pusb_dev_desc->bNumConfigurations)
                {
                    //still have configurations left
                    *((PULONG) & context) += psetup->wLength;
                    purb->data_buffer = &pdev->desc_buf[(LONG) context];
                    purb->data_length = 8;
                    psetup->wLength = 8;
                    psetup->wValue = (((USB_DT_CONFIG) << 8) | (config_idx + 1));
                    purb->reference++;
                    purb->context = context;

                    if (((LONG) context) + 8 > pdev->desc_buf_size)
                        realloc_buf(pdev, purb);

                    purb->status = 0;
                    unlock_dev(pdev, TRUE);
                    status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
                    if (status != STATUS_PENDING)
                        goto LBL_OUT;
                }
                else
                {
                    //config descriptors have all been fetched
                    unlock_dev(pdev, TRUE);
                    usb_free_mem(purb);
                    purb = NULL;

                    // load driver for the device
                    dev_mgr_start_select_driver(pdev);
                }
            }
            return;
        }
    }

LBL_OUT:
    usb_free_mem(purb);
    purb = NULL;

    lock_dev(pdev, TRUE);
    if (dev_state(pdev) != USB_DEV_STATE_ZOMB)
    {
        if (pdev->desc_buf)
        {

⌨️ 快捷键说明

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