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 + -
显示快捷键?