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

📄 hub.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 5 页
字号:
        purb->status = 0;
        hcd_dbg_print(DBGLVL_MAXIMUM, ("hub_set_address_completion: can not set address\n"));
        status = hcd->hcd_submit_urb(hcd, pdev, pendp, purb);
        //some error occured, disable the port
        if (status != STATUS_PENDING)
        {
            usb_free_mem(purb);
            status = hub_disable_port_request(hub_dev, (UCHAR) port_idx);
        }
        return;
    }

    usb_free_mem(purb);
    //let address settle
    usb_wait_ms_dpc(10);

    //let's config the dev
    dev_mgr_start_config_dev(pdev);

LBL_RESET_NEXT:
    //second, remove the event in the queue
    hub_reexamine_port_status_queue(hub_dev, port_idx, TRUE);
    if (hub_remove_reset_event(hub_dev, port_idx, TRUE))
        hub_start_next_reset_port(dev_mgr, TRUE);
    return;
};

VOID
hub_disable_port_completion(PURB purb, PVOID pcontext)
{
    PUSB_DEV pdev;
    PUSB_DEV_MANAGER dev_mgr;
    UCHAR port_idx;
    PUSB_ENDPOINT pendp;
    PUSB_CTRL_SETUP_PACKET psetup;

    UNREFERENCED_PARAMETER(pcontext);

    if (purb == NULL)
        return;

    pdev = purb->pdev;
    pendp = purb->pendp;
    psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
    port_idx = (UCHAR) psetup->wIndex;

    dev_mgr = dev_mgr_from_dev(pdev);

    usb_free_mem(purb);

    hub_reexamine_port_status_queue(pdev, port_idx, TRUE);
    if (hub_remove_reset_event(pdev, port_idx, TRUE))
        hub_start_next_reset_port(dev_mgr, TRUE);

    return;
}

//caller should guarantee the validity of the dev
NTSTATUS
hub_disable_port_request(PUSB_DEV pdev, UCHAR port_idx)
{
    PURB purb;
    PUSB_ENDPOINT pendp;
    PHUB2_EXTENSION hub_ext;
    PUSB_CTRL_SETUP_PACKET psetup;
    NTSTATUS status;
    PHCD hcd;
    USE_BASIC_NON_PENDING_IRQL;;

    if (pdev == NULL || port_idx == 0)
        return STATUS_INVALID_PARAMETER;

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

    purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
    if (purb == NULL)
    {
        unlock_dev(pdev, FALSE);
        return STATUS_NO_MEMORY;
    }

    RtlZeroMemory(purb, sizeof(URB));

    purb->flags = 0;
    purb->status = STATUS_SUCCESS;

    hub_ext = hub_ext_from_dev(pdev);

    purb->data_buffer = NULL;
    purb->data_length = 0;

    pendp = purb->pendp = &pdev->default_endp;
    purb->pdev = pdev;

    purb->completion = hub_disable_port_completion;
    purb->context = hub_ext;

    purb->pirp = NULL;
    purb->reference = 0;

    psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;

    psetup->bmRequestType = 0x23;       //host-device other recepient
    psetup->bRequest = USB_REQ_CLEAR_FEATURE;   //clear_feature
    psetup->wValue = USB_PORT_FEAT_ENABLE;
    psetup->wIndex = (USHORT) port_idx;
    psetup->wLength = 0;

    purb->pirp = NULL;
    //enter another state
    hcd = pdev->hcd;
    unlock_dev(pdev, FALSE);

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

    usb_free_mem(purb);
    return status;
}


BOOLEAN
hub_remove_reset_event(PUSB_DEV pdev, ULONG port_idx, BOOLEAN from_dpc)
{
    PUSB_DEV_MANAGER dev_mgr;
    PLIST_ENTRY pthis, pnext;
    PUSB_EVENT pevent, pnext_event;
    BOOLEAN found;

    KIRQL old_irql = 0;

    if (pdev == NULL)
        return FALSE;

    if (port_idx == 0)
        return FALSE;

    dev_mgr = dev_mgr_from_dev(pdev);
    found = FALSE;

    if (from_dpc)
        KeAcquireSpinLockAtDpcLevel(&dev_mgr->event_list_lock);
    else
        KeAcquireSpinLock(&dev_mgr->event_list_lock, &old_irql);

    ListFirst(&dev_mgr->event_list, pthis);
    while (pthis)
    {
        pevent = (PUSB_EVENT) pthis;
        if (pevent->event == USB_EVENT_WAIT_RESET_PORT &&
            (pevent->flags & USB_EVENT_FLAG_QUE_TYPE) == USB_EVENT_FLAG_QUE_RESET)
        {
            if (pevent->pdev == pdev && pevent->param == port_idx)
            {
                //remove it
                RemoveEntryList(&pevent->event_link);
                pnext_event = pevent->pnext;
                free_event(&dev_mgr->event_pool, pevent);

                if (pnext_event)
                    InsertHeadList(&dev_mgr->event_list, &pnext_event->event_link);

                found = TRUE;
                break;
            }
        }
        ListNext(&dev_mgr->event_list, pthis, pnext);
        pthis = pnext;
    }

    if (from_dpc)
        KeReleaseSpinLockFromDpcLevel(&dev_mgr->event_list_lock);
    else
        KeReleaseSpinLock(&dev_mgr->event_list_lock, old_irql);
    return found;
}

BOOLEAN
hub_start_next_reset_port(PUSB_DEV_MANAGER dev_mgr, BOOLEAN from_dpc)
{
    PLIST_ENTRY pthis, pnext;
    PUSB_EVENT pevent, pnext_event;
    PUSB_DEV pdev = NULL;
    PHUB2_EXTENSION hub_ext;
    BOOLEAN bret;
    PURB purb = NULL;
    BOOLEAN processed;
    PUSB_CTRL_SETUP_PACKET psetup;
    PHCD hcd = NULL;

    USE_NON_PENDING_IRQL;;

    if (dev_mgr == NULL)
        return FALSE;

    bret = FALSE;
    processed = FALSE;

    if (from_dpc)
        KeAcquireSpinLockAtDpcLevel(&dev_mgr->event_list_lock);
    else
        KeAcquireSpinLock(&dev_mgr->event_list_lock, &old_irql);

    ListFirst(&dev_mgr->event_list, pthis);

    while ((pevent = (PUSB_EVENT) pthis))
    {
        while (pevent->event == USB_EVENT_WAIT_RESET_PORT &&
               (pevent->flags & USB_EVENT_FLAG_QUE_TYPE) == USB_EVENT_FLAG_QUE_RESET)
        {

            processed = TRUE;

            pdev = pevent->pdev;
            lock_dev(pdev, TRUE);

            if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
            {
                unlock_dev(pdev, TRUE);
                pnext_event = pevent->pnext;
                free_event(&dev_mgr->event_pool, pevent);
                pevent = pnext_event;
                if (pevent == NULL)
                {
                    bret = FALSE;
                    break;
                }
                continue;
            }

            purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
            RtlZeroMemory(purb, sizeof(URB));

            purb->data_buffer = NULL;
            purb->data_length = 0;
            purb->pendp = &pdev->default_endp;

            hub_ext = hub_ext_from_dev(pdev);
            purb->context = hub_ext;
            purb->pdev = pdev;
            purb->completion = hub_start_reset_port_completion;
            purb->reference = pevent->param;

            psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;

            psetup->bmRequestType = 0x23;       //host-device other recepient
            psetup->bRequest = 3;       //set_feature
            psetup->wValue = USB_PORT_FEAT_RESET;
            psetup->wIndex = (USHORT) pevent->param;
            psetup->wLength = 0;

            purb->pirp = NULL;
            hcd = pdev->hcd;
            set_port_state(hub_ext->port_status_queue[pevent->param].port_flags, STATE_WAIT_RESET_COMPLETE);
            unlock_dev(pdev, TRUE);

            bret = TRUE;
            break;
        }

        if (!processed)
        {
            ListNext(&dev_mgr->event_list, pthis, pnext);
            pthis = pnext;
        }
        else
            break;
    }

    if (from_dpc)
        KeReleaseSpinLockFromDpcLevel(&dev_mgr->event_list_lock);
    else
        KeReleaseSpinLock(&dev_mgr->event_list_lock, old_irql);

    if (processed && bret)
    {
        if (hcd->hcd_submit_urb(hcd, pdev, purb->pendp, purb) != STATUS_PENDING)
        {
            //fatal error
            usb_free_mem(purb);
            bret = FALSE;
            //do not know what to do
        }
    }

    if (pthis == NULL)
        bret = TRUE;

    return bret;
}

//
//must have event-list-lock and dev-lock acquired
//
VOID
hub_post_esq_event(PUSB_DEV pdev, BYTE port_idx, PROCESS_EVENT pe)
{
    PUSB_DEV_MANAGER dev_mgr;
    PUSB_EVENT pevent;

    if (pdev == NULL || port_idx == 0 || pe == NULL)
        return;

    dev_mgr = dev_mgr_from_dev(pdev);

    pevent = alloc_event(&dev_mgr->event_pool, 1);
    pevent->event = USB_EVENT_DEFAULT;
    pevent->process_queue = event_list_default_process_queue;
    pevent->process_event = pe;
    pevent->context = (ULONG) hub_ext_from_dev(pdev);
    pevent->param = port_idx;
    pevent->flags = USB_EVENT_FLAG_ACTIVE;
    pevent->pdev = pdev;
    pevent->pnext = NULL;

    InsertTailList(&dev_mgr->event_list, &pevent->event_link);
    KeSetEvent(&dev_mgr->wake_up_event, 0, FALSE);
    // usb_dbg_print( DBGLVL_MAXIMUM, ( "hub_post_esq_event(): current element in event list is 0x%x\n",
    //                      dbg_count_list( &dev_mgr->event_list ) ) );
    return;
}

// called only in hub_clear_port_feature_completion
BOOLEAN
hub_check_reset_port_status(PUSB_DEV pdev, LONG port_idx)
{
    PUSB_DEV_MANAGER dev_mgr;
    PHUB2_EXTENSION hub_ext;
    BOOLEAN bReset;
    USB_PORT_STATUS port_status;
    PUSB_DEV pdev2;
    PURB purb2;
    PHCD hcd;

    PUSB_CTRL_SETUP_PACKET psetup;
    ULONG status;

    USE_BASIC_NON_PENDING_IRQL;;

    //let's check whether the status change is a reset complete
    usb_dbg_print(DBGLVL_MAXIMUM, ("hub_check_reset_port_status(): entering...\n"));
    dev_mgr = dev_mgr_from_dev(pdev);
    KeAcquireSpinLockAtDpcLevel(&dev_mgr->dev_list_lock);
    lock_dev(pdev, TRUE);

    dev_mgr = dev_mgr_from_dev(pdev);
    hcd = pdev->hcd;

    if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
    {
        unlock_dev(pdev, TRUE);
        KeReleaseSpinLockFromDpcLevel(&dev_mgr->dev_list_lock);
        return FALSE;
    }

    hub_ext = hub_ext_from_dev(pdev);
    port_status = psq_peek(&hub_ext->port_status_queue[port_idx], 0);

    bReset = FALSE;
    if (port_status.wPortChange & USB_PORT_STAT_C_RESET)
        bReset = TRUE;

    pdev2 = NULL;
    purb2 = NULL;

    if (bReset
        && (port_state(hub_ext->port_status_queue[port_idx].port_flags) == STATE_WAIT_RESET_COMPLETE)
        && (psq_count(&hub_ext->port_status_queue[port_idx]) == 1))
    {
        // a port-reset complete, empty the queue, keep the state
        psq_outqueue(&hub_ext->port_status_queue[port_idx]);
        set_port_state(hub_ext->port_status_queue[port_idx].port_flags, STATE_WAIT_ADDRESSED);

        //let's new a dev, and start the set-addr request
        if (hub_ext->child_dev[port_idx] == 0)
        {
            pdev2 = hub_ext->child_dev[port_idx] = dev_mgr_alloc_device(dev_mgr, hcd);
            if (pdev2)
            {
                purb2 = usb_alloc_mem(NonPagedPool, sizeof(URB));
                if (!purb2)
                {
                    dev_mgr_free_device(dev_mgr, pdev2);
                    pdev2 = hub_ext->child_dev[port_idx] = NULL;
                }
                else
                {
                    if (port_status.wPortStatus & USB_PORT_STAT_LOW_SPEED)
                    {
                        pdev2->flags |= USB_DEV_FLAG_LOW_SPEED;
                    }
                    else if (port_status.wPortStatus & USB_PORT_STAT_HIGH_SPEED)
                        pdev2->flags |= USB_DEV_FLAG_HIGH_SPEED;

                    pdev2->parent_dev = pdev;
                    pdev2->port_idx = (UCHAR) port_idx;
                    pdev2->ref_count++;

                    RtlZeroMemory(purb2, sizeof(URB));

                    purb2->pdev = pdev2;
                    purb2->pendp = &pdev2->default_endp;
                    purb2->context = hub_ext;
                    purb2->completion = hub_set_address_completion;

                    InitializeListHead(&purb2->trasac_list);
                    purb2->reference = port_idx;
                    purb2->pirp = 0;

                    psetup = (PUSB_CTRL_SETUP_PACKET) purb2->setup_packet;
                    psetup->bmRequestType = 0;
                    psetup->bRequest = USB_REQ_SET_ADDRESS;
                    psetup->wValue = pdev2->dev_addr;
                }
            }
        }

        if (pdev2 && purb2)
        {
            //creation success, emit the urb
            //add to dev list
            InsertTailList(&dev_mgr->dev_list, &pdev2->dev_link);

            unlock_dev(pdev, TRUE);
            KeReleaseSpinLockFromDpcLevel(&dev_mgr->dev_list_lock);

            status = hcd->hcd_submit_urb(hcd, pdev2, purb2->pendp, purb2);

            lock_dev(pdev2, TRUE);
            pdev2->ref_count--;
            usb_dbg_print(DBGLVL_MAXIMUM,
                          ("hub_check_reset_port_status(): new dev ref_count=0x%x\n", pdev2->ref_count));
            unlock_dev(pdev2, TRUE);

            if (status != STATUS_PENDING)
            {
                usb_free_mem(purb2);
                //??? do we need to lock it for SMP?
                //dev_mgr_free_device( dev_mgr, pdev2 ), let dev_mgr_thread to clean it;
                // disable the port
                if (hub_disable_port_request(pdev, (UCHAR) port_idx) != STATUS_PENDING)
                    goto LBL_RESET_FAIL;
            }

            return TRUE;
        }
    }
    else
    {
        usb_dbg_print(DBGLVL_MAXIMUM, ("hub_check_reset_port_status(): not a correct reset status\n"));
    }
    unlock_dev(pdev, TRUE);
    KeReleaseSpinLockFromDpcLevel(&dev_mgr->dev_list_lock);

LBL_RESET_FAIL:
    //Any event other than reset cause the reset process stall and another
    //pending reset-port requeset is serviced
    hub_reexamine_port_status_queue(pdev, port_idx, TRUE);
    if (hub_remove_reset_event(pdev, port_idx, TRUE))

⌨️ 快捷键说明

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