?? ehci.c
字號:
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;
ehci = sync_param->ehci;
if (ehci == NULL || dest_dev == NULL)
{
return (UCHAR) (sync_param->ret = FALSE);
}
count = 0;
ListFirst(&ehci->urb_list, pthis);
while (pthis)
{
pdev = dev_from_endp(((PURB) pthis)->pendp);
if (pdev == dest_dev)
{
((PURB) pthis)->flags |= URB_FLAG_FORCE_CANCEL;
}
ListNext(&ehci->urb_list, pthis, pnext);
pthis = pnext;
count++;
}
if (count)
{
// signal an int for further process
press_doorbell(ehci);
}
return (UCHAR) (sync_param->ret = TRUE);
}
BOOLEAN
ehci_remove_device(PEHCI_DEV ehci, 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 (ehci == NULL || dev == NULL)
return FALSE;
InitializeListHead(&temp_list);
//free pending endp that has purb queued from pending endp list
lock_pending_endp_list(&ehci->pending_endp_list_lock);
ListFirst(&ehci->pending_endp_list, pthis);
while (pthis)
{
ppending_endp = (PUHCI_PENDING_ENDP) pthis;
ListNext(&ehci->pending_endp_list, pthis, pnext);
if (dev_from_endp(ppending_endp->pendp) == dev)
{
RemoveEntryList(pthis);
free_pending_endp(&ehci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
}
pthis = pnext;
}
unlock_pending_endp_list(&ehci->pending_endp_list_lock);
//cancel all the urbs in the purb-list
sync_param.ehci = ehci;
sync_param.context = (PVOID) dev;
KeSynchronizeExecution(ehci->pdev_ext->ehci_int, ehci_sync_cancel_urbs_dev, &sync_param);
//cancel all the purb in the endp's purb-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;
{
ehci_generic_urb_completion(purb, purb->context);
}
}
}
lock_dev(dev, FALSE) dev->ref_count -= k;
unlock_dev(dev, FALSE);
return TRUE;
}
static BOOLEAN
ehci_insert_urb_schedule(PEHCI_DEV ehci, PURB purb)
// must have dev_lock( ehci_process_pending_endp ) and frame_list_lock acquired
{
PURB_HS_PIPE_CONTENT pipe_content;
if (ehci == NULL || purb == NULL)
return FALSE;
pipe_content = (PURB_HS_PIPE_CONTENT) & purb->pipe;
switch (pipe_content->trans_type)
{
case USB_ENDPOINT_XFER_CONTROL:
ehci_insert_control_schedule(ehci, purb);
break;
case USB_ENDPOINT_XFER_BULK:
ehci_insert_bulk_schedule(ehci, purb);
break;
case USB_ENDPOINT_XFER_INT:
ehci_insert_int_schedule(ehci, purb);
break;
case USB_ENDPOINT_XFER_ISOC:
ehci_insert_iso_schedule(ehci, purb);
break;
default:
return FALSE;
}
purb->flags &= ~URB_FLAG_STATE_MASK;
purb->flags |= URB_FLAG_STATE_IN_PROCESS | URB_FLAG_IN_SCHEDULE;
InsertTailList(&ehci->urb_list, (PLIST_ENTRY) purb);
return TRUE;
}
static BOOLEAN
ehci_insert_tds_qh(PEHCI_DEV ehci, PEHCI_QH pqh, PEHCI_QTD td_chain)
{
if (pqh == NULL || td_chain == NULL)
return FALSE;
UNREFERENCED_PARAMETER(ehci);
ehci_copy_overlay((PEHCI_QH_CONTENT) pqh, (PEHCI_QTD_CONTENT) td_chain);
InsertTailList(&td_chain->elem_head_link->elem_link, &pqh->elem_head_link->elem_link);
return TRUE;
}
static BOOLEAN
ehci_insert_qh_urb(PURB purb, PEHCI_QH pqh)
{
PLIST_ENTRY pthis, pnext;
if (pqh == NULL || purb == NULL)
return FALSE;
InsertTailList(&pqh->elem_head_link->elem_link, &purb->trasac_list);
ListFirst(&purb->trasac_list, pthis) while (pthis)
{
// note: fstn may in this chain
struct_ptr(pthis, EHCI_ELEM_LINKS, elem_link)->purb = purb;
ListNext(&purb->trasac_list, pthis, pnext);
pthis = pnext;
}
return TRUE;
}
#define calc_td_count( pURB, start_aDDR, td_coUNT ) \
{\
LONG i, j, k;\
td_coUNT = 0;\
k = ( ( pURB )->bytes_to_transfer + max_packet_size - 1 ) / max_packet_size;\
if( k != 0 )\
{\
LONG packets_per_td, packets_per_page;\
packets_per_td = EHCI_QTD_MAX_TRANS_SIZE / max_packet_size;\
packets_per_page = PAGE_SIZE / max_packet_size;\
i = ( ( LONG )&( pURB )->data_buffer[ ( start_aDDR ) ] ) & ( PAGE_SIZE - 1 );\
if( i )\
{\
i = PAGE_SIZE - i;\
j = i & ( max_packet_size - 1 );\
k -= ( EHCI_QTD_MAX_TRANS_SIZE - PAGE_SIZE + i - j ) / max_packet_size;\
if( k < 0 )\
td_coUNT = 1;\
else\
{\
if( j )\
i = packets_per_td - packets_per_page;\
else\
i = packets_per_td;\
td_coUNT = 1 + ( k + i - 1 ) / i; \
}\
}\
else\
{\
td_coUNT = ( k + packets_per_td - 1 ) / packets_per_td;\
}\
}\
}
static BOOLEAN
ehci_fill_td_buf_ptr(PURB purb, LONG start_addr, // start idx into purb->data_buffer
PLIST_ENTRY td_list, LONG td_count, ULONG toggle)
// fill the tds' bytes_to_transfer and hw_buf, return next toggle value: true 1, false 0
{
LONG i, j, k, data_load;
LONG packets_per_td, packets_per_page, bytes_to_transfer, max_packet_size;
PLIST_ENTRY pthis, pnext;
PEHCI_QTD_CONTENT ptdc;
PEHCI_QTD ptd;
PVOID ptr;
if (purb == NULL || td_list == NULL || td_count == 0)
return toggle;
max_packet_size = 1 << ((PURB_HS_PIPE_CONTENT) & purb->pipe)->max_packet_size;
packets_per_td = EHCI_QTD_MAX_TRANS_SIZE / max_packet_size;
packets_per_page = PAGE_SIZE / max_packet_size;
pthis = td_list;
bytes_to_transfer = purb->bytes_to_transfer;
i = ((LONG) & (purb)->data_buffer[(start_addr)]) & (PAGE_SIZE - 1);
if (i)
{
i = PAGE_SIZE - i;
j = i & (max_packet_size - 1);
}
else
{
i = j = 0;
}
while (bytes_to_transfer)
{
ptd = qtd_from_list_entry(pthis);
ptd->hw_buf[0] = MmGetPhysicalAddress(&purb->data_buffer[start_addr]).LowPart;
ptdc = (PEHCI_QTD_CONTENT) ptd;
if (i != 0)
{
data_load = (LONG) (EHCI_QTD_MAX_TRANS_SIZE - PAGE_SIZE + i - j) < bytes_to_transfer
? (LONG) (EHCI_QTD_MAX_TRANS_SIZE - PAGE_SIZE + i - j) : bytes_to_transfer;
ptdc->bytes_to_transfer = (USHORT) data_load;
ptd->bytes_to_transfer = (USHORT) data_load;
// subtract the header part
data_load -= (i < data_load ? i : data_load);
for(k = 1; data_load > 0; k++)
{
ptr = &purb->data_buffer[start_addr + i + (k - 1) * PAGE_SIZE];
ptr = (PVOID) (((ULONG) ptr) & ~(PAGE_SIZE - 1));
ptd->hw_buf[k] = MmGetPhysicalAddress(ptr).LowPart;
data_load -= PAGE_SIZE < data_load ? PAGE_SIZE : data_load;
}
}
else
{
// aligned on page boundary
data_load = EHCI_QTD_MAX_TRANS_SIZE < bytes_to_transfer
? EHCI_QTD_MAX_TRANS_SIZE : bytes_to_transfer;
ptdc->bytes_to_transfer = (USHORT) data_load;
ptd->bytes_to_transfer = (USHORT) data_load;
data_load -= (PAGE_SIZE < data_load ? PAGE_SIZE : data_load);
for(k = 1; data_load > 0; k++)
{
ptr = &purb->data_buffer[start_addr + k * PAGE_SIZE];
ptr = (PVOID) (((ULONG) ptr) & ~(PAGE_SIZE - 1));
ptd->hw_buf[k] = MmGetPhysicalAddress(ptr).LowPart;
data_load -= PAGE_SIZE < data_load ? PAGE_SIZE : data_load;
}
}
ptdc->data_toggle = toggle;
if (((ptdc->bytes_to_transfer + max_packet_size - 1) / max_packet_size) & 1)
{
//only odd num of transactions has effect
toggle ^= 1;
}
start_addr += ptdc->bytes_to_transfer;
bytes_to_transfer -= ptdc->bytes_to_transfer;
ListNext(td_list, pthis, pnext);
pthis = pnext;
i = j;
}
return toggle;
}
static NTSTATUS
ehci_internal_submit_bulk(PEHCI_DEV ehci, PURB purb)
//
// assume that the purb has its rest_bytes and bytes_to_transfer set
// and bytes_transfered is zeroed.
// dev_lock must be acquired outside
// purb comes from dev's endpoint purb-list. it is already removed from
// the endpoint purb-list.
//
{
LONG max_packet_size, td_count, offset, bytes_to_transfer;
PBYTE start_addr;
PEHCI_QTD ptd;
PEHCI_QH pqh;
LIST_ENTRY td_list, *pthis, *pnext;
BOOLEAN old_toggle, toggle, ret;
UCHAR pid;
LONG i, j;
PURB_HS_PIPE_CONTENT pipe_content;
PEHCI_QTD_CONTENT ptdc;
PEHCI_QH_CONTENT pqhc;
PEHCI_ELEM_LINKS pelnk;
if (ehci == NULL || purb == NULL)
return STATUS_INVALID_PARAMETER;
max_packet_size = endp_max_packet_size(purb->pendp);
if (purb->bytes_to_transfer == 0)
{
return STATUS_INVALID_PARAMETER;
}
start_addr = &purb->data_buffer[purb->data_length - purb->rest_bytes];
calc_td_count(purb, purb->data_length - purb->rest_bytes, td_count);
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_UNSUCCESSFUL;
}
ptd = (PEHCI_QTD) ((ULONG) pelnk->phys_part & PHYS_PART_ADDR_MASK);
InitializeListHead(&td_list);
InsertTailList(&ptd->elem_head_link->elem_link, &td_list);
ListFirst(&td_list, pthis);
ListNext(&td_list, pthis, pnext);
offset = 0;
old_toggle = toggle = (purb->pendp->flags & USB_ENDP_FLAG_DATATOGGLE) ? TRUE : FALSE;
bytes_to_transfer = purb->bytes_to_transfer;
ehci_dbg_print(DBGLVL_MAXIMUM, ("ehci_internal_submit_bulk():dev toggle=%d\n", toggle));
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_from_endp(purb->pendp)->dev_addr;
pipe_content->trans_dir = endp_dir(purb->pendp);
pipe_content->trans_type = USB_ENDPOINT_XFER_BULK;
pipe_content->data_toggle = toggle;
pipe_content->speed_high = (dev_from_endp(purb->pendp)->flags & USB_DEV_FLAG_HIGH_SPEED) ? 1 : 0;
pipe_content->speed_low = (dev_from_endp(purb->pendp)->flags & USB_DEV_FLAG_LOW_SPEED) ? 1 : 0;
pid = (((ULONG) purb->pendp->pusb_endp_desc->bEndpointAddress & USB_DIR_IN) ? QTD_PID_IN : QTD_PID_OUT);
i = ((ULONG) start_addr) & (PAGE_SIZE - 1); // header part within first page
if (i)
{
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -