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

📄 ehci.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:
        i = PAGE_SIZE - i;
        if (i < purb->bytes_to_transfer)
            j = i & (max_packet_size - 1);
        else
            j = 0;
    }
    else
        j = 0;

    // fill the page pointer and toggle

    toggle = ehci_fill_td_buf_ptr(purb, purb->data_length - purb->rest_bytes, pthis, td_count, toggle);
    while (pthis)
    {
        ptd = qtd_from_list_entry(pthis);
        ptdc = (PEHCI_QTD_CONTENT) ptd;

        // ptdc->alt_terminal = 1;
        // ptdc->alt_qtd = 0;
        ptd->hw_alt_next = EHCI_PTR_TERM;
        ptdc->pid = pid;

        // ptd->elem_head_link->purb = purb; will be filled later
        ptdc->err_count = 3;
        ptdc->status = 0x80;    // active, and do_start_split for split transfer
        ptdc->cur_page = 0;
        // ptdc->data_toggle = toggle;

        if (pnext)
        {
            ptd->hw_next = qtd_from_list_entry(pnext)->phys_addr;
        }
        else
        {
            //Last one, enable ioc and short packet detect if necessary
            ptd->hw_next = EHCI_PTR_TERM;
            ptdc->ioc = TRUE;
            if (bytes_to_transfer < max_packet_size && (pid == QTD_PID_IN))
            {
                //ptd->status |= TD_CTRL_SPD;
            }
        }

        pthis = pnext;

        if (pthis)
            ListNext(&td_list, pthis, pnext);
    }

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

    elem_pool_lock(qh_pool, TRUE);
    pqh = (PEHCI_QH) ((ULONG) elem_pool_alloc_elem(qh_pool)->phys_part & PHYS_PART_ADDR_MASK);
    elem_pool_unlock(qh_pool, TRUE);

    if (pqh == NULL)
    {
        // free the qtds
        elem_safe_free(pthis, TRUE);
        return STATUS_NO_MORE_ENTRIES;

    }

    purb->td_count = td_count;
    pqhc = (PEHCI_QH_CONTENT) pqh;
    pqh->hw_next = EHCI_PTR_TERM;       // filled later
    pqhc->dev_addr = pipe_content->dev_addr;
    pqhc->inactive = 0;
    pqhc->endp_addr = pipe_content->endp_addr;
    pqhc->data_toggle = 0;      //pipe_content->data_toggle;
    pqhc->is_async_head = 0;
    pqhc->max_packet_size = (1 << pipe_content->max_packet_size);
    pqhc->is_ctrl_endp = 0;
    pqhc->reload_counter = EHCI_NAK_RL_COUNT;

    if (pipe_content->speed_high)
        pqhc->endp_spd = USB_SPEED_HIGH;
    else if (pipe_content->speed_low)
        pqhc->endp_spd = USB_SPEED_LOW;
    else
        pqhc->endp_spd = USB_SPEED_FULL;

    pqh->hw_info2 = 0;
    pqhc->mult = 1;
    pqh->hw_current = 0;
    pqh->hw_qtd_next = 0;       // filled later
    pqh->hw_alt_next = EHCI_PTR_TERM;
    pqh->hw_token = 0;          //indicate to advance queue before execution

    if (!pipe_content->speed_high)
    {
        pqhc->hub_addr = ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->hub_addr;
        pqhc->port_idx = ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->port_idx;
    }

    ptd = qtd_from_list_entry(pthis);
    ehci_insert_tds_qh(ehci, pqh, ptd);
    ehci_insert_qh_urb(purb, pqh);
    purb->pendp->flags =
        (purb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | (toggle ? USB_ENDP_FLAG_DATATOGGLE : 0);
    usb_endp_busy_count_inc(purb->pendp);
    ehci_insert_urb_to_schedule(ehci, purb, ret);

    if (ret == FALSE)
    {
        // undo all we have done
        ListFirst(&pqh->elem_head_link->elem_link, pthis);

        RemoveEntryList(&purb->trasac_list);
        RemoveEntryList(&pqh->elem_head_link->elem_link);       //remove qh from td_chain

        elem_safe_free(pthis, FALSE);
        elem_safe_free(&pqh->elem_head_link->elem_link, TRUE);

        InitializeListHead(&purb->trasac_list);
        // usb_endp_busy_count_dec( purb->pendp ); // the decrement is done in the dpc callback
        purb->pendp->flags =
            (purb->pendp->flags & ~USB_ENDP_FLAG_DATATOGGLE) | (old_toggle ? USB_ENDP_FLAG_DATATOGGLE : 0);
        return STATUS_UNSUCCESSFUL;
    }
    return STATUS_SUCCESS;
}

static NTSTATUS
ehci_internal_submit_ctrl(PEHCI_DEV ehci, PURB purb)
{

    LIST_ENTRY td_list, *pthis, *pnext;
    LONG i, td_count;
    LONG toggle;
    LONG max_packet_size, bytes_to_transfer, bytes_rest, start_idx;

    PEHCI_QTD ptd;
    PEHCI_QH pqh;
    PEHCI_QH_CONTENT pqhc;
    UCHAR dev_addr;
    BOOLEAN ret;
    PURB_HS_PIPE_CONTENT pipe_content;
    PEHCI_QTD_CONTENT ptdc;
    PEHCI_ELEM_LINKS pelnk;
    PUSB_DEV pdev;

    if (ehci == NULL || purb == NULL)
        return STATUS_INVALID_PARAMETER;

    bytes_rest = purb->rest_bytes;
    bytes_to_transfer = purb->bytes_to_transfer;
    max_packet_size = endp_max_packet_size(purb->pendp);
    start_idx = purb->data_length - purb->rest_bytes;

    calc_td_count(purb, start_idx, td_count);
    td_count += 2;              // add setup td and handshake td

    elem_pool_lock(qtd_pool, TRUE);
    pelnk = elem_pool_alloc_elems(qtd_pool, td_count);
    elem_pool_unlock(qtd_pool, TRUE);

    if (pelnk == NULL)
    {
        return STATUS_NO_MORE_ENTRIES;
    }

    InsertTailList(&pelnk->elem_link, &td_list);
    ListFirst(&td_list, pthis);
    ListNext(&td_list, pthis, pnext);

    ptd = qtd_from_list_entry(pthis);

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

    if (dev_state(pdev) <= USB_DEV_STATE_RESET) //only valid for control transfer
        dev_addr = 0;

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

    // fill the setup packet
    ptdc = (PEHCI_QTD_CONTENT) ptd;
    ptd->hw_next = qtd_from_list_entry(pnext)->phys_addr;
    ptd->hw_alt_next = EHCI_PTR_TERM;
    ptdc->status = 0x80;        // active
    ptdc->pid = QTD_PID_SETUP;
    ptdc->err_count = 3;
    ptdc->cur_page = 0;
    ptdc->ioc = 0;
    ptdc->bytes_to_transfer = sizeof(USB_CTRL_SETUP_PACKET);
    ptdc->data_toggle = 0;
    ptd->hw_buf[0] = MmGetPhysicalAddress(purb->setup_packet).LowPart;

    for(i = 1; i < 16; i++)
    {
        if ((max_packet_size >> i) == 0)
            break;
    }
    i--;
    i &= 0xf;

    purb->pipe = 0;
    pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
    pipe_content->max_packet_size = i;
    pipe_content->endp_addr = endp_num(purb->pendp);
    pipe_content->dev_addr = dev_addr;
    pipe_content->speed_low = (pdev->flags & USB_DEV_FLAG_LOW_SPEED) ? 1 : 0;
    pipe_content->speed_high = (pdev->flags & USB_DEV_FLAG_HIGH_SPEED) ? 1 : 0;
    pipe_content->trans_type = USB_ENDPOINT_XFER_CONTROL;

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

    // all the tds's toggle and data_buffer pointer is filled here
    toggle = 1;
    ehci_fill_td_buf_ptr(purb, start_idx, pthis, td_count - 2, toggle);

    for(i = 0; ((i < td_count - 2) && pthis); i++)
    {
        //construct tds for DATA packets of data stage.
        ptd = qtd_from_list_entry(pthis);
        ptdc = (PEHCI_QTD_CONTENT) ptd;
        ptd->hw_alt_next = EHCI_PTR_TERM;
        ptdc->status = 0x80;    // active and startXSplit
        ptdc->pid = ((purb->setup_packet[0] & USB_DIR_IN) ? QTD_PID_IN : QTD_PID_OUT);
        ptdc->err_count = 3;
        ptdc->cur_page = 0;
        ptdc->ioc = 0;

        if (pnext)
            ptd->hw_next = qtd_from_list_entry(pnext)->phys_addr;
        else
            ptd->hw_next = EHCI_PTR_TERM;

        pthis = pnext;
        if (pthis)
            ListNext(&td_list, pthis, pnext);
    }

    if (pthis)
        ptd->hw_next = qtd_from_list_entry(pthis)->phys_addr;
    else
        TRAP();

    // ListFirstPrev( &td_list, pthis );
    ptd = qtd_from_list_entry(pthis);

    //the last is an IN transaction
    ptdc = (PEHCI_QTD_CONTENT) ptd;
    ptd->hw_alt_next = EHCI_PTR_TERM;
    ptdc->status = 0x80;
    ptdc->pid = ((td_count > 2)
                 ? ((purb->setup_packet[0] & USB_DIR_IN) ? QTD_PID_OUT : QTD_PID_IN) : QTD_PID_IN);

    ptdc->err_count = 3;
    ptdc->cur_page = 0;
    ptdc->ioc = 1;
    ptdc->bytes_to_transfer = 0;
    ptdc->data_toggle = 1;
    ptd->hw_next = EHCI_PTR_TERM;

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

    ptd = qtd_from_list_entry(pthis);
    elem_pool_lock(qh_pool, TRUE);
    pelnk = elem_pool_alloc_elem(qh_pool);
    elem_pool_unlock(qh_pool, TRUE);

    if (pelnk == NULL)
    {
        elem_safe_free(pthis, FALSE);
        return STATUS_NO_MORE_ENTRIES;

    }
    pqh = (PEHCI_QH) ((ULONG) pelnk->phys_part & PHYS_PART_ADDR_MASK);
    pqhc = (PEHCI_QH_CONTENT) pqh;

    pqh->hw_alt_next = pqh->hw_next = EHCI_PTR_TERM;

    pqhc->dev_addr = dev_addr;
    pqhc->inactive = 0;
    pqhc->endp_addr = endp_num(purb->pendp);

    if (pipe_content->speed_high)
        pqhc->endp_spd = USB_SPEED_HIGH;
    else if (pipe_content->speed_low)
        pqhc->endp_spd = USB_SPEED_LOW;
    else
        pqhc->endp_spd = USB_SPEED_FULL;

    pqhc->data_toggle = 1;      // use dt from qtd
    pqhc->is_async_head = 0;
    pqhc->max_packet_size = endp_max_packet_size(purb->pendp);

    if (pipe_content->speed_high == 0)
        pqhc->is_ctrl_endp = 1;
    else
        pqhc->is_ctrl_endp = 0;

    pqhc->reload_counter = EHCI_NAK_RL_COUNT;

    // DWORD 2
    pqh->hw_info2 = 0;
    pqhc->mult = 1;

    if (!pipe_content->speed_high)
    {
        pqhc->hub_addr = ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->hub_addr;
        pqhc->port_idx = ((PURB_HS_CONTEXT_CONTENT) & purb->hs_context)->port_idx;
    }

    purb->td_count = td_count;

    ehci_insert_tds_qh(ehci, pqh, ptd);
    ehci_insert_qh_urb(purb, pqh);

    usb_endp_busy_count_inc(purb->pendp);
    ehci_insert_urb_to_schedule(ehci, purb, ret);

    if (ret == FALSE)
    {
        RemoveEntryList(&purb->trasac_list);
        RemoveEntryList(&pqh->elem_head_link->elem_link);

        elem_safe_free(&pqh->elem_head_link->elem_link, TRUE);
        elem_safe_free(pthis, FALSE);

        InitializeListHead(&purb->trasac_list);
        // usb_endp_busy_count_dec( purb->pendp );
        return STATUS_UNSUCCESSFUL;
    }
    return STATUS_SUCCESS;
}

static NTSTATUS
ehci_internal_submit_int(PEHCI_DEV ehci, PURB purb)
{
    LONG i, max_packet_size;
    PEHCI_QTD ptd;
    BOOLEAN ret;
    PUSB_DEV pdev;
    PURB_HS_PIPE_CONTENT pipe_content;
    UCHAR mult_trans, toggle, old_toggle;
    PEHCI_ELEM_LINKS pelnk;
    PEHCI_QTD_CONTENT ptdc;
    PEHCI_QH pqh;
    PEHCI_QH_CONTENT pqhc;
    PEHCI_FSTN pfstn;

    if (ehci == NULL || purb == NULL)
        return STATUS_INVALID_PARAMETER;

    old_toggle = toggle = (purb->pendp->flags & USB_ENDP_FLAG_DATATOGGLE) ? TRUE : FALSE;
    max_packet_size = endp_max_packet_size(purb->pendp);
    pdev = dev_from_endp(purb->pendp);

    if (max_packet_size == 0 || max_packet_size > 64)
        return STATUS_INVALID_PARAMETER;

    if ((pdev->flags & USB_DEV_FLAG_HIGH_SPEED) == 0)
    {
        if (max_packet_size < purb->data_length)
            return STATUS_INVALID_PARAMETER;

        for(i = 1; i < 16; i++)
        {
            if ((((ULONG) purb->pendp->pusb_endp_desc->bInterval) >> i) == 0)
                break;
        }
        i--;
        mult_trans = 1;
    }
    else
    {
        mult_trans = endp_mult_count(purb->pendp);
        if (max_packet_size * endp_mult_count(purb->pendp) < purb->data_length)
            return STATUS_INVALID_PARAMETER;
        i = purb->pendp->pusb_endp_desc->bInterval - 1;
    }

    purb->pipe = 0;
    pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
    pipe_content->interval = i;
    pipe_content->trans_type = USB_ENDPOINT_XFER_INT;   // bit 0-1
    pipe_content->speed_high = (pdev->flags & USB_DEV_FLAG_HIGH_SPEED) ? 1 : 0; // bit 5
    pipe_content->speed_low = (pdev->flags & USB_DEV_FLAG_LOW_SPEED) ? 1 : 0;   // bit 6
    pipe_content->trans_dir = endp_dir(purb->pendp) == USB_DIR_IN ? 1 : 0;      // bit 7
    pipe_content->dev_addr = pdev->dev_addr;    // bit 8-14
    pipe_content->endp_addr = endp_num(purb->pendp);    // bit 15-18
    pipe_content->data_toggle = 1;      // bit 19
    pipe_content->mult_count = mult_trans;

    // pipe_content->start_uframe : 3; // bit 28-30 will be filled later

    for(i = 1; i <= 16; i++)
    {
        if (((ULONG) max_packet_size) >> i)
            continue;
        else
            break;
    }
    i--;
    i &= 0xf;

    pipe_content->max_packet_size = i;  // bit 20-23 log2( max_packet_size )

    if (ehci_claim_bandwidth(ehci, purb, TRUE) == FALSE)
    {
 

⌨️ 快捷键说明

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