uhci.c
来自「ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机」· C语言 代码 · 共 2,164 行 · 第 1/5 页
C
2,164 行
BOOLEAN
uhci_release(PDEVICE_OBJECT pdev)
{
PDEVICE_EXTENSION pdev_ext;
PUHCI_DEV uhci;
if (pdev == NULL)
return FALSE;
pdev_ext = pdev->DeviceExtension;
if (pdev_ext == NULL)
return FALSE;
uhci = pdev_ext->uhci;
if (uhci == NULL)
return FALSE;
uhci_stop(uhci);
//pdev_ext->uhci->conn_count = 0;
pdev_ext->uhci->fsbr_cnt = 0;
if (pdev_ext->uhci_int)
{
IoDisconnectInterrupt(pdev_ext->uhci_int);
pdev_ext->uhci_int = NULL;
}
else
TRAP();
destroy_pending_endp_pool(&pdev_ext->uhci->pending_endp_pool);
//pdev_ext->uhci->pending_endp_pool = NULL;
uhci_destroy_schedule(uhci);
release_adapter(pdev_ext->padapter);
pdev_ext->padapter = NULL;
uhci_delete_device(pdev);
return FALSE;
}
// send cmds to start the uhc
// shamelessly copied from linux's uhci.c (reset_hc(), configure_hc() routines)
BOOLEAN
uhci_start(PHCD hcd)
{
PUHCI_DEV uhci;
PBYTE io_addr;
USHORT pirq;
PCI_SLOT_NUMBER SlotNum;
int timeout = 10000;
uhci = uhci_from_hcd(hcd);
io_addr = uhci->port_base;
/*
* Reset the HC - this will force us to get a
* new notification of any already connected
* ports due to the virtual disconnect that it
* implies.
*/
WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_HCRESET);
while (READ_PORT_USHORT((PUSHORT) (io_addr + USBCMD)) & USBCMD_HCRESET)
{
if (!--timeout)
{
break;
}
}
/* Turn on all interrupts */
WRITE_PORT_USHORT((PUSHORT) (io_addr + USBINTR),
USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP);
/* Start at frame 0 */
WRITE_PORT_USHORT((PUSHORT) (io_addr + USBFRNUM), 0);
WRITE_PORT_ULONG((PULONG) (io_addr + USBFLBASEADD), uhci->frame_list_logic_addr.LowPart);
/* Run and mark it configured with a 64-byte max packet */
WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_RS | USBCMD_CF | USBCMD_MAXP);
DbgPrint("uhci_start(): current uhci status=0x%x\n", uhci_status(uhci));
/* Enable PIRQ */
pirq = USBLEGSUP_DEFAULT;
SlotNum.u.AsULONG = 0;
SlotNum.u.bits.DeviceNumber = ((uhci->pdev_ext->pci_addr & 0xff) >> 3);
SlotNum.u.bits.FunctionNumber = (uhci->pdev_ext->pci_addr & 0x07);
DbgPrint("uhci_start(): set bus %d data at slot 0x%x\n", (uhci->pdev_ext->pci_addr >> 8),
SlotNum.u.AsULONG);
HalSetBusDataByOffset(PCIConfiguration, (uhci->pdev_ext->pci_addr >> 8), SlotNum.u.AsULONG,
&pirq, USBLEGSUP, sizeof(pirq));
return TRUE;
}
VOID
uhci_stop(PUHCI_DEV uhci)
{
PBYTE io_addr = uhci->port_base;
// turn off all the interrupt
WRITE_PORT_USHORT((PUSHORT) (io_addr + USBINTR), 0);
WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), 0);
}
static VOID
uhci_reset(PUHCI_DEV uhci)
{
PBYTE io_addr = uhci->port_base;
uhci_stop(uhci);
/* Global reset for 50ms */
WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_GRESET);
//uhci_wait_ms( uhci, 50 );
usb_wait_ms_dpc(50);
WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), 0);
//uhci_wait_ms( uhci, 10 );
usb_wait_ms_dpc(10);
}
VOID
uhci_suspend(PUHCI_DEV uhci)
{
PBYTE io_addr = uhci->port_base;
//uhci->is_suspended = 1;
WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_EGSM);
}
VOID
uhci_wakeup(PUHCI_DEV uhci)
{
PBYTE io_addr;
unsigned int status;
io_addr = uhci->port_base;
WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), 0);
/* wait for EOP to be sent */
status = READ_PORT_USHORT((PUSHORT) (io_addr + USBCMD));
while (status & USBCMD_FGR)
status = READ_PORT_USHORT((PUSHORT) (io_addr + USBCMD));
//uhci->is_suspended = 0;
/* Run and mark it configured with a 64-byte max packet */
WRITE_PORT_USHORT((PUSHORT) (io_addr + USBCMD), USBCMD_RS | USBCMD_CF | USBCMD_MAXP);
}
BOOLEAN
uhci_init_schedule(PUHCI_DEV uhci, PADAPTER_OBJECT padapter)
{
int i, irq;
uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_init_schedule(): entering..., uhci=0x%x\n", uhci));
if (uhci == NULL || padapter == NULL)
return FALSE;
if (init_td_pool_list(&uhci->td_pool, padapter) == FALSE)
{
return FALSE;
}
if (init_qh_pool(&uhci->qh_pool, padapter) == FALSE)
{
return FALSE;
}
//since uhci is not started we can freely access all resources.
for(i = 0; i < UHCI_MAX_SKELTDS; i++)
{
uhci->skel_td[i] = alloc_td(&uhci->td_pool);
uhci_fill_td(uhci->skel_td[i], 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
if (i > 0)
{
uhci->skel_td[i]->link = uhci->skel_td[i - 1]->phy_addr;
}
}
/*for( i = UHCI_MAX_SKELTDS - 3; i >= 0; i-- )
{
InsertTailList( &uhci->skel_int256_td->ptde->hori_link,
&uhci->skel_td[ i ]->ptde->hori_link );
} */
for(i = 0; i < UHCI_MAX_SKELQHS; i++)
{
uhci->skel_qh[i] = alloc_qh(&uhci->qh_pool);
if (i > 0)
{
uhci->skel_qh[i - 1]->link = uhci->skel_qh[i]->phy_addr;
}
uhci->skel_qh[i]->element = UHCI_PTR_TERM;
}
uhci->skel_int1_td->link = uhci->skel_ls_control_qh->phy_addr;
// Hack for PIIX
uhci_fill_td(uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
uhci->skel_term_td->link = uhci->skel_term_td->phy_addr;
uhci->skel_term_qh->link = UHCI_PTR_TERM;
uhci->skel_term_qh->element = uhci->skel_term_td->phy_addr;
InsertTailList(&uhci->skel_term_qh->pqhe->vert_link, &uhci->skel_term_td->ptde->vert_link);
/*for( i = 0; i < UHCI_MAX_SKELQHS; i++ )
{
InsertTailList( &uhci->skel_int256_td->ptde->hori_link,
&uhci->skel_qh[ i ]->pqhe->hori_link );
} */
if (uhci_init_frame_list(uhci, uhci->pdev_ext->padapter) == FALSE)
uhci_destroy_frame_list(uhci);
//well all have been chained, now scatter the int tds to frame-list
//shamelessly pasted from linux's uhci.c :-)
for(i = 0; i < UHCI_MAX_FRAMES; i++)
{
irq = 0;
if (i & 1)
{
irq++;
if (i & 2)
{
irq++;
if (i & 4)
{
irq++;
if (i & 8)
{
irq++;
if (i & 16)
{
irq++;
if (i & 32)
{
irq++;
if (i & 64)
irq++;
}
}
}
}
}
}
/* Only place we don't use the frame list routines */
uhci->frame_list[i] = uhci->skel_td[irq]->phy_addr;
}
return TRUE;
}
BOOLEAN
uhci_destroy_schedule(PUHCI_DEV uhci)
{
BOOLEAN ret;
ret = uhci_destroy_frame_list(uhci);
ret = destroy_qh_pool(&uhci->qh_pool);
ret = destroy_td_pool_list(&uhci->td_pool);
return ret;
}
VOID NTAPI
uhci_cancel_pending_endp_urb(IN PVOID Parameter)
{
PLIST_ENTRY abort_list;
PUSB_DEV pdev;
PURB purb;
USE_BASIC_NON_PENDING_IRQL;
abort_list = (PLIST_ENTRY) Parameter;
if (abort_list == NULL)
return;
while (IsListEmpty(abort_list) == FALSE)
{
//these devs are protected by urb's ref-count
purb = (PURB) RemoveHeadList(abort_list);
pdev = purb->pdev;
// purb->status is set when they are added to abort_list
uhci_generic_urb_completion(purb, purb->context);
lock_dev(pdev, FALSE);
pdev->ref_count--;
unlock_dev(pdev, FALSE);
}
usb_free_mem(abort_list);
return;
}
BOOLEAN
uhci_process_pending_endp(PUHCI_DEV uhci)
{
PUSB_DEV pdev;
LIST_ENTRY temp_list, abort_list;
PLIST_ENTRY pthis;
PURB purb;
PUSB_ENDPOINT pendp;
NTSTATUS can_submit = STATUS_UNSUCCESSFUL;
PWORK_QUEUE_ITEM pwork_item;
PLIST_ENTRY cancel_list;
USE_BASIC_IRQL;
if (uhci == NULL)
return FALSE;
InitializeListHead(&temp_list);
InitializeListHead(&abort_list);
purb = NULL;
uhci_dbg_print(DBGLVL_MEDIUM, ("uhci_process_pending_endp(): entering..., uhci=0x%x\n", uhci));
lock_pending_endp_list(&uhci->pending_endp_list_lock);
while (IsListEmpty(&uhci->pending_endp_list) == FALSE)
{
uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_process_pending_endp(): pending_endp_list=0x%x\n",
&uhci->pending_endp_list));
pthis = RemoveHeadList(&uhci->pending_endp_list);
pendp = ((PUHCI_PENDING_ENDP) pthis)->pendp;
pdev = dev_from_endp(pendp);
lock_dev(pdev, TRUE);
if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
{
unlock_dev(pdev, TRUE);
free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
//delegate to uhci_remove_device for removing the urb queue on the endpoint
continue;
}
if (endp_state(pendp) == USB_ENDP_FLAG_STALL)
{
while (IsListEmpty(&pendp->urb_list) == FALSE)
{
purb = (PURB) RemoveHeadList(&pendp->urb_list);
purb->status = USB_STATUS_ENDPOINT_HALTED;
InsertTailList(&abort_list, (LIST_ENTRY *) purb);
}
InitializeListHead(&pendp->urb_list);
unlock_dev(pdev, TRUE);
free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
continue;
}
if (IsListEmpty(&pendp->urb_list) == FALSE)
{
purb = (PURB) RemoveHeadList(&pendp->urb_list);
ASSERT(purb);
}
else
{
InitializeListHead(&pendp->urb_list);
unlock_dev(pdev, TRUE);
free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
continue;
}
// if can_submit is STATUS_SUCCESS, the purb is inserted into the schedule
uhci_dbg_print(DBGLVL_MAXIMUM, ("uhci_process_pending_endp(): endp_type=0x%x\n",
endp_type(pendp)));
switch (endp_type(pendp))
{
case USB_ENDPOINT_XFER_BULK:
{
#ifdef DEMO
can_submit = STATUS_UNSUCCESSFUL;
#else
can_submit = uhci_internal_submit_bulk(uhci, purb);
#endif
break;
}
case USB_ENDPOINT_XFER_CONTROL:
{
can_submit = uhci_internal_submit_ctrl(uhci, purb);
break;
}
case USB_ENDPOINT_XFER_INT:
{
can_submit = uhci_internal_submit_int(uhci, purb);
break;
}
case USB_ENDPOINT_XFER_ISOC:
{
can_submit = uhci_internal_submit_iso(uhci, purb);
break;
}
}
if (can_submit == STATUS_NO_MORE_ENTRIES)
{
//no enough bandwidth or tds
InsertHeadList(&pendp->urb_list, (PLIST_ENTRY) purb);
InsertTailList(&temp_list, pthis);
}
else
{
// other error or success
free_pending_endp(&uhci->pending_endp_pool, struct_ptr(pthis, UHCI_PENDING_ENDP, endp_link));
if (can_submit != STATUS_SUCCESS)
{
//abort these URBs
InsertTailList(&abort_list, (LIST_ENTRY *) purb);
uhci_dbg_print(DBGLVL_MEDIUM, ("uhci_process_pending_endp(): unable to submit urb 0x%x, "
"with status=0x%x\n", purb, can_submit));
purb->status = can_submit;
}
}
unlock_dev(pdev, TRUE);
}
if (IsListEmpty(&temp_list) == FALSE)
{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?