?? ehci.c
字號:
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 + -