uhci.c

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

C
2,164
字号
        if (finished == FALSE)
        {
            //a split bulk transfer
            purb->bytes_transfered = 0;
            purb->bytes_to_transfer =
                UHCI_MAX_TDS_PER_TRANSFER * purb->pendp->pusb_endp_desc->wMaxPacketSize
                > purb->rest_bytes
                ? purb->rest_bytes : UHCI_MAX_TDS_PER_TRANSFER * purb->pendp->pusb_endp_desc->wMaxPacketSize;

            //the urb is not finished
            purb->flags &= ~URB_FLAG_STATE_MASK;
            purb->flags |= URB_FLAG_STATE_PENDING;

            InsertHeadList(&pendp->urb_list, (PLIST_ENTRY) purb);
        }

        pending_endp = alloc_pending_endp(&uhci->pending_endp_pool, 1);
        pending_endp->pendp = pendp;
        InsertTailList(&uhci->pending_endp_list, &pending_endp->endp_link);

        unlock_dev(pdev, TRUE);
        KeReleaseSpinLockFromDpcLevel(&uhci->pending_endp_list_lock);
    }

    //ah...exhausted, let's find some in the pending_endp_list to rock
    uhci_process_pending_endp(uhci);
    return;
}

BOOLEAN
uhci_add_device(PUHCI_DEV uhci, PUSB_DEV dev)
{
    if (dev == NULL || uhci == NULL)
        return FALSE;

    return TRUE;
}

BOOLEAN NTAPI
uhci_sync_cancel_urbs_dev(PVOID context)
{
    //cancel all the urbs on one dev
    PUHCI_DEV uhci;
    PUSB_DEV pdev, dest_dev;
    PSYNC_PARAM sync_param;
    PLIST_ENTRY pthis, pnext;
    LONG count;

    sync_param = (PSYNC_PARAM) context;
    dest_dev = (PUSB_DEV) sync_param->context;
    uhci = sync_param->uhci;

    if (uhci == NULL || dest_dev == NULL)
    {
        return (UCHAR) (sync_param->ret = FALSE);
    }
    count = 0;
    ListFirst(&uhci->urb_list, pthis);
    while (pthis)
    {
        pdev = dev_from_endp(((PURB) pthis)->pendp);
        if (pdev == dest_dev)
        {
            ((PURB) pthis)->flags |= URB_FLAG_FORCE_CANCEL;
        }
        ListNext(&uhci->urb_list, pthis, pnext);
        pthis = pnext;
        count++;
    }
    if (count)
        uhci->skel_term_td->status |= TD_CTRL_IOC;

    return (UCHAR) (sync_param->ret = TRUE);
}

BOOLEAN
uhci_remove_device(PUHCI_DEV uhci, PUSB_DEV dev)
{
    PUHCI_PENDING_ENDP ppending_endp;
    PLIST_ENTRY pthis, pnext;
    PURB purb;
    LIST_HEAD temp_list;
    int i, j, k;
    SYNC_PARAM sync_param;

    USE_BASIC_IRQL;

    if (uhci == NULL || dev == NULL)
        return FALSE;

    InitializeListHead(&temp_list);

    //free pending endp that has urb queued from pending endp list
    lock_pending_endp_list(&uhci->pending_endp_list_lock);

    ListFirst(&uhci->pending_endp_list, pthis);

    while (pthis)
    {
        ppending_endp = (PUHCI_PENDING_ENDP) pthis;
        ListNext(&uhci->pending_endp_list, pthis, pnext);
        if (dev_from_endp(ppending_endp->pendp) == dev)
        {
            RemoveEntryList(pthis);
            free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
        }
        pthis = pnext;
    }
    unlock_pending_endp_list(&uhci->pending_endp_list_lock);

    //cancel all the urbs in the urb-list
    sync_param.uhci = uhci;
    sync_param.context = (PVOID) dev;

    KeSynchronizeExecution(uhci->pdev_ext->uhci_int, uhci_sync_cancel_urbs_dev, &sync_param);

    //cancel all the urb in the endp's urb-list
    k = 0;
    lock_dev(dev, FALSE);
    if (dev->usb_config)
    {
        //only for configed dev 
        for(i = 0; i < dev->usb_config->if_count; i++)
        {
            for(j = 0; j < dev->usb_config->interf[i].endp_count; j++)
            {
                ListFirst(&dev->usb_config->interf[i].endp[j].urb_list, pthis);
                while (pthis)
                {
                    ListNext(&dev->usb_config->interf[i].endp[j].urb_list, pthis, pnext);

                    RemoveEntryList(pthis);
                    InsertHeadList(&temp_list, pthis);
                    pthis = pnext;
                    k++;
                }

            }
        }
    }
    ListFirst(&dev->default_endp.urb_list, pthis);

    while (pthis)
    {
        ListNext(&dev->default_endp.urb_list, pthis, pnext);

        RemoveEntryList(pthis);
        InsertHeadList(&temp_list, pthis);
        pthis = pnext;
        k++;
    }
    unlock_dev(dev, FALSE);

    if (IsListEmpty(&temp_list) == FALSE)
    {
        for(i = 0; i < k; i++)
        {
            //complete those urbs with error
            pthis = RemoveHeadList(&temp_list);
            purb = (PURB) pthis;
            purb->status = STATUS_DEVICE_DOES_NOT_EXIST;
            {
                uhci_generic_urb_completion(purb, purb->context);
            }
        }
    }

    lock_dev(dev, FALSE) dev->ref_count -= k;
    unlock_dev(dev, FALSE);

    return TRUE;
}


//
// assume that the urb has its rest_bytes and bytes_to_transfer set
// and bytes_transfered is zeroed.
// dev_lock must be acquired outside
// urb comes from dev's endpoint urb-list. it is already removed from
// the endpoint urb-list.
//
NTSTATUS
uhci_internal_submit_bulk(PUHCI_DEV uhci, PURB urb)
{

    LONG max_packet_size, td_count, offset, bytes_to_transfer, data_load;
    PBYTE start_addr;
    PUHCI_TD ptd;
    PUHCI_QH pqh;
    LIST_ENTRY td_list, *pthis, *pnext;
    BOOLEAN old_toggle, toggle, ret;
    UCHAR pid;

    if (uhci == NULL || urb == NULL)
        return STATUS_INVALID_PARAMETER;

    max_packet_size = endp_max_packet_size(urb->pendp);
    if (urb->bytes_to_transfer == 0)
    {
        return STATUS_INVALID_PARAMETER;
    }

    td_count = (urb->bytes_to_transfer + max_packet_size - 1) / max_packet_size;

    lock_td_pool(&uhci->td_pool, TRUE);
    if (can_transfer(&uhci->td_pool, td_count) == FALSE)
    {
        unlock_td_pool(&uhci->td_pool, TRUE);
        return STATUS_NO_MORE_ENTRIES;
    }

    ptd = alloc_tds(&uhci->td_pool, td_count);
    unlock_td_pool(&uhci->td_pool, TRUE);

    if (ptd == NULL)
    {
        return STATUS_UNSUCCESSFUL;
    }

    InitializeListHead(&td_list);
    InsertTailList(&ptd->ptde->vert_link, &td_list);

    ListFirst(&td_list, pthis);
    ListNext(&td_list, pthis, pnext);

    start_addr = &urb->data_buffer[urb->data_length - urb->rest_bytes];
    offset = 0;

    old_toggle = toggle = urb->pendp->flags & USB_ENDP_FLAG_DATATOGGLE ? TRUE : FALSE;
    bytes_to_transfer = urb->bytes_to_transfer;

    urb->pipe = ((max_packet_size - 1) << 21)
        | ((ULONG) endp_num(urb->pendp) << 15)
        | (dev_from_endp(urb->pendp)->dev_addr << 8)
        | ((ULONG) endp_dir(urb->pendp)) | USB_ENDPOINT_XFER_BULK;

    pid = (((ULONG) urb->pendp->pusb_endp_desc->bEndpointAddress & USB_DIR_IN) ? USB_PID_IN : USB_PID_OUT);
    while (pthis)
    {
        ptd = ((PTD_EXTENSION) pthis)->ptd;

        data_load = max_packet_size < bytes_to_transfer ? max_packet_size : bytes_to_transfer;
        ptd->purb = urb;
        uhci_fill_td(ptd,
                     (3 << TD_CTRL_C_ERR_SHIFT)
                     | (TD_CTRL_ACTIVE),
                     ((data_load - 1) << 21)
                     | (toggle << 19)
                     | ((ULONG) endp_num(urb->pendp) << 15)
                     | (dev_from_endp(urb->pendp)->dev_addr << 8)
                     | pid, MmGetPhysicalAddress(start_addr + offset).LowPart);

        bytes_to_transfer -= data_load;
        offset += data_load;

        if (pnext)
        {
            ptd->link = ((PTD_EXTENSION) pnext)->ptd->phy_addr;
        }
        else
        {
            //Last one, enable ioc and short packet detect if necessary
            ptd->link = UHCI_PTR_TERM;
            ptd->status |= TD_CTRL_IOC;
            if (bytes_to_transfer < max_packet_size && (pid == USB_PID_IN))
            {
                //ptd->status |= TD_CTRL_SPD;
            }
        }

        pthis = pnext;
        toggle ^= 1;
        if (pthis)
            ListNext(&td_list, pthis, pnext);

    }

    ListFirst(&td_list, pthis);
    RemoveEntryList(&td_list);

    lock_qh_pool(&uhci->qh_pool, TRUE);
    pqh = alloc_qh(&uhci->qh_pool);
    unlock_qh_pool(&uhci->qh_pool, TRUE);

    if (pqh == NULL)
    {
        lock_td_pool(&uhci->td_pool, TRUE);

        if (pthis)
            free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);

        unlock_td_pool(&uhci->td_pool, TRUE);
        return STATUS_NO_MORE_ENTRIES;

    }

    urb->td_count = td_count;

    uhci_insert_tds_qh(pqh, ((PTD_EXTENSION) pthis)->ptd);
    uhci_insert_qh_urb(urb, pqh);
    urb->pendp->flags =
        (urb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | (toggle ? USB_ENDP_FLAG_DATATOGGLE : 0);
    usb_endp_busy_count_inc(urb->pendp);
    uhci_insert_urb_to_schedule(uhci, urb, ret);

    if (ret == FALSE)
    {
        // undo all we have done
        RemoveEntryList(&pqh->pqhe->vert_link); //remove qh from td_chain
        RemoveEntryList(&urb->trasac_list);

        lock_td_pool(&uhci->td_pool, TRUE);
        if (pthis)
            free_tds(&uhci->td_pool, ((PTD_EXTENSION) pthis)->ptd);
        unlock_td_pool(&uhci->td_pool, TRUE);

        lock_qh_pool(&uhci->qh_pool, TRUE);
        if (pqh)
            free_qh(&uhci->qh_pool, pqh);
        unlock_qh_pool(&uhci->qh_pool, TRUE);

        InitializeListHead(&urb->trasac_list);
        usb_endp_busy_count_dec(urb->pendp);
        urb->pendp->flags =
            (urb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | (old_toggle ? USB_ENDP_FLAG_DATATOGGLE : 0);
        return STATUS_UNSUCCESSFUL;
    }
    return STATUS_SUCCESS;
}

NTSTATUS
uhci_internal_submit_ctrl(PUHCI_DEV uhci, PURB urb)
{
    LIST_ENTRY td_list, *pthis, *pnext;
    LONG i, td_count;
    LONG toggle;
    LONG max_packet_size, bytes_to_transfer, bytes_rest, start_idx;
    PUHCI_TD ptd;
    PUHCI_QH pqh;
    ULONG dev_addr;
    PUSB_DEV pdev;
    BOOLEAN ret;

    if (uhci == NULL || urb == NULL)
        return STATUS_INVALID_PARAMETER;

    toggle = 0;
    bytes_rest = urb->rest_bytes;
    bytes_to_transfer = urb->bytes_to_transfer;
    max_packet_size = endp_max_packet_size(urb->pendp);
    start_idx = urb->data_length - urb->rest_bytes;
    td_count = 2 + (urb->bytes_to_transfer + max_packet_size - 1) / max_packet_size;

    lock_td_pool(&uhci->td_pool, TRUE);

    if (can_transfer(&uhci->td_pool, td_count) == FALSE)
    {
        unlock_td_pool(&uhci->td_pool, TRUE);
        return STATUS_NO_MORE_ENTRIES;
    }

    ptd = alloc_tds(&uhci->td_pool, td_count);
    unlock_td_pool(&uhci->td_pool, TRUE);

    if (ptd == NULL)
    {
        return STATUS_UNSUCCESSFUL;
    }

    InsertTailList(&ptd->ptde->vert_link, &td_list);

    ListFirst(&td_list, pthis);
    ListNext(&td_list, pthis, pnext);

    ptd = ((PTD_EXTENSION) pthis)->ptd;

    pdev = dev_from_endp(urb->pendp);
    dev_addr = pdev->dev_addr;

    if (dev_state(pdev) <= USB_DEV_STATE_RESET)
        dev_addr = 0;

    usb_dbg_print(DBGLVL_MAXIMUM, ("uhci_internal_submit_ctrl(): dev_addr =0x%x\n", dev_addr));

    RtlCopyMemory(uhci->io_buf, urb->setup_packet, 8);

    if ((urb->setup_packet[0] & USB_DIR_IN) == 0)       //out
        RtlCopyMemory(&uhci->io_buf[8], urb->data_buffer, bytes_to_transfer);
    else
        RtlZeroMemory(&uhci->io_buf[8], bytes_to_transfer);

    uhci_fill_td(ptd,
                 (3 << TD_CTRL_C_ERR_SHIFT) | (TD_CTRL_ACTIVE),
                 (7 << 21) | (((ULONG) endp_num(urb->pendp)) << 15) | (dev_addr << 8) | (USB_PID_SETUP),
                 //uhci->io_buf_logic_addr.LowPart);
                 MmGetPhysicalAddress(urb->setup_packet).LowPart);

    ptd->link = ((PTD_EXTENSION) pnext)->ptd->phy_addr;
    pthis = pnext;
    ListNext(&td_list, pthis, pnext);

    urb->pipe = ((max_packet_size - 1) << 21)
        | ((ULONG) endp_num(urb->pendp) << 15)
        | (dev_addr << 8) | (pdev->flags & USB_DEV_FLAG_LOW_SPEED) | USB_ENDPOINT_XFER_CONTROL;

    for(i = 0, toggle = 1; ((i < td_count - 2) && pthis); i++, toggle ^= 1)
    {
        //construct tds for DATA packets of data stage.
        ptd = ((PTD_EXTENSION) pthis)->ptd;
        uhci_fill_td(ptd,
                     (3 << TD_CTRL_C_ERR_SHIFT)
                     | (TD_CTRL_ACTIVE),
                     ((bytes_to_transfer >
                       max_packet_size ? max_packet_size - 1 : bytes_to_transfer -
                       1) << 21) | (toggle << 19) | (((ULONG) endp_num(urb->
                                                                       pendp)) << 15) | (dev_addr << 8) |
                     ((urb->setup_packet[0] & USB_DIR_IN) ? USB_PID_IN : USB_PID_OUT),
                     //uhci->io_buf_logic_addr.LowPart + 8 + i * max_packet_size );
                     MmGetPhysicalAddress(&urb->data_buffer[start_idx + i * max_packet_size]).LowPart);

        if (pnext)
            ptd->link = ((PTD_EXTENSION) pnext)->ptd->phy_addr;

        if (i < td_count - 3)
        {
            bytes_to_transfer -= max_packet_size;
        }
        else
        {
            if (bytes_to_transfer > 0)
            {
                if (bytes_to_transfer < max_

⌨️ 快捷键说明

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