version 1.111, 2006/08/30 00:49:56 |
version 1.111.2.4, 2007/02/06 13:32:31 |
Line 188 Static void ehci_noop(usbd_pipe_handle |
|
Line 188 Static void ehci_noop(usbd_pipe_handle |
|
|
|
Static int ehci_str(usb_string_descriptor_t *, int, const char *); |
Static int ehci_str(usb_string_descriptor_t *, int, const char *); |
Static void ehci_pcd(ehci_softc_t *, usbd_xfer_handle); |
Static void ehci_pcd(ehci_softc_t *, usbd_xfer_handle); |
Static void ehci_pcd_able(ehci_softc_t *, int); |
|
Static void ehci_pcd_enable(void *); |
|
Static void ehci_disown(ehci_softc_t *, int, int); |
Static void ehci_disown(ehci_softc_t *, int, int); |
|
|
Static ehci_soft_qh_t *ehci_alloc_sqh(ehci_softc_t *); |
Static ehci_soft_qh_t *ehci_alloc_sqh(ehci_softc_t *); |
Line 336 ehci_init(ehci_softc_t *sc) |
|
Line 334 ehci_init(ehci_softc_t *sc) |
|
sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH); |
sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH); |
|
|
vers = EREAD2(sc, EHCI_HCIVERSION); |
vers = EREAD2(sc, EHCI_HCIVERSION); |
aprint_normal("%s: EHCI version %x.%x\n", USBDEVNAME(sc->sc_bus.bdev), |
aprint_verbose("%s: EHCI version %x.%x\n", USBDEVNAME(sc->sc_bus.bdev), |
vers >> 8, vers & 0xff); |
vers >> 8, vers & 0xff); |
|
|
sparams = EREAD4(sc, EHCI_HCSPARAMS); |
sparams = EREAD4(sc, EHCI_HCSPARAMS); |
Line 344 ehci_init(ehci_softc_t *sc) |
|
Line 342 ehci_init(ehci_softc_t *sc) |
|
sc->sc_npcomp = EHCI_HCS_N_PCC(sparams); |
sc->sc_npcomp = EHCI_HCS_N_PCC(sparams); |
ncomp = EHCI_HCS_N_CC(sparams); |
ncomp = EHCI_HCS_N_CC(sparams); |
if (ncomp != sc->sc_ncomp) { |
if (ncomp != sc->sc_ncomp) { |
aprint_error("%s: wrong number of companions (%d != %d)\n", |
aprint_verbose("%s: wrong number of companions (%d != %d)\n", |
USBDEVNAME(sc->sc_bus.bdev), |
USBDEVNAME(sc->sc_bus.bdev), |
ncomp, sc->sc_ncomp); |
ncomp, sc->sc_ncomp); |
#if NOHCI == 0 || NUHCI == 0 |
#if NOHCI == 0 || NUHCI == 0 |
Line 417 ehci_init(ehci_softc_t *sc) |
|
Line 415 ehci_init(ehci_softc_t *sc) |
|
sc->sc_bus.methods = &ehci_bus_methods; |
sc->sc_bus.methods = &ehci_bus_methods; |
sc->sc_bus.pipe_size = sizeof(struct ehci_pipe); |
sc->sc_bus.pipe_size = sizeof(struct ehci_pipe); |
|
|
sc->sc_powerhook = powerhook_establish(ehci_power, sc); |
sc->sc_powerhook = powerhook_establish(USBDEVNAME(sc->sc_bus.bdev), |
|
ehci_power, sc); |
sc->sc_shutdownhook = shutdownhook_establish(ehci_shutdown, sc); |
sc->sc_shutdownhook = shutdownhook_establish(ehci_shutdown, sc); |
|
|
sc->sc_eintrs = EHCI_NORMAL_INTRS; |
sc->sc_eintrs = EHCI_NORMAL_INTRS; |
Line 493 ehci_init(ehci_softc_t *sc) |
|
Line 492 ehci_init(ehci_softc_t *sc) |
|
sc->sc_async_head = sqh; |
sc->sc_async_head = sqh; |
EOWRITE4(sc, EHCI_ASYNCLISTADDR, sqh->physaddr | EHCI_LINK_QH); |
EOWRITE4(sc, EHCI_ASYNCLISTADDR, sqh->physaddr | EHCI_LINK_QH); |
|
|
usb_callout_init(sc->sc_tmo_pcd); |
|
usb_callout_init(sc->sc_tmo_intrlist); |
usb_callout_init(sc->sc_tmo_intrlist); |
|
|
lockinit(&sc->sc_doorbell_lock, PZERO, "ehcidb", 0, 0); |
lockinit(&sc->sc_doorbell_lock, PZERO, "ehcidb", 0, 0); |
Line 606 ehci_intr1(ehci_softc_t *sc) |
|
Line 604 ehci_intr1(ehci_softc_t *sc) |
|
} |
} |
if (eintrs & EHCI_STS_PCD) { |
if (eintrs & EHCI_STS_PCD) { |
ehci_pcd(sc, sc->sc_intrxfer); |
ehci_pcd(sc, sc->sc_intrxfer); |
/* |
|
* Disable PCD interrupt for now, because it will be |
|
* on until the port has been reset. |
|
*/ |
|
ehci_pcd_able(sc, 0); |
|
/* Do not allow RHSC interrupts > 1 per second */ |
|
usb_callout(sc->sc_tmo_pcd, hz, ehci_pcd_enable, sc); |
|
eintrs &= ~EHCI_STS_PCD; |
eintrs &= ~EHCI_STS_PCD; |
} |
} |
|
|
Line 629 ehci_intr1(ehci_softc_t *sc) |
|
Line 620 ehci_intr1(ehci_softc_t *sc) |
|
return (1); |
return (1); |
} |
} |
|
|
void |
|
ehci_pcd_able(ehci_softc_t *sc, int on) |
|
{ |
|
DPRINTFN(4, ("ehci_pcd_able: on=%d\n", on)); |
|
if (on) |
|
sc->sc_eintrs |= EHCI_STS_PCD; |
|
else |
|
sc->sc_eintrs &= ~EHCI_STS_PCD; |
|
EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); |
|
} |
|
|
|
void |
|
ehci_pcd_enable(void *v_sc) |
|
{ |
|
ehci_softc_t *sc = v_sc; |
|
|
|
ehci_pcd_able(sc, 1); |
|
} |
|
|
|
void |
void |
ehci_pcd(ehci_softc_t *sc, usbd_xfer_handle xfer) |
ehci_pcd(ehci_softc_t *sc, usbd_xfer_handle xfer) |
Line 772 ehci_idone(struct ehci_xfer *ex) |
|
Line 745 ehci_idone(struct ehci_xfer *ex) |
|
ehci_soft_qtd_t *sqtd, *lsqtd; |
ehci_soft_qtd_t *sqtd, *lsqtd; |
u_int32_t status = 0, nstatus = 0; |
u_int32_t status = 0, nstatus = 0; |
int actlen; |
int actlen; |
uint pkts_left; |
|
|
|
DPRINTFN(/*12*/2, ("ehci_idone: ex=%p\n", ex)); |
DPRINTFN(/*12*/2, ("ehci_idone: ex=%p\n", ex)); |
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
Line 822 ehci_idone(struct ehci_xfer *ex) |
|
Line 794 ehci_idone(struct ehci_xfer *ex) |
|
* If there are left over TDs we need to update the toggle. |
* If there are left over TDs we need to update the toggle. |
* The default pipe doesn't need it since control transfers |
* The default pipe doesn't need it since control transfers |
* start the toggle at 0 every time. |
* start the toggle at 0 every time. |
|
* For a short transfer we need to update the toggle for the missing |
|
* packets within the qTD. |
*/ |
*/ |
if (sqtd != lsqtd->nextqtd && |
if ((sqtd != lsqtd->nextqtd || EHCI_QTD_GET_BYTES(status)) && |
xfer->pipe->device->default_pipe != xfer->pipe) { |
xfer->pipe->device->default_pipe != xfer->pipe) { |
printf("ehci_idone: need toggle update status=%08x nstatus=%08x\n", status, nstatus); |
DPRINTFN(2, ("ehci_idone: need toggle update " |
|
"status=%08x nstatus=%08x\n", status, nstatus)); |
#if 0 |
#if 0 |
ehci_dump_sqh(epipe->sqh); |
ehci_dump_sqh(epipe->sqh); |
ehci_dump_sqtds(ex->sqtdstart); |
ehci_dump_sqtds(ex->sqtdstart); |
Line 833 ehci_idone(struct ehci_xfer *ex) |
|
Line 808 ehci_idone(struct ehci_xfer *ex) |
|
epipe->nexttoggle = EHCI_QTD_GET_TOGGLE(nstatus); |
epipe->nexttoggle = EHCI_QTD_GET_TOGGLE(nstatus); |
} |
} |
|
|
/* |
|
* For a short transfer we need to update the toggle for the missing |
|
* packets within the qTD. |
|
*/ |
|
pkts_left = EHCI_QTD_GET_BYTES(status) / |
|
UGETW(xfer->pipe->endpoint->edesc->wMaxPacketSize); |
|
epipe->nexttoggle ^= pkts_left % 2; |
|
|
|
DPRINTFN(/*10*/2, ("ehci_idone: len=%d, actlen=%d, status=0x%x\n", |
DPRINTFN(/*10*/2, ("ehci_idone: len=%d, actlen=%d, status=0x%x\n", |
xfer->length, actlen, status)); |
xfer->length, actlen, status)); |
xfer->actlen = actlen; |
xfer->actlen = actlen; |
Line 956 ehci_detach(struct ehci_softc *sc, int f |
|
Line 923 ehci_detach(struct ehci_softc *sc, int f |
|
return (rv); |
return (rv); |
|
|
usb_uncallout(sc->sc_tmo_intrlist, ehci_intrlist_timeout, sc); |
usb_uncallout(sc->sc_tmo_intrlist, ehci_intrlist_timeout, sc); |
usb_uncallout(sc->sc_tmo_pcd, ehci_pcd_enable, sc); |
|
|
|
if (sc->sc_powerhook != NULL) |
if (sc->sc_powerhook != NULL) |
powerhook_disestablish(sc->sc_powerhook); |
powerhook_disestablish(sc->sc_powerhook); |
Line 1398 ehci_open(usbd_pipe_handle pipe) |
|
Line 1364 ehci_open(usbd_pipe_handle pipe) |
|
naks = 8; /* XXX */ |
naks = 8; /* XXX */ |
sqh = ehci_alloc_sqh(sc); |
sqh = ehci_alloc_sqh(sc); |
if (sqh == NULL) |
if (sqh == NULL) |
goto bad0; |
return (USBD_NOMEM); |
/* qh_link filled when the QH is added */ |
/* qh_link filled when the QH is added */ |
sqh->qh.qh_endp = htole32( |
sqh->qh.qh_endp = htole32( |
EHCI_QH_SET_ADDR(addr) | |
EHCI_QH_SET_ADDR(addr) | |
Line 1434 ehci_open(usbd_pipe_handle pipe) |
|
Line 1400 ehci_open(usbd_pipe_handle pipe) |
|
printf("ehci_open: usb_allocmem()=%d\n", err); |
printf("ehci_open: usb_allocmem()=%d\n", err); |
#endif |
#endif |
if (err) |
if (err) |
goto bad1; |
goto bad; |
pipe->methods = &ehci_device_ctrl_methods; |
pipe->methods = &ehci_device_ctrl_methods; |
s = splusb(); |
s = splusb(); |
ehci_add_qh(sqh, sc->sc_async_head); |
ehci_add_qh(sqh, sc->sc_async_head); |
Line 1449 ehci_open(usbd_pipe_handle pipe) |
|
Line 1415 ehci_open(usbd_pipe_handle pipe) |
|
case UE_INTERRUPT: |
case UE_INTERRUPT: |
pipe->methods = &ehci_device_intr_methods; |
pipe->methods = &ehci_device_intr_methods; |
ival = pipe->interval; |
ival = pipe->interval; |
if (ival == USBD_DEFAULT_INTERVAL) |
if (ival == USBD_DEFAULT_INTERVAL) { |
ival = ed->bInterval; |
if (speed == EHCI_QH_SPEED_HIGH) { |
return (ehci_device_setintr(sc, sqh, ival)); |
if (ed->bInterval > 16) { |
|
/* |
|
* illegal with high-speed, but there |
|
* were documentation bugs in the spec, |
|
* so be generous |
|
*/ |
|
ival = 256; |
|
} else |
|
ival = (1 << (ed->bInterval - 1)) / 8; |
|
} else |
|
ival = ed->bInterval; |
|
} |
|
err = ehci_device_setintr(sc, sqh, ival); |
|
if (err) |
|
goto bad; |
|
break; |
case UE_ISOCHRONOUS: |
case UE_ISOCHRONOUS: |
pipe->methods = &ehci_device_isoc_methods; |
pipe->methods = &ehci_device_isoc_methods; |
return (USBD_INVAL); |
/* FALLTHROUGH */ |
default: |
default: |
return (USBD_INVAL); |
err = USBD_INVAL; |
|
goto bad; |
} |
} |
return (USBD_NORMAL_COMPLETION); |
return (USBD_NORMAL_COMPLETION); |
|
|
bad1: |
bad: |
ehci_free_sqh(sc, sqh); |
ehci_free_sqh(sc, sqh); |
bad0: |
return (err); |
return (USBD_NOMEM); |
|
} |
} |
|
|
/* |
/* |
Line 1603 Static usb_config_descriptor_t ehci_conf |
|
Line 1584 Static usb_config_descriptor_t ehci_conf |
|
1, |
1, |
1, |
1, |
0, |
0, |
UC_SELF_POWERED, |
UC_ATTR_MBO | UC_SELF_POWERED, |
0 /* max power */ |
0 /* max power */ |
}; |
}; |
|
|
Line 1625 Static usb_endpoint_descriptor_t ehci_en |
|
Line 1606 Static usb_endpoint_descriptor_t ehci_en |
|
UE_DIR_IN | EHCI_INTR_ENDPT, |
UE_DIR_IN | EHCI_INTR_ENDPT, |
UE_INTERRUPT, |
UE_INTERRUPT, |
{8, 0}, /* max packet */ |
{8, 0}, /* max packet */ |
255 |
12 |
}; |
}; |
|
|
Static usb_hub_descriptor_t ehci_hubd = { |
Static usb_hub_descriptor_t ehci_hubd = { |
Line 1898 ehci_root_ctrl_start(usbd_xfer_handle xf |
|
Line 1879 ehci_root_ctrl_start(usbd_xfer_handle xf |
|
case UHF_C_PORT_SUSPEND: |
case UHF_C_PORT_SUSPEND: |
case UHF_C_PORT_OVER_CURRENT: |
case UHF_C_PORT_OVER_CURRENT: |
case UHF_C_PORT_RESET: |
case UHF_C_PORT_RESET: |
/* Enable RHSC interrupt if condition is cleared. */ |
|
if ((OREAD4(sc, port) >> 16) == 0) |
|
ehci_pcd_able(sc, 1); |
|
break; |
|
default: |
default: |
break; |
break; |
} |
} |
Line 2598 ehci_timeout(void *addr) |
|
Line 2575 ehci_timeout(void *addr) |
|
|
|
/* Execute the abort in a process context. */ |
/* Execute the abort in a process context. */ |
usb_init_task(&exfer->abort_task, ehci_timeout_task, addr); |
usb_init_task(&exfer->abort_task, ehci_timeout_task, addr); |
usb_add_task(exfer->xfer.pipe->device, &exfer->abort_task); |
usb_add_task(exfer->xfer.pipe->device, &exfer->abort_task, |
|
USB_TASKQ_HC); |
} |
} |
|
|
void |
void |
Line 3230 ehci_device_intr_done(usbd_xfer_handle x |
|
Line 3208 ehci_device_intr_done(usbd_xfer_handle x |
|
|
|
/************************/ |
/************************/ |
|
|
Static usbd_status ehci_device_isoc_transfer(usbd_xfer_handle xfer) { return USBD_IOERROR; } |
Static usbd_status |
Static usbd_status ehci_device_isoc_start(usbd_xfer_handle xfer) { return USBD_IOERROR; } |
ehci_device_isoc_transfer(usbd_xfer_handle xfer) |
Static void ehci_device_isoc_abort(usbd_xfer_handle xfer) { } |
{ |
Static void ehci_device_isoc_close(usbd_pipe_handle pipe) { } |
return USBD_IOERROR; |
Static void ehci_device_isoc_done(usbd_xfer_handle xfer) { } |
} |
|
Static usbd_status |
|
ehci_device_isoc_start(usbd_xfer_handle xfer) |
|
{ |
|
return USBD_IOERROR; |
|
} |
|
Static void |
|
ehci_device_isoc_abort(usbd_xfer_handle xfer) |
|
{ |
|
} |
|
Static void |
|
ehci_device_isoc_close(usbd_pipe_handle pipe) |
|
{ |
|
} |
|
Static void |
|
ehci_device_isoc_done(usbd_xfer_handle xfer) |
|
{ |
|
} |