version 1.181, 2011/07/01 23:48:20 |
version 1.181.6.17, 2012/03/11 01:52:28 |
|
|
/* $NetBSD$ */ |
/* $NetBSD$ */ |
|
|
/* |
/* |
* Copyright (c) 2004-2008 The NetBSD Foundation, Inc. |
* Copyright (c) 2004-2012 The NetBSD Foundation, Inc. |
* All rights reserved. |
* All rights reserved. |
* |
* |
* This code is derived from software contributed to The NetBSD Foundation |
* This code is derived from software contributed to The NetBSD Foundation |
* by Lennart Augustsson (lennart@augustsson.net), Charles M. Hannum and |
* by Lennart Augustsson (lennart@augustsson.net), Charles M. Hannum, |
* Jeremy Morse (jeremy.morse@gmail.com). |
* Jeremy Morse (jeremy.morse@gmail.com), Jared D. McNeill |
|
* (jmcneill@invisible.ca) and Matthew R. Green (mrg@eterna.com.au). |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* modification, are permitted provided that the following conditions |
Line 61 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 62 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/systm.h> |
#include <sys/systm.h> |
#include <sys/kernel.h> |
#include <sys/kernel.h> |
#include <sys/malloc.h> |
#include <sys/kmem.h> |
#include <sys/device.h> |
#include <sys/device.h> |
#include <sys/select.h> |
#include <sys/select.h> |
#include <sys/proc.h> |
#include <sys/proc.h> |
#include <sys/queue.h> |
#include <sys/queue.h> |
#include <sys/mutex.h> |
#include <sys/mutex.h> |
#include <sys/bus.h> |
#include <sys/bus.h> |
|
#include <sys/cpu.h> |
|
|
#include <machine/endian.h> |
#include <machine/endian.h> |
|
|
Line 82 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 84 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <dev/usb/usbroothub_subr.h> |
#include <dev/usb/usbroothub_subr.h> |
|
|
#ifdef EHCI_DEBUG |
#ifdef EHCI_DEBUG |
#define DPRINTF(x) do { if (ehcidebug) printf x; } while(0) |
#include <sys/kprintf.h> |
#define DPRINTFN(n,x) do { if (ehcidebug>(n)) printf x; } while (0) |
static void |
|
ehciprintf(const char *fmt, ...) |
|
{ |
|
va_list ap; |
|
|
|
va_start(ap, fmt); |
|
kprintf(fmt, TOLOG|TOCONS, NULL, NULL, ap); |
|
va_end(ap); |
|
} |
|
|
|
#define DPRINTF(x) do { if (ehcidebug) ehciprintf x; } while(0) |
|
#define DPRINTFN(n,x) do { if (ehcidebug>(n)) ehciprintf x; } while (0) |
int ehcidebug = 0; |
int ehcidebug = 0; |
#else |
#else |
#define DPRINTF(x) |
#define DPRINTF(x) |
Line 133 Static void ehci_idone(struct ehci_xfer |
|
Line 146 Static void ehci_idone(struct ehci_xfer |
|
Static void ehci_timeout(void *); |
Static void ehci_timeout(void *); |
Static void ehci_timeout_task(void *); |
Static void ehci_timeout_task(void *); |
Static void ehci_intrlist_timeout(void *); |
Static void ehci_intrlist_timeout(void *); |
|
Static void ehci_doorbell(void *); |
|
Static void ehci_pcd(void *); |
|
|
Static usbd_status ehci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t); |
Static usbd_status ehci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t); |
Static void ehci_freem(struct usbd_bus *, usb_dma_t *); |
Static void ehci_freem(struct usbd_bus *, usb_dma_t *); |
|
|
Static usbd_xfer_handle ehci_allocx(struct usbd_bus *); |
Static usbd_xfer_handle ehci_allocx(struct usbd_bus *); |
Static void ehci_freex(struct usbd_bus *, usbd_xfer_handle); |
Static void ehci_freex(struct usbd_bus *, usbd_xfer_handle); |
|
Static void ehci_get_lock(struct usbd_bus *, kmutex_t **); |
|
|
Static usbd_status ehci_root_ctrl_transfer(usbd_xfer_handle); |
Static usbd_status ehci_root_ctrl_transfer(usbd_xfer_handle); |
Static usbd_status ehci_root_ctrl_start(usbd_xfer_handle); |
Static usbd_status ehci_root_ctrl_start(usbd_xfer_handle); |
Line 179 Static void ehci_device_isoc_done(usbd_ |
|
Line 195 Static void ehci_device_isoc_done(usbd_ |
|
Static void ehci_device_clear_toggle(usbd_pipe_handle pipe); |
Static void ehci_device_clear_toggle(usbd_pipe_handle pipe); |
Static void ehci_noop(usbd_pipe_handle pipe); |
Static void ehci_noop(usbd_pipe_handle pipe); |
|
|
Static void ehci_pcd(ehci_softc_t *, usbd_xfer_handle); |
|
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 205 Static usbd_status ehci_device_request(u |
|
Line 220 Static usbd_status ehci_device_request(u |
|
Static usbd_status ehci_device_setintr(ehci_softc_t *, ehci_soft_qh_t *, |
Static usbd_status ehci_device_setintr(ehci_softc_t *, ehci_soft_qh_t *, |
int ival); |
int ival); |
|
|
Static void ehci_add_qh(ehci_soft_qh_t *, ehci_soft_qh_t *); |
Static void ehci_add_qh(ehci_softc_t *, ehci_soft_qh_t *, |
|
ehci_soft_qh_t *); |
Static void ehci_rem_qh(ehci_softc_t *, ehci_soft_qh_t *, |
Static void ehci_rem_qh(ehci_softc_t *, ehci_soft_qh_t *, |
ehci_soft_qh_t *); |
ehci_soft_qh_t *); |
Static void ehci_set_qh_qtd(ehci_soft_qh_t *, ehci_soft_qtd_t *); |
Static void ehci_set_qh_qtd(ehci_soft_qh_t *, ehci_soft_qtd_t *); |
Line 246 Static void ehci_dump_exfer(struct ehci |
|
Line 262 Static void ehci_dump_exfer(struct ehci |
|
#define ehci_active_intr_list(ex) ((ex)->inext.tqe_prev != NULL) |
#define ehci_active_intr_list(ex) ((ex)->inext.tqe_prev != NULL) |
|
|
Static const struct usbd_bus_methods ehci_bus_methods = { |
Static const struct usbd_bus_methods ehci_bus_methods = { |
ehci_open, |
.open_pipe = ehci_open, |
ehci_softintr, |
.soft_intr = ehci_softintr, |
ehci_poll, |
.do_poll = ehci_poll, |
ehci_allocm, |
.allocm = ehci_allocm, |
ehci_freem, |
.freem = ehci_freem, |
ehci_allocx, |
.allocx = ehci_allocx, |
ehci_freex, |
.freex = ehci_freex, |
|
.get_lock = ehci_get_lock, |
}; |
}; |
|
|
Static const struct usbd_pipe_methods ehci_root_ctrl_methods = { |
Static const struct usbd_pipe_methods ehci_root_ctrl_methods = { |
ehci_root_ctrl_transfer, |
.transfer = ehci_root_ctrl_transfer, |
ehci_root_ctrl_start, |
.start = ehci_root_ctrl_start, |
ehci_root_ctrl_abort, |
.abort = ehci_root_ctrl_abort, |
ehci_root_ctrl_close, |
.close = ehci_root_ctrl_close, |
ehci_noop, |
.cleartoggle = ehci_noop, |
ehci_root_ctrl_done, |
.done = ehci_root_ctrl_done, |
}; |
}; |
|
|
Static const struct usbd_pipe_methods ehci_root_intr_methods = { |
Static const struct usbd_pipe_methods ehci_root_intr_methods = { |
ehci_root_intr_transfer, |
.transfer = ehci_root_intr_transfer, |
ehci_root_intr_start, |
.start = ehci_root_intr_start, |
ehci_root_intr_abort, |
.abort = ehci_root_intr_abort, |
ehci_root_intr_close, |
.close = ehci_root_intr_close, |
ehci_noop, |
.cleartoggle = ehci_noop, |
ehci_root_intr_done, |
.done = ehci_root_intr_done, |
}; |
}; |
|
|
Static const struct usbd_pipe_methods ehci_device_ctrl_methods = { |
Static const struct usbd_pipe_methods ehci_device_ctrl_methods = { |
ehci_device_ctrl_transfer, |
.transfer = ehci_device_ctrl_transfer, |
ehci_device_ctrl_start, |
.start = ehci_device_ctrl_start, |
ehci_device_ctrl_abort, |
.abort = ehci_device_ctrl_abort, |
ehci_device_ctrl_close, |
.close = ehci_device_ctrl_close, |
ehci_noop, |
.cleartoggle = ehci_noop, |
ehci_device_ctrl_done, |
.done = ehci_device_ctrl_done, |
}; |
}; |
|
|
Static const struct usbd_pipe_methods ehci_device_intr_methods = { |
Static const struct usbd_pipe_methods ehci_device_intr_methods = { |
ehci_device_intr_transfer, |
.transfer = ehci_device_intr_transfer, |
ehci_device_intr_start, |
.start = ehci_device_intr_start, |
ehci_device_intr_abort, |
.abort = ehci_device_intr_abort, |
ehci_device_intr_close, |
.close = ehci_device_intr_close, |
ehci_device_clear_toggle, |
.cleartoggle = ehci_device_clear_toggle, |
ehci_device_intr_done, |
.done = ehci_device_intr_done, |
}; |
}; |
|
|
Static const struct usbd_pipe_methods ehci_device_bulk_methods = { |
Static const struct usbd_pipe_methods ehci_device_bulk_methods = { |
ehci_device_bulk_transfer, |
.transfer = ehci_device_bulk_transfer, |
ehci_device_bulk_start, |
.start = ehci_device_bulk_start, |
ehci_device_bulk_abort, |
.abort = ehci_device_bulk_abort, |
ehci_device_bulk_close, |
.close = ehci_device_bulk_close, |
ehci_device_clear_toggle, |
.cleartoggle = ehci_device_clear_toggle, |
ehci_device_bulk_done, |
.done = ehci_device_bulk_done, |
}; |
}; |
|
|
Static const struct usbd_pipe_methods ehci_device_isoc_methods = { |
Static const struct usbd_pipe_methods ehci_device_isoc_methods = { |
ehci_device_isoc_transfer, |
.transfer = ehci_device_isoc_transfer, |
ehci_device_isoc_start, |
.start = ehci_device_isoc_start, |
ehci_device_isoc_abort, |
.abort = ehci_device_isoc_abort, |
ehci_device_isoc_close, |
.close = ehci_device_isoc_close, |
ehci_noop, |
.cleartoggle = ehci_noop, |
ehci_device_isoc_done, |
.done = ehci_device_isoc_done, |
}; |
}; |
|
|
static const uint8_t revbits[EHCI_MAX_POLLRATE] = { |
static const uint8_t revbits[EHCI_MAX_POLLRATE] = { |
Line 334 ehci_init(ehci_softc_t *sc) |
|
Line 351 ehci_init(ehci_softc_t *sc) |
|
theehci = sc; |
theehci = sc; |
#endif |
#endif |
|
|
|
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); |
|
mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED); |
|
cv_init(&sc->sc_softwake_cv, "ehciab"); |
|
cv_init(&sc->sc_doorbell, "ehcidi"); |
|
|
|
sc->sc_doorbell_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, |
|
ehci_doorbell, sc); |
|
sc->sc_pcd_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE, |
|
ehci_pcd, 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); |
Line 431 ehci_init(ehci_softc_t *sc) |
|
Line 458 ehci_init(ehci_softc_t *sc) |
|
|
|
EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0)); |
EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0)); |
|
|
sc->sc_softitds = malloc(sc->sc_flsize * sizeof(ehci_soft_itd_t *), |
sc->sc_softitds = kmem_zalloc(sc->sc_flsize * sizeof(ehci_soft_itd_t *), |
M_USB, M_NOWAIT | M_ZERO); |
KM_SLEEP); |
if (sc->sc_softitds == NULL) |
if (sc->sc_softitds == NULL) |
return ENOMEM; |
return ENOMEM; |
LIST_INIT(&sc->sc_freeitds); |
LIST_INIT(&sc->sc_freeitds); |
TAILQ_INIT(&sc->sc_intrhead); |
TAILQ_INIT(&sc->sc_intrhead); |
mutex_init(&sc->sc_intrhead_lock, MUTEX_DEFAULT, IPL_USB); |
|
|
|
/* Set up the bus struct. */ |
/* Set up the bus struct. */ |
sc->sc_bus.methods = &ehci_bus_methods; |
sc->sc_bus.methods = &ehci_bus_methods; |
Line 522 ehci_init(ehci_softc_t *sc) |
|
Line 548 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); |
|
|
callout_init(&(sc->sc_tmo_intrlist), 0); |
callout_init(&sc->sc_tmo_intrlist, CALLOUT_MPSAFE); |
|
|
mutex_init(&sc->sc_doorbell_lock, MUTEX_DEFAULT, IPL_NONE); |
|
|
|
/* Turn on controller */ |
/* Turn on controller */ |
EOWRITE4(sc, EHCI_USBCMD, |
EOWRITE4(sc, EHCI_USBCMD, |
|
|
ehci_intr(void *v) |
ehci_intr(void *v) |
{ |
{ |
ehci_softc_t *sc = v; |
ehci_softc_t *sc = v; |
|
int ret = 0; |
|
|
if (sc == NULL || sc->sc_dying || !device_has_power(sc->sc_dev)) |
if (sc == NULL) |
return (0); |
return 0; |
|
|
|
mutex_spin_enter(&sc->sc_intr_lock); |
|
|
|
if (sc->sc_dying || !device_has_power(sc->sc_dev)) |
|
goto done; |
|
|
/* If we get an interrupt while polling, then just ignore it. */ |
/* If we get an interrupt while polling, then just ignore it. */ |
if (sc->sc_bus.use_polling) { |
if (sc->sc_bus.use_polling) { |
Line 580 ehci_intr(void *v) |
|
Line 610 ehci_intr(void *v) |
|
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
DPRINTFN(16, ("ehci_intr: ignored interrupt while polling\n")); |
DPRINTFN(16, ("ehci_intr: ignored interrupt while polling\n")); |
#endif |
#endif |
return (0); |
goto done; |
} |
} |
|
|
return (ehci_intr1(sc)); |
ret = ehci_intr1(sc); |
|
|
|
done: |
|
mutex_spin_exit(&sc->sc_intr_lock); |
|
return ret; |
} |
} |
|
|
Static int |
Static int |
Line 601 ehci_intr1(ehci_softc_t *sc) |
|
Line 635 ehci_intr1(ehci_softc_t *sc) |
|
return (0); |
return (0); |
} |
} |
|
|
|
KASSERT(mutex_owned(&sc->sc_intr_lock)); |
|
|
intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)); |
intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS)); |
if (!intrs) |
if (!intrs) |
return (0); |
return (0); |
Line 613 ehci_intr1(ehci_softc_t *sc) |
|
Line 649 ehci_intr1(ehci_softc_t *sc) |
|
return (0); |
return (0); |
|
|
EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */ |
EOWRITE4(sc, EHCI_USBSTS, intrs); /* Acknowledge */ |
sc->sc_bus.intr_context++; |
|
sc->sc_bus.no_intrs++; |
sc->sc_bus.no_intrs++; |
if (eintrs & EHCI_STS_IAA) { |
if (eintrs & EHCI_STS_IAA) { |
DPRINTF(("ehci_intr1: door bell\n")); |
DPRINTF(("ehci_intr1: door bell\n")); |
wakeup(&sc->sc_async_head); |
kpreempt_disable(); |
|
softint_schedule(sc->sc_doorbell_si); |
|
kpreempt_enable(); |
eintrs &= ~EHCI_STS_IAA; |
eintrs &= ~EHCI_STS_IAA; |
} |
} |
if (eintrs & (EHCI_STS_INT | EHCI_STS_ERRINT)) { |
if (eintrs & (EHCI_STS_INT | EHCI_STS_ERRINT)) { |
Line 633 ehci_intr1(ehci_softc_t *sc) |
|
Line 670 ehci_intr1(ehci_softc_t *sc) |
|
/* XXX what else */ |
/* XXX what else */ |
} |
} |
if (eintrs & EHCI_STS_PCD) { |
if (eintrs & EHCI_STS_PCD) { |
ehci_pcd(sc, sc->sc_intrxfer); |
kpreempt_disable(); |
|
softint_schedule(sc->sc_pcd_si); |
|
kpreempt_enable(); |
eintrs &= ~EHCI_STS_PCD; |
eintrs &= ~EHCI_STS_PCD; |
} |
} |
|
|
sc->sc_bus.intr_context--; |
|
|
|
if (eintrs != 0) { |
if (eintrs != 0) { |
/* Block unprocessed interrupts. */ |
/* Block unprocessed interrupts. */ |
sc->sc_eintrs &= ~eintrs; |
sc->sc_eintrs &= ~eintrs; |
Line 650 ehci_intr1(ehci_softc_t *sc) |
|
Line 687 ehci_intr1(ehci_softc_t *sc) |
|
return (1); |
return (1); |
} |
} |
|
|
|
Static void |
|
ehci_doorbell(void *addr) |
|
{ |
|
ehci_softc_t *sc = addr; |
|
|
|
mutex_enter(&sc->sc_lock); |
|
cv_broadcast(&sc->sc_doorbell); |
|
mutex_exit(&sc->sc_lock); |
|
} |
|
|
Static void |
Static void |
ehci_pcd(ehci_softc_t *sc, usbd_xfer_handle xfer) |
ehci_pcd(void *addr) |
{ |
{ |
|
ehci_softc_t *sc = addr; |
|
usbd_xfer_handle xfer; |
usbd_pipe_handle pipe; |
usbd_pipe_handle pipe; |
u_char *p; |
u_char *p; |
int i, m; |
int i, m; |
|
|
|
mutex_enter(&sc->sc_lock); |
|
xfer = sc->sc_intrxfer; |
|
|
if (xfer == NULL) { |
if (xfer == NULL) { |
/* Just ignore the change. */ |
/* Just ignore the change. */ |
return; |
goto done; |
} |
} |
|
|
pipe = xfer->pipe; |
pipe = xfer->pipe; |
Line 678 ehci_pcd(ehci_softc_t *sc, usbd_xfer_han |
|
Line 729 ehci_pcd(ehci_softc_t *sc, usbd_xfer_han |
|
xfer->status = USBD_NORMAL_COMPLETION; |
xfer->status = USBD_NORMAL_COMPLETION; |
|
|
usb_transfer_complete(xfer); |
usb_transfer_complete(xfer); |
|
|
|
done: |
|
mutex_exit(&sc->sc_lock); |
} |
} |
|
|
Static void |
Static void |
Line 687 ehci_softintr(void *v) |
|
Line 741 ehci_softintr(void *v) |
|
ehci_softc_t *sc = bus->hci_private; |
ehci_softc_t *sc = bus->hci_private; |
struct ehci_xfer *ex, *nextex; |
struct ehci_xfer *ex, *nextex; |
|
|
DPRINTFN(10,("%s: ehci_softintr (%d)\n", device_xname(sc->sc_dev), |
KASSERT(sc->sc_bus.use_polling || mutex_owned(&sc->sc_lock)); |
sc->sc_bus.intr_context)); |
|
|
|
sc->sc_bus.intr_context++; |
DPRINTFN(10,("%s: ehci_softintr\n", device_xname(sc->sc_dev))); |
|
|
/* |
/* |
* The only explanation I can think of for why EHCI is as brain dead |
* The only explanation I can think of for why EHCI is as brain dead |
Line 706 ehci_softintr(void *v) |
|
Line 759 ehci_softintr(void *v) |
|
/* Schedule a callout to catch any dropped transactions. */ |
/* Schedule a callout to catch any dropped transactions. */ |
if ((sc->sc_flags & EHCIF_DROPPED_INTR_WORKAROUND) && |
if ((sc->sc_flags & EHCIF_DROPPED_INTR_WORKAROUND) && |
!TAILQ_EMPTY(&sc->sc_intrhead)) |
!TAILQ_EMPTY(&sc->sc_intrhead)) |
callout_reset(&(sc->sc_tmo_intrlist), |
callout_reset(&sc->sc_tmo_intrlist, |
(hz), (ehci_intrlist_timeout), (sc)); |
hz, ehci_intrlist_timeout, sc); |
|
|
#ifdef USB_USE_SOFTINTR |
|
if (sc->sc_softwake) { |
if (sc->sc_softwake) { |
sc->sc_softwake = 0; |
sc->sc_softwake = 0; |
wakeup(&sc->sc_softwake); |
cv_broadcast(&sc->sc_softwake_cv); |
} |
} |
#endif /* USB_USE_SOFTINTR */ |
|
|
|
sc->sc_bus.intr_context--; |
|
} |
} |
|
|
/* Check for an interrupt. */ |
/* Check for an interrupt. */ |
Line 727 ehci_check_intr(ehci_softc_t *sc, struct |
|
Line 776 ehci_check_intr(ehci_softc_t *sc, struct |
|
|
|
DPRINTFN(/*15*/2, ("ehci_check_intr: ex=%p\n", ex)); |
DPRINTFN(/*15*/2, ("ehci_check_intr: ex=%p\n", ex)); |
|
|
|
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
attr = ex->xfer.pipe->endpoint->edesc->bmAttributes; |
attr = ex->xfer.pipe->endpoint->edesc->bmAttributes; |
if (UE_GET_XFERTYPE(attr) == UE_ISOCHRONOUS) |
if (UE_GET_XFERTYPE(attr) == UE_ISOCHRONOUS) |
ehci_check_itd_intr(sc, ex); |
ehci_check_itd_intr(sc, ex); |
Line 742 ehci_check_qh_intr(ehci_softc_t *sc, str |
|
Line 793 ehci_check_qh_intr(ehci_softc_t *sc, str |
|
ehci_soft_qtd_t *sqtd, *lsqtd; |
ehci_soft_qtd_t *sqtd, *lsqtd; |
__uint32_t status; |
__uint32_t status; |
|
|
|
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
if (ex->sqtdstart == NULL) { |
if (ex->sqtdstart == NULL) { |
printf("ehci_check_qh_intr: not valid sqtd\n"); |
printf("ehci_check_qh_intr: not valid sqtd\n"); |
return; |
return; |
Line 798 ehci_check_qh_intr(ehci_softc_t *sc, str |
|
Line 851 ehci_check_qh_intr(ehci_softc_t *sc, str |
|
} |
} |
|
|
Static void |
Static void |
ehci_check_itd_intr(ehci_softc_t *sc, struct ehci_xfer *ex) { |
ehci_check_itd_intr(ehci_softc_t *sc, struct ehci_xfer *ex) |
|
{ |
ehci_soft_itd_t *itd; |
ehci_soft_itd_t *itd; |
int i; |
int i; |
|
|
|
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
if (&ex->xfer != SIMPLEQ_FIRST(&ex->xfer.pipe->queue)) |
if (&ex->xfer != SIMPLEQ_FIRST(&ex->xfer.pipe->queue)) |
return; |
return; |
|
|
Line 849 ehci_idone(struct ehci_xfer *ex) |
|
Line 905 ehci_idone(struct ehci_xfer *ex) |
|
{ |
{ |
usbd_xfer_handle xfer = &ex->xfer; |
usbd_xfer_handle xfer = &ex->xfer; |
struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; |
struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; |
|
struct ehci_softc *sc = xfer->pipe->device->bus->hci_private; |
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; |
|
|
|
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
DPRINTFN(/*12*/2, ("ehci_idone: ex=%p\n", ex)); |
DPRINTFN(/*12*/2, ("ehci_idone: ex=%p\n", ex)); |
|
|
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
{ |
{ |
int s = splhigh(); |
|
if (ex->isdone) { |
if (ex->isdone) { |
splx(s); |
|
#ifdef EHCI_DEBUG |
#ifdef EHCI_DEBUG |
printf("ehci_idone: ex is done!\n "); |
printf("ehci_idone: ex is done!\n "); |
ehci_dump_exfer(ex); |
ehci_dump_exfer(ex); |
Line 868 ehci_idone(struct ehci_xfer *ex) |
|
Line 926 ehci_idone(struct ehci_xfer *ex) |
|
return; |
return; |
} |
} |
ex->isdone = 1; |
ex->isdone = 1; |
splx(s); |
|
} |
} |
#endif |
#endif |
if (xfer->status == USBD_CANCELLED || |
if (xfer->status == USBD_CANCELLED || |
Line 999 ehci_idone(struct ehci_xfer *ex) |
|
Line 1056 ehci_idone(struct ehci_xfer *ex) |
|
} |
} |
/* XXX need to reset TT on missed microframe */ |
/* XXX need to reset TT on missed microframe */ |
if (status & EHCI_QTD_MISSEDMICRO) { |
if (status & EHCI_QTD_MISSEDMICRO) { |
ehci_softc_t *sc = |
|
xfer->pipe->device->bus->hci_private; |
|
|
|
printf("%s: missed microframe, TT reset not " |
printf("%s: missed microframe, TT reset not " |
"implemented, hub might be inoperational\n", |
"implemented, hub might be inoperational\n", |
device_xname(sc->sc_dev)); |
device_xname(sc->sc_dev)); |
Line 1042 ehci_waitintr(ehci_softc_t *sc, usbd_xfe |
|
Line 1096 ehci_waitintr(ehci_softc_t *sc, usbd_xfe |
|
ehci_dump_regs(sc); |
ehci_dump_regs(sc); |
#endif |
#endif |
if (intrs) { |
if (intrs) { |
|
mutex_spin_enter(&sc->sc_intr_lock); |
ehci_intr1(sc); |
ehci_intr1(sc); |
|
mutex_spin_exit(&sc->sc_intr_lock); |
if (xfer->status != USBD_IN_PROGRESS) |
if (xfer->status != USBD_IN_PROGRESS) |
return; |
return; |
} |
} |
Line 1051 ehci_waitintr(ehci_softc_t *sc, usbd_xfe |
|
Line 1107 ehci_waitintr(ehci_softc_t *sc, usbd_xfe |
|
/* Timeout */ |
/* Timeout */ |
DPRINTF(("ehci_waitintr: timeout\n")); |
DPRINTF(("ehci_waitintr: timeout\n")); |
xfer->status = USBD_TIMEOUT; |
xfer->status = USBD_TIMEOUT; |
|
mutex_enter(&sc->sc_lock); |
usb_transfer_complete(xfer); |
usb_transfer_complete(xfer); |
|
mutex_exit(&sc->sc_lock); |
/* XXX should free TD */ |
/* XXX should free TD */ |
} |
} |
|
|
Line 1069 ehci_poll(struct usbd_bus *bus) |
|
Line 1127 ehci_poll(struct usbd_bus *bus) |
|
} |
} |
#endif |
#endif |
|
|
if (EOREAD4(sc, EHCI_USBSTS) & sc->sc_eintrs) |
if (EOREAD4(sc, EHCI_USBSTS) & sc->sc_eintrs) { |
|
mutex_spin_enter(&sc->sc_intr_lock); |
ehci_intr1(sc); |
ehci_intr1(sc); |
|
mutex_spin_exit(&sc->sc_intr_lock); |
|
} |
} |
} |
|
|
void |
void |
Line 1085 ehci_childdet(device_t self, device_t ch |
|
Line 1146 ehci_childdet(device_t self, device_t ch |
|
int |
int |
ehci_detach(struct ehci_softc *sc, int flags) |
ehci_detach(struct ehci_softc *sc, int flags) |
{ |
{ |
|
usbd_xfer_handle xfer; |
int rv = 0; |
int rv = 0; |
|
|
if (sc->sc_child != NULL) |
if (sc->sc_child != NULL) |
Line 1093 ehci_detach(struct ehci_softc *sc, int f |
|
Line 1155 ehci_detach(struct ehci_softc *sc, int f |
|
if (rv != 0) |
if (rv != 0) |
return (rv); |
return (rv); |
|
|
callout_stop(&sc->sc_tmo_intrlist); |
callout_halt(&sc->sc_tmo_intrlist, NULL); |
|
callout_destroy(&sc->sc_tmo_intrlist); |
usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */ |
|
|
|
/* XXX free other data structures XXX */ |
/* XXX free other data structures XXX */ |
mutex_destroy(&sc->sc_doorbell_lock); |
if (sc->sc_softitds) |
mutex_destroy(&sc->sc_intrhead_lock); |
kmem_free(sc->sc_softitds, |
|
sc->sc_flsize * sizeof(ehci_soft_itd_t *)); |
|
cv_destroy(&sc->sc_doorbell); |
|
cv_destroy(&sc->sc_softwake_cv); |
|
|
|
softint_disestablish(sc->sc_doorbell_si); |
|
softint_disestablish(sc->sc_pcd_si); |
|
|
|
while ((xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers)) != NULL) { |
|
SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next); |
|
kmem_free(xfer, sizeof(struct ehci_xfer)); |
|
} |
|
|
EOWRITE4(sc, EHCI_CONFIGFLAG, 0); |
EOWRITE4(sc, EHCI_CONFIGFLAG, 0); |
|
|
|
|
ehci_suspend(device_t dv, const pmf_qual_t *qual) |
ehci_suspend(device_t dv, const pmf_qual_t *qual) |
{ |
{ |
ehci_softc_t *sc = device_private(dv); |
ehci_softc_t *sc = device_private(dv); |
int i, s; |
int i; |
uint32_t cmd, hcr; |
uint32_t cmd, hcr; |
|
|
s = splhardusb(); |
mutex_spin_enter(&sc->sc_intr_lock); |
|
|
sc->sc_bus.use_polling++; |
sc->sc_bus.use_polling++; |
|
mutex_spin_exit(&sc->sc_intr_lock); |
|
|
for (i = 1; i <= sc->sc_noport; i++) { |
for (i = 1; i <= sc->sc_noport; i++) { |
cmd = EOREAD4(sc, EHCI_PORTSC(i)) & ~EHCI_PS_CLEAR; |
cmd = EOREAD4(sc, EHCI_PORTSC(i)) & ~EHCI_PS_CLEAR; |
Line 1176 ehci_suspend(device_t dv, const pmf_qual |
|
Line 1248 ehci_suspend(device_t dv, const pmf_qual |
|
if (hcr != EHCI_STS_HCH) |
if (hcr != EHCI_STS_HCH) |
printf("%s: config timeout\n", device_xname(dv)); |
printf("%s: config timeout\n", device_xname(dv)); |
|
|
|
mutex_spin_enter(&sc->sc_intr_lock); |
sc->sc_bus.use_polling--; |
sc->sc_bus.use_polling--; |
splx(s); |
mutex_spin_exit(&sc->sc_intr_lock); |
|
|
return true; |
return true; |
} |
} |
Line 1296 ehci_allocx(struct usbd_bus *bus) |
|
Line 1369 ehci_allocx(struct usbd_bus *bus) |
|
} |
} |
#endif |
#endif |
} else { |
} else { |
xfer = malloc(sizeof(struct ehci_xfer), M_USB, M_NOWAIT); |
xfer = kmem_alloc(sizeof(struct ehci_xfer), KM_SLEEP); |
} |
} |
if (xfer != NULL) { |
if (xfer != NULL) { |
memset(xfer, 0, sizeof(struct ehci_xfer)); |
memset(xfer, 0, sizeof(struct ehci_xfer)); |
Line 1327 ehci_freex(struct usbd_bus *bus, usbd_xf |
|
Line 1400 ehci_freex(struct usbd_bus *bus, usbd_xf |
|
} |
} |
|
|
Static void |
Static void |
|
ehci_get_lock(struct usbd_bus *bus, kmutex_t **lock) |
|
{ |
|
struct ehci_softc *sc = bus->hci_private; |
|
|
|
*lock = &sc->sc_lock; |
|
} |
|
|
|
Static void |
ehci_device_clear_toggle(usbd_pipe_handle pipe) |
ehci_device_clear_toggle(usbd_pipe_handle pipe) |
{ |
{ |
struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; |
struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; |
Line 1540 ehci_open(usbd_pipe_handle pipe) |
|
Line 1621 ehci_open(usbd_pipe_handle pipe) |
|
struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; |
struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; |
ehci_soft_qh_t *sqh; |
ehci_soft_qh_t *sqh; |
usbd_status err; |
usbd_status err; |
int s; |
|
int ival, speed, naks; |
int ival, speed, naks; |
int hshubaddr, hshubport; |
int hshubaddr, hshubport; |
|
|
Line 1665 ehci_open(usbd_pipe_handle pipe) |
|
Line 1745 ehci_open(usbd_pipe_handle pipe) |
|
if (err) |
if (err) |
goto bad; |
goto bad; |
pipe->methods = &ehci_device_ctrl_methods; |
pipe->methods = &ehci_device_ctrl_methods; |
s = splusb(); |
mutex_enter(&sc->sc_lock); |
ehci_add_qh(sqh, sc->sc_async_head); |
ehci_add_qh(sc, sqh, sc->sc_async_head); |
splx(s); |
mutex_exit(&sc->sc_lock); |
break; |
break; |
case UE_BULK: |
case UE_BULK: |
pipe->methods = &ehci_device_bulk_methods; |
pipe->methods = &ehci_device_bulk_methods; |
s = splusb(); |
mutex_enter(&sc->sc_lock); |
ehci_add_qh(sqh, sc->sc_async_head); |
ehci_add_qh(sc, sqh, sc->sc_async_head); |
splx(s); |
mutex_exit(&sc->sc_lock); |
break; |
break; |
case UE_INTERRUPT: |
case UE_INTERRUPT: |
pipe->methods = &ehci_device_intr_methods; |
pipe->methods = &ehci_device_intr_methods; |
Line 1725 ehci_open(usbd_pipe_handle pipe) |
|
Line 1805 ehci_open(usbd_pipe_handle pipe) |
|
} |
} |
|
|
/* |
/* |
* Add an ED to the schedule. Called at splusb(). |
* Add an ED to the schedule. Called with USB lock held. |
*/ |
*/ |
Static void |
Static void |
ehci_add_qh(ehci_soft_qh_t *sqh, ehci_soft_qh_t *head) |
ehci_add_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qh_t *head) |
{ |
{ |
SPLUSBCHECK; |
|
|
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
usb_syncmem(&head->dma, head->offs + offsetof(ehci_qh_t, qh_link), |
usb_syncmem(&head->dma, head->offs + offsetof(ehci_qh_t, qh_link), |
sizeof(head->qh.qh_link), BUS_DMASYNC_POSTWRITE); |
sizeof(head->qh.qh_link), BUS_DMASYNC_POSTWRITE); |
Line 1752 ehci_add_qh(ehci_soft_qh_t *sqh, ehci_so |
|
Line 1833 ehci_add_qh(ehci_soft_qh_t *sqh, ehci_so |
|
} |
} |
|
|
/* |
/* |
* Remove an ED from the schedule. Called at splusb(). |
* Remove an ED from the schedule. Called with USB lock held. |
*/ |
*/ |
Static void |
Static void |
ehci_rem_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qh_t *head) |
ehci_rem_qh(ehci_softc_t *sc, ehci_soft_qh_t *sqh, ehci_soft_qh_t *head) |
{ |
{ |
ehci_soft_qh_t *p; |
ehci_soft_qh_t *p; |
|
|
SPLUSBCHECK; |
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
/* XXX */ |
/* XXX */ |
for (p = head; p != NULL && p->next != sqh; p = p->next) |
for (p = head; p != NULL && p->next != sqh; p = p->next) |
; |
; |
Line 1819 ehci_set_qh_qtd(ehci_soft_qh_t *sqh, ehc |
|
Line 1901 ehci_set_qh_qtd(ehci_soft_qh_t *sqh, ehc |
|
Static void |
Static void |
ehci_sync_hc(ehci_softc_t *sc) |
ehci_sync_hc(ehci_softc_t *sc) |
{ |
{ |
int s, error; |
int error; |
|
|
|
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
if (sc->sc_dying) { |
if (sc->sc_dying) { |
DPRINTFN(2,("ehci_sync_hc: dying\n")); |
DPRINTFN(2,("ehci_sync_hc: dying\n")); |
return; |
return; |
} |
} |
DPRINTFN(2,("ehci_sync_hc: enter\n")); |
DPRINTFN(2,("ehci_sync_hc: enter\n")); |
mutex_enter(&sc->sc_doorbell_lock); /* get doorbell */ |
|
s = splhardusb(); |
|
/* ask for doorbell */ |
/* ask for doorbell */ |
EOWRITE4(sc, EHCI_USBCMD, EOREAD4(sc, EHCI_USBCMD) | EHCI_CMD_IAAD); |
EOWRITE4(sc, EHCI_USBCMD, EOREAD4(sc, EHCI_USBCMD) | EHCI_CMD_IAAD); |
DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n", |
DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n", |
EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS))); |
EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS))); |
error = tsleep(&sc->sc_async_head, PZERO, "ehcidi", hz); /* bell wait */ |
error = cv_timedwait(&sc->sc_doorbell, &sc->sc_lock, hz); /* bell wait */ |
DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n", |
DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n", |
EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS))); |
EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS))); |
splx(s); |
|
mutex_exit(&sc->sc_doorbell_lock); /* release doorbell */ |
|
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
if (error) |
if (error) |
printf("ehci_sync_hc: tsleep() = %d\n", error); |
printf("ehci_sync_hc: cv_timedwait() = %d\n", error); |
#endif |
#endif |
DPRINTFN(2,("ehci_sync_hc: exit\n")); |
DPRINTFN(2,("ehci_sync_hc: exit\n")); |
} |
} |
|
|
/*Call at splusb*/ |
|
Static void |
Static void |
ehci_rem_free_itd_chain(ehci_softc_t *sc, struct ehci_xfer *exfer) |
ehci_rem_free_itd_chain(ehci_softc_t *sc, struct ehci_xfer *exfer) |
{ |
{ |
Line 1974 Static const usb_hub_descriptor_t ehci_h |
|
Line 2053 Static const usb_hub_descriptor_t ehci_h |
|
Static usbd_status |
Static usbd_status |
ehci_root_ctrl_transfer(usbd_xfer_handle xfer) |
ehci_root_ctrl_transfer(usbd_xfer_handle xfer) |
{ |
{ |
|
ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; |
usbd_status err; |
usbd_status err; |
|
|
/* Insert last in queue. */ |
/* Insert last in queue. */ |
|
mutex_enter(&sc->sc_lock); |
err = usb_insert_transfer(xfer); |
err = usb_insert_transfer(xfer); |
|
mutex_exit(&sc->sc_lock); |
if (err) |
if (err) |
return (err); |
return (err); |
|
|
Line 1992 ehci_root_ctrl_start(usbd_xfer_handle xf |
|
Line 2074 ehci_root_ctrl_start(usbd_xfer_handle xf |
|
usb_device_request_t *req; |
usb_device_request_t *req; |
void *buf = NULL; |
void *buf = NULL; |
int port, i; |
int port, i; |
int s, len, value, index, l, totlen = 0; |
int len, value, index, l, totlen = 0; |
usb_port_status_t ps; |
usb_port_status_t ps; |
usb_hub_descriptor_t hubd; |
usb_hub_descriptor_t hubd; |
usbd_status err; |
usbd_status err; |
Line 2414 ehci_root_ctrl_start(usbd_xfer_handle xf |
|
Line 2496 ehci_root_ctrl_start(usbd_xfer_handle xf |
|
xfer->actlen = totlen; |
xfer->actlen = totlen; |
err = USBD_NORMAL_COMPLETION; |
err = USBD_NORMAL_COMPLETION; |
ret: |
ret: |
|
mutex_enter(&sc->sc_lock); |
xfer->status = err; |
xfer->status = err; |
s = splusb(); |
|
usb_transfer_complete(xfer); |
usb_transfer_complete(xfer); |
splx(s); |
mutex_exit(&sc->sc_lock); |
return (USBD_IN_PROGRESS); |
return (USBD_IN_PROGRESS); |
} |
} |
|
|
Line 2473 ehci_root_intr_done(usbd_xfer_handle xfe |
|
Line 2555 ehci_root_intr_done(usbd_xfer_handle xfe |
|
Static usbd_status |
Static usbd_status |
ehci_root_intr_transfer(usbd_xfer_handle xfer) |
ehci_root_intr_transfer(usbd_xfer_handle xfer) |
{ |
{ |
|
ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; |
usbd_status err; |
usbd_status err; |
|
|
/* Insert last in queue. */ |
/* Insert last in queue. */ |
|
mutex_enter(&sc->sc_lock); |
err = usb_insert_transfer(xfer); |
err = usb_insert_transfer(xfer); |
|
mutex_exit(&sc->sc_lock); |
if (err) |
if (err) |
return (err); |
return (err); |
|
|
Line 2493 ehci_root_intr_start(usbd_xfer_handle xf |
|
Line 2578 ehci_root_intr_start(usbd_xfer_handle xf |
|
if (sc->sc_dying) |
if (sc->sc_dying) |
return (USBD_IOERROR); |
return (USBD_IOERROR); |
|
|
|
mutex_enter(&sc->sc_lock); |
sc->sc_intrxfer = xfer; |
sc->sc_intrxfer = xfer; |
|
mutex_exit(&sc->sc_lock); |
|
|
return (USBD_IN_PROGRESS); |
return (USBD_IN_PROGRESS); |
} |
} |
Line 2502 ehci_root_intr_start(usbd_xfer_handle xf |
|
Line 2589 ehci_root_intr_start(usbd_xfer_handle xf |
|
Static void |
Static void |
ehci_root_intr_abort(usbd_xfer_handle xfer) |
ehci_root_intr_abort(usbd_xfer_handle xfer) |
{ |
{ |
int s; |
ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; |
|
|
|
KASSERT(mutex_owned(&sc->sc_lock)); |
if (xfer->pipe->intrxfer == xfer) { |
if (xfer->pipe->intrxfer == xfer) { |
DPRINTF(("ehci_root_intr_abort: remove\n")); |
DPRINTF(("ehci_root_intr_abort: remove\n")); |
xfer->pipe->intrxfer = NULL; |
xfer->pipe->intrxfer = NULL; |
} |
} |
xfer->status = USBD_CANCELLED; |
xfer->status = USBD_CANCELLED; |
s = splusb(); |
|
usb_transfer_complete(xfer); |
usb_transfer_complete(xfer); |
splx(s); |
|
} |
} |
|
|
/* Close the root pipe. */ |
/* Close the root pipe. */ |
Line 2520 ehci_root_intr_close(usbd_pipe_handle pi |
|
Line 2606 ehci_root_intr_close(usbd_pipe_handle pi |
|
{ |
{ |
ehci_softc_t *sc = pipe->device->bus->hci_private; |
ehci_softc_t *sc = pipe->device->bus->hci_private; |
|
|
|
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
DPRINTF(("ehci_root_intr_close\n")); |
DPRINTF(("ehci_root_intr_close\n")); |
|
|
sc->sc_intrxfer = NULL; |
sc->sc_intrxfer = NULL; |
Line 2578 ehci_free_sqh(ehci_softc_t *sc, ehci_sof |
|
Line 2666 ehci_free_sqh(ehci_softc_t *sc, ehci_sof |
|
Static ehci_soft_qtd_t * |
Static ehci_soft_qtd_t * |
ehci_alloc_sqtd(ehci_softc_t *sc) |
ehci_alloc_sqtd(ehci_softc_t *sc) |
{ |
{ |
ehci_soft_qtd_t *sqtd; |
ehci_soft_qtd_t *sqtd = NULL; |
usbd_status err; |
usbd_status err; |
int i, offs; |
int i, offs; |
usb_dma_t dma; |
usb_dma_t dma; |
int s; |
|
|
|
if (sc->sc_freeqtds == NULL) { |
if (sc->sc_freeqtds == NULL) { |
DPRINTFN(2, ("ehci_alloc_sqtd: allocating chunk\n")); |
DPRINTFN(2, ("ehci_alloc_sqtd: allocating chunk\n")); |
|
|
err = usb_allocmem(&sc->sc_bus, EHCI_SQTD_SIZE*EHCI_SQTD_CHUNK, |
err = usb_allocmem(&sc->sc_bus, EHCI_SQTD_SIZE*EHCI_SQTD_CHUNK, |
EHCI_PAGE_SIZE, &dma); |
EHCI_PAGE_SIZE, &dma); |
#ifdef EHCI_DEBUG |
#ifdef EHCI_DEBUG |
Line 2593 ehci_alloc_sqtd(ehci_softc_t *sc) |
|
Line 2681 ehci_alloc_sqtd(ehci_softc_t *sc) |
|
printf("ehci_alloc_sqtd: usb_allocmem()=%d\n", err); |
printf("ehci_alloc_sqtd: usb_allocmem()=%d\n", err); |
#endif |
#endif |
if (err) |
if (err) |
return (NULL); |
goto done; |
s = splusb(); |
|
for(i = 0; i < EHCI_SQTD_CHUNK; i++) { |
for(i = 0; i < EHCI_SQTD_CHUNK; i++) { |
offs = i * EHCI_SQTD_SIZE; |
offs = i * EHCI_SQTD_SIZE; |
sqtd = KERNADDR(&dma, offs); |
sqtd = KERNADDR(&dma, offs); |
sqtd->physaddr = DMAADDR(&dma, offs); |
sqtd->physaddr = DMAADDR(&dma, offs); |
sqtd->dma = dma; |
sqtd->dma = dma; |
sqtd->offs = offs; |
sqtd->offs = offs; |
|
|
sqtd->nextqtd = sc->sc_freeqtds; |
sqtd->nextqtd = sc->sc_freeqtds; |
sc->sc_freeqtds = sqtd; |
sc->sc_freeqtds = sqtd; |
} |
} |
splx(s); |
|
} |
} |
|
|
s = splusb(); |
|
sqtd = sc->sc_freeqtds; |
sqtd = sc->sc_freeqtds; |
sc->sc_freeqtds = sqtd->nextqtd; |
sc->sc_freeqtds = sqtd->nextqtd; |
memset(&sqtd->qtd, 0, sizeof(ehci_qtd_t)); |
memset(&sqtd->qtd, 0, sizeof(ehci_qtd_t)); |
sqtd->nextqtd = NULL; |
sqtd->nextqtd = NULL; |
sqtd->xfer = NULL; |
sqtd->xfer = NULL; |
splx(s); |
|
|
|
|
done: |
return (sqtd); |
return (sqtd); |
} |
} |
|
|
Static void |
Static void |
ehci_free_sqtd(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd) |
ehci_free_sqtd(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd) |
{ |
{ |
int s; |
|
|
|
s = splusb(); |
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
sqtd->nextqtd = sc->sc_freeqtds; |
sqtd->nextqtd = sc->sc_freeqtds; |
sc->sc_freeqtds = sqtd; |
sc->sc_freeqtds = sqtd; |
splx(s); |
|
} |
} |
|
|
Static usbd_status |
Static usbd_status |
Line 2794 ehci_alloc_itd(ehci_softc_t *sc) |
|
Line 2880 ehci_alloc_itd(ehci_softc_t *sc) |
|
{ |
{ |
struct ehci_soft_itd *itd, *freeitd; |
struct ehci_soft_itd *itd, *freeitd; |
usbd_status err; |
usbd_status err; |
int i, s, offs, frindex, previndex; |
int i, offs, frindex, previndex; |
usb_dma_t dma; |
usb_dma_t dma; |
|
|
s = splusb(); |
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
/* Find an itd that wasn't freed this frame or last frame. This can |
/* Find an itd that wasn't freed this frame or last frame. This can |
* discard itds that were freed before frindex wrapped around |
* discard itds that were freed before frindex wrapped around |
Line 2848 ehci_alloc_itd(ehci_softc_t *sc) |
|
Line 2934 ehci_alloc_itd(ehci_softc_t *sc) |
|
itd->u.frame_list.prev = NULL; |
itd->u.frame_list.prev = NULL; |
itd->xfer_next = NULL; |
itd->xfer_next = NULL; |
itd->slot = 0; |
itd->slot = 0; |
splx(s); |
|
|
|
return itd; |
return itd; |
} |
} |
Line 2856 ehci_alloc_itd(ehci_softc_t *sc) |
|
Line 2941 ehci_alloc_itd(ehci_softc_t *sc) |
|
Static void |
Static void |
ehci_free_itd(ehci_softc_t *sc, ehci_soft_itd_t *itd) |
ehci_free_itd(ehci_softc_t *sc, ehci_soft_itd_t *itd) |
{ |
{ |
int s; |
|
|
|
s = splusb(); |
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
LIST_INSERT_HEAD(&sc->sc_freeitds, itd, u.free_list); |
LIST_INSERT_HEAD(&sc->sc_freeitds, itd, u.free_list); |
splx(s); |
|
} |
} |
|
|
/****************/ |
/****************/ |
Line 2875 ehci_close_pipe(usbd_pipe_handle pipe, e |
|
Line 2959 ehci_close_pipe(usbd_pipe_handle pipe, e |
|
struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; |
struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; |
ehci_softc_t *sc = pipe->device->bus->hci_private; |
ehci_softc_t *sc = pipe->device->bus->hci_private; |
ehci_soft_qh_t *sqh = epipe->sqh; |
ehci_soft_qh_t *sqh = epipe->sqh; |
int s; |
|
|
|
s = splusb(); |
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
ehci_rem_qh(sc, sqh, head); |
ehci_rem_qh(sc, sqh, head); |
splx(s); |
|
ehci_free_sqh(sc, epipe->sqh); |
ehci_free_sqh(sc, epipe->sqh); |
} |
} |
|
|
Line 2893 ehci_close_pipe(usbd_pipe_handle pipe, e |
|
Line 2976 ehci_close_pipe(usbd_pipe_handle pipe, e |
|
* If the transaction has already happened we rely on the ordinary |
* If the transaction has already happened we rely on the ordinary |
* interrupt processing to process it. |
* interrupt processing to process it. |
* XXX This is most probably wrong. |
* XXX This is most probably wrong. |
|
* XXXMRG this doesn't make sense anymore. |
*/ |
*/ |
Static void |
Static void |
ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) |
ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) |
Line 2904 ehci_abort_xfer(usbd_xfer_handle xfer, u |
|
Line 2988 ehci_abort_xfer(usbd_xfer_handle xfer, u |
|
ehci_soft_qtd_t *sqtd; |
ehci_soft_qtd_t *sqtd; |
ehci_physaddr_t cur; |
ehci_physaddr_t cur; |
u_int32_t qhstatus; |
u_int32_t qhstatus; |
int s; |
|
int hit; |
int hit; |
int wake; |
int wake; |
|
|
DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p\n", xfer, epipe)); |
DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p\n", xfer, epipe)); |
|
|
|
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
if (sc->sc_dying) { |
if (sc->sc_dying) { |
/* If we're dying, just do the software part. */ |
/* If we're dying, just do the software part. */ |
s = splusb(); |
|
xfer->status = status; /* make software ignore it */ |
xfer->status = status; /* make software ignore it */ |
callout_stop(&xfer->timeout_handle); |
callout_stop(&xfer->timeout_handle); |
usb_transfer_complete(xfer); |
usb_transfer_complete(xfer); |
splx(s); |
|
return; |
return; |
} |
} |
|
|
if (xfer->device->bus->intr_context) |
if (cpu_intr_p() || cpu_softintr_p()) |
panic("ehci_abort_xfer: not in process context"); |
panic("ehci_abort_xfer: not in process context"); |
|
|
/* |
/* |
Line 2938 ehci_abort_xfer(usbd_xfer_handle xfer, u |
|
Line 3021 ehci_abort_xfer(usbd_xfer_handle xfer, u |
|
DPRINTFN(2, ("ehci_abort_xfer: waiting for abort to finish\n")); |
DPRINTFN(2, ("ehci_abort_xfer: waiting for abort to finish\n")); |
xfer->hcflags |= UXFER_ABORTWAIT; |
xfer->hcflags |= UXFER_ABORTWAIT; |
while (xfer->hcflags & UXFER_ABORTING) |
while (xfer->hcflags & UXFER_ABORTING) |
tsleep(&xfer->hcflags, PZERO, "ehciaw", 0); |
cv_wait(&xfer->hccv, &sc->sc_lock); |
return; |
return; |
} |
} |
xfer->hcflags |= UXFER_ABORTING; |
xfer->hcflags |= UXFER_ABORTING; |
Line 2946 ehci_abort_xfer(usbd_xfer_handle xfer, u |
|
Line 3029 ehci_abort_xfer(usbd_xfer_handle xfer, u |
|
/* |
/* |
* Step 1: Make interrupt routine and hardware ignore xfer. |
* Step 1: Make interrupt routine and hardware ignore xfer. |
*/ |
*/ |
s = splusb(); |
|
xfer->status = status; /* make software ignore it */ |
xfer->status = status; /* make software ignore it */ |
callout_stop(&xfer->timeout_handle); |
callout_stop(&xfer->timeout_handle); |
|
|
Line 2973 ehci_abort_xfer(usbd_xfer_handle xfer, u |
|
Line 3055 ehci_abort_xfer(usbd_xfer_handle xfer, u |
|
if (sqtd == exfer->sqtdend) |
if (sqtd == exfer->sqtdend) |
break; |
break; |
} |
} |
splx(s); |
|
|
|
/* |
/* |
* Step 2: Wait until we know hardware has finished any possible |
* Step 2: Wait until we know hardware has finished any possible |
Line 2981 ehci_abort_xfer(usbd_xfer_handle xfer, u |
|
Line 3062 ehci_abort_xfer(usbd_xfer_handle xfer, u |
|
* has run. |
* has run. |
*/ |
*/ |
ehci_sync_hc(sc); |
ehci_sync_hc(sc); |
s = splusb(); |
|
#ifdef USB_USE_SOFTINTR |
|
sc->sc_softwake = 1; |
sc->sc_softwake = 1; |
#endif /* USB_USE_SOFTINTR */ |
|
usb_schedsoftintr(&sc->sc_bus); |
usb_schedsoftintr(&sc->sc_bus); |
#ifdef USB_USE_SOFTINTR |
cv_wait(&sc->sc_softwake_cv, &sc->sc_lock); |
tsleep(&sc->sc_softwake, PZERO, "ehciab", 0); |
|
#endif /* USB_USE_SOFTINTR */ |
|
splx(s); |
|
|
|
/* |
/* |
* Step 3: Remove any vestiges of the xfer from the hardware. |
* Step 3: Remove any vestiges of the xfer from the hardware. |
Line 2998 ehci_abort_xfer(usbd_xfer_handle xfer, u |
|
Line 3073 ehci_abort_xfer(usbd_xfer_handle xfer, u |
|
* the TDs of this xfer we check if the hardware points to |
* the TDs of this xfer we check if the hardware points to |
* any of them. |
* any of them. |
*/ |
*/ |
s = splusb(); /* XXX why? */ |
|
|
|
usb_syncmem(&sqh->dma, |
usb_syncmem(&sqh->dma, |
sqh->offs + offsetof(ehci_qh_t, qh_curqtd), |
sqh->offs + offsetof(ehci_qh_t, qh_curqtd), |
Line 3038 ehci_abort_xfer(usbd_xfer_handle xfer, u |
|
Line 3112 ehci_abort_xfer(usbd_xfer_handle xfer, u |
|
wake = xfer->hcflags & UXFER_ABORTWAIT; |
wake = xfer->hcflags & UXFER_ABORTWAIT; |
xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); |
xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); |
usb_transfer_complete(xfer); |
usb_transfer_complete(xfer); |
if (wake) |
if (wake) { |
wakeup(&xfer->hcflags); |
cv_broadcast(&xfer->hccv); |
|
} |
|
|
splx(s); |
KASSERT(mutex_owned(&sc->sc_lock)); |
#undef exfer |
#undef exfer |
} |
} |
|
|
Line 3053 ehci_abort_isoc_xfer(usbd_xfer_handle xf |
|
Line 3128 ehci_abort_isoc_xfer(usbd_xfer_handle xf |
|
struct ehci_xfer *exfer; |
struct ehci_xfer *exfer; |
ehci_softc_t *sc; |
ehci_softc_t *sc; |
struct ehci_soft_itd *itd; |
struct ehci_soft_itd *itd; |
int s, i, wake; |
int i, wake; |
|
|
epipe = (struct ehci_pipe *) xfer->pipe; |
epipe = (struct ehci_pipe *) xfer->pipe; |
exfer = EXFER(xfer); |
exfer = EXFER(xfer); |
Line 3061 ehci_abort_isoc_xfer(usbd_xfer_handle xf |
|
Line 3136 ehci_abort_isoc_xfer(usbd_xfer_handle xf |
|
|
|
DPRINTF(("ehci_abort_isoc_xfer: xfer %p pipe %p\n", xfer, epipe)); |
DPRINTF(("ehci_abort_isoc_xfer: xfer %p pipe %p\n", xfer, epipe)); |
|
|
|
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
if (sc->sc_dying) { |
if (sc->sc_dying) { |
s = splusb(); |
|
xfer->status = status; |
xfer->status = status; |
callout_stop(&xfer->timeout_handle); |
callout_stop(&xfer->timeout_handle); |
usb_transfer_complete(xfer); |
usb_transfer_complete(xfer); |
splx(s); |
|
return; |
return; |
} |
} |
|
|
Line 3075 ehci_abort_isoc_xfer(usbd_xfer_handle xf |
|
Line 3150 ehci_abort_isoc_xfer(usbd_xfer_handle xf |
|
|
|
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
if (status == USBD_TIMEOUT) |
if (status == USBD_TIMEOUT) |
printf("ehci_abort_xfer: TIMEOUT while aborting\n"); |
printf("ehci_abort_isoc_xfer: TIMEOUT while aborting\n"); |
#endif |
#endif |
|
|
xfer->status = status; |
xfer->status = status; |
DPRINTFN(2, ("ehci_abort_xfer: waiting for abort to finish\n")); |
DPRINTFN(2, ("ehci_abort_isoc_xfer: waiting for abort to finish\n")); |
xfer->hcflags |= UXFER_ABORTWAIT; |
xfer->hcflags |= UXFER_ABORTWAIT; |
while (xfer->hcflags & UXFER_ABORTING) |
while (xfer->hcflags & UXFER_ABORTING) |
tsleep(&xfer->hcflags, PZERO, "ehciiaw", 0); |
cv_wait(&xfer->hccv, &sc->sc_lock); |
return; |
goto done; |
} |
} |
xfer->hcflags |= UXFER_ABORTING; |
xfer->hcflags |= UXFER_ABORTING; |
|
|
xfer->status = status; |
xfer->status = status; |
callout_stop(&xfer->timeout_handle); |
callout_stop(&xfer->timeout_handle); |
|
|
s = splusb(); |
|
for (itd = exfer->itdstart; itd != NULL; itd = itd->xfer_next) { |
for (itd = exfer->itdstart; itd != NULL; itd = itd->xfer_next) { |
usb_syncmem(&itd->dma, |
usb_syncmem(&itd->dma, |
itd->offs + offsetof(ehci_itd_t, itd_ctl), |
itd->offs + offsetof(ehci_itd_t, itd_ctl), |
Line 3108 ehci_abort_isoc_xfer(usbd_xfer_handle xf |
|
Line 3182 ehci_abort_isoc_xfer(usbd_xfer_handle xf |
|
sizeof(itd->itd.itd_ctl), |
sizeof(itd->itd.itd_ctl), |
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
} |
} |
splx(s); |
|
|
|
s = splusb(); |
|
#ifdef USB_USE_SOFTINTR |
|
sc->sc_softwake = 1; |
sc->sc_softwake = 1; |
#endif /* USB_USE_SOFTINTR */ |
|
usb_schedsoftintr(&sc->sc_bus); |
usb_schedsoftintr(&sc->sc_bus); |
#ifdef USB_USE_SOFTINTR |
cv_wait(&sc->sc_softwake_cv, &sc->sc_lock); |
tsleep(&sc->sc_softwake, PZERO, "ehciab", 0); |
|
#endif /* USB_USE_SOFTINTR */ |
|
splx(s); |
|
|
|
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
exfer->isdone = 1; |
exfer->isdone = 1; |
Line 3126 ehci_abort_isoc_xfer(usbd_xfer_handle xf |
|
Line 3193 ehci_abort_isoc_xfer(usbd_xfer_handle xf |
|
wake = xfer->hcflags & UXFER_ABORTWAIT; |
wake = xfer->hcflags & UXFER_ABORTWAIT; |
xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); |
xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT); |
usb_transfer_complete(xfer); |
usb_transfer_complete(xfer); |
if (wake) |
if (wake) { |
wakeup(&xfer->hcflags); |
cv_broadcast(&xfer->hccv); |
|
} |
|
|
|
done: |
|
KASSERT(mutex_owned(&sc->sc_lock)); |
return; |
return; |
} |
} |
|
|
Line 3146 ehci_timeout(void *addr) |
|
Line 3216 ehci_timeout(void *addr) |
|
#endif |
#endif |
|
|
if (sc->sc_dying) { |
if (sc->sc_dying) { |
|
mutex_enter(&sc->sc_lock); |
ehci_abort_xfer(&exfer->xfer, USBD_TIMEOUT); |
ehci_abort_xfer(&exfer->xfer, USBD_TIMEOUT); |
|
mutex_exit(&sc->sc_lock); |
return; |
return; |
} |
} |
|
|
|
|
ehci_timeout_task(void *addr) |
ehci_timeout_task(void *addr) |
{ |
{ |
usbd_xfer_handle xfer = addr; |
usbd_xfer_handle xfer = addr; |
int s; |
ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; |
|
|
DPRINTF(("ehci_timeout_task: xfer=%p\n", xfer)); |
DPRINTF(("ehci_timeout_task: xfer=%p\n", xfer)); |
|
|
s = splusb(); |
mutex_enter(&sc->sc_lock); |
ehci_abort_xfer(xfer, USBD_TIMEOUT); |
ehci_abort_xfer(xfer, USBD_TIMEOUT); |
splx(s); |
mutex_exit(&sc->sc_lock); |
} |
} |
|
|
/************************/ |
/************************/ |
Line 3174 ehci_timeout_task(void *addr) |
|
Line 3246 ehci_timeout_task(void *addr) |
|
Static usbd_status |
Static usbd_status |
ehci_device_ctrl_transfer(usbd_xfer_handle xfer) |
ehci_device_ctrl_transfer(usbd_xfer_handle xfer) |
{ |
{ |
|
ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; |
usbd_status err; |
usbd_status err; |
|
|
/* Insert last in queue. */ |
/* Insert last in queue. */ |
|
mutex_enter(&sc->sc_lock); |
err = usb_insert_transfer(xfer); |
err = usb_insert_transfer(xfer); |
|
mutex_exit(&sc->sc_lock); |
if (err) |
if (err) |
return (err); |
return (err); |
|
|
Line 3203 ehci_device_ctrl_start(usbd_xfer_handle |
|
Line 3278 ehci_device_ctrl_start(usbd_xfer_handle |
|
#endif |
#endif |
|
|
err = ehci_device_request(xfer); |
err = ehci_device_request(xfer); |
if (err) |
if (err) { |
return (err); |
return (err); |
|
} |
|
|
if (sc->sc_bus.use_polling) |
if (sc->sc_bus.use_polling) |
ehci_waitintr(sc, xfer); |
ehci_waitintr(sc, xfer); |
|
|
return (USBD_IN_PROGRESS); |
return (USBD_IN_PROGRESS); |
} |
} |
|
|
Line 3223 ehci_device_ctrl_done(usbd_xfer_handle x |
|
Line 3300 ehci_device_ctrl_done(usbd_xfer_handle x |
|
|
|
DPRINTFN(10,("ehci_ctrl_done: xfer=%p\n", xfer)); |
DPRINTFN(10,("ehci_ctrl_done: xfer=%p\n", xfer)); |
|
|
|
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
if (!(xfer->rqflags & URQ_REQUEST)) { |
if (!(xfer->rqflags & URQ_REQUEST)) { |
panic("ehci_ctrl_done: not a request"); |
panic("ehci_ctrl_done: not a request"); |
} |
} |
#endif |
#endif |
|
|
mutex_enter(&sc->sc_intrhead_lock); |
|
if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) { |
if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) { |
ehci_del_intr_list(sc, ex); /* remove from active list */ |
ehci_del_intr_list(sc, ex); /* remove from active list */ |
ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); |
ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); |
Line 3239 ehci_device_ctrl_done(usbd_xfer_handle x |
|
Line 3317 ehci_device_ctrl_done(usbd_xfer_handle x |
|
usb_syncmem(&xfer->dmabuf, 0, len, |
usb_syncmem(&xfer->dmabuf, 0, len, |
rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); |
rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); |
} |
} |
mutex_exit(&sc->sc_intrhead_lock); |
|
|
|
DPRINTFN(5, ("ehci_ctrl_done: length=%d\n", xfer->actlen)); |
DPRINTFN(5, ("ehci_ctrl_done: length=%d\n", xfer->actlen)); |
} |
} |
Line 3259 ehci_device_ctrl_close(usbd_pipe_handle |
|
Line 3336 ehci_device_ctrl_close(usbd_pipe_handle |
|
ehci_softc_t *sc = pipe->device->bus->hci_private; |
ehci_softc_t *sc = pipe->device->bus->hci_private; |
/*struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;*/ |
/*struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;*/ |
|
|
|
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
DPRINTF(("ehci_device_ctrl_close: pipe=%p\n", pipe)); |
DPRINTF(("ehci_device_ctrl_close: pipe=%p\n", pipe)); |
|
|
ehci_close_pipe(pipe, sc->sc_async_head); |
ehci_close_pipe(pipe, sc->sc_async_head); |
} |
} |
|
|
Line 3277 ehci_device_request(usbd_xfer_handle xfe |
|
Line 3357 ehci_device_request(usbd_xfer_handle xfe |
|
int isread; |
int isread; |
int len; |
int len; |
usbd_status err; |
usbd_status err; |
int s; |
|
|
|
isread = req->bmRequestType & UT_READ; |
isread = req->bmRequestType & UT_READ; |
len = UGETW(req->wLength); |
len = UGETW(req->wLength); |
Line 3299 ehci_device_request(usbd_xfer_handle xfe |
|
Line 3378 ehci_device_request(usbd_xfer_handle xfe |
|
goto bad2; |
goto bad2; |
} |
} |
|
|
|
mutex_enter(&sc->sc_lock); |
|
|
sqh = epipe->sqh; |
sqh = epipe->sqh; |
epipe->u.ctl.length = len; |
epipe->u.ctl.length = len; |
|
|
Line 3387 ehci_device_request(usbd_xfer_handle xfe |
|
Line 3468 ehci_device_request(usbd_xfer_handle xfe |
|
#endif |
#endif |
|
|
/* Insert qTD in QH list. */ |
/* Insert qTD in QH list. */ |
s = splusb(); |
|
ehci_set_qh_qtd(sqh, setup); /* also does usb_syncmem(sqh) */ |
ehci_set_qh_qtd(sqh, setup); /* also does usb_syncmem(sqh) */ |
if (xfer->timeout && !sc->sc_bus.use_polling) { |
if (xfer->timeout && !sc->sc_bus.use_polling) { |
callout_reset(&(xfer->timeout_handle), (mstohz(xfer->timeout)), |
callout_reset(&xfer->timeout_handle, mstohz(xfer->timeout), |
(ehci_timeout), (xfer)); |
ehci_timeout, xfer); |
} |
} |
mutex_enter(&sc->sc_intrhead_lock); |
|
ehci_add_intr_list(sc, exfer); |
ehci_add_intr_list(sc, exfer); |
mutex_exit(&sc->sc_intrhead_lock); |
|
xfer->status = USBD_IN_PROGRESS; |
xfer->status = USBD_IN_PROGRESS; |
splx(s); |
mutex_exit(&sc->sc_lock); |
|
|
#ifdef EHCI_DEBUG |
#ifdef EHCI_DEBUG |
if (ehcidebug > 10) { |
if (ehcidebug > 10) { |
Line 3414 ehci_device_request(usbd_xfer_handle xfe |
|
Line 3492 ehci_device_request(usbd_xfer_handle xfe |
|
return (USBD_NORMAL_COMPLETION); |
return (USBD_NORMAL_COMPLETION); |
|
|
bad3: |
bad3: |
|
mutex_exit(&sc->sc_lock); |
ehci_free_sqtd(sc, stat); |
ehci_free_sqtd(sc, stat); |
bad2: |
bad2: |
ehci_free_sqtd(sc, setup); |
ehci_free_sqtd(sc, setup); |
bad1: |
bad1: |
DPRINTFN(-1,("ehci_device_request: no memory\n")); |
DPRINTFN(-1,("ehci_device_request: no memory\n")); |
|
mutex_enter(&sc->sc_lock); |
xfer->status = err; |
xfer->status = err; |
usb_transfer_complete(xfer); |
usb_transfer_complete(xfer); |
|
mutex_exit(&sc->sc_lock); |
return (err); |
return (err); |
#undef exfer |
#undef exfer |
} |
} |
|
|
ehci_intrlist_timeout(void *arg) |
ehci_intrlist_timeout(void *arg) |
{ |
{ |
ehci_softc_t *sc = arg; |
ehci_softc_t *sc = arg; |
int s = splusb(); |
|
|
|
DPRINTF(("ehci_intrlist_timeout\n")); |
DPRINTF(("ehci_intrlist_timeout\n")); |
usb_schedsoftintr(&sc->sc_bus); |
usb_schedsoftintr(&sc->sc_bus); |
|
|
splx(s); |
|
} |
} |
|
|
/************************/ |
/************************/ |
Line 3453 ehci_intrlist_timeout(void *arg) |
|
Line 3531 ehci_intrlist_timeout(void *arg) |
|
Static usbd_status |
Static usbd_status |
ehci_device_bulk_transfer(usbd_xfer_handle xfer) |
ehci_device_bulk_transfer(usbd_xfer_handle xfer) |
{ |
{ |
|
ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; |
usbd_status err; |
usbd_status err; |
|
|
/* Insert last in queue. */ |
/* Insert last in queue. */ |
|
mutex_enter(&sc->sc_lock); |
err = usb_insert_transfer(xfer); |
err = usb_insert_transfer(xfer); |
|
mutex_exit(&sc->sc_lock); |
if (err) |
if (err) |
return (err); |
return (err); |
|
|
Line 3475 ehci_device_bulk_start(usbd_xfer_handle |
|
Line 3556 ehci_device_bulk_start(usbd_xfer_handle |
|
ehci_soft_qh_t *sqh; |
ehci_soft_qh_t *sqh; |
usbd_status err; |
usbd_status err; |
int len, isread, endpt; |
int len, isread, endpt; |
int s; |
|
|
|
DPRINTFN(2, ("ehci_device_bulk_start: xfer=%p len=%d flags=%d\n", |
DPRINTFN(2, ("ehci_device_bulk_start: xfer=%p len=%d flags=%d\n", |
xfer, xfer->length, xfer->flags)); |
xfer, xfer->length, xfer->flags)); |
Line 3488 ehci_device_bulk_start(usbd_xfer_handle |
|
Line 3568 ehci_device_bulk_start(usbd_xfer_handle |
|
panic("ehci_device_bulk_start: a request"); |
panic("ehci_device_bulk_start: a request"); |
#endif |
#endif |
|
|
|
mutex_enter(&sc->sc_lock); |
|
|
len = xfer->length; |
len = xfer->length; |
endpt = epipe->pipe.endpoint->edesc->bEndpointAddress; |
endpt = epipe->pipe.endpoint->edesc->bEndpointAddress; |
isread = UE_GET_DIR(endpt) == UE_DIR_IN; |
isread = UE_GET_DIR(endpt) == UE_DIR_IN; |
Line 3501 ehci_device_bulk_start(usbd_xfer_handle |
|
Line 3583 ehci_device_bulk_start(usbd_xfer_handle |
|
DPRINTFN(-1,("ehci_device_bulk_transfer: no memory\n")); |
DPRINTFN(-1,("ehci_device_bulk_transfer: no memory\n")); |
xfer->status = err; |
xfer->status = err; |
usb_transfer_complete(xfer); |
usb_transfer_complete(xfer); |
|
mutex_exit(&sc->sc_lock); |
return (err); |
return (err); |
} |
} |
|
|
Line 3522 ehci_device_bulk_start(usbd_xfer_handle |
|
Line 3605 ehci_device_bulk_start(usbd_xfer_handle |
|
exfer->isdone = 0; |
exfer->isdone = 0; |
#endif |
#endif |
|
|
s = splusb(); |
|
ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */ |
ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */ |
if (xfer->timeout && !sc->sc_bus.use_polling) { |
if (xfer->timeout && !sc->sc_bus.use_polling) { |
callout_reset(&(xfer->timeout_handle), (mstohz(xfer->timeout)), |
callout_reset(&xfer->timeout_handle, mstohz(xfer->timeout), |
(ehci_timeout), (xfer)); |
ehci_timeout, xfer); |
} |
} |
mutex_enter(&sc->sc_intrhead_lock); |
|
ehci_add_intr_list(sc, exfer); |
ehci_add_intr_list(sc, exfer); |
mutex_exit(&sc->sc_intrhead_lock); |
|
xfer->status = USBD_IN_PROGRESS; |
xfer->status = USBD_IN_PROGRESS; |
splx(s); |
mutex_exit(&sc->sc_lock); |
|
|
#ifdef EHCI_DEBUG |
#ifdef EHCI_DEBUG |
if (ehcidebug > 10) { |
if (ehcidebug > 10) { |
Line 3573 ehci_device_bulk_close(usbd_pipe_handle |
|
Line 3653 ehci_device_bulk_close(usbd_pipe_handle |
|
ehci_softc_t *sc = pipe->device->bus->hci_private; |
ehci_softc_t *sc = pipe->device->bus->hci_private; |
struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; |
struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; |
|
|
|
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
DPRINTF(("ehci_device_bulk_close: pipe=%p\n", pipe)); |
DPRINTF(("ehci_device_bulk_close: pipe=%p\n", pipe)); |
pipe->endpoint->datatoggle = epipe->nexttoggle; |
pipe->endpoint->datatoggle = epipe->nexttoggle; |
ehci_close_pipe(pipe, sc->sc_async_head); |
ehci_close_pipe(pipe, sc->sc_async_head); |
Line 3590 ehci_device_bulk_done(usbd_xfer_handle x |
|
Line 3672 ehci_device_bulk_done(usbd_xfer_handle x |
|
DPRINTFN(10,("ehci_bulk_done: xfer=%p, actlen=%d\n", |
DPRINTFN(10,("ehci_bulk_done: xfer=%p, actlen=%d\n", |
xfer, xfer->actlen)); |
xfer, xfer->actlen)); |
|
|
mutex_enter(&sc->sc_intrhead_lock); |
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) { |
if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) { |
ehci_del_intr_list(sc, ex); /* remove from active list */ |
ehci_del_intr_list(sc, ex); /* remove from active list */ |
ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); |
ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); |
usb_syncmem(&xfer->dmabuf, 0, xfer->length, |
usb_syncmem(&xfer->dmabuf, 0, xfer->length, |
rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); |
rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); |
} |
} |
mutex_exit(&sc->sc_intrhead_lock); |
|
|
|
DPRINTFN(5, ("ehci_bulk_done: length=%d\n", xfer->actlen)); |
DPRINTFN(5, ("ehci_bulk_done: length=%d\n", xfer->actlen)); |
} |
} |
Line 3622 ehci_device_setintr(ehci_softc_t *sc, eh |
|
Line 3704 ehci_device_setintr(ehci_softc_t *sc, eh |
|
|
|
sqh->islot = islot; |
sqh->islot = islot; |
isp = &sc->sc_islots[islot]; |
isp = &sc->sc_islots[islot]; |
ehci_add_qh(sqh, isp->sqh); |
mutex_enter(&sc->sc_lock); |
|
ehci_add_qh(sc, sqh, isp->sqh); |
|
mutex_exit(&sc->sc_lock); |
|
|
return (USBD_NORMAL_COMPLETION); |
return (USBD_NORMAL_COMPLETION); |
} |
} |
Line 3630 ehci_device_setintr(ehci_softc_t *sc, eh |
|
Line 3714 ehci_device_setintr(ehci_softc_t *sc, eh |
|
Static usbd_status |
Static usbd_status |
ehci_device_intr_transfer(usbd_xfer_handle xfer) |
ehci_device_intr_transfer(usbd_xfer_handle xfer) |
{ |
{ |
|
ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; |
usbd_status err; |
usbd_status err; |
|
|
/* Insert last in queue. */ |
/* Insert last in queue. */ |
|
mutex_enter(&sc->sc_lock); |
err = usb_insert_transfer(xfer); |
err = usb_insert_transfer(xfer); |
|
mutex_exit(&sc->sc_lock); |
if (err) |
if (err) |
return (err); |
return (err); |
|
|
Line 3655 ehci_device_intr_start(usbd_xfer_handle |
|
Line 3742 ehci_device_intr_start(usbd_xfer_handle |
|
ehci_soft_qh_t *sqh; |
ehci_soft_qh_t *sqh; |
usbd_status err; |
usbd_status err; |
int len, isread, endpt; |
int len, isread, endpt; |
int s; |
|
|
|
DPRINTFN(2, ("ehci_device_intr_start: xfer=%p len=%d flags=%d\n", |
DPRINTFN(2, ("ehci_device_intr_start: xfer=%p len=%d flags=%d\n", |
xfer, xfer->length, xfer->flags)); |
xfer, xfer->length, xfer->flags)); |
Line 3668 ehci_device_intr_start(usbd_xfer_handle |
|
Line 3754 ehci_device_intr_start(usbd_xfer_handle |
|
panic("ehci_device_intr_start: a request"); |
panic("ehci_device_intr_start: a request"); |
#endif |
#endif |
|
|
|
mutex_enter(&sc->sc_lock); |
|
|
len = xfer->length; |
len = xfer->length; |
endpt = epipe->pipe.endpoint->edesc->bEndpointAddress; |
endpt = epipe->pipe.endpoint->edesc->bEndpointAddress; |
isread = UE_GET_DIR(endpt) == UE_DIR_IN; |
isread = UE_GET_DIR(endpt) == UE_DIR_IN; |
Line 3681 ehci_device_intr_start(usbd_xfer_handle |
|
Line 3769 ehci_device_intr_start(usbd_xfer_handle |
|
DPRINTFN(-1, ("ehci_device_intr_start: no memory\n")); |
DPRINTFN(-1, ("ehci_device_intr_start: no memory\n")); |
xfer->status = err; |
xfer->status = err; |
usb_transfer_complete(xfer); |
usb_transfer_complete(xfer); |
|
mutex_exit(&sc->sc_lock); |
return (err); |
return (err); |
} |
} |
|
|
Line 3702 ehci_device_intr_start(usbd_xfer_handle |
|
Line 3791 ehci_device_intr_start(usbd_xfer_handle |
|
exfer->isdone = 0; |
exfer->isdone = 0; |
#endif |
#endif |
|
|
s = splusb(); |
|
ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */ |
ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */ |
if (xfer->timeout && !sc->sc_bus.use_polling) { |
if (xfer->timeout && !sc->sc_bus.use_polling) { |
callout_reset(&(xfer->timeout_handle), (mstohz(xfer->timeout)), |
callout_reset(&xfer->timeout_handle, mstohz(xfer->timeout), |
(ehci_timeout), (xfer)); |
ehci_timeout, xfer); |
} |
} |
mutex_enter(&sc->sc_intrhead_lock); |
|
ehci_add_intr_list(sc, exfer); |
ehci_add_intr_list(sc, exfer); |
mutex_exit(&sc->sc_intrhead_lock); |
|
xfer->status = USBD_IN_PROGRESS; |
xfer->status = USBD_IN_PROGRESS; |
splx(s); |
mutex_exit(&sc->sc_lock); |
|
|
#ifdef EHCI_DEBUG |
#ifdef EHCI_DEBUG |
if (ehcidebug > 10) { |
if (ehcidebug > 10) { |
Line 3756 ehci_device_intr_close(usbd_pipe_handle |
|
Line 3842 ehci_device_intr_close(usbd_pipe_handle |
|
struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; |
struct ehci_pipe *epipe = (struct ehci_pipe *)pipe; |
struct ehci_soft_islot *isp; |
struct ehci_soft_islot *isp; |
|
|
|
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
isp = &sc->sc_islots[epipe->sqh->islot]; |
isp = &sc->sc_islots[epipe->sqh->islot]; |
ehci_close_pipe(pipe, isp->sqh); |
ehci_close_pipe(pipe, isp->sqh); |
} |
} |
Line 3770 ehci_device_intr_done(usbd_xfer_handle x |
|
Line 3858 ehci_device_intr_done(usbd_xfer_handle x |
|
ehci_soft_qtd_t *data, *dataend; |
ehci_soft_qtd_t *data, *dataend; |
ehci_soft_qh_t *sqh; |
ehci_soft_qh_t *sqh; |
usbd_status err; |
usbd_status err; |
int len, isread, endpt, s; |
int len, isread, endpt; |
|
|
DPRINTFN(10, ("ehci_device_intr_done: xfer=%p, actlen=%d\n", |
DPRINTFN(10, ("ehci_device_intr_done: xfer=%p, actlen=%d\n", |
xfer, xfer->actlen)); |
xfer, xfer->actlen)); |
|
|
mutex_enter(&sc->sc_intrhead_lock); |
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
if (xfer->pipe->repeat) { |
if (xfer->pipe->repeat) { |
ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); |
ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL); |
|
|
Line 3792 ehci_device_intr_done(usbd_xfer_handle x |
|
Line 3881 ehci_device_intr_done(usbd_xfer_handle x |
|
if (err) { |
if (err) { |
DPRINTFN(-1, ("ehci_device_intr_done: no memory\n")); |
DPRINTFN(-1, ("ehci_device_intr_done: no memory\n")); |
xfer->status = err; |
xfer->status = err; |
mutex_exit(&sc->sc_intrhead_lock); |
|
return; |
return; |
} |
} |
|
|
Line 3807 ehci_device_intr_done(usbd_xfer_handle x |
|
Line 3895 ehci_device_intr_done(usbd_xfer_handle x |
|
exfer->isdone = 0; |
exfer->isdone = 0; |
#endif |
#endif |
|
|
s = splusb(); |
|
ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */ |
ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */ |
if (xfer->timeout && !sc->sc_bus.use_polling) { |
if (xfer->timeout && !sc->sc_bus.use_polling) { |
callout_reset(&(xfer->timeout_handle), |
callout_reset(&xfer->timeout_handle, |
(mstohz(xfer->timeout)), (ehci_timeout), (xfer)); |
mstohz(xfer->timeout), ehci_timeout, xfer); |
} |
} |
splx(s); |
|
|
|
xfer->status = USBD_IN_PROGRESS; |
xfer->status = USBD_IN_PROGRESS; |
} else if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) { |
} else if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) { |
Line 3824 ehci_device_intr_done(usbd_xfer_handle x |
|
Line 3910 ehci_device_intr_done(usbd_xfer_handle x |
|
usb_syncmem(&xfer->dmabuf, 0, xfer->length, |
usb_syncmem(&xfer->dmabuf, 0, xfer->length, |
isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); |
isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); |
} |
} |
mutex_exit(&sc->sc_intrhead_lock); |
|
#undef exfer |
#undef exfer |
} |
} |
|
|
Line 3833 ehci_device_intr_done(usbd_xfer_handle x |
|
Line 3918 ehci_device_intr_done(usbd_xfer_handle x |
|
Static usbd_status |
Static usbd_status |
ehci_device_isoc_transfer(usbd_xfer_handle xfer) |
ehci_device_isoc_transfer(usbd_xfer_handle xfer) |
{ |
{ |
|
ehci_softc_t *sc = xfer->pipe->device->bus->hci_private; |
usbd_status err; |
usbd_status err; |
|
|
|
mutex_enter(&sc->sc_lock); |
err = usb_insert_transfer(xfer); |
err = usb_insert_transfer(xfer); |
|
mutex_exit(&sc->sc_lock); |
if (err && err != USBD_IN_PROGRESS) |
if (err && err != USBD_IN_PROGRESS) |
return err; |
return err; |
|
|
Line 3852 ehci_device_isoc_start(usbd_xfer_handle |
|
Line 3940 ehci_device_isoc_start(usbd_xfer_handle |
|
ehci_soft_itd_t *itd, *prev, *start, *stop; |
ehci_soft_itd_t *itd, *prev, *start, *stop; |
usb_dma_t *dma_buf; |
usb_dma_t *dma_buf; |
int i, j, k, frames, uframes, ufrperframe; |
int i, j, k, frames, uframes, ufrperframe; |
int s, trans_count, offs, total_length; |
int trans_count, offs, total_length; |
int frindex; |
int frindex; |
|
|
start = NULL; |
start = NULL; |
Line 4036 ehci_device_isoc_start(usbd_xfer_handle |
|
Line 4124 ehci_device_isoc_start(usbd_xfer_handle |
|
* more than the period frame list. |
* more than the period frame list. |
*/ |
*/ |
|
|
s = splusb(); |
mutex_enter(&sc->sc_lock); |
|
|
/* Start inserting frames */ |
/* Start inserting frames */ |
if (epipe->u.isoc.cur_xfers > 0) { |
if (epipe->u.isoc.cur_xfers > 0) { |
Line 4102 ehci_device_isoc_start(usbd_xfer_handle |
|
Line 4190 ehci_device_isoc_start(usbd_xfer_handle |
|
exfer->sqtdstart = NULL; |
exfer->sqtdstart = NULL; |
exfer->sqtdstart = NULL; |
exfer->sqtdstart = NULL; |
|
|
mutex_enter(&sc->sc_intrhead_lock); |
|
ehci_add_intr_list(sc, exfer); |
ehci_add_intr_list(sc, exfer); |
mutex_exit(&sc->sc_intrhead_lock); |
|
xfer->status = USBD_IN_PROGRESS; |
xfer->status = USBD_IN_PROGRESS; |
xfer->done = 0; |
xfer->done = 0; |
splx(s); |
mutex_exit(&sc->sc_lock); |
|
|
if (sc->sc_bus.use_polling) { |
if (sc->sc_bus.use_polling) { |
printf("Starting ehci isoc xfer with polling. Bad idea?\n"); |
printf("Starting ehci isoc xfer with polling. Bad idea?\n"); |
Line 4136 ehci_device_isoc_done(usbd_xfer_handle x |
|
Line 4222 ehci_device_isoc_done(usbd_xfer_handle x |
|
struct ehci_xfer *exfer; |
struct ehci_xfer *exfer; |
ehci_softc_t *sc; |
ehci_softc_t *sc; |
struct ehci_pipe *epipe; |
struct ehci_pipe *epipe; |
int s; |
|
|
|
exfer = EXFER(xfer); |
exfer = EXFER(xfer); |
sc = xfer->pipe->device->bus->hci_private; |
sc = xfer->pipe->device->bus->hci_private; |
epipe = (struct ehci_pipe *) xfer->pipe; |
epipe = (struct ehci_pipe *) xfer->pipe; |
|
|
s = splusb(); |
KASSERT(mutex_owned(&sc->sc_lock)); |
|
|
epipe->u.isoc.cur_xfers--; |
epipe->u.isoc.cur_xfers--; |
mutex_enter(&sc->sc_intrhead_lock); |
|
if (xfer->status != USBD_NOMEM && ehci_active_intr_list(exfer)) { |
if (xfer->status != USBD_NOMEM && ehci_active_intr_list(exfer)) { |
ehci_del_intr_list(sc, exfer); |
ehci_del_intr_list(sc, exfer); |
ehci_rem_free_itd_chain(sc, exfer); |
ehci_rem_free_itd_chain(sc, exfer); |
} |
} |
mutex_exit(&sc->sc_intrhead_lock); |
|
splx(s); |
|
|
|
usb_syncmem(&xfer->dmabuf, 0, xfer->length, BUS_DMASYNC_POSTWRITE | |
usb_syncmem(&xfer->dmabuf, 0, xfer->length, BUS_DMASYNC_POSTWRITE | |
BUS_DMASYNC_POSTREAD); |
BUS_DMASYNC_POSTREAD); |