- Add roothub status operations.

- Ports count is correctly detected now.
- Added all necessary stubs for HCD interface, so that usbdriver can work further.

svn path=/trunk/; revision=30596
This commit is contained in:
Aleksey Bragin 2007-11-20 15:16:16 +00:00
parent 9a0b86e617
commit 418e0cc05a
2 changed files with 255 additions and 17 deletions

View file

@ -39,8 +39,13 @@ VOID ohci_init_hcd_interface(POHCI_DEV ohci);
// shared with EHCI
NTSTATUS ehci_dispatch_irp(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp);
PUSB_DEV_MANAGER ehci_get_dev_mgr(PHCD hcd);
VOID ehci_set_dev_mgr(PHCD hcd, PUSB_DEV_MANAGER dev_mgr);
VOID ehci_set_id(PHCD hcd, UCHAR id);
UCHAR ehci_get_id(PHCD hcd);
UCHAR ehci_alloc_addr(PHCD hcd);
VOID ehci_free_addr(PHCD hcd, UCHAR addr);
BOOLEAN NTAPI ehci_cal_cpu_freq(PVOID context);
extern USB_DEV_MANAGER g_dev_mgr;
@ -57,6 +62,31 @@ extern USB_DEV_MANAGER g_dev_mgr;
#define OHCI_READ_PORT_USHORT( psh ) ( *psh )
#define OHCI_WRITE_PORT_USHORT( psh, src ) ( *psh = ( USHORT )src )
/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
* The erratum (#4) description is incorrect. AMD's workaround waits
* till some bits (mostly reserved) are clear; ok for all revs.
*/
#define read_roothub(hc, register, mask) ({ \
ULONG temp = OHCI_READ_PORT_ULONG(&((hc)->regs->roothub.register)); \
if (temp == -1) \
/*disable (hc)*/; \
/*else if (hc->flags & OHCI_QUIRK_AMD756) \
while (temp & mask) \
temp = ohci_readl (hc, &hc->regs->roothub.register); */ \
temp; })
static ULONG roothub_a (POHCI_DEV hc)
{ return read_roothub (hc, a, 0xfc0fe000); }
/*
static inline u32 roothub_b (struct ohci_hcd *hc)
{ return ohci_readl (hc, &hc->regs->roothub.b); }
static inline u32 roothub_status (struct ohci_hcd *hc)
{ return ohci_readl (hc, &hc->regs->roothub.status); }
static u32 roothub_portstatus (struct ohci_hcd *hc, int i)
{ return read_roothub (hc, portstatus [i], 0xffe0fce0); }
*/
VOID
ohci_wait_ms(POHCI_DEV ohci, LONG ms)
{
@ -261,6 +291,7 @@ ohci_alloc(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, ULONG bus_addr, PU
//before we connect the interrupt, we have to init ohci
pdev_ext->ohci->pdev_ext = pdev_ext;
pdev_ext->ohci->regs = (POHCI_REGS)pdev_ext->ohci->port_base;
KeInitializeTimer(&pdev_ext->ohci->reset_timer);
@ -292,6 +323,23 @@ ohci_alloc(PDRIVER_OBJECT drvr_obj, PUNICODE_STRING reg_path, ULONG bus_addr, PU
//ohci_usb_reset (ohci);
}
/* Disable HC interrupts */
OHCI_WRITE_PORT_ULONG((PULONG)(pdev_ext->ohci->port_base + OHCI_INTRDISABLE), OHCI_INTR_MIE);
// flush the writes
(VOID)OHCI_READ_PORT_ULONG((PULONG)(pdev_ext->ohci->port_base + OHCI_CONTROL));
/* Read the number of ports unless overridden */
pdev_ext->ohci->num_ports = roothub_a(pdev_ext->ohci) & RH_A_NDP;
DbgPrint("OHCI: %d ports\n", pdev_ext->ohci->num_ports);
//ohci->hcca = dma_alloc_coherent (ohci_to_hcd(ohci)->self.controller,
// sizeof *ohci->hcca, &ohci->hcca_dma, 0);
//if (!ohci->hcca)
// return -ENOMEM;
//if ((ret = ohci_mem_init (ohci)) < 0)
// ohci_stop (ohci_to_hcd(ohci));
#if 0
//init ehci_caps
@ -413,30 +461,217 @@ ohci_create_device(PDRIVER_OBJECT drvr_obj, PUSB_DEV_MANAGER dev_mgr)
return pdev;
}
BOOLEAN
ohci_start(PHCD hcd)
{
//ULONG tmp;
//PBYTE base;
//PEHCI_USBCMD_CONTENT usbcmd;
//POHCI_DEV ohci;
if (hcd == NULL)
return FALSE;
return TRUE;
#if 0
ehci = struct_ptr(hcd, EHCI_DEV, hcd_interf);
base = ehci->port_base;
// stop the controller
tmp = EHCI_READ_PORT_ULONG((PULONG) (base + EHCI_USBCMD));
usbcmd = (PEHCI_USBCMD_CONTENT) & tmp;
usbcmd->run_stop = 0;
EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_USBCMD), tmp);
// wait the controller stop( ehci spec, 16 microframe )
usb_wait_ms_dpc(2);
// reset the controller
usbcmd = (PEHCI_USBCMD_CONTENT) & tmp;
usbcmd->hcreset = TRUE;
EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_USBCMD), tmp);
for(;;)
{
// interval.QuadPart = -100 * 10000; // 10 ms
// KeDelayExecutionThread( KernelMode, FALSE, &interval );
KeStallExecutionProcessor(10);
tmp = EHCI_READ_PORT_ULONG((PULONG) (base + EHCI_USBCMD));
if (!usbcmd->hcreset)
break;
}
// prepare the registers
EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_CTRLDSSEGMENT), 0);
// turn on all the int
EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_USBINTR),
EHCI_USBINTR_INTE | EHCI_USBINTR_ERR | EHCI_USBINTR_ASYNC | EHCI_USBINTR_HSERR
// EHCI_USBINTR_FLROVR | \ // it is noisy
// EHCI_USBINTR_PC // we detect it by polling
);
// write the list base reg
EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_PERIODICLISTBASE), ehci->frame_list_phys_addr.LowPart);
EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_ASYNCLISTBASE), ehci->skel_async_qh->phys_addr & ~(0x1f));
usbcmd->int_threshold = 1;
EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_USBCMD), tmp);
// let's rock
usbcmd->run_stop = 1;
EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_USBCMD), tmp);
// set the configuration flag
EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_CONFIGFLAG), 1);
// enable the list traversaling
usbcmd->async_enable = 1;
usbcmd->periodic_enable = 1;
EHCI_WRITE_PORT_ULONG((PULONG) (base + EHCI_USBCMD), tmp);
#endif
return TRUE;
}
ULONG
ohci_get_type(PHCD hcd)
{
return HCD_TYPE_OHCI; // ( hcd->flags & HCD_TYPE_MASK );
}
NTSTATUS
ohci_submit_urb2(PHCD hcd, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
{
return STATUS_UNSUCCESSFUL;
}
PUSB_DEV
ohci_get_root_hub(PHCD hcd)
{
return ohci_from_hcd(hcd)->root_hub;
}
VOID
ohci_set_root_hub(PHCD hcd, PUSB_DEV root_hub)
{
if (hcd == NULL || root_hub == NULL)
return;
ohci_from_hcd(hcd)->root_hub = root_hub;
return;
}
BOOLEAN
ohci_remove_device2(PHCD hcd, PUSB_DEV pdev)
{
if (hcd == NULL || pdev == NULL)
return FALSE;
return FALSE;
//return ehci_remove_device(ehci_from_hcd(hcd), pdev);
}
BOOLEAN
ohci_hcd_release(PHCD hcd)
{
POHCI_DEV ohci;
POHCI_DEVICE_EXTENSION pdev_ext;
if (hcd == NULL)
return FALSE;
ohci = ohci_from_hcd(hcd);
pdev_ext = ohci->pdev_ext;
return FALSE;//ehci_release(pdev_ext->pdev_obj);
}
NTSTATUS
ohci_cancel_urb2(PHCD hcd, PUSB_DEV pdev, PUSB_ENDPOINT pendp, PURB purb)
{
POHCI_DEV ohci;
if (hcd == NULL)
return STATUS_INVALID_PARAMETER;
ohci = ohci_from_hcd(hcd);
return STATUS_UNSUCCESSFUL;//ehci_cancel_urb(ehci, pdev, pendp, purb);
}
VOID
ohci_generic_urb_completion(PURB purb, PVOID context)
{
}
BOOLEAN
ohci_rh_reset_port(PHCD hcd, UCHAR port_idx)
{
//ULONG i;
POHCI_DEV ohci;
//ULONG status;
//UCHAR port_count;
if (hcd == NULL)
return FALSE;
ohci = ohci_from_hcd(hcd);
//port_count = (UCHAR) ((PEHCI_HCS_CONTENT) & ehci->ehci_caps.hcs_params)->port_count;
//if (port_idx < 1 || port_idx > port_count)
// return FALSE;
//usb_dbg_print(DBGLVL_MAXIMUM, ("ohci_rh_reset_port(): status after written=0x%x\n", status));
return TRUE;
}
NTSTATUS
ohci_hcd_dispatch(PHCD hcd, LONG disp_code, PVOID param)
{
POHCI_DEV ohci;
if (hcd == NULL)
return STATUS_INVALID_PARAMETER;
ohci = ohci_from_hcd(hcd);
#if 0
switch (disp_code)
{
case HCD_DISP_READ_PORT_COUNT:
{
if (param == NULL)
return STATUS_INVALID_PARAMETER;
*((PUCHAR) param) = (UCHAR) HCS_N_PORTS(ehci->ehci_caps.hcs_params);
return STATUS_SUCCESS;
}
case HCD_DISP_READ_RH_DEV_CHANGE:
{
if (ehci_rh_get_dev_change(hcd, param) == FALSE)
return STATUS_INVALID_PARAMETER;
return STATUS_SUCCESS;
}
}
#endif
return STATUS_NOT_IMPLEMENTED;
}
VOID
ohci_init_hcd_interface(POHCI_DEV ohci)
{
ohci->hcd_interf.hcd_set_dev_mgr = ehci_set_dev_mgr;
#if 0
ohci->hcd_interf.hcd_get_dev_mgr = ehci_get_dev_mgr;
ohci->hcd_interf.hcd_get_type = ehci_get_type;
#endif
ohci->hcd_interf.hcd_get_type = ohci_get_type;
ohci->hcd_interf.hcd_set_id = ehci_set_id;
#if 0
ohci->hcd_interf.hcd_get_id = ehci_get_id;
ohci->hcd_interf.hcd_alloc_addr = ehci_alloc_addr;
ohci->hcd_interf.hcd_free_addr = ehci_free_addr;
ohci->hcd_interf.hcd_submit_urb = ehci_submit_urb2;
ohci->hcd_interf.hcd_generic_urb_completion = ehci_generic_urb_completion;
ohci->hcd_interf.hcd_get_root_hub = ehci_get_root_hub;
ohci->hcd_interf.hcd_set_root_hub = ehci_set_root_hub;
ohci->hcd_interf.hcd_remove_device = ehci_remove_device2;
ohci->hcd_interf.hcd_rh_reset_port = ehci_rh_reset_port;
ohci->hcd_interf.hcd_release = ehci_hcd_release;
ohci->hcd_interf.hcd_cancel_urb = ehci_cancel_urb2;
ohci->hcd_interf.hcd_start = ehci_start;
ohci->hcd_interf.hcd_dispatch = ehci_hcd_dispatch;
#endif
ohci->hcd_interf.hcd_submit_urb = ohci_submit_urb2;
ohci->hcd_interf.hcd_generic_urb_completion = ohci_generic_urb_completion;
ohci->hcd_interf.hcd_get_root_hub = ohci_get_root_hub;
ohci->hcd_interf.hcd_set_root_hub = ohci_set_root_hub;
ohci->hcd_interf.hcd_remove_device = ohci_remove_device2;
ohci->hcd_interf.hcd_rh_reset_port = ohci_rh_reset_port;
ohci->hcd_interf.hcd_release = ohci_hcd_release;
ohci->hcd_interf.hcd_cancel_urb = ohci_cancel_urb2;
ohci->hcd_interf.hcd_start = ohci_start;
ohci->hcd_interf.hcd_dispatch = ohci_hcd_dispatch;
ohci->hcd_interf.flags = HCD_TYPE_OHCI; //hcd types | hcd id
}

View file

@ -119,7 +119,7 @@
* You must use readl() and writel() (in <asm/io.h>) to access these fields!!
* Layout is in section 7 (and appendix B) of the spec.
*/
struct _OHCI_REGS
typedef struct _OHCI_REGS
{
/* control and status registers (section 7.1) */
ULONG revision;
@ -164,6 +164,9 @@ typedef struct _OHCI_DEV
PHYSICAL_ADDRESS ohci_reg_base; // io space
BOOLEAN port_mapped;
PBYTE port_base; // note: added by ehci_caps.length, operational regs base addr, not the actural base
struct _OHCI_REGS *regs;
USHORT num_ports;
KTIMER reset_timer; //used to reset the host controller
struct _OHCI_DEVICE_EXTENSION *pdev_ext;
@ -193,6 +196,6 @@ typedef struct _OHCI_DEVICE_EXTENSION
KDPC ohci_dpc;
} OHCI_DEVICE_EXTENSION, *POHCI_DEVICE_EXTENSION;
#define ohci_from_hcd( hCD ) ( struct_ptr( ( hCD ), OHCI_DEV, hcd_interf ) )
#endif /* __OHCI_H__ */