merge the jmcneill-usbmp branch. many thanks to jared for the

initial work, and every one else who has tested things for me.
this is largely my fault at this point :-)

the main changes are something like:

        - usbd_bus_methods{} gains a get_lock() to enable the
          host controller to provide a lock for the USB code.
          if the lock isn't provided, old-style protection is
          (partially) applied.

        - ehci/ohci/uhci have been converted to the new
          interfaces, including mutex/cv/etc conversion.

        - usbdivar.h contains a discussion about locking and
          what locks are held for which method calls.  more
          to come for usbdi(9) here.

        - audio drivers (uaudio, umidi, auvitek) have been
          properly SMPified now that USB is ready.

        - scsi drivers have been modified to take the kernel
          lock explicitly before calling into scsi code.

        - usb pipes are associated with a lock, that is the
          same as the controller lock.  (this could be split
          up further in the future.)

        - several usbfoo_locked() or usbfoo_unlocked()
          functions have been added to the usbdi(9) to
          enable functionality with or without the USB
          lock (per controller) already being held.

the TODO.usbmp file has specific details on what is left to
do, including what device-specific changes should be done now
that the whole framework is ready.
This commit is contained in:
mrg 2012-06-10 06:15:52 +00:00
parent e848a9e55e
commit dc74fbbf85
30 changed files with 1692 additions and 765 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: sl811hs.c,v 1.32 2012/03/11 00:34:46 mrg Exp $ */
/* $NetBSD: sl811hs.c,v 1.33 2012/06/10 06:15:52 mrg Exp $ */
/*
* Not (c) 2007 Matthew Orgass
@ -84,7 +84,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sl811hs.c,v 1.32 2012/03/11 00:34:46 mrg Exp $");
__KERNEL_RCSID(0, "$NetBSD: sl811hs.c,v 1.33 2012/06/10 06:15:52 mrg Exp $");
#include "opt_slhci.h"
@ -694,6 +694,7 @@ const struct usbd_bus_methods slhci_bus_methods = {
slhci_freem,
slhci_allocx,
slhci_freex,
NULL, /* slhci_get_lock */
};
const struct usbd_pipe_methods slhci_pipe_methods = {

View File

@ -1,4 +1,4 @@
/* $NetBSD: ehci_pci.c,v 1.54 2012/01/30 19:41:19 drochner Exp $ */
/* $NetBSD: ehci_pci.c,v 1.55 2012/06/10 06:15:53 mrg Exp $ */
/*
* Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v 1.54 2012/01/30 19:41:19 drochner Exp $");
__KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v 1.55 2012/06/10 06:15:53 mrg Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -177,7 +177,7 @@ ehci_pci_attach(device_t parent, device_t self, void *aux)
* Allocate IRQ
*/
intrstr = pci_intr_string(pc, ih);
sc->sc_ih = pci_intr_establish(pc, ih, IPL_USB, ehci_intr, sc);
sc->sc_ih = pci_intr_establish(pc, ih, IPL_SCHED, ehci_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(self, "couldn't establish interrupt");
if (intrstr != NULL)
@ -299,6 +299,15 @@ ehci_pci_detach(device_t self, int flags)
sc->sc.sc_size = 0;
}
#if 1
/* XXX created in ehci.c */
mutex_destroy(&sc->sc.sc_lock);
mutex_destroy(&sc->sc.sc_intr_lock);
softint_disestablish(sc->sc.sc_doorbell_si);
softint_disestablish(sc->sc.sc_pcd_si);
#endif
return 0;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ohci_pci.c,v 1.49 2012/04/05 04:04:05 macallan Exp $ */
/* $NetBSD: ohci_pci.c,v 1.50 2012/06/10 06:15:53 mrg Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ohci_pci.c,v 1.49 2012/04/05 04:04:05 macallan Exp $");
__KERNEL_RCSID(0, "$NetBSD: ohci_pci.c,v 1.50 2012/06/10 06:15:53 mrg Exp $");
#include "ehci.h"
@ -136,7 +136,7 @@ ohci_pci_attach(device_t parent, device_t self, void *aux)
* Allocate IRQ
*/
intrstr = pci_intr_string(pc, ih);
sc->sc_ih = pci_intr_establish(pc, ih, IPL_USB, ohci_intr, sc);
sc->sc_ih = pci_intr_establish(pc, ih, IPL_SCHED, ohci_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(self, "couldn't establish interrupt");
if (intrstr != NULL)

View File

@ -1,4 +1,4 @@
/* $NetBSD: uhci_pci.c,v 1.54 2012/01/30 19:41:23 drochner Exp $ */
/* $NetBSD: uhci_pci.c,v 1.55 2012/06/10 06:15:53 mrg Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uhci_pci.c,v 1.54 2012/01/30 19:41:23 drochner Exp $");
__KERNEL_RCSID(0, "$NetBSD: uhci_pci.c,v 1.55 2012/06/10 06:15:53 mrg Exp $");
#include "ehci.h"
@ -129,7 +129,7 @@ uhci_pci_attach(device_t parent, device_t self, void *aux)
return;
}
intrstr = pci_intr_string(pc, ih);
sc->sc_ih = pci_intr_establish(pc, ih, IPL_USB, uhci_intr, sc);
sc->sc_ih = pci_intr_establish(pc, ih, IPL_SCHED, uhci_intr, sc);
if (sc->sc_ih == NULL) {
aprint_error_dev(self, "couldn't establish interrupt");
if (intrstr != NULL)

186
sys/dev/usb/TODO.usbmp Normal file
View File

@ -0,0 +1,186 @@
$NetBSD: TODO.usbmp,v 1.2 2012/06/10 06:15:53 mrg Exp $
the majority of the USB MP device interface is documented in usbdivar.h.
flesh out most of usbdi(9).
host controllers needing to be ported:
- dev/ic/slhci.c
- arch/mips/adm5120/dev/ahci.c
- rump/dev/lib/libugenhc/ugenhc.c
use /* XXXSMP ok */ markers for non-SMP-safe host controller driver uses.
eg, "if (lock_ptr) mutex_enter(lock_ptr); else s = splusb();"
add lots more asserts
usb_event_thread() startup should use something to sync companions
wake/wakeup conversion:
- usb_detach_waitold/wakeupold() -> usb_detach_wait/broadcast()
- drivers:
if_aue.c
if_axe.c
if_udav.c
if_url.c
ubt.c
ucom.c
ucycom.c
ugen.c - done
uhid.c - done
uhso.c
uirda.c
ulpt.c
umass.c - done, partially done -- need to check umass_scsipi.c change
urio.c
uscanner.c
usscanner.c
ustir.c
utoppy.c
use usb_delay_ms_locked() in places
convert uhidev users to MPSAFE:
ucycom(4)
- own cdevsw that isn't D_MPSAFE; need to check intr handlers
uhid(4)
- needs some locking here (not completely tested changes)
- done
ukbd(4)
ums(4)
uts(4)
pbms(4)
- depends upon wscons? check intr
uyurex(4)
- sysmon -- hm?
wakeup/tsleep drivers:
- if_otus.c
- if_upgt.c
- if_zyd.c
- ucom.c
- ucycom.c
- ugen.c - done
- uirda.c
- ulpt.c
- umass_isdata.c
- ustir.c
- uthum.c
- utoppy.c
- uvscom.c
- uyurex.c
missing D_MPSAFE drivers:
- ucom
- ucycom
- ugen - partially ready
- uhso
- ulpt
- urio
- usb
- uscanner
- utoppy
missing CALLOUT_MPSAFE drivers:
- if_aue
- if_axe
- if_cue
- if_otus
- if_rum
- if_run
- if_udav
- if_upgt
- if_ural
- if_url
- if_urtw
- if_urtwn
- if_zyd
- ukbd
- ulpt
- uyurex
driver testing: STATUS
- uhub working
- uhid working
- uhidev working
- ums working
- uts
- ukbd working
- ucycom
- uep
- udl
- ulpt attaches ok
- uhso working (must take kernel lock for scsipi)
- umass working (must take kernel lock for scsipi)
- uaudio working
- umidi working
- uirda
- stuirda
- ustir
- irmce
- aue
- axe working
- cdce
- cue
- kue
- udav
- url
- urndis
- atu
- otus
- ral
- rum
- run
- urtw
- urtwn
- upgt
- zyd
- upl
- uberry
- uipad
- urio
- uscanner ? (must take kernel lock for scsipi)
- usscanner
- utoppy
- uyap
- udsbr
- ugen mostly done
- pseye working
- uvideo
- auvitek ? (must take kernel lock for scsipi)
- emdtv ? (must take kernel lock for scsipi)
- ubt working (must take kernel lock for scsipi)
- aubtfwl
- u3ginit
ucom attachments:
- umodem working
- uark
- ubsa
- uchcom
- uftdi
- uipaq
- umct
- uplcom attaches ok
- uslsa
- uvscom
- moscom
- uvisor
- ukyopon
- u3g
- ugensa

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* $NetBSD: ehcivar.h,v 1.39 2012/03/06 02:49:02 mrg Exp $ */
/* $NetBSD: ehcivar.h,v 1.40 2012/06/10 06:15:53 mrg Exp $ */
/*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@ -109,6 +109,11 @@ struct ehci_soft_islot {
typedef struct ehci_softc {
device_t sc_dev;
kmutex_t sc_lock;
kmutex_t sc_intr_lock;
kcondvar_t sc_doorbell;
void *sc_doorbell_si;
void *sc_pcd_si;
struct usbd_bus sc_bus;
bus_space_tag_t iot;
bus_space_handle_t ioh;
@ -140,7 +145,6 @@ typedef struct ehci_softc {
struct ehci_soft_itd **sc_softitds;
TAILQ_HEAD(, ehci_xfer) sc_intrhead;
kmutex_t sc_intrhead_lock;
ehci_soft_qh_t *sc_freeqhs;
ehci_soft_qtd_t *sc_freeqtds;
@ -153,14 +157,13 @@ typedef struct ehci_softc {
usbd_xfer_handle sc_intrxfer;
char sc_isreset[EHCI_MAX_PORTS];
char sc_softwake;
kcondvar_t sc_softwake_cv;
u_int32_t sc_eintrs;
ehci_soft_qh_t *sc_async_head;
SIMPLEQ_HEAD(, usbd_xfer) sc_free_xfers; /* free xfers */
kmutex_t sc_doorbell_lock;
struct callout sc_tmo_intrlist;
device_t sc_child; /* /dev/usb# device */

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,4 @@
/* $NetBSD: ohcivar.h,v 1.52 2012/03/06 02:49:03 mrg Exp $ */
/* $FreeBSD: src/sys/dev/usb/ohcivar.h,v 1.13 1999/11/17 22:33:41 n_hibma Exp $ */
/* $NetBSD: ohcivar.h,v 1.53 2012/06/10 06:15:53 mrg Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -87,6 +86,10 @@ typedef struct ohci_softc {
bus_space_handle_t ioh;
bus_size_t sc_size;
kmutex_t sc_lock;
kmutex_t sc_intr_lock;
void *sc_rhsc_si;
usb_dma_t sc_hccadma;
struct ohci_hcca *sc_hcca;
ohci_soft_ed_t *sc_eds[OHCI_NO_EDS];
@ -110,6 +113,7 @@ typedef struct ohci_softc {
#define OHCI_HOST_ENDIAN 2 /* if OHCI always matches CPU */
char sc_softwake;
kcondvar_t sc_softwake_cv;
ohci_soft_ed_t *sc_freeeds;
ohci_soft_td_t *sc_freetds;

View File

@ -1,12 +1,12 @@
/* $NetBSD: uaudio.c,v 1.132 2012/05/18 07:52:54 jdc Exp $ */
/* $NetBSD: uaudio.c,v 1.133 2012/06/10 06:15:53 mrg Exp $ */
/*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* Copyright (c) 1999, 2012 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson (lennart@augustsson.net) at
* Carlstedt Research & Technology.
* Carlstedt Research & Technology, and Matthew R. Green (mrg@eterna.com.au).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uaudio.c,v 1.132 2012/05/18 07:52:54 jdc Exp $");
__KERNEL_RCSID(0, "$NetBSD: uaudio.c,v 1.133 2012/06/10 06:15:53 mrg Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -421,7 +421,7 @@ uaudio_attach(device_t parent, device_t self, void *aux)
sc->sc_dev = self;
sc->sc_udev = uaa->device;
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB);
mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED);
strlcpy(sc->sc_adev.name, "USB audio", sizeof(sc->sc_adev.name));
strlcpy(sc->sc_adev.version, "", sizeof(sc->sc_adev.version));
@ -2095,7 +2095,7 @@ uaudio_query_devinfo(void *addr, mixer_devinfo_t *mi)
struct mixerctl *mc;
int n, nctls, i;
DPRINTFN(2, "index=%d\n", mi->index);
DPRINTFN(7, "index=%d\n", mi->index);
sc = addr;
if (sc->sc_dying)
return EIO;
@ -2218,7 +2218,6 @@ uaudio_halt_out_dma(void *addr)
DPRINTF("%s", "enter\n");
KERNEL_LOCK(1, curlwp);
mutex_spin_exit(&sc->sc_intr_lock);
if (sc->sc_playchan.pipe != NULL) {
uaudio_chan_close(sc, &sc->sc_playchan);
@ -2227,7 +2226,6 @@ uaudio_halt_out_dma(void *addr)
sc->sc_playchan.intr = NULL;
}
mutex_spin_enter(&sc->sc_intr_lock);
KERNEL_UNLOCK_ONE(curlwp);
return 0;
}
@ -2239,7 +2237,6 @@ uaudio_halt_in_dma(void *addr)
DPRINTF("%s", "enter\n");
KERNEL_LOCK(1, curlwp);
mutex_spin_exit(&sc->sc_intr_lock);
if (sc->sc_recchan.pipe != NULL) {
uaudio_chan_close(sc, &sc->sc_recchan);
@ -2248,7 +2245,6 @@ uaudio_halt_in_dma(void *addr)
sc->sc_recchan.intr = NULL;
}
mutex_spin_enter(&sc->sc_intr_lock);
KERNEL_UNLOCK_ONE(curlwp);
return 0;
}
@ -2462,10 +2458,10 @@ uaudio_ctl_get(struct uaudio_softc *sc, int which, struct mixerctl *mc,
int val;
DPRINTFN(5,"which=%d chan=%d\n", which, chan);
KERNEL_LOCK(1, curlwp);
mutex_exit(&sc->sc_lock);
val = uaudio_get(sc, which, UT_READ_CLASS_INTERFACE, mc->wValue[chan],
mc->wIndex, MIX_SIZE(mc->type));
KERNEL_UNLOCK_ONE(curlwp);
mutex_enter(&sc->sc_lock);
return uaudio_value2bsd(mc, val);
}
@ -2475,10 +2471,10 @@ uaudio_ctl_set(struct uaudio_softc *sc, int which, struct mixerctl *mc,
{
val = uaudio_bsd2value(mc, val);
KERNEL_LOCK(1, curlwp);
mutex_exit(&sc->sc_lock);
uaudio_set(sc, which, UT_WRITE_CLASS_INTERFACE, mc->wValue[chan],
mc->wIndex, MIX_SIZE(mc->type), val);
KERNEL_UNLOCK_ONE(curlwp);
mutex_enter(&sc->sc_lock);
}
Static int
@ -2576,7 +2572,7 @@ uaudio_trigger_input(void *addr, void *start, void *end, int blksize,
struct uaudio_softc *sc;
struct chan *ch;
usbd_status err;
int i, s;
int i;
sc = addr;
if (sc->sc_dying)
@ -2590,18 +2586,15 @@ uaudio_trigger_input(void *addr, void *start, void *end, int blksize,
"fraction=0.%03d\n", ch->sample_size, ch->bytes_per_frame,
ch->fraction);
KERNEL_LOCK(1, curlwp);
mutex_spin_exit(&sc->sc_intr_lock);
err = uaudio_chan_alloc_buffers(sc, ch);
if (err) {
mutex_spin_enter(&sc->sc_intr_lock);
KERNEL_UNLOCK_ONE(curlwp);
return EIO;
}
err = uaudio_chan_open(sc, ch);
mutex_spin_enter(&sc->sc_intr_lock);
KERNEL_UNLOCK_ONE(curlwp);
if (err) {
uaudio_chan_free_buffers(sc, ch);
return EIO;
@ -2610,14 +2603,10 @@ uaudio_trigger_input(void *addr, void *start, void *end, int blksize,
ch->intr = intr;
ch->arg = arg;
KERNEL_LOCK(1, curlwp);
mutex_spin_exit(&sc->sc_intr_lock);
s = splusb();
for (i = 0; i < UAUDIO_NCHANBUFS-1; i++) /* XXX -1 shouldn't be needed */
uaudio_chan_rtransfer(ch);
splx(s);
mutex_spin_enter(&sc->sc_intr_lock);
KERNEL_UNLOCK_ONE(curlwp);
return 0;
}
@ -2630,7 +2619,7 @@ uaudio_trigger_output(void *addr, void *start, void *end, int blksize,
struct uaudio_softc *sc;
struct chan *ch;
usbd_status err;
int i, s;
int i;
sc = addr;
if (sc->sc_dying)
@ -2644,18 +2633,15 @@ uaudio_trigger_output(void *addr, void *start, void *end, int blksize,
"fraction=0.%03d\n", ch->sample_size, ch->bytes_per_frame,
ch->fraction);
KERNEL_LOCK(1, curlwp);
mutex_spin_exit(&sc->sc_intr_lock);
err = uaudio_chan_alloc_buffers(sc, ch);
if (err) {
mutex_spin_enter(&sc->sc_intr_lock);
KERNEL_UNLOCK_ONE(curlwp);
return EIO;
}
err = uaudio_chan_open(sc, ch);
mutex_spin_enter(&sc->sc_intr_lock);
KERNEL_UNLOCK_ONE(curlwp);
if (err) {
uaudio_chan_free_buffers(sc, ch);
return EIO;
@ -2664,14 +2650,10 @@ uaudio_trigger_output(void *addr, void *start, void *end, int blksize,
ch->intr = intr;
ch->arg = arg;
KERNEL_LOCK(1, curlwp);
mutex_spin_exit(&sc->sc_intr_lock);
s = splusb();
for (i = 0; i < UAUDIO_NCHANBUFS-1; i++) /* XXX */
uaudio_chan_ptransfer(ch);
splx(s);
mutex_spin_enter(&sc->sc_intr_lock);
KERNEL_UNLOCK_ONE(curlwp);
return 0;
}
@ -2783,7 +2765,7 @@ uaudio_chan_free_buffers(struct uaudio_softc *sc, struct chan *ch)
usbd_free_xfer(ch->chanbufs[i].xfer);
}
/* Called at splusb() */
/* Called with USB lock held. */
Static void
uaudio_chan_ptransfer(struct chan *ch)
{
@ -2886,7 +2868,7 @@ uaudio_chan_pintr(usbd_xfer_handle xfer, usbd_private_handle priv,
uaudio_chan_ptransfer(ch);
}
/* Called at splusb() */
/* Called with USB lock held. */
Static void
uaudio_chan_rtransfer(struct chan *ch)
{
@ -3129,9 +3111,7 @@ uaudio_set_speed(struct uaudio_softc *sc, int endpt, u_int speed)
data[1] = speed >> 8;
data[2] = speed >> 16;
KERNEL_LOCK(1, curlwp);
err = usbd_do_request(sc->sc_udev, &req, data);
KERNEL_UNLOCK_ONE(curlwp);
return err;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ugen.c,v 1.119 2012/04/25 07:57:15 dholland Exp $ */
/* $NetBSD: ugen.c,v 1.120 2012/06/10 06:15:53 mrg Exp $ */
/*
* Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
@ -37,7 +37,7 @@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ugen.c,v 1.119 2012/04/25 07:57:15 dholland Exp $");
__KERNEL_RCSID(0, "$NetBSD: ugen.c,v 1.120 2012/06/10 06:15:53 mrg Exp $");
#include "opt_compat_netbsd.h"
@ -108,12 +108,17 @@ struct ugen_endpoint {
void *dmabuf;
u_int16_t sizes[UGEN_NISORFRMS];
} isoreqs[UGEN_NISOREQS];
/* Keep this last; we don't overwrite it in ugen_set_config() */
kcondvar_t cv;
};
struct ugen_softc {
device_t sc_dev; /* base device */
usbd_device_handle sc_udev;
kmutex_t sc_lock;
kcondvar_t sc_detach_cv;
char sc_is_open[USB_MAX_ENDPOINTS];
struct ugen_endpoint sc_endpoints[USB_MAX_ENDPOINTS][2];
#define OUT 0
@ -201,6 +206,9 @@ ugen_attach(device_t parent, device_t self, void *aux)
aprint_naive("\n");
aprint_normal("\n");
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_USB);
cv_init(&sc->sc_detach_cv, "ugendet");
devinfop = usbd_devinfo_alloc(uaa->device, 0);
aprint_normal_dev(self, "%s\n", devinfop);
usbd_devinfo_free(devinfop);
@ -233,6 +241,7 @@ ugen_attach(device_t parent, device_t self, void *aux)
sce = &sc->sc_endpoints[i][dir];
selinit(&sce->rsel);
cv_init(&sce->cv, "ugensce");
}
}
@ -256,7 +265,7 @@ ugen_set_config(struct ugen_softc *sc, int configno)
u_int8_t niface, nendpt;
int ifaceno, endptno, endpt;
usbd_status err;
int dir;
int dir, i;
DPRINTFN(1,("ugen_set_config: %s to configno %d, sc=%p\n",
device_xname(sc->sc_dev), configno, sc));
@ -284,7 +293,15 @@ ugen_set_config(struct ugen_softc *sc, int configno)
err = usbd_interface_count(dev, &niface);
if (err)
return (err);
memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints);
/* Clear out the old info, but leave the cv initialised. */
for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
for (dir = OUT; dir <= IN; dir++) {
sce = &sc->sc_endpoints[i][dir];
memset(sce, 0, offsetof(struct ugen_endpoint, cv));
}
}
for (ifaceno = 0; ifaceno < niface; ifaceno++) {
DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno));
err = usbd_device2interface_handle(dev, ifaceno, &iface);
@ -537,7 +554,6 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
u_int32_t n, tn;
usbd_xfer_handle xfer;
usbd_status err;
int s;
int error = 0;
DPRINTFN(5, ("%s: ugenread: %d\n", device_xname(sc->sc_dev), endpt));
@ -562,15 +578,17 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
case UE_INTERRUPT:
/* Block until activity occurred. */
s = splusb();
mutex_enter(&sc->sc_lock);
while (sce->q.c_cc == 0) {
if (flag & IO_NDELAY) {
splx(s);
mutex_exit(&sc->sc_lock);
return (EWOULDBLOCK);
}
sce->state |= UGEN_ASLP;
DPRINTFN(5, ("ugenread: sleep on %p\n", sce));
error = tsleep(sce, PZERO | PCATCH, "ugenri", mstohz(sce->timeout));
/* "ugenri" */
error = cv_timedwait_sig(&sce->cv, &sc->sc_lock,
mstohz(sce->timeout));
DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
if (sc->sc_dying)
error = EIO;
@ -579,7 +597,7 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
break;
}
}
splx(s);
mutex_exit(&sc->sc_lock);
/* Transfer as many chunks as possible. */
while (sce->q.c_cc > 0 && uio->uio_resid > 0 && !error) {
@ -603,9 +621,9 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
uio->uio_resid, sce->ra_wb_used));
xfer = sce->ra_wb_xfer;
s = splusb();
mutex_enter(&sc->sc_lock);
if (sce->ra_wb_used == 0 && flag & IO_NDELAY) {
splx(s);
mutex_exit(&sc->sc_lock);
return (EWOULDBLOCK);
}
while (uio->uio_resid > 0 && !error) {
@ -614,8 +632,9 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
DPRINTFN(5,
("ugenread: sleep on %p\n",
sce));
error = tsleep(sce, PZERO | PCATCH,
"ugenrb", mstohz(sce->timeout));
/* "ugenrb" */
error = cv_timedwait_sig(&sce->cv,
&sc->sc_lock, mstohz(sce->timeout));
DPRINTFN(5,
("ugenread: woke, error=%d\n",
error));
@ -667,7 +686,7 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
sce->state |= UGEN_RA_WB_STOP;
}
}
splx(s);
mutex_exit(&sc->sc_lock);
break;
}
xfer = usbd_alloc_xfer(sc->sc_udev);
@ -698,15 +717,17 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
usbd_free_xfer(xfer);
break;
case UE_ISOCHRONOUS:
s = splusb();
mutex_enter(&sc->sc_lock);
while (sce->cur == sce->fill) {
if (flag & IO_NDELAY) {
splx(s);
mutex_exit(&sc->sc_lock);
return (EWOULDBLOCK);
}
sce->state |= UGEN_ASLP;
/* "ugenri" */
DPRINTFN(5, ("ugenread: sleep on %p\n", sce));
error = tsleep(sce, PZERO | PCATCH, "ugenri", mstohz(sce->timeout));
error = cv_timedwait_sig(&sce->cv, &sc->sc_lock,
mstohz(sce->timeout));
DPRINTFN(5, ("ugenread: woke, error=%d\n", error));
if (sc->sc_dying)
error = EIO;
@ -729,10 +750,10 @@ ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
if (error)
break;
sce->cur += n;
if(sce->cur >= sce->limit)
if (sce->cur >= sce->limit)
sce->cur = sce->ibuf;
}
splx(s);
mutex_exit(&sc->sc_lock);
break;
@ -753,10 +774,17 @@ ugenread(dev_t dev, struct uio *uio, int flag)
if (sc == NULL)
return ENXIO;
mutex_enter(&sc->sc_lock);
sc->sc_refcnt++;
mutex_exit(&sc->sc_lock);
error = ugen_do_read(sc, endpt, uio, flag);
mutex_enter(&sc->sc_lock);
if (--sc->sc_refcnt < 0)
usb_detach_wakeupold(sc->sc_dev);
usb_detach_broadcast(sc->sc_dev, &sc->sc_detach_cv);
mutex_exit(&sc->sc_lock);
return (error);
}
@ -767,7 +795,6 @@ ugen_do_write(struct ugen_softc *sc, int endpt, struct uio *uio,
struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][OUT];
u_int32_t n;
int error = 0;
int s;
u_int32_t tn;
char *dbuf;
usbd_xfer_handle xfer;
@ -799,10 +826,10 @@ ugen_do_write(struct ugen_softc *sc, int endpt, struct uio *uio,
uio->uio_resid, sce->ra_wb_used));
xfer = sce->ra_wb_xfer;
s = splusb();
mutex_enter(&sc->sc_lock);
if (sce->ra_wb_used == sce->limit - sce->ibuf &&
flag & IO_NDELAY) {
splx(s);
mutex_exit(&sc->sc_lock);
return (EWOULDBLOCK);
}
while (uio->uio_resid > 0 && !error) {
@ -812,8 +839,9 @@ ugen_do_write(struct ugen_softc *sc, int endpt, struct uio *uio,
DPRINTFN(5,
("ugenwrite: sleep on %p\n",
sce));
error = tsleep(sce, PZERO | PCATCH,
"ugenwb", mstohz(sce->timeout));
/* "ugenwb" */
error = cv_timedwait_sig(&sce->cv,
&sc->sc_lock, mstohz(sce->timeout));
DPRINTFN(5,
("ugenwrite: woke, error=%d\n",
error));
@ -872,7 +900,7 @@ ugen_do_write(struct ugen_softc *sc, int endpt, struct uio *uio,
sce->state |= UGEN_RA_WB_STOP;
}
}
splx(s);
mutex_exit(&sc->sc_lock);
break;
}
xfer = usbd_alloc_xfer(sc->sc_udev);
@ -938,10 +966,17 @@ ugenwrite(dev_t dev, struct uio *uio, int flag)
if (sc == NULL)
return ENXIO;
mutex_enter(&sc->sc_lock);
sc->sc_refcnt++;
mutex_exit(&sc->sc_lock);
error = ugen_do_write(sc, endpt, uio, flag);
mutex_enter(&sc->sc_lock);
if (--sc->sc_refcnt < 0)
usb_detach_wakeupold(sc->sc_dev);
usb_detach_broadcast(sc->sc_dev, &sc->sc_detach_cv);
mutex_exit(&sc->sc_lock);
return (error);
}
@ -965,7 +1000,6 @@ ugen_detach(device_t self, int flags)
struct ugen_softc *sc = device_private(self);
struct ugen_endpoint *sce;
int i, dir;
int s;
int maj, mn;
DPRINTF(("ugen_detach: sc=%p flags=%d\n", sc, flags));
@ -981,15 +1015,15 @@ ugen_detach(device_t self, int flags)
}
}
s = splusb();
mutex_enter(&sc->sc_lock);
if (--sc->sc_refcnt >= 0) {
/* Wake everyone */
for (i = 0; i < USB_MAX_ENDPOINTS; i++)
wakeup(&sc->sc_endpoints[i][IN]);
cv_signal(&sc->sc_endpoints[i][IN].cv);
/* Wait for processes to go away. */
usb_detach_waitold(sc->sc_dev);
usb_detach_wait(sc->sc_dev, &sc->sc_detach_cv, &sc->sc_lock);
}
splx(s);
mutex_exit(&sc->sc_lock);
/* locate the major number */
maj = cdevsw_lookup_major(&ugen_cdevsw);
@ -1005,9 +1039,13 @@ ugen_detach(device_t self, int flags)
for (dir = OUT; dir <= IN; dir++) {
sce = &sc->sc_endpoints[i][dir];
seldestroy(&sce->rsel);
cv_destroy(&sce->cv);
}
}
cv_destroy(&sc->sc_detach_cv);
mutex_destroy(&sc->sc_lock);
return (0);
}
@ -1015,7 +1053,7 @@ Static void
ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
{
struct ugen_endpoint *sce = addr;
/*struct ugen_softc *sc = sce->sc;*/
struct ugen_softc *sc = sce->sc;
u_int32_t count;
u_char *ibuf;
@ -1039,11 +1077,13 @@ ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status)
(void)b_to_q(ibuf, count, &sce->q);
mutex_enter(&sc->sc_lock);
if (sce->state & UGEN_ASLP) {
sce->state &= ~UGEN_ASLP;
DPRINTFN(5, ("ugen_intr: waking %p\n", sce));
wakeup(sce);
cv_signal(&sce->cv);
}
mutex_exit(&sc->sc_lock);
selnotify(&sce->rsel, 0, 0);
}
@ -1053,6 +1093,7 @@ ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr,
{
struct isoreq *req = addr;
struct ugen_endpoint *sce = req->sce;
struct ugen_softc *sc = sce->sc;
u_int32_t count, n;
int i, isize;
@ -1098,11 +1139,13 @@ ugen_isoc_rintr(usbd_xfer_handle xfer, usbd_private_handle addr,
USBD_NO_COPY, ugen_isoc_rintr);
(void)usbd_transfer(xfer);
mutex_enter(&sc->sc_lock);
if (sce->state & UGEN_ASLP) {
sce->state &= ~UGEN_ASLP;
DPRINTFN(5, ("ugen_isoc_rintr: waking %p\n", sce));
wakeup(sce);
cv_signal(&sce->cv);
}
mutex_exit(&sc->sc_lock);
selnotify(&sce->rsel, 0, 0);
}
@ -1111,6 +1154,7 @@ ugen_bulkra_intr(usbd_xfer_handle xfer, usbd_private_handle addr,
usbd_status status)
{
struct ugen_endpoint *sce = addr;
struct ugen_softc *sc = sce->sc;
u_int32_t count, n;
char const *tbuf;
usbd_status err;
@ -1165,11 +1209,13 @@ ugen_bulkra_intr(usbd_xfer_handle xfer, usbd_private_handle addr,
else
sce->state |= UGEN_RA_WB_STOP;
mutex_enter(&sc->sc_lock);
if (sce->state & UGEN_ASLP) {
sce->state &= ~UGEN_ASLP;
DPRINTFN(5, ("ugen_bulkra_intr: waking %p\n", sce));
wakeup(sce);
cv_signal(&sce->cv);
}
mutex_exit(&sc->sc_lock);
selnotify(&sce->rsel, 0, 0);
}
@ -1178,6 +1224,7 @@ ugen_bulkwb_intr(usbd_xfer_handle xfer, usbd_private_handle addr,
usbd_status status)
{
struct ugen_endpoint *sce = addr;
struct ugen_softc *sc = sce->sc;
u_int32_t count, n;
char *tbuf;
usbd_status err;
@ -1230,11 +1277,13 @@ ugen_bulkwb_intr(usbd_xfer_handle xfer, usbd_private_handle addr,
else
sce->state |= UGEN_RA_WB_STOP;
mutex_enter(&sc->sc_lock);
if (sce->state & UGEN_ASLP) {
sce->state &= ~UGEN_ASLP;
DPRINTFN(5, ("ugen_bulkwb_intr: waking %p\n", sce));
wakeup(sce);
cv_signal(&sce->cv);
}
mutex_exit(&sc->sc_lock);
selnotify(&sce->rsel, 0, 0);
}
@ -1782,7 +1831,7 @@ ugenioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
sc->sc_refcnt++;
error = ugen_do_ioctl(sc, endpt, cmd, addr, flag, l);
if (--sc->sc_refcnt < 0)
usb_detach_wakeupold(sc->sc_dev);
usb_detach_broadcast(sc->sc_dev, &sc->sc_detach_cv);
return (error);
}
@ -1792,7 +1841,6 @@ ugenpoll(dev_t dev, int events, struct lwp *l)
struct ugen_softc *sc;
struct ugen_endpoint *sce_in, *sce_out;
int revents = 0;
int s;
sc = device_lookup_private(&ugen_cd, UGENUNIT(dev));
if (sc == NULL)
@ -1819,7 +1867,8 @@ ugenpoll(dev_t dev, int events, struct lwp *l)
return (POLLERR);
}
#endif
s = splusb();
mutex_enter(&sc->sc_lock);
if (sce_in && sce_in->pipeh && (events & (POLLIN | POLLRDNORM)))
switch (sce_in->edesc->bmAttributes & UE_XFERTYPE) {
case UE_INTERRUPT:
@ -1880,8 +1929,8 @@ ugenpoll(dev_t dev, int events, struct lwp *l)
break;
}
mutex_exit(&sc->sc_lock);
splx(s);
return (revents);
}
@ -1889,11 +1938,11 @@ static void
filt_ugenrdetach(struct knote *kn)
{
struct ugen_endpoint *sce = kn->kn_hook;
int s;
struct ugen_softc *sc = sce->sc;
s = splusb();
mutex_enter(&sc->sc_lock);
SLIST_REMOVE(&sce->rsel.sel_klist, kn, knote, kn_selnext);
splx(s);
mutex_exit(&sc->sc_lock);
}
static int
@ -1982,7 +2031,6 @@ ugenkqfilter(dev_t dev, struct knote *kn)
struct ugen_softc *sc;
struct ugen_endpoint *sce;
struct klist *klist;
int s;
sc = device_lookup_private(&ugen_cd, UGENUNIT(dev));
if (sc == NULL)
@ -2042,9 +2090,9 @@ ugenkqfilter(dev_t dev, struct knote *kn)
kn->kn_hook = sce;
s = splusb();
mutex_enter(&sc->sc_lock);
SLIST_INSERT_HEAD(klist, kn, kn_selnext);
splx(s);
mutex_exit(&sc->sc_lock);
return (0);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,4 @@
/* $NetBSD: uhcivar.h,v 1.50 2012/03/06 02:49:03 mrg Exp $ */
/* $FreeBSD: src/sys/dev/usb/uhcivar.h,v 1.14 1999/11/17 22:33:42 n_hibma Exp $ */
/* $NetBSD: uhcivar.h,v 1.51 2012/06/10 06:15:54 mrg Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -133,6 +132,10 @@ typedef struct uhci_softc {
bus_space_handle_t ioh;
bus_size_t sc_size;
kmutex_t sc_lock;
kmutex_t sc_intr_lock;
kcondvar_t sc_softwake_cv;
uhci_physaddr_t *sc_pframes;
usb_dma_t sc_dma;
struct uhci_vframe sc_vframes[UHCI_VFRAMELIST_COUNT];

View File

@ -1,12 +1,12 @@
/* $NetBSD: uhid.c,v 1.87 2012/05/14 04:28:28 erh Exp $ */
/* $NetBSD: uhid.c,v 1.88 2012/06/10 06:15:54 mrg Exp $ */
/*
* Copyright (c) 1998, 2004, 2008 The NetBSD Foundation, Inc.
* Copyright (c) 1998, 2004, 2008, 2012 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson (lennart@augustsson.net) at
* Carlstedt Research & Technology.
* Carlstedt Research & Technology and Matthew R. Green (mrg@eterna.com.au).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uhid.c,v 1.87 2012/05/14 04:28:28 erh Exp $");
__KERNEL_RCSID(0, "$NetBSD: uhid.c,v 1.88 2012/06/10 06:15:54 mrg Exp $");
#include "opt_compat_netbsd.h"
@ -78,6 +78,11 @@ int uhiddebug = 0;
struct uhid_softc {
struct uhidev sc_hdev;
kmutex_t sc_access_lock; /* serialises syscall accesses */
kmutex_t sc_lock; /* protects refcnt, others */
kcondvar_t sc_cv;
kcondvar_t sc_detach_cv;
int sc_isize;
int sc_osize;
int sc_fsize;
@ -110,7 +115,7 @@ dev_type_kqfilter(uhidkqfilter);
const struct cdevsw uhid_cdevsw = {
uhidopen, uhidclose, uhidread, uhidwrite, uhidioctl,
nostop, notty, uhidpoll, nommap, uhidkqfilter, D_OTHER,
nostop, notty, uhidpoll, nommap, uhidkqfilter, D_OTHER | D_MPSAFE,
};
Static void uhid_intr(struct uhidev *, void *, u_int len);
@ -168,6 +173,11 @@ uhid_attach(device_t parent, device_t self, void *aux)
aprint_normal(": input=%d, output=%d, feature=%d\n",
sc->sc_isize, sc->sc_osize, sc->sc_fsize);
mutex_init(&sc->sc_access_lock, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_USB);
cv_init(&sc->sc_cv, "uhidrea");
cv_init(&sc->sc_detach_cv, "uhiddet");
if (!pmf_device_register(self, NULL, NULL))
aprint_error_dev(self, "couldn't establish power handler\n");
@ -192,23 +202,23 @@ int
uhid_detach(device_t self, int flags)
{
struct uhid_softc *sc = device_private(self);
int s;
int maj, mn;
DPRINTF(("uhid_detach: sc=%p flags=%d\n", sc, flags));
sc->sc_dying = 1;
mutex_enter(&sc->sc_lock);
if (sc->sc_hdev.sc_state & UHIDEV_OPEN) {
s = splusb();
if (--sc->sc_refcnt >= 0) {
/* Wake everyone */
wakeup(&sc->sc_q);
cv_broadcast(&sc->sc_cv);
/* Wait for processes to go away. */
usb_detach_waitold(sc->sc_hdev.sc_dev);
usb_detach_wait(sc->sc_hdev.sc_dev,
&sc->sc_detach_cv, &sc->sc_lock);
}
splx(s);
}
mutex_exit(&sc->sc_lock);
/* locate the major number */
maj = cdevsw_lookup_major(&uhid_cdevsw);
@ -222,6 +232,10 @@ uhid_detach(device_t self, int flags)
sc->sc_hdev.sc_parent->sc_udev,
sc->sc_hdev.sc_dev);
#endif
cv_destroy(&sc->sc_cv);
cv_destroy(&sc->sc_detach_cv);
mutex_destroy(&sc->sc_lock);
mutex_destroy(&sc->sc_access_lock);
seldestroy(&sc->sc_rsel);
softint_disestablish(sc->sc_sih);
@ -244,18 +258,20 @@ uhid_intr(struct uhidev *addr, void *data, u_int len)
}
#endif
mutex_enter(&sc->sc_lock);
(void)b_to_q(data, len, &sc->sc_q);
if (sc->sc_state & UHID_ASLP) {
sc->sc_state &= ~UHID_ASLP;
DPRINTFN(5, ("uhid_intr: waking %p\n", &sc->sc_q));
wakeup(&sc->sc_q);
cv_broadcast(&sc->sc_cv);
}
selnotify(&sc->sc_rsel, 0, 0);
if (sc->sc_async != NULL) {
DPRINTFN(3, ("uhid_intr: sending SIGIO %p\n", sc->sc_async));
softint_schedule(sc->sc_sih);
}
mutex_exit(&sc->sc_lock);
}
void
@ -272,8 +288,7 @@ uhid_softintr(void *cookie)
}
int
uhidopen(dev_t dev, int flag, int mode,
struct lwp *l)
uhidopen(dev_t dev, int flag, int mode, struct lwp *l)
{
struct uhid_softc *sc;
int error;
@ -287,16 +302,23 @@ uhidopen(dev_t dev, int flag, int mode,
if (sc->sc_dying)
return (ENXIO);
mutex_enter(&sc->sc_access_lock);
error = uhidev_open(&sc->sc_hdev);
if (error)
if (error) {
mutex_exit(&sc->sc_access_lock);
return (error);
}
mutex_exit(&sc->sc_access_lock);
if (clalloc(&sc->sc_q, UHID_BSIZE, 0) == -1) {
mutex_enter(&sc->sc_access_lock);
uhidev_close(&sc->sc_hdev);
mutex_exit(&sc->sc_access_lock);
return (ENOMEM);
}
sc->sc_obuf = malloc(sc->sc_osize, M_USBDEV, M_WAITOK);
sc->sc_state &= ~UHID_IMMED;
mutex_enter(proc_lock);
sc->sc_async = NULL;
mutex_exit(proc_lock);
@ -305,8 +327,7 @@ uhidopen(dev_t dev, int flag, int mode,
}
int
uhidclose(dev_t dev, int flag, int mode,
struct lwp *l)
uhidclose(dev_t dev, int flag, int mode, struct lwp *l)
{
struct uhid_softc *sc;
@ -316,10 +337,14 @@ uhidclose(dev_t dev, int flag, int mode,
clfree(&sc->sc_q);
free(sc->sc_obuf, M_USBDEV);
mutex_enter(proc_lock);
sc->sc_async = NULL;
mutex_exit(proc_lock);
mutex_enter(&sc->sc_access_lock);
uhidev_close(&sc->sc_hdev);
mutex_exit(&sc->sc_access_lock);
return (0);
}
@ -327,7 +352,6 @@ uhidclose(dev_t dev, int flag, int mode,
int
uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag)
{
int s;
int error = 0;
int extra;
size_t length;
@ -345,15 +369,15 @@ uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag)
return (uiomove(buffer+extra, sc->sc_isize, uio));
}
s = splusb();
mutex_enter(&sc->sc_lock);
while (sc->sc_q.c_cc == 0) {
if (flag & IO_NDELAY) {
splx(s);
mutex_exit(&sc->sc_lock);
return (EWOULDBLOCK);
}
sc->sc_state |= UHID_ASLP;
DPRINTFN(5, ("uhidread: sleep on %p\n", &sc->sc_q));
error = tsleep(&sc->sc_q, PZERO | PCATCH, "uhidrea", 0);
error = cv_wait_sig(&sc->sc_cv, &sc->sc_lock);
DPRINTFN(5, ("uhidread: woke, error=%d\n", error));
if (sc->sc_dying)
error = EIO;
@ -362,7 +386,7 @@ uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag)
break;
}
}
splx(s);
mutex_exit(&sc->sc_lock);
/* Transfer as many chunks as possible. */
while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0 && !error) {
@ -390,10 +414,18 @@ uhidread(dev_t dev, struct uio *uio, int flag)
sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev));
mutex_enter(&sc->sc_lock);
sc->sc_refcnt++;
mutex_exit(&sc->sc_lock);
mutex_enter(&sc->sc_access_lock);
error = uhid_do_read(sc, uio, flag);
mutex_exit(&sc->sc_access_lock);
mutex_enter(&sc->sc_lock);
if (--sc->sc_refcnt < 0)
usb_detach_wakeupold(sc->sc_hdev.sc_dev);
usb_detach_broadcast(sc->sc_hdev.sc_dev, &sc->sc_detach_cv);
mutex_exit(&sc->sc_lock);
return (error);
}
@ -432,10 +464,18 @@ uhidwrite(dev_t dev, struct uio *uio, int flag)
sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev));
mutex_enter(&sc->sc_lock);
sc->sc_refcnt++;
mutex_exit(&sc->sc_lock);
mutex_enter(&sc->sc_access_lock);
error = uhid_do_write(sc, uio, flag);
mutex_exit(&sc->sc_access_lock);
mutex_enter(&sc->sc_lock);
if (--sc->sc_refcnt < 0)
usb_detach_wakeupold(sc->sc_hdev.sc_dev);
usb_detach_broadcast(sc->sc_hdev.sc_dev, &sc->sc_detach_cv);
mutex_exit(&sc->sc_lock);
return (error);
}
@ -610,11 +650,24 @@ uhidioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
int error;
sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev));
if (sc == NULL)
return ENXIO;
if (sc->sc_dying)
return EIO;
mutex_enter(&sc->sc_lock);
sc->sc_refcnt++;
mutex_exit(&sc->sc_lock);
mutex_enter(&sc->sc_access_lock);
error = uhid_do_ioctl(sc, cmd, addr, flag, l);
mutex_exit(&sc->sc_access_lock);
mutex_enter(&sc->sc_lock);
if (--sc->sc_refcnt < 0)
usb_detach_wakeupold(sc->sc_hdev.sc_dev);
usb_detach_broadcast(sc->sc_hdev.sc_dev, &sc->sc_detach_cv);
mutex_exit(&sc->sc_lock);
return (error);
}
@ -623,14 +676,15 @@ uhidpoll(dev_t dev, int events, struct lwp *l)
{
struct uhid_softc *sc;
int revents = 0;
int s;
sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev));
if (sc == NULL)
return ENXIO;
if (sc->sc_dying)
return (POLLHUP);
return EIO;
s = splusb();
mutex_enter(&sc->sc_lock);
if (events & (POLLOUT | POLLWRNORM))
revents |= events & (POLLOUT | POLLWRNORM);
if (events & (POLLIN | POLLRDNORM)) {
@ -639,8 +693,8 @@ uhidpoll(dev_t dev, int events, struct lwp *l)
else
selrecord(l, &sc->sc_rsel);
}
mutex_exit(&sc->sc_lock);
splx(s);
return (revents);
}
@ -648,11 +702,10 @@ static void
filt_uhidrdetach(struct knote *kn)
{
struct uhid_softc *sc = kn->kn_hook;
int s;
s = splusb();
mutex_enter(&sc->sc_lock);
SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext);
splx(s);
mutex_exit(&sc->sc_lock);
}
static int
@ -675,7 +728,6 @@ uhidkqfilter(dev_t dev, struct knote *kn)
{
struct uhid_softc *sc;
struct klist *klist;
int s;
sc = device_lookup_private(&uhid_cd, UHIDUNIT(dev));
@ -699,9 +751,9 @@ uhidkqfilter(dev_t dev, struct knote *kn)
kn->kn_hook = sc;
s = splusb();
mutex_enter(&sc->sc_lock);
SLIST_INSERT_HEAD(klist, kn, kn_selnext);
splx(s);
mutex_exit(&sc->sc_lock);
return (0);
}

View File

@ -1,12 +1,12 @@
/* $NetBSD: uhidev.c,v 1.55 2012/02/02 19:43:07 tls Exp $ */
/* $NetBSD: uhidev.c,v 1.56 2012/06/10 06:15:54 mrg Exp $ */
/*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* Copyright (c) 2001, 2012 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson (lennart@augustsson.net) at
* Carlstedt Research & Technology.
* Carlstedt Research & Technology and Matthew R. Green (mrg@eterna.com.au).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uhidev.c,v 1.55 2012/02/02 19:43:07 tls Exp $");
__KERNEL_RCSID(0, "$NetBSD: uhidev.c,v 1.56 2012/06/10 06:15:54 mrg Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -129,6 +129,8 @@ uhidev_attach(device_t parent, device_t self, void *aux)
aprint_naive("\n");
aprint_normal("\n");
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_USB);
id = usbd_get_interface_descriptor(iface);
devinfop = usbd_devinfo_alloc(uaa->device, 0);
@ -450,6 +452,7 @@ uhidev_detach(device_t self, int flags)
sc->sc_dev);
pmf_device_deregister(self);
mutex_destroy(&sc->sc_lock);
return (rv);
}
@ -534,14 +537,15 @@ uhidev_open(struct uhidev *scd)
usbd_status err;
int error;
DPRINTF(("uhidev_open: open pipe, state=%d refcnt=%d\n",
scd->sc_state, sc->sc_refcnt));
DPRINTF(("uhidev_open: open pipe, state=%d\n", scd->sc_state));
if (scd->sc_state & UHIDEV_OPEN)
mutex_enter(&sc->sc_lock);
if (scd->sc_state & UHIDEV_OPEN) {
mutex_exit(&sc->sc_lock);
return (EBUSY);
}
scd->sc_state |= UHIDEV_OPEN;
if (sc->sc_refcnt++)
return (0);
mutex_exit(&sc->sc_lock);
if (sc->sc_isize == 0)
return (0);
@ -598,11 +602,12 @@ out2:
out1:
DPRINTF(("uhidev_open: failed in someway"));
free(sc->sc_ibuf, M_USBDEV);
mutex_enter(&sc->sc_lock);
scd->sc_state &= ~UHIDEV_OPEN;
sc->sc_refcnt = 0;
sc->sc_ipipe = NULL;
sc->sc_opipe = NULL;
sc->sc_oxfer = NULL;
mutex_exit(&sc->sc_lock);
return error;
}
@ -611,11 +616,14 @@ uhidev_close(struct uhidev *scd)
{
struct uhidev_softc *sc = scd->sc_parent;
if (!(scd->sc_state & UHIDEV_OPEN))
mutex_enter(&sc->sc_lock);
if (!(scd->sc_state & UHIDEV_OPEN)) {
mutex_exit(&sc->sc_lock);
return;
}
scd->sc_state &= ~UHIDEV_OPEN;
if (--sc->sc_refcnt)
return;
mutex_exit(&sc->sc_lock);
DPRINTF(("uhidev_close: close pipe\n"));
if (sc->sc_oxfer != NULL)

View File

@ -1,4 +1,4 @@
/* $NetBSD: uhidev.h,v 1.12 2012/02/02 19:43:07 tls Exp $ */
/* $NetBSD: uhidev.h,v 1.13 2012/06/10 06:15:54 mrg Exp $ */
/*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@ -53,8 +53,9 @@ struct uhidev_softc {
u_int sc_nrepid;
device_t *sc_subdevs;
int sc_refcnt;
u_char sc_dying;
kmutex_t sc_lock; /* protects writes to sc_state */
};
struct uhidev {

View File

@ -1,4 +1,4 @@
/* $NetBSD: ukbd.c,v 1.123 2012/04/24 01:02:12 khorben Exp $ */
/* $NetBSD: ukbd.c,v 1.124 2012/06/10 06:15:54 mrg Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ukbd.c,v 1.123 2012/04/24 01:02:12 khorben Exp $");
__KERNEL_RCSID(0, "$NetBSD: ukbd.c,v 1.124 2012/06/10 06:15:54 mrg Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -328,9 +328,9 @@ Static void ukbd_cngetc(void *, u_int *, int *);
Static void ukbd_cnpollc(void *, int);
const struct wskbd_consops ukbd_consops = {
ukbd_cngetc,
ukbd_cnpollc,
NULL, /* bell */
.getc = ukbd_cngetc,
.pollc = ukbd_cnpollc,
.bell = NULL,
};
Static const char *ukbd_parse_desc(struct ukbd_softc *sc);

View File

@ -1,4 +1,4 @@
/* $NetBSD: umass.c,v 1.144 2012/03/06 03:35:30 mrg Exp $ */
/* $NetBSD: umass.c,v 1.145 2012/06/10 06:15:54 mrg Exp $ */
/*
* Copyright (c) 2003 The NetBSD Foundation, Inc.
@ -124,7 +124,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: umass.c,v 1.144 2012/03/06 03:35:30 mrg Exp $");
__KERNEL_RCSID(0, "$NetBSD: umass.c,v 1.145 2012/06/10 06:15:54 mrg Exp $");
#ifdef _KERNEL_OPT
#include "opt_umass.h"
@ -309,6 +309,9 @@ umass_attach(device_t parent, device_t self, void *aux)
aprint_naive("\n");
aprint_normal("\n");
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_USB);
cv_init(&sc->sc_detach_cv, "umassdet");
devinfop = usbd_devinfo_alloc(uaa->device, 0);
aprint_normal_dev(self, "%s\n", devinfop);
usbd_devinfo_free(devinfop);
@ -658,7 +661,7 @@ umass_detach(device_t self, int flags)
{
struct umass_softc *sc = device_private(self);
struct umassbus_softc *scbus;
int rv = 0, i, s;
int rv = 0, i;
DPRINTF(UDMASS_USB, ("%s: detached\n", device_xname(sc->sc_dev)));
@ -671,15 +674,15 @@ umass_detach(device_t self, int flags)
}
/* Do we really need reference counting? Perhaps in ioctl() */
s = splusb();
mutex_enter(&sc->sc_lock);
if (--sc->sc_refcnt >= 0) {
#ifdef DIAGNOSTIC
aprint_normal_dev(self, "waiting for refcnt\n");
#endif
/* Wait for processes to go away. */
usb_detach_waitold(sc->sc_dev);
usb_detach_wait(sc->sc_dev, &sc->sc_detach_cv, &sc->sc_lock);
}
splx(s);
mutex_exit(&sc->sc_lock);
scbus = sc->bus;
if (scbus != NULL) {
@ -697,6 +700,9 @@ umass_detach(device_t self, int flags)
usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
sc->sc_dev);
mutex_destroy(&sc->sc_lock);
cv_destroy(&sc->sc_detach_cv);
return (rv);
}

View File

@ -1,4 +1,5 @@
/* $NetBSD: umassvar.h,v 1.32 2012/03/04 00:21:20 mrg Exp $ */
/* $NetBSD: umassvar.h,v 1.33 2012/06/10 06:15:54 mrg Exp $ */
/*-
* Copyright (c) 1999 MAEKAWA Masahide <bishop@rr.iij4u.or.jp>,
* Nick Hibma <n_hibma@freebsd.org>
@ -161,6 +162,9 @@ struct umass_softc {
const struct umass_wire_methods *sc_methods;
kmutex_t sc_lock;
kcondvar_t sc_detach_cv;
u_int8_t sc_wire; /* wire protocol */
#define UMASS_WPROTO_UNSPEC 0
#define UMASS_WPROTO_BBB 1

View File

@ -1,4 +1,4 @@
/* $NetBSD: umidi.c,v 1.62 2012/05/18 07:52:54 jdc Exp $ */
/* $NetBSD: umidi.c,v 1.63 2012/06/10 06:15:54 mrg Exp $ */
/*
* Copyright (c) 2001, 2012 The NetBSD Foundation, Inc.
* All rights reserved.
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: umidi.c,v 1.62 2012/05/18 07:52:54 jdc Exp $");
__KERNEL_RCSID(0, "$NetBSD: umidi.c,v 1.63 2012/06/10 06:15:54 mrg Exp $");
#include <sys/types.h>
#include <sys/param.h>
@ -211,7 +211,6 @@ umidi_attach(device_t parent, device_t self, void *aux)
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_USB);
cv_init(&sc->sc_cv, "umidopcl");
KERNEL_LOCK(1, curlwp);
err = alloc_all_endpoints(sc);
if (err != USBD_NORMAL_COMPLETION) {
aprint_error_dev(self,
@ -244,7 +243,6 @@ umidi_attach(device_t parent, device_t self, void *aux)
aprint_error_dev(self,
"attach_all_mididevs failed. (err=%d)\n", err);
}
KERNEL_UNLOCK_ONE(curlwp);
#ifdef UMIDI_DEBUG
dump_sc(sc);
@ -302,7 +300,6 @@ umidi_detach(device_t self, int flags)
DPRINTFN(1,("umidi_detach\n"));
sc->sc_dying = 1;
KERNEL_LOCK(1, curlwp);
detach_all_mididevs(sc, flags);
free_all_mididevs(sc);
free_all_jacks(sc);
@ -310,7 +307,6 @@ umidi_detach(device_t self, int flags)
usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev,
sc->sc_dev);
KERNEL_UNLOCK_ONE(curlwp);
mutex_destroy(&sc->sc_lock);
cv_destroy(&sc->sc_cv);
@ -369,10 +365,8 @@ umidi_close(void *addr)
{
struct umidi_mididev *mididev = addr;
/* XXX SMP */
mididev->closing = 1;
KERNEL_LOCK(1, curlwp);
mutex_spin_exit(&mididev->sc->sc_lock);
if ((mididev->flags & FWRITE) && mididev->out_jack)
@ -380,9 +374,7 @@ umidi_close(void *addr)
if ((mididev->flags & FREAD) && mididev->in_jack)
close_in_jack(mididev->in_jack);
/* XXX SMP */
mutex_spin_enter(&mididev->sc->sc_lock);
KERNEL_UNLOCK_ONE(curlwp);
mididev->opened = 0;
}
@ -1140,9 +1132,7 @@ open_in_jack(struct umidi_jack *jack, void *arg, void (*intr)(void *, int))
jack->u.in.intr = intr;
jack->opened = 1;
if (ep->num_open++ == 0 && UE_GET_DIR(ep->addr)==UE_DIR_IN) {
KERNEL_LOCK(1, curlwp);
err = start_input_transfer(ep);
KERNEL_UNLOCK_ONE(curlwp);
if (err != USBD_NORMAL_COMPLETION &&
err != USBD_IN_PROGRESS) {
ep->num_open--;
@ -1456,13 +1446,11 @@ start_output_transfer(struct umidi_endpoint *ep)
length = (ep->next_slot - ep->buffer) * sizeof *ep->buffer;
DPRINTFN(200,("umidi out transfer: start %p end %p length %u\n",
ep->buffer, ep->next_slot, length));
KERNEL_LOCK(1, curlwp);
usbd_setup_xfer(ep->xfer, ep->pipe,
(usbd_private_handle)ep,
ep->buffer, length,
USBD_NO_COPY, USBD_NO_TIMEOUT, out_intr);
rv = usbd_transfer(ep->xfer);
KERNEL_UNLOCK_ONE(curlwp);
/*
* Once the transfer is scheduled, no more adding to partial

View File

@ -1,4 +1,4 @@
/* $NetBSD: usb.c,v 1.129 2012/03/11 01:06:07 mrg Exp $ */
/* $NetBSD: usb.c,v 1.130 2012/06/10 06:15:54 mrg Exp $ */
/*
* Copyright (c) 1998, 2002, 2008, 2012 The NetBSD Foundation, Inc.
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: usb.c,v 1.129 2012/03/11 01:06:07 mrg Exp $");
__KERNEL_RCSID(0, "$NetBSD: usb.c,v 1.130 2012/06/10 06:15:54 mrg Exp $");
#include "opt_compat_netbsd.h"
#include "opt_usb.h"
@ -57,19 +57,19 @@ __KERNEL_RCSID(0, "$NetBSD: usb.c,v 1.129 2012/03/11 01:06:07 mrg Exp $");
#include <sys/signalvar.h>
#include <sys/intr.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/bus.h>
#include <sys/once.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usb_verbose.h>
#include <dev/usb/usb_quirks.h>
#define USB_DEV_MINOR 255
#include <sys/bus.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usb_quirks.h>
#ifdef USB_DEBUG
#define DPRINTF(x) if (usbdebug) printf x
#define DPRINTFN(n,x) if (usbdebug>(n)) printf x
@ -83,6 +83,7 @@ int usb_noexplore = 0;
#else
#define DPRINTF(x)
#define DPRINTFN(n,x)
#define usb_noexplore 0
#endif
struct usb_softc {
@ -99,6 +100,8 @@ struct usb_softc {
struct usb_taskq {
TAILQ_HEAD(, usb_task) tasks;
kmutex_t lock;
kcondvar_t cv;
struct lwp *task_thread_lwp;
const char *name;
int taskcreated; /* task thread exists. */
@ -132,6 +135,8 @@ Static SIMPLEQ_HEAD(, usb_event_q) usb_events =
SIMPLEQ_HEAD_INITIALIZER(usb_events);
Static int usb_nevents = 0;
Static struct selinfo usb_selevent;
Static kmutex_t usb_event_lock;
Static kcondvar_t usb_event_cv;
Static proc_t *usb_async_proc; /* process that wants USB SIGIO */
Static void *usb_async_sih;
Static int usb_dev_open = 0;
@ -140,6 +145,7 @@ Static void usb_free_event(struct usb_event *);
Static void usb_add_event(int, struct usb_event *);
Static int usb_get_next_event(struct usb_event *);
Static void usb_async_intr(void *);
Static void usb_soft_intr(void *);
#ifdef COMPAT_30
Static void usb_copy_old_devinfo(struct usb_device_info_old *, const struct usb_device_info *);
@ -152,6 +158,7 @@ static void usb_attach(device_t, device_t, void *);
static int usb_detach(device_t, int);
static int usb_activate(device_t, enum devact);
static void usb_childdet(device_t, device_t);
static int usb_once_init(void);
static void usb_doattach(device_t);
extern struct cfdriver usb_cd;
@ -170,6 +177,7 @@ usb_match(device_t parent, cfdata_t match, void *aux)
void
usb_attach(device_t parent, device_t self, void *aux)
{
static ONCE_DECL(init_control);
struct usb_softc *sc = device_private(self);
int usbrev;
@ -190,23 +198,30 @@ usb_attach(device_t parent, device_t self, void *aux)
}
aprint_normal("\n");
RUN_ONCE(&init_control, usb_once_init);
config_interrupts(self, usb_doattach);
}
static int
usb_once_init(void)
{
selinit(&usb_selevent);
mutex_init(&usb_event_lock, MUTEX_DEFAULT, IPL_NONE);
cv_init(&usb_event_cv, "usbrea");
return 0;
}
static void
usb_doattach(device_t self)
{
static bool usb_selevent_init; /* XXX */
struct usb_softc *sc = device_private(self);
usbd_device_handle dev;
usbd_status err;
int speed;
struct usb_event *ue;
bool mpsafe = sc->sc_bus->methods->get_lock ? true : false;
if (!usb_selevent_init) {
selinit(&usb_selevent);
usb_selevent_init = true;
}
DPRINTF(("usbd_doattach\n"));
sc->sc_bus->usbctl = self;
@ -224,13 +239,21 @@ usb_doattach(device_t self)
panic("usb_doattach");
}
if (mpsafe) {
sc->sc_bus->methods->get_lock(sc->sc_bus, &sc->sc_bus->lock);
} else {
sc->sc_bus->lock = NULL;
}
cv_init(&sc->sc_bus->needs_explore_cv, "usbevt");
ue = usb_alloc_event();
ue->u.ue_ctrlr.ue_bus = device_unit(self);
usb_add_event(USB_EVENT_CTRLR_ATTACH, ue);
/* XXX we should have our own level */
sc->sc_bus->soft = softint_establish(SOFTINT_NET,
sc->sc_bus->methods->soft_intr, sc->sc_bus);
sc->sc_bus->soft = softint_establish(
SOFTINT_NET | (mpsafe ? SOFTINT_MPSAFE : 0),
usb_soft_intr, sc->sc_bus);
if (sc->sc_bus->soft == NULL) {
aprint_error("%s: can't register softintr\n",
device_xname(self));
@ -285,8 +308,10 @@ usb_create_event_thread(device_t self)
struct usb_taskq *taskq;
int i;
if (kthread_create(PRI_NONE, 0, NULL, usb_event_thread, sc,
&sc->sc_event_thread, "%s", device_xname(self))) {
if (kthread_create(PRI_NONE,
sc->sc_bus->lock ? KTHREAD_MPSAFE : 0, NULL,
usb_event_thread, sc, &sc->sc_event_thread,
"%s", device_xname(self))) {
printf("%s: unable to create event thread for\n",
device_xname(self));
panic("usb_create_event_thread");
@ -298,10 +323,13 @@ usb_create_event_thread(device_t self)
continue;
TAILQ_INIT(&taskq->tasks);
mutex_init(&taskq->lock, MUTEX_DEFAULT, IPL_NONE);
cv_init(&taskq->cv, "usbtsk");
taskq->taskcreated = 1;
taskq->name = taskq_names[i];
if (kthread_create(PRI_NONE, 0, NULL, usb_task_thread,
taskq, &taskq->task_thread_lwp, "%s", taskq->name)) {
if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL,
usb_task_thread, taskq, &taskq->task_thread_lwp,
"%s", taskq->name)) {
printf("unable to create task thread: %s\n", taskq->name);
panic("usb_create_event_thread task");
}
@ -317,10 +345,9 @@ void
usb_add_task(usbd_device_handle dev, struct usb_task *task, int queue)
{
struct usb_taskq *taskq;
int s;
taskq = &usb_taskq[queue];
s = splusb();
mutex_enter(&taskq->lock);
if (task->queue == -1) {
DPRINTFN(2,("usb_add_task: task=%p\n", task));
TAILQ_INSERT_TAIL(&taskq->tasks, task, next);
@ -328,23 +355,22 @@ usb_add_task(usbd_device_handle dev, struct usb_task *task, int queue)
} else {
DPRINTFN(3,("usb_add_task: task=%p on q\n", task));
}
wakeup(&taskq->tasks);
splx(s);
cv_signal(&taskq->cv);
mutex_exit(&taskq->lock);
}
void
usb_rem_task(usbd_device_handle dev, struct usb_task *task)
{
struct usb_taskq *taskq;
int s;
taskq = &usb_taskq[task->queue];
s = splusb();
mutex_enter(&taskq->lock);
if (task->queue != -1) {
TAILQ_REMOVE(&taskq->tasks, task, next);
task->queue = -1;
}
splx(s);
mutex_exit(&taskq->lock);
}
void
@ -365,28 +391,36 @@ usb_event_thread(void *arg)
usb_delay_ms(sc->sc_bus, 500);
/* Make sure first discover does something. */
if (sc->sc_bus->lock)
mutex_enter(sc->sc_bus->lock);
sc->sc_bus->needs_explore = 1;
usb_discover(sc);
if (sc->sc_bus->lock)
mutex_exit(sc->sc_bus->lock);
config_pending_decr();
if (sc->sc_bus->lock)
mutex_enter(sc->sc_bus->lock);
while (!sc->sc_dying) {
#ifdef USB_DEBUG
if (usb_noexplore < 2)
#endif
usb_discover(sc);
#ifdef USB_DEBUG
(void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt",
usb_noexplore ? 0 : hz * 60);
#else
(void)tsleep(&sc->sc_bus->needs_explore, PWAIT, "usbevt",
hz * 60);
#endif
usb_discover(sc);
if (sc->sc_bus->lock)
cv_timedwait(&sc->sc_bus->needs_explore_cv,
sc->sc_bus->lock, usb_noexplore ? 0 : hz * 60);
else
(void)tsleep(&sc->sc_bus->needs_explore, /* XXXSMP ok */
PWAIT, "usbevt", usb_noexplore ? 0 : hz * 60);
DPRINTFN(2,("usb_event_thread: woke up\n"));
}
sc->sc_event_thread = NULL;
/* In case parent is waiting for us to exit. */
wakeup(sc);
if (sc->sc_bus->lock) {
cv_signal(&sc->sc_bus->needs_explore_cv);
mutex_exit(sc->sc_bus->lock);
} else
wakeup(sc); /* XXXSMP ok */
DPRINTF(("usb_event_thread: exit\n"));
kthread_exit(0);
@ -397,27 +431,27 @@ usb_task_thread(void *arg)
{
struct usb_task *task;
struct usb_taskq *taskq;
int s;
taskq = arg;
DPRINTF(("usb_task_thread: start taskq %s\n", taskq->name));
s = splusb();
mutex_enter(&taskq->lock);
for (;;) {
task = TAILQ_FIRST(&taskq->tasks);
if (task == NULL) {
tsleep(&taskq->tasks, PWAIT, "usbtsk", 0);
cv_wait(&taskq->cv, &taskq->lock);
task = TAILQ_FIRST(&taskq->tasks);
}
DPRINTFN(2,("usb_task_thread: woke up task=%p\n", task));
if (task != NULL) {
TAILQ_REMOVE(&taskq->tasks, task, next);
task->queue = -1;
splx(s);
mutex_exit(&taskq->lock);
task->fun(task->arg);
s = splusb();
mutex_enter(&taskq->lock);
}
}
mutex_exit(&taskq->lock);
}
int
@ -463,7 +497,7 @@ usbread(dev_t dev, struct uio *uio, int flag)
#ifdef COMPAT_30
struct usb_event_old *ueo = NULL; /* XXXGCC */
#endif
int s, error, n, useold;
int error, n, useold;
if (minor(dev) != USB_DEV_MINOR)
return (ENXIO);
@ -485,7 +519,7 @@ usbread(dev_t dev, struct uio *uio, int flag)
}
error = 0;
s = splusb();
mutex_enter(&usb_event_lock);
for (;;) {
n = usb_get_next_event(ue);
if (n != 0)
@ -494,11 +528,11 @@ usbread(dev_t dev, struct uio *uio, int flag)
error = EWOULDBLOCK;
break;
}
error = tsleep(&usb_events, PZERO | PCATCH, "usbrea", 0);
error = cv_wait_sig(&usb_event_cv, &usb_event_lock);
if (error)
break;
}
splx(s);
mutex_exit(&usb_event_lock);
if (!error) {
#ifdef COMPAT_30
if (useold) { /* copy fields to old struct */
@ -699,18 +733,18 @@ usbioctl(dev_t devt, u_long cmd, void *data, int flag, struct lwp *l)
int
usbpoll(dev_t dev, int events, struct lwp *l)
{
int revents, mask, s;
int revents, mask;
if (minor(dev) == USB_DEV_MINOR) {
revents = 0;
mask = POLLIN | POLLRDNORM;
s = splusb();
mutex_enter(&usb_event_lock);
if (events & mask && usb_nevents > 0)
revents |= events & mask;
if (revents == 0 && events & mask)
selrecord(l, &usb_selevent);
splx(s);
mutex_exit(&usb_event_lock);
return (revents);
} else {
@ -721,11 +755,10 @@ usbpoll(dev_t dev, int events, struct lwp *l)
static void
filt_usbrdetach(struct knote *kn)
{
int s;
s = splusb();
mutex_enter(&usb_event_lock);
SLIST_REMOVE(&usb_selevent.sel_klist, kn, knote, kn_selnext);
splx(s);
mutex_exit(&usb_event_lock);
}
static int
@ -746,7 +779,6 @@ int
usbkqfilter(dev_t dev, struct knote *kn)
{
struct klist *klist;
int s;
switch (kn->kn_filter) {
case EVFILT_READ:
@ -762,9 +794,9 @@ usbkqfilter(dev_t dev, struct knote *kn)
kn->kn_hook = NULL;
s = splusb();
mutex_enter(&usb_event_lock);
SLIST_INSERT_HEAD(klist, kn, kn_selnext);
splx(s);
mutex_exit(&usb_event_lock);
return (0);
}
@ -774,19 +806,25 @@ Static void
usb_discover(struct usb_softc *sc)
{
KASSERT(sc->sc_bus->lock == NULL || mutex_owned(sc->sc_bus->lock));
DPRINTFN(2,("usb_discover\n"));
#ifdef USB_DEBUG
if (usb_noexplore > 1)
return;
#endif
/*
* We need mutual exclusion while traversing the device tree,
* but this is guaranteed since this function is only called
* from the event thread for the controller.
*
* Also, we now have sc_bus->lock held for MPSAFE controllers.
*/
while (sc->sc_bus->needs_explore && !sc->sc_dying) {
sc->sc_bus->needs_explore = 0;
if (sc->sc_bus->lock)
mutex_exit(sc->sc_bus->lock);
sc->sc_bus->root_hub->hub->explore(sc->sc_bus->root_hub);
if (sc->sc_bus->lock)
mutex_enter(sc->sc_bus->lock);
}
}
@ -794,25 +832,39 @@ void
usb_needs_explore(usbd_device_handle dev)
{
DPRINTFN(2,("usb_needs_explore\n"));
if (dev->bus->lock)
mutex_enter(dev->bus->lock);
dev->bus->needs_explore = 1;
wakeup(&dev->bus->needs_explore);
if (dev->bus->lock) {
cv_signal(&dev->bus->needs_explore_cv);
mutex_exit(dev->bus->lock);
} else
wakeup(&dev->bus->needs_explore); /* XXXSMP ok */
}
void
usb_needs_reattach(usbd_device_handle dev)
{
DPRINTFN(2,("usb_needs_reattach\n"));
if (dev->bus->lock)
mutex_enter(dev->bus->lock);
dev->powersrc->reattach = 1;
dev->bus->needs_explore = 1;
wakeup(&dev->bus->needs_explore);
if (dev->bus->lock) {
cv_signal(&dev->bus->needs_explore_cv);
mutex_exit(dev->bus->lock);
} else
wakeup(&dev->bus->needs_explore); /* XXXSMP ok */
}
/* Called at splusb() */
/* Called at with usb_event_lock held. */
int
usb_get_next_event(struct usb_event *ue)
{
struct usb_event_q *ueq;
KASSERT(mutex_owned(&usb_event_lock));
if (usb_nevents <= 0)
return (0);
ueq = SIMPLEQ_FIRST(&usb_events);
@ -869,28 +921,29 @@ usb_add_event(int type, struct usb_event *uep)
{
struct usb_event_q *ueq;
struct timeval thetime;
int s;
microtime(&thetime);
/* Don't want to wait here inside splusb() */
/* Don't want to wait here with usb_event_lock held */
ueq = (struct usb_event_q *)(void *)uep;
ueq->ue = *uep;
ueq->ue.ue_type = type;
TIMEVAL_TO_TIMESPEC(&thetime, &ueq->ue.ue_time);
s = splusb();
mutex_enter(&usb_event_lock);
if (++usb_nevents >= USB_MAX_EVENTS) {
/* Too many queued events, drop an old one. */
DPRINTFN(-1,("usb: event dropped\n"));
(void)usb_get_next_event(0);
}
SIMPLEQ_INSERT_TAIL(&usb_events, ueq, next);
wakeup(&usb_events);
cv_signal(&usb_event_cv);
selnotify(&usb_selevent, 0, 0);
if (usb_async_proc != NULL) {
kpreempt_disable();
softint_schedule(usb_async_sih);
kpreempt_enable();
}
splx(s);
mutex_exit(&usb_event_lock);
}
Static void
@ -904,14 +957,30 @@ usb_async_intr(void *cookie)
mutex_exit(proc_lock);
}
Static void
usb_soft_intr(void *arg)
{
usbd_bus_handle bus = arg;
if (bus->lock)
mutex_enter(bus->lock);
(*bus->methods->soft_intr)(bus);
if (bus->lock)
mutex_exit(bus->lock);
}
void
usb_schedsoftintr(usbd_bus_handle bus)
{
DPRINTFN(10,("usb_schedsoftintr: polling=%d\n", bus->use_polling));
if (bus->use_polling) {
bus->methods->soft_intr(bus);
} else {
kpreempt_disable();
softint_schedule(bus->soft);
kpreempt_enable();
}
}
@ -962,8 +1031,16 @@ usb_detach(device_t self, int flags)
/* Kill off event thread. */
sc->sc_dying = 1;
while (sc->sc_event_thread != NULL) {
wakeup(&sc->sc_bus->needs_explore);
tsleep(sc, PWAIT, "usbdet", hz * 60);
if (sc->sc_bus->lock) {
mutex_enter(sc->sc_bus->lock);
cv_signal(&sc->sc_bus->needs_explore_cv);
cv_timedwait(&sc->sc_bus->needs_explore_cv,
sc->sc_bus->lock, hz * 60);
mutex_exit(sc->sc_bus->lock);
} else {
wakeup(&sc->sc_bus->needs_explore); /* XXXSMP ok */
tsleep(sc, PWAIT, "usbdet", hz * 60); /* XXXSMP ok */
}
}
DPRINTF(("usb_detach: event thread dead\n"));
@ -976,6 +1053,8 @@ usb_detach(device_t self, int flags)
ue->u.ue_ctrlr.ue_bus = device_unit(self);
usb_add_event(USB_EVENT_CTRLR_DETACH, ue);
cv_destroy(&sc->sc_bus->needs_explore_cv);
return (0);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: usb_mem.c,v 1.52 2012/02/24 06:48:27 mrg Exp $ */
/* $NetBSD: usb_mem.c,v 1.53 2012/06/10 06:15:54 mrg Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -38,7 +38,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: usb_mem.c,v 1.52 2012/02/24 06:48:27 mrg Exp $");
__KERNEL_RCSID(0, "$NetBSD: usb_mem.c,v 1.53 2012/06/10 06:15:54 mrg Exp $");
#ifdef _KERNEL_OPT
#include "opt_usb.h"
@ -52,6 +52,8 @@ __KERNEL_RCSID(0, "$NetBSD: usb_mem.c,v 1.52 2012/02/24 06:48:27 mrg Exp $");
#include <sys/device.h> /* for usbdivar.h */
#include <sys/bus.h>
#include <sys/cpu.h>
#include <sys/once.h>
#include <sys/extent.h>
#ifdef DIAGNOSTIC
@ -90,6 +92,8 @@ Static void usb_block_freemem(usb_dma_block_t *);
LIST_HEAD(usb_dma_block_qh, usb_dma_block);
Static struct usb_dma_block_qh usb_blk_freelist =
LIST_HEAD_INITIALIZER(usb_blk_freelist);
kmutex_t usb_blk_lock;
#ifdef DEBUG
Static struct usb_dma_block_qh usb_blk_fraglist =
LIST_HEAD_INITIALIZER(usb_blk_fraglist);
@ -101,13 +105,22 @@ Static u_int usb_blk_nfree = 0;
Static LIST_HEAD(, usb_frag_dma) usb_frag_freelist =
LIST_HEAD_INITIALIZER(usb_frag_freelist);
Static int usb_mem_init(void);
Static int
usb_mem_init(void)
{
mutex_init(&usb_blk_lock, MUTEX_DEFAULT, IPL_NONE);
return 0;
}
Static usbd_status
usb_block_allocmem(bus_dma_tag_t tag, size_t size, size_t align,
usb_dma_block_t **dmap)
{
usb_dma_block_t *b;
int error;
int s;
DPRINTFN(5, ("usb_block_allocmem: size=%zu align=%zu\n", size, align));
@ -118,20 +131,19 @@ usb_block_allocmem(bus_dma_tag_t tag, size_t size, size_t align,
}
#endif
s = splusb();
KASSERT(mutex_owned(&usb_blk_lock));
/* First check the free list. */
LIST_FOREACH(b, &usb_blk_freelist, next) {
if (b->tag == tag && b->size >= size && b->align >= align) {
LIST_REMOVE(b, next);
usb_blk_nfree--;
splx(s);
*dmap = b;
DPRINTFN(6,("usb_block_allocmem: free list size=%zu\n",
b->size));
return (USBD_NORMAL_COMPLETION);
}
}
splx(s);
#ifdef DIAGNOSTIC
if (cpu_intr_p()) {
@ -225,16 +237,15 @@ usb_valid_block_p(usb_dma_block_t *b, struct usb_dma_block_qh *qh)
Static void
usb_block_freemem(usb_dma_block_t *b)
{
int s;
KASSERT(mutex_owned(&usb_blk_lock));
DPRINTFN(6, ("usb_block_freemem: size=%zu\n", b->size));
s = splusb();
#ifdef DEBUG
LIST_REMOVE(b, next);
#endif
LIST_INSERT_HEAD(&usb_blk_freelist, b, next);
usb_blk_nfree++;
splx(s);
}
usbd_status
@ -245,12 +256,15 @@ usb_allocmem(usbd_bus_handle bus, size_t size, size_t align, usb_dma_t *p)
struct usb_frag_dma *f;
usb_dma_block_t *b;
int i;
int s;
static ONCE_DECL(init_control);
RUN_ONCE(&init_control, usb_mem_init);
/* If the request is large then just use a full block. */
if (size > USB_MEM_SMALL || align > USB_MEM_SMALL) {
DPRINTFN(1, ("usb_allocmem: large alloc %d\n", (int)size));
size = (size + USB_MEM_BLOCK - 1) & ~(USB_MEM_BLOCK - 1);
mutex_enter(&usb_blk_lock);
err = usb_block_allocmem(tag, size, align, &p->block);
if (!err) {
#ifdef DEBUG
@ -259,10 +273,11 @@ usb_allocmem(usbd_bus_handle bus, size_t size, size_t align, usb_dma_t *p)
p->block->flags = USB_DMA_FULLBLOCK;
p->offs = 0;
}
mutex_exit(&usb_blk_lock);
return (err);
}
s = splusb();
mutex_enter(&usb_blk_lock);
/* Check for free fragments. */
LIST_FOREACH(f, &usb_frag_freelist, next) {
KDASSERTMSG(usb_valid_block_p(f->block, &usb_blk_fraglist),
@ -275,7 +290,7 @@ usb_allocmem(usbd_bus_handle bus, size_t size, size_t align, usb_dma_t *p)
DPRINTFN(1, ("usb_allocmem: adding fragments\n"));
err = usb_block_allocmem(tag, USB_MEM_BLOCK, USB_MEM_SMALL,&b);
if (err) {
splx(s);
mutex_exit(&usb_blk_lock);
return (err);
}
#ifdef DEBUG
@ -300,7 +315,7 @@ usb_allocmem(usbd_bus_handle bus, size_t size, size_t align, usb_dma_t *p)
#endif
p->block->flags &= ~USB_DMA_RESERVE;
LIST_REMOVE(f, next);
splx(s);
mutex_exit(&usb_blk_lock);
DPRINTFN(5, ("usb_allocmem: use frag=%p size=%d\n", f, (int)size));
return (USBD_NORMAL_COMPLETION);
}
@ -309,14 +324,15 @@ void
usb_freemem(usbd_bus_handle bus, usb_dma_t *p)
{
struct usb_frag_dma *f;
int s;
mutex_enter(&usb_blk_lock);
if (p->block->flags & USB_DMA_FULLBLOCK) {
KDASSERTMSG(usb_valid_block_p(p->block, &usb_blk_fulllist),
"%s: dma %p: invalid block pointer %p",
__func__, p, p->block);
DPRINTFN(1, ("usb_freemem: large free\n"));
usb_block_freemem(p->block);
mutex_exit(&usb_blk_lock);
return;
}
KDASSERTMSG(usb_valid_block_p(p->block, &usb_blk_fraglist),
@ -332,9 +348,8 @@ usb_freemem(usbd_bus_handle bus, usb_dma_t *p)
#ifdef USB_FRAG_DMA_WORKAROUND
f->offs -= USB_MEM_SMALL;
#endif
s = splusb();
LIST_INSERT_HEAD(&usb_frag_freelist, f, next);
splx(s);
mutex_exit(&usb_blk_lock);
DPRINTFN(5, ("usb_freemem: frag=%p\n", f));
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: usb_subr.c,v 1.181 2012/05/22 19:11:21 martin Exp $ */
/* $NetBSD: usb_subr.c,v 1.182 2012/06/10 06:15:54 mrg Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */
/*
@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.181 2012/05/22 19:11:21 martin Exp $");
__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.182 2012/06/10 06:15:54 mrg Exp $");
#include "opt_compat_netbsd.h"
#include "opt_usbverbose.h"
@ -297,20 +297,33 @@ usbd_devinfo_free(char *devinfop)
/* Delay for a certain number of ms */
void
usb_delay_ms(usbd_bus_handle bus, u_int ms)
usb_delay_ms_locked(usbd_bus_handle bus, u_int ms, kmutex_t *lock)
{
/* Wait at least two clock ticks so we know the time has passed. */
if (bus->use_polling || cold)
delay((ms+1) * 1000);
else
tsleep(&ms, PRIBIO, "usbdly", (ms*hz+999)/1000 + 1);
kpause("usbdly", false, (ms*hz+999)/1000 + 1, lock);
}
void
usb_delay_ms(usbd_bus_handle bus, u_int ms)
{
usb_delay_ms_locked(bus, ms, NULL);
}
/* Delay given a device handle. */
void
usbd_delay_ms_locked(usbd_device_handle dev, u_int ms, kmutex_t *lock)
{
usb_delay_ms_locked(dev->bus, ms, lock);
}
/* Delay given a device handle. */
void
usbd_delay_ms(usbd_device_handle dev, u_int ms)
{
usb_delay_ms(dev->bus, ms);
usb_delay_ms_locked(dev->bus, ms, NULL);
}
usbd_status
@ -760,8 +773,12 @@ usbd_setup_pipe(usbd_device_handle dev, usbd_interface_handle iface,
void
usbd_kill_pipe(usbd_pipe_handle pipe)
{
int s;
usbd_abort_pipe(pipe);
usbd_lock_pipe(pipe);
pipe->methods->close(pipe);
usbd_unlock_pipe(pipe);
pipe->endpoint->refcnt--;
free(pipe, M_USB);
}
@ -1281,6 +1298,7 @@ usbd_reload_device_desc(usbd_device_handle dev)
void
usbd_remove_device(usbd_device_handle dev, struct usbd_port *up)
{
DPRINTF(("usbd_remove_device: %p\n", dev));
if (dev->default_pipe != NULL)

View File

@ -1,4 +1,4 @@
/* $NetBSD: usbdi.c,v 1.137 2012/03/11 01:06:07 mrg Exp $ */
/* $NetBSD: usbdi.c,v 1.138 2012/06/10 06:15:55 mrg Exp $ */
/*
* Copyright (c) 1998, 2012 The NetBSD Foundation, Inc.
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.137 2012/03/11 01:06:07 mrg Exp $");
__KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.138 2012/06/10 06:15:55 mrg Exp $");
#include "opt_compat_netbsd.h"
#include "opt_usb.h"
@ -228,6 +228,8 @@ usbd_open_pipe_intr(usbd_interface_handle iface, u_int8_t address,
usbd_status
usbd_close_pipe(usbd_pipe_handle pipe)
{
int s;
#ifdef DIAGNOSTIC
if (pipe == NULL) {
printf("usbd_close_pipe: pipe==NULL\n");
@ -235,13 +237,19 @@ usbd_close_pipe(usbd_pipe_handle pipe)
}
#endif
if (--pipe->refcnt != 0)
usbd_lock_pipe(pipe);
if (--pipe->refcnt != 0) {
usbd_unlock_pipe(pipe);
return (USBD_NORMAL_COMPLETION);
if (! SIMPLEQ_EMPTY(&pipe->queue))
}
if (! SIMPLEQ_EMPTY(&pipe->queue)) {
usbd_unlock_pipe(pipe);
return (USBD_PENDING_REQUESTS);
}
LIST_REMOVE(pipe, next);
pipe->endpoint->refcnt--;
pipe->methods->close(pipe);
usbd_unlock_pipe(pipe);
if (pipe->intrxfer != NULL)
usbd_free_xfer(pipe->intrxfer);
free(pipe, M_USB);
@ -260,8 +268,6 @@ usbd_transfer(usbd_xfer_handle xfer)
DPRINTFN(5,("usbd_transfer: xfer=%p, flags=%#x, pipe=%p, running=%d\n",
xfer, xfer->flags, pipe, pipe->running));
KASSERT(KERNEL_LOCKED_P());
#ifdef USB_DEBUG
if (usbdebug > 5)
usbd_dump_queue(pipe);
@ -311,13 +317,24 @@ usbd_transfer(usbd_xfer_handle xfer)
/* Sync transfer, wait for completion. */
if (err != USBD_IN_PROGRESS)
return (err);
s = splusb();
usbd_lock_pipe(pipe);
if (!xfer->done) {
if (pipe->device->bus->use_polling)
panic("usbd_transfer: not done");
tsleep(xfer, PRIBIO, "usbsyn", 0);
if ((flags & USBD_SYNCHRONOUS_SIG) != 0) {
if (pipe->device->bus->lock)
cv_wait_sig(&xfer->cv, pipe->device->bus->lock);
else
tsleep(xfer, PZERO|PCATCH, "usbsyn", 0);
} else {
if (pipe->device->bus->lock)
cv_wait(&xfer->cv, pipe->device->bus->lock);
else
tsleep(xfer, PRIBIO, "usbsyn", 0);
}
}
splx(s);
usbd_unlock_pipe(pipe);
return (xfer->status);
}
@ -329,6 +346,14 @@ usbd_sync_transfer(usbd_xfer_handle xfer)
return (usbd_transfer(xfer));
}
/* Like usbd_transfer(), but waits for completion and listens for signals. */
usbd_status
usbd_sync_transfer_sig(usbd_xfer_handle xfer)
{
xfer->flags |= USBD_SYNCHRONOUS | USBD_SYNCHRONOUS_SIG;
return (usbd_transfer(xfer));
}
void *
usbd_alloc_buffer(usbd_xfer_handle xfer, u_int32_t size)
{
@ -376,7 +401,10 @@ usbd_alloc_xfer(usbd_device_handle dev)
if (xfer == NULL)
return (NULL);
xfer->device = dev;
callout_init(&xfer->timeout_handle, 0);
callout_init(&xfer->timeout_handle,
dev->bus->methods->get_lock ? CALLOUT_MPSAFE : 0);
cv_init(&xfer->cv, "usbxfer");
cv_init(&xfer->hccv, "usbhcxfer");
DPRINTFN(5,("usbd_alloc_xfer() = %p\n", xfer));
return (xfer);
}
@ -393,6 +421,8 @@ usbd_free_xfer(usbd_xfer_handle xfer)
printf("usbd_free_xfer: timout_handle pending");
}
#endif
cv_destroy(&xfer->cv);
cv_destroy(&xfer->hccv);
xfer->device->bus->methods->freex(xfer->device->bus, xfer);
return (USBD_NORMAL_COMPLETION);
}
@ -530,9 +560,9 @@ usbd_abort_pipe(usbd_pipe_handle pipe)
return (USBD_NORMAL_COMPLETION);
}
#endif
s = splusb();
usbd_lock_pipe(pipe);
err = usbd_ar_pipe(pipe);
splx(s);
usbd_unlock_pipe(pipe);
if (pipe->intrxfer != intrxfer)
usbd_free_xfer(intrxfer);
return (err);
@ -720,6 +750,8 @@ usbd_ar_pipe(usbd_pipe_handle pipe)
{
usbd_xfer_handle xfer;
KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock));
DPRINTFN(2,("usbd_ar_pipe: pipe=%p\n", pipe));
#ifdef USB_DEBUG
if (usbdebug > 5)
@ -738,7 +770,7 @@ usbd_ar_pipe(usbd_pipe_handle pipe)
return (USBD_NORMAL_COMPLETION);
}
/* Called at splusb() */
/* Called with USB lock held. */
void
usb_transfer_complete(usbd_xfer_handle xfer)
{
@ -752,7 +784,7 @@ usb_transfer_complete(usbd_xfer_handle xfer)
DPRINTFN(5, ("usb_transfer_complete: pipe=%p xfer=%p status=%d "
"actlen=%d\n", pipe, xfer, xfer->status, xfer->actlen));
KASSERT(KERNEL_LOCKED_P());
KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock));
#ifdef DIAGNOSTIC
if (xfer->busy_free != XFER_ONQU) {
@ -763,7 +795,7 @@ usb_transfer_complete(usbd_xfer_handle xfer)
#ifdef DIAGNOSTIC
if (pipe == NULL) {
printf("usbd_transfer_cb: pipe==0, xfer=%p\n", xfer);
printf("usb_transfer_complete: pipe==0, xfer=%p\n", xfer);
return;
}
#endif
@ -814,23 +846,37 @@ usb_transfer_complete(usbd_xfer_handle xfer)
xfer->done = 1;
if (!xfer->status && xfer->actlen < xfer->length &&
!(xfer->flags & USBD_SHORT_XFER_OK)) {
DPRINTFN(-1,("usbd_transfer_cb: short transfer %d<%d\n",
DPRINTFN(-1,("usb_transfer_complete: short transfer %d<%d\n",
xfer->actlen, xfer->length));
xfer->status = USBD_SHORT_XFER;
}
if (repeat) {
if (xfer->callback)
if (xfer->callback) {
if (pipe->device->bus->lock)
mutex_exit(pipe->device->bus->lock);
xfer->callback(xfer, xfer->priv, xfer->status);
if (pipe->device->bus->lock)
mutex_enter(pipe->device->bus->lock);
}
pipe->methods->done(xfer);
} else {
pipe->methods->done(xfer);
if (xfer->callback)
if (xfer->callback) {
if (pipe->device->bus->lock)
mutex_exit(pipe->device->bus->lock);
xfer->callback(xfer, xfer->priv, xfer->status);
if (pipe->device->bus->lock)
mutex_enter(pipe->device->bus->lock);
}
}
if (sync && !polling)
wakeup(xfer);
if (sync && !polling) {
if (pipe->device->bus->lock)
cv_broadcast(&xfer->cv);
else
wakeup(xfer); /* XXXSMP ok */
}
if (!repeat) {
/* XXX should we stop the queue on all errors? */
@ -841,17 +887,17 @@ usb_transfer_complete(usbd_xfer_handle xfer)
}
}
/* Called with USB lock held. */
usbd_status
usb_insert_transfer(usbd_xfer_handle xfer)
{
usbd_pipe_handle pipe = xfer->pipe;
usbd_status err;
int s;
DPRINTFN(5,("usb_insert_transfer: pipe=%p running=%d timeout=%d\n",
pipe, pipe->running, xfer->timeout));
KASSERT(KERNEL_LOCKED_P());
KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock));
#ifdef DIAGNOSTIC
if (xfer->busy_free != XFER_BUSY) {
@ -861,7 +907,6 @@ usb_insert_transfer(usbd_xfer_handle xfer)
}
xfer->busy_free = XFER_ONQU;
#endif
s = splusb();
SIMPLEQ_INSERT_TAIL(&pipe->queue, xfer, next);
if (pipe->running)
err = USBD_IN_PROGRESS;
@ -869,11 +914,10 @@ usb_insert_transfer(usbd_xfer_handle xfer)
pipe->running = 1;
err = USBD_NORMAL_COMPLETION;
}
splx(s);
return (err);
}
/* Called at splusb() */
/* Called with USB lock held. */
void
usbd_start_next(usbd_pipe_handle pipe)
{
@ -891,19 +935,27 @@ usbd_start_next(usbd_pipe_handle pipe)
}
#endif
KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock));
/* Get next request in queue. */
xfer = SIMPLEQ_FIRST(&pipe->queue);
DPRINTFN(5, ("usbd_start_next: pipe=%p, xfer=%p\n", pipe, xfer));
if (xfer == NULL) {
pipe->running = 0;
} else {
if (pipe->device->bus->lock)
mutex_exit(pipe->device->bus->lock);
err = pipe->methods->start(xfer);
if (pipe->device->bus->lock)
mutex_enter(pipe->device->bus->lock);
if (err != USBD_IN_PROGRESS) {
printf("usbd_start_next: error=%d\n", err);
pipe->running = 0;
/* XXX do what? */
}
}
KASSERT(pipe->device->bus->lock == NULL || mutex_owned(pipe->device->bus->lock));
}
usbd_status
@ -1068,6 +1120,9 @@ usbd_dopoll(usbd_interface_handle iface)
iface->device->bus->methods->do_poll(iface->device->bus);
}
/*
* XXX use this more??? use_polling it touched manually all over
*/
void
usbd_set_polling(usbd_device_handle dev, int on)
{
@ -1077,7 +1132,12 @@ usbd_set_polling(usbd_device_handle dev, int on)
dev->bus->use_polling--;
/* Kick the host controller when switching modes */
dev->bus->methods->soft_intr(dev->bus);
if (dev->bus->lock)
mutex_enter(dev->bus->lock);
(*dev->bus->methods->soft_intr)(dev->bus);
if (dev->bus->lock)
mutex_exit(dev->bus->lock);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: usbdi.h,v 1.82 2012/04/24 17:16:42 jakllsch Exp $ */
/* $NetBSD: usbdi.h,v 1.83 2012/06/10 06:15:55 mrg Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdi.h,v 1.18 1999/11/17 22:33:49 n_hibma Exp $ */
/*
@ -80,6 +80,8 @@ typedef void (*usbd_callback)(usbd_xfer_handle, usbd_private_handle,
#define USBD_SYNCHRONOUS 0x02 /* wait for completion */
/* in usb.h #define USBD_SHORT_XFER_OK 0x04*/ /* allow short reads */
#define USBD_FORCE_SHORT_XFER 0x08 /* force last short packet on write */
#define USBD_SYNCHRONOUS_SIG 0x10 /* if waiting for completion,
* also take signals */
#define USBD_NO_TIMEOUT 0
#define USBD_DEFAULT_TIMEOUT 5000 /* ms = 5 s */
@ -125,6 +127,7 @@ void *usbd_alloc_buffer(usbd_xfer_handle, u_int32_t);
void usbd_free_buffer(usbd_xfer_handle);
void *usbd_get_buffer(usbd_xfer_handle);
usbd_status usbd_sync_transfer(usbd_xfer_handle);
usbd_status usbd_sync_transfer_sig(usbd_xfer_handle);
usbd_status usbd_open_pipe_intr(usbd_interface_handle, u_int8_t,
u_int8_t, usbd_pipe_handle *,
usbd_private_handle, void *,

View File

@ -1,12 +1,12 @@
/* $NetBSD: usbdi_util.c,v 1.56 2012/03/06 03:35:30 mrg Exp $ */
/* $NetBSD: usbdi_util.c,v 1.57 2012/06/10 06:15:55 mrg Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* Copyright (c) 1998, 2012 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson (lennart@augustsson.net) at
* Carlstedt Research & Technology.
* Carlstedt Research & Technology and Matthew R. Green (mrg@eterna.com.au).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: usbdi_util.c,v 1.56 2012/03/06 03:35:30 mrg Exp $");
__KERNEL_RCSID(0, "$NetBSD: usbdi_util.c,v 1.57 2012/06/10 06:15:55 mrg Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -39,11 +39,13 @@ __KERNEL_RCSID(0, "$NetBSD: usbdi_util.c,v 1.56 2012/03/06 03:35:30 mrg Exp $");
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/device.h>
#include <sys/bus.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbhid.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usbdi_util.h>
#ifdef USB_DEBUG
@ -419,7 +421,11 @@ Static void
usbd_bulk_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
usbd_status status)
{
wakeup(xfer);
if (xfer->pipe->device->bus->lock)
cv_broadcast(&xfer->cv);
else
wakeup(xfer); /* XXXSMP ok */
}
usbd_status
@ -428,25 +434,13 @@ usbd_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
u_int32_t *size, const char *lbl)
{
usbd_status err;
int s, error;
usbd_setup_xfer(xfer, pipe, 0, buf, *size,
flags, timeout, usbd_bulk_transfer_cb);
DPRINTFN(1, ("usbd_bulk_transfer: start transfer %d bytes\n", *size));
s = splusb(); /* don't want callback until tsleep() */
err = usbd_transfer(xfer);
if (err != USBD_IN_PROGRESS) {
splx(s);
return (err);
}
error = tsleep(xfer, PZERO | PCATCH, lbl, 0);
splx(s);
if (error) {
DPRINTF(("usbd_bulk_transfer: tsleep=%d\n", error));
usbd_abort_pipe(pipe);
return (USBD_INTERRUPTED);
}
usbd_get_xfer_status(xfer, NULL, NULL, size, &err);
err = usbd_sync_transfer_sig(xfer);
usbd_get_xfer_status(xfer, NULL, NULL, size, NULL);
DPRINTFN(1,("usbd_bulk_transfer: transferred %d\n", *size));
if (err) {
DPRINTF(("usbd_bulk_transfer: error=%d\n", err));
@ -461,7 +455,11 @@ Static void
usbd_intr_transfer_cb(usbd_xfer_handle xfer, usbd_private_handle priv,
usbd_status status)
{
wakeup(xfer);
if (xfer->pipe->device->bus->lock)
cv_broadcast(&xfer->cv);
else
wakeup(xfer); /* XXXSMP ok */
}
usbd_status
@ -470,25 +468,12 @@ usbd_intr_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
u_int32_t *size, const char *lbl)
{
usbd_status err;
int s, error;
usbd_setup_xfer(xfer, pipe, 0, buf, *size,
flags, timeout, usbd_intr_transfer_cb);
DPRINTFN(1, ("usbd_intr_transfer: start transfer %d bytes\n", *size));
s = splusb(); /* don't want callback until tsleep() */
err = usbd_transfer(xfer);
if (err != USBD_IN_PROGRESS) {
splx(s);
return (err);
}
error = tsleep(xfer, PZERO | PCATCH, lbl, 0);
splx(s);
if (error) {
DPRINTF(("usbd_intr_transfer: tsleep=%d\n", error));
usbd_abort_pipe(pipe);
return (USBD_INTERRUPTED);
}
usbd_get_xfer_status(xfer, NULL, NULL, size, &err);
err = usbd_sync_transfer_sig(xfer);
usbd_get_xfer_status(xfer, NULL, NULL, size, NULL);
DPRINTFN(1,("usbd_intr_transfer: transferred %d\n", *size));
if (err) {
DPRINTF(("usbd_intr_transfer: error=%d\n", err));
@ -497,11 +482,28 @@ usbd_intr_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
return (err);
}
void
usb_detach_wait(device_t dv, kcondvar_t *cv, kmutex_t *lock)
{
DPRINTF(("usb_detach_wait: waiting for %s\n", device_xname(dv)));
if (cv_timedwait(cv, lock, hz * 60)) // dv, PZERO, "usbdet", hz * 60
printf("usb_detach_wait: %s didn't detach\n",
device_xname(dv));
DPRINTF(("usb_detach_waitold: %s done\n", device_xname(dv)));
}
void
usb_detach_broadcast(device_t dv, kcondvar_t *cv)
{
DPRINTF(("usb_detach_broadcast: for %s\n", device_xname(dv)));
cv_broadcast(cv);
}
void
usb_detach_waitold(device_t dv)
{
DPRINTF(("usb_detach_waitold: waiting for %s\n", device_xname(dv)));
if (tsleep(dv, PZERO, "usbdet", hz * 60))
if (tsleep(dv, PZERO, "usbdet", hz * 60)) /* XXXSMP ok */
printf("usb_detach_waitold: %s didn't detach\n",
device_xname(dv));
DPRINTF(("usb_detach_waitold: %s done\n", device_xname(dv)));
@ -511,7 +513,7 @@ void
usb_detach_wakeupold(device_t dv)
{
DPRINTF(("usb_detach_wakeupold: for %s\n", device_xname(dv)));
wakeup(dv);
wakeup(dv); /* XXXSMP ok */
}
const usb_cdc_descriptor_t *

View File

@ -1,4 +1,4 @@
/* $NetBSD: usbdi_util.h,v 1.43 2012/03/11 01:06:07 mrg Exp $ */
/* $NetBSD: usbdi_util.h,v 1.44 2012/06/10 06:15:55 mrg Exp $ */
/*
* Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
@ -85,6 +85,12 @@ usbd_status usbd_intr_transfer(usbd_xfer_handle, usbd_pipe_handle,
void usb_detach_waitold(device_t);
void usb_detach_wakeupold(device_t);
/*
* MPSAFE versions - mutex must be at IPL_USB.
*/
void usb_detach_wait(device_t dv, kcondvar_t *, kmutex_t *);
void usb_detach_broadcast(device_t, kcondvar_t *);
typedef struct {
uByte bLength;

View File

@ -1,13 +1,12 @@
/* $NetBSD: usbdivar.h,v 1.96 2012/03/11 01:06:07 mrg Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdivar.h,v 1.11 1999/11/17 22:33:51 n_hibma Exp $ */
/* $NetBSD: usbdivar.h,v 1.97 2012/06/10 06:15:55 mrg Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* Copyright (c) 1998, 2012 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson (lennart@augustsson.net) at
* Carlstedt Research & Technology.
* Carlstedt Research & Technology and Matthew R. Green (mrg@eterna.com.au).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -31,7 +30,47 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Discussion about locking in the USB code:
*
* The host controller presents one lock at IPL_USB.
*
* List of hardware interface methods, and which locks are held when each
* is called by this module:
*
* BUS METHOD LOCK NOTES
* ----------------------- ------- -------------------------
* open_pipe - might want to take lock?
* soft_intr x
* do_poll - might want to take lock?
* allocm -
* freem -
* allocx -
* freex -
* get_lock - Called at attach time
*
* PIPE METHOD LOCK NOTES
* ----------------------- ------- -------------------------
* transfer -
* start - might want to take lock?
* abort x
* close x
* cleartoggle -
* done x
*
* The above semantics are likely to change. Little performance
* evaluation has been done on this code and the locking strategy.
*
* USB functions known to expect the lock taken include (this list is
* probably not exhaustive):
* usb_transfer_complete()
* usb_insert_transfer()
* usb_start_next()
*
*/
#include <sys/callout.h>
#include <sys/mutex.h>
#include <sys/bus.h>
/* From usb_mem.h */
@ -59,6 +98,7 @@ struct usbd_bus_methods {
void (*freem)(struct usbd_bus *, usb_dma_t *);
struct usbd_xfer * (*allocx)(struct usbd_bus *);
void (*freex)(struct usbd_bus *, struct usbd_xfer *);
void (*get_lock)(struct usbd_bus *, kmutex_t **);
};
struct usbd_pipe_methods {
@ -105,8 +145,10 @@ struct usbd_bus {
const struct usbd_bus_methods *methods;
u_int32_t pipe_size; /* size of a pipe struct */
/* Filled by usb driver */
struct usbd_device *root_hub;
kmutex_t *lock;
struct usbd_device *root_hub;
usbd_device_handle devices[USB_MAX_DEVICES];
kcondvar_t needs_explore_cv;
char needs_explore;/* a hub a signalled a change */
char use_polling;
device_t usbctl;
@ -183,6 +225,7 @@ struct usbd_xfer {
struct usbd_pipe *pipe;
void *priv;
void *buffer;
kcondvar_t cv;
u_int32_t length;
u_int32_t actlen;
u_int16_t flags;
@ -217,6 +260,7 @@ struct usbd_xfer {
u_int8_t hcflags; /* private use by the HC driver */
#define UXFER_ABORTING 0x01 /* xfer is aborting. */
#define UXFER_ABORTWAIT 0x02 /* abort completion is being awaited. */
kcondvar_t hccv; /* private use by the HC driver */
struct callout timeout_handle;
};
@ -234,7 +278,9 @@ void usbd_dump_pipe(usbd_pipe_handle pipe);
/* Routines from usb_subr.c */
int usbctlprint(void *, const char *);
void usb_delay_ms_locked(usbd_bus_handle, u_int, kmutex_t *);
void usb_delay_ms(usbd_bus_handle, u_int);
void usbd_delay_ms_locked(usbd_device_handle, u_int, kmutex_t *);
void usbd_delay_ms(usbd_device_handle, u_int);
usbd_status usbd_reset_port(usbd_device_handle, int, usb_port_status_t *);
usbd_status usbd_setup_pipe(usbd_device_handle dev,
@ -259,3 +305,25 @@ int usb_disconnect_port(struct usbd_port *, device_t, int);
void usb_needs_explore(usbd_device_handle);
void usb_needs_reattach(usbd_device_handle);
void usb_schedsoftintr(struct usbd_bus *);
/*
* These macros help while not all host controllers are ported to the MP code.
*/
#define usbd_mutex_enter(m) do { \
if (m) { \
s = -1; \
mutex_enter(m); \
} else \
s = splusb(); \
} while (0)
#define usbd_mutex_exit(m) do { \
if (m) { \
s = -1; \
mutex_exit(m); \
} else \
splx(s); \
} while (0)
#define usbd_lock_pipe(p) usbd_mutex_enter((p)->device->bus->lock)
#define usbd_unlock_pipe(p) usbd_mutex_exit((p)->device->bus->lock)

View File

@ -1,4 +1,4 @@
/* $NetBSD: utoppy.c,v 1.19 2012/03/11 01:06:07 mrg Exp $ */
/* $NetBSD: utoppy.c,v 1.20 2012/06/10 06:15:55 mrg Exp $ */
/*-
* Copyright (c) 2006 The NetBSD Foundation, Inc.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: utoppy.c,v 1.19 2012/03/11 01:06:07 mrg Exp $");
__KERNEL_RCSID(0, "$NetBSD: utoppy.c,v 1.20 2012/06/10 06:15:55 mrg Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -521,7 +521,10 @@ utoppy_bulk_transfer_cb(usbd_xfer_handle xfer,
usbd_status status)
{
wakeup(xfer);
if (xfer->pipe->device->bus->lock)
cv_broadcast(&xfer->cv);
else
wakeup(xfer);
}
static usbd_status
@ -534,14 +537,17 @@ utoppy_bulk_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe,
usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout,
utoppy_bulk_transfer_cb);
s = splusb();
usbd_lock_pipe(pipe); /* don't want callback until tsleep() */
err = usbd_transfer(xfer);
if (err != USBD_IN_PROGRESS) {
splx(s);
usbd_unlock_pipe(pipe);
return (err);
}
error = tsleep((void *)xfer, PZERO, lbl, 0);
splx(s);
if (pipe->device->bus->lock)
error = cv_wait_sig(&xfer->cv, pipe->device->bus->lock);
else
error = tsleep((void *)xfer, PZERO, lbl, 0);
usbd_unlock_pipe(pipe);
if (error) {
usbd_abort_pipe(pipe);
return (USBD_INTERRUPTED);

View File

@ -1,4 +1,4 @@
/* $NetBSD: ugenhc.c,v 1.9 2010/03/22 12:05:45 pooka Exp $ */
/* $NetBSD: ugenhc.c,v 1.10 2012/06/10 06:15:55 mrg Exp $ */
/*
* Copyright (c) 2009, 2010 Antti Kantee. All Rights Reserved.
@ -61,7 +61,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ugenhc.c,v 1.9 2010/03/22 12:05:45 pooka Exp $");
__KERNEL_RCSID(0, "$NetBSD: ugenhc.c,v 1.10 2012/06/10 06:15:55 mrg Exp $");
#include <sys/param.h>
#include <sys/bus.h>
@ -312,6 +312,7 @@ rumpusb_root_ctrl_start(usbd_xfer_handle xfer)
ret:
xfer->status = err;
/* XXX locking */
usb_transfer_complete(xfer);
return (USBD_IN_PROGRESS);
}
@ -842,6 +843,7 @@ rumpusb_device_bulk_transfer(usbd_xfer_handle xfer)
SIMPLEQ_FIRST(&xfer->pipe->queue));
} else {
/* biglocked */
/* XXX locking */
err = usb_insert_transfer(xfer);
if (err)
return err;