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:
parent
e848a9e55e
commit
dc74fbbf85
|
@ -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 = {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 *,
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue