summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorjdolecek <jdolecek@NetBSD.org>2002-02-12 19:52:43 +0000
committerjdolecek <jdolecek@NetBSD.org>2002-02-12 19:52:43 +0000
commita2803fa7984c11ce1e4a394a4fa95d87ab7ed346 (patch)
tree11a15d566fbc1deb9a1e90fb12081071454b88df /sys/dev
parent6dc9bb6c370695c20c060fbb17a9562597e1d0a4 (diff)
split the channel stuff into record and play parts, so that this driver is
full duplex, independent
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/uaudio.c169
1 files changed, 103 insertions, 66 deletions
diff --git a/sys/dev/usb/uaudio.c b/sys/dev/usb/uaudio.c
index bf90543ee77..2ed294e2e88 100644
--- a/sys/dev/usb/uaudio.c
+++ b/sys/dev/usb/uaudio.c
@@ -1,4 +1,4 @@
-/* $NetBSD: uaudio.c,v 1.46 2002/02/11 07:10:36 kent Exp $ */
+/* $NetBSD: uaudio.c,v 1.47 2002/02/12 19:52:43 jdolecek Exp $ */
/*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -44,7 +44,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uaudio.c,v 1.46 2002/02/11 07:10:36 kent Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uaudio.c,v 1.47 2002/02/12 19:52:43 jdolecek Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -114,14 +114,13 @@ struct as_info {
usb_interface_descriptor_t *idesc;
usb_endpoint_descriptor_audio_t *edesc;
struct usb_audio_streaming_type1_descriptor *asf1desc;
+ int sc_busy; /* currently used */
};
struct chan {
- int terminal; /* terminal id */
void (*intr)(void *); /* dma completion intr handler */
void *arg; /* arg for intr() */
usbd_pipe_handle pipe;
- int dir; /* direction */
u_int sample_size;
u_int sample_rate;
@@ -135,7 +134,7 @@ struct chan {
int blksize; /* chunk size to report up */
int transferred; /* transferred bytes not reported up */
- char nofrac; /* don't do sample rate adjustment */
+ int altidx; /* currently used altidx */
int curchanbuf;
struct chanbuf {
@@ -156,9 +155,8 @@ struct uaudio_softc {
int sc_ac_iface; /* Audio Control interface */
usbd_interface_handle sc_ac_ifaceh;
- struct chan sc_chan;
-
- int sc_curaltidx;
+ struct chan sc_playchan; /* play channel */
+ struct chan sc_recchan; /* record channel */
int sc_nullalt;
@@ -166,7 +164,6 @@ struct uaudio_softc {
struct as_info *sc_alts;
int sc_nalts;
- int sc_props;
int sc_altflags;
#define HAS_8 0x01
@@ -174,6 +171,9 @@ struct uaudio_softc {
#define HAS_8U 0x04
#define HAS_ALAW 0x08
#define HAS_MULAW 0x10
+#define UA_NOFRAC 0x20 /* don't do sample rate adjustment */
+
+ int sc_mode; /* play/record capability */
struct mixerctl *sc_ctls;
int sc_nctls;
@@ -395,10 +395,10 @@ USB_ATTACH(uaudio)
printf("%s: audio rev %d.%02x\n", USBDEVNAME(sc->sc_dev),
sc->sc_audio_rev >> 8, sc->sc_audio_rev & 0xff);
- sc->sc_chan.sc = sc;
+ sc->sc_playchan.sc = sc->sc_recchan.sc = sc;
if (usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_AU_NO_FRAC)
- sc->sc_chan.nofrac = 1;
+ sc->sc_altflags |= UA_NOFRAC;
#ifndef UAUDIO_DEBUG
if (bootverbose)
@@ -1026,7 +1026,7 @@ void
uaudio_add_alt(struct uaudio_softc *sc, struct as_info *ai)
{
size_t len = sizeof(*ai) * (sc->sc_nalts + 1);
- struct as_info *nai = sc->sc_nalts == 0 ?
+ struct as_info *nai = (sc->sc_nalts == 0) ?
malloc(len, M_USBDEV, M_NOWAIT) :
realloc(sc->sc_alts, len, M_USBDEV, M_NOWAIT);
@@ -1153,8 +1153,8 @@ uaudio_process_as(struct uaudio_softc *sc, char *buf, int *offsp,
ai.edesc = ed;
ai.asf1desc = asf1d;
uaudio_add_alt(sc, &ai);
- sc->sc_chan.terminal = asid->bTerminalLink; /* XXX */
- sc->sc_chan.dir |= dir == UE_DIR_OUT ? AUMODE_PLAY : AUMODE_RECORD;
+ sc->sc_mode |= (dir == UE_DIR_OUT) ? AUMODE_PLAY : AUMODE_RECORD;
+
return (USBD_NORMAL_COMPLETION);
}
#undef offs
@@ -1176,9 +1176,6 @@ uaudio_identify_as(struct uaudio_softc *sc, usb_config_descriptor_t *cdesc)
if (id == NULL)
return (USBD_INVAL);
- sc->sc_chan.terminal = -1;
- sc->sc_chan.dir = 0;
-
/* Loop through all the alternate settings. */
while (offs <= size) {
DPRINTFN(2, ("uaudio_identify: interface %d\n",
@@ -1207,15 +1204,13 @@ uaudio_identify_as(struct uaudio_softc *sc, usb_config_descriptor_t *cdesc)
if (offs > size)
return (USBD_INVAL);
DPRINTF(("uaudio_identify_as: %d alts available\n", sc->sc_nalts));
- if (sc->sc_chan.terminal < 0) {
- printf("%s: no useable endpoint found\n",
+
+ if ((sc->sc_mode & (AUMODE_PLAY | AUMODE_RECORD)) == 0) {
+ printf("%s: no usable endpoint found\n",
USBDEVNAME(sc->sc_dev));
return (USBD_INVAL);
}
-#if 0
- if (sc->sc_chan.dir == (AUMODE_PLAY | AUMODE_RECORD))
- sc->sc_props |= AUDIO_PROP_FULLDUPLEX;
-#endif
+
return (USBD_NORMAL_COMPLETION);
}
@@ -1395,15 +1390,20 @@ uaudio_open(void *addr, int flags)
if (sc->sc_dying)
return (EIO);
- if (sc->sc_chan.terminal < 0)
+ if (sc->sc_mode == 0)
return (ENXIO);
- if ((flags & FREAD) && !(sc->sc_chan.dir & AUMODE_RECORD))
- return (EACCES);
- if ((flags & FWRITE) && !(sc->sc_chan.dir & AUMODE_PLAY))
+ if (flags & FREAD) {
+ if ((sc->sc_mode & AUMODE_RECORD) == 0)
return (EACCES);
+ sc->sc_recchan.intr = NULL;
+ }
- sc->sc_chan.intr = 0;
+ if (flags & FWRITE) {
+ if ((sc->sc_mode & AUMODE_PLAY) == 0)
+ return (EACCES);
+ sc->sc_playchan.intr = NULL;
+ }
return (0);
}
@@ -1420,7 +1420,7 @@ uaudio_close(void *addr)
uaudio_halt_in_dma(sc);
uaudio_halt_out_dma(sc);
- sc->sc_chan.intr = 0;
+ sc->sc_playchan.intr = sc->sc_recchan.intr = NULL;
}
int
@@ -1439,10 +1439,10 @@ uaudio_halt_out_dma(void *addr)
struct uaudio_softc *sc = addr;
DPRINTF(("uaudio_halt_out_dma: enter\n"));
- if (sc->sc_chan.pipe != NULL) {
- uaudio_chan_close(sc, &sc->sc_chan);
- sc->sc_chan.pipe = 0;
- uaudio_chan_free_buffers(sc, &sc->sc_chan);
+ if (sc->sc_playchan.pipe != NULL) {
+ uaudio_chan_close(sc, &sc->sc_playchan);
+ sc->sc_playchan.pipe = NULL;
+ uaudio_chan_free_buffers(sc, &sc->sc_playchan);
}
return (0);
}
@@ -1453,10 +1453,10 @@ uaudio_halt_in_dma(void *addr)
struct uaudio_softc *sc = addr;
DPRINTF(("uaudio_halt_in_dma: enter\n"));
- if (sc->sc_chan.pipe != NULL) {
- uaudio_chan_close(sc, &sc->sc_chan);
- sc->sc_chan.pipe = 0;
- uaudio_chan_free_buffers(sc, &sc->sc_chan);
+ if (sc->sc_recchan.pipe != NULL) {
+ uaudio_chan_close(sc, &sc->sc_recchan);
+ sc->sc_recchan.pipe = NULL;
+ uaudio_chan_free_buffers(sc, &sc->sc_recchan);
}
return (0);
}
@@ -1483,7 +1483,13 @@ uaudio_round_blocksize(void *addr, int blk)
struct uaudio_softc *sc = addr;
int bpf;
- bpf = sc->sc_chan.bytes_per_frame + sc->sc_chan.sample_size;
+ if (sc->sc_playchan.bytes_per_frame > sc->sc_recchan.bytes_per_frame) {
+ bpf = sc->sc_playchan.bytes_per_frame
+ + sc->sc_playchan.sample_size;
+ } else {
+ bpf = sc->sc_recchan.bytes_per_frame
+ + sc->sc_recchan.sample_size;
+ }
/* XXX */
bpf *= UAUDIO_NFRAMES * UAUDIO_NCHANBUFS;
@@ -1506,9 +1512,8 @@ uaudio_round_blocksize(void *addr, int blk)
int
uaudio_get_props(void *addr)
{
- struct uaudio_softc *sc = addr;
+ return (AUDIO_PROP_FULLDUPLEX | AUDIO_PROP_INDEPENDENT);
- return (sc->sc_props);
}
int
@@ -1531,7 +1536,7 @@ uaudio_get(struct uaudio_softc *sc, int which, int type, int wValue,
DPRINTFN(2,("uaudio_get: type=0x%02x req=0x%02x wValue=0x%04x "
"wIndex=0x%04x len=%d\n",
type, which, wValue, wIndex, len));
- err = usbd_do_request(sc->sc_udev, &req, &data);
+ err = usbd_do_request(sc->sc_udev, &req, data);
if (err) {
DPRINTF(("uaudio_get: err=%s\n", usbd_errstr(err)));
return (-1);
@@ -1581,7 +1586,7 @@ uaudio_set(struct uaudio_softc *sc, int which, int type, int wValue,
DPRINTFN(2,("uaudio_set: type=0x%02x req=0x%02x wValue=0x%04x "
"wIndex=0x%04x len=%d, val=%d\n",
type, which, wValue, wIndex, len, val & 0xffff));
- err = usbd_do_request(sc->sc_udev, &req, &data);
+ err = usbd_do_request(sc->sc_udev, &req, data);
#ifdef UAUDIO_DEBUG
if (err)
DPRINTF(("uaudio_set: err=%d\n", err));
@@ -1606,7 +1611,7 @@ uaudio_value2bsd(struct mixerctl *mc, int val)
DPRINTFN(5, ("uaudio_value2bsd: type=%03x val=%d min=%d max=%d ",
mc->type, val, mc->minval, mc->maxval));
if (mc->type == MIX_ON_OFF)
- val = val != 0;
+ val = (val != 0);
else
val = ((uaudio_signext(mc->type, val) - mc->minval) * 256
+ mc->mul/2) / mc->mul;
@@ -1620,7 +1625,7 @@ uaudio_bsd2value(struct mixerctl *mc, int val)
DPRINTFN(5,("uaudio_bsd2value: type=%03x val=%d min=%d max=%d ",
mc->type, val, mc->minval, mc->maxval));
if (mc->type == MIX_ON_OFF)
- val = val != 0;
+ val = (val != 0);
else
val = (val + mc->delta/2) * mc->mul / 256 + mc->minval;
DPRINTFN(5, ("val'=%d\n", val));
@@ -1732,7 +1737,7 @@ uaudio_trigger_input(void *addr, void *start, void *end, int blksize,
struct audio_params *param)
{
struct uaudio_softc *sc = addr;
- struct chan *ch = &sc->sc_chan;
+ struct chan *ch = &sc->sc_recchan;
usbd_status err;
int i, s;
@@ -1757,8 +1762,8 @@ uaudio_trigger_input(void *addr, void *start, void *end, int blksize,
return (EIO);
}
- sc->sc_chan.intr = intr;
- sc->sc_chan.arg = arg;
+ ch->intr = intr;
+ ch->arg = arg;
s = splusb();
for (i = 0; i < UAUDIO_NCHANBUFS-1; i++) /* XXX -1 shouldn't be needed */
@@ -1774,7 +1779,7 @@ uaudio_trigger_output(void *addr, void *start, void *end, int blksize,
struct audio_params *param)
{
struct uaudio_softc *sc = addr;
- struct chan *ch = &sc->sc_chan;
+ struct chan *ch = &sc->sc_playchan;
usbd_status err;
int i, s;
@@ -1799,8 +1804,8 @@ uaudio_trigger_output(void *addr, void *start, void *end, int blksize,
return (EIO);
}
- sc->sc_chan.intr = intr;
- sc->sc_chan.arg = arg;
+ ch->intr = intr;
+ ch->arg = arg;
s = splusb();
for (i = 0; i < UAUDIO_NCHANBUFS-1; i++) /* XXX */
@@ -1814,11 +1819,11 @@ uaudio_trigger_output(void *addr, void *start, void *end, int blksize,
usbd_status
uaudio_chan_open(struct uaudio_softc *sc, struct chan *ch)
{
- struct as_info *as = &sc->sc_alts[sc->sc_curaltidx];
+ struct as_info *as = &sc->sc_alts[ch->altidx];
int endpt = as->edesc->bEndpointAddress;
usbd_status err;
- DPRINTF(("uaudio_open_chan: endpt=0x%02x, speed=%d, alt=%d\n",
+ DPRINTF(("uaudio_chan_open: endpt=0x%02x, speed=%d, alt=%d\n",
endpt, ch->sample_rate, as->alt));
/* Set alternate interface corresponding to the mode. */
@@ -1836,7 +1841,7 @@ uaudio_chan_open(struct uaudio_softc *sc, struct chan *ch)
(void)uaudio_set_speed(sc, endpt, ch->sample_rate);
#endif
- DPRINTF(("uaudio_open_chan: create pipe to 0x%02x\n", endpt));
+ DPRINTF(("uaudio_chan_open: create pipe to 0x%02x\n", endpt));
err = usbd_open_pipe(as->ifaceh, endpt, 0, &ch->pipe);
return (err);
}
@@ -1844,10 +1849,10 @@ uaudio_chan_open(struct uaudio_softc *sc, struct chan *ch)
void
uaudio_chan_close(struct uaudio_softc *sc, struct chan *ch)
{
- struct as_info *as = &sc->sc_alts[sc->sc_curaltidx];
+ struct as_info *as = &sc->sc_alts[ch->altidx];
if (sc->sc_nullalt >= 0) {
- DPRINTF(("uaudio_close_chan: set null alt=%d\n",
+ DPRINTF(("uaudio_chan_close: set null alt=%d\n",
sc->sc_nullalt));
usbd_set_interface(as->ifaceh, sc->sc_nullalt);
}
@@ -1917,7 +1922,7 @@ uaudio_chan_ptransfer(struct chan *ch)
size = ch->bytes_per_frame;
residue += ch->fraction;
if (residue >= USB_FRAMES_PER_SECOND) {
- if (!ch->nofrac)
+ if ((ch->sc->sc_altflags & UA_NOFRAC) == 0)
size += ch->sample_size;
residue -= USB_FRAMES_PER_SECOND;
}
@@ -2021,7 +2026,7 @@ uaudio_chan_rtransfer(struct chan *ch)
size = ch->bytes_per_frame;
residue += ch->fraction;
if (residue >= USB_FRAMES_PER_SECOND) {
- if (!ch->nofrac)
+ if ((ch->sc->sc_altflags & UA_NOFRAC) == 0)
size += ch->sample_size;
residue -= USB_FRAMES_PER_SECOND;
}
@@ -2141,6 +2146,7 @@ uaudio_set_params(void *addr, int setmode, int usemode,
int flags = sc->sc_altflags;
int factor, precision;
int enc, i, j;
+ int paltidx=-1, raltidx=-1;
void (*swcode)(void *, u_char *buf, int cnt);
struct audio_params *p;
int mode;
@@ -2148,17 +2154,24 @@ uaudio_set_params(void *addr, int setmode, int usemode,
if (sc->sc_dying)
return (EIO);
- if (sc->sc_chan.pipe != NULL)
+ if ((mode == AUMODE_RECORD && sc->sc_recchan.pipe != NULL)
+ || (mode == AUMODE_PLAY && sc->sc_playchan.pipe != NULL))
return (EBUSY);
+ if (usemode & AUMODE_PLAY && sc->sc_playchan.altidx != -1)
+ sc->sc_alts[sc->sc_playchan.altidx].sc_busy = 0;
+ if (usemode & AUMODE_RECORD && sc->sc_recchan.altidx != -1)
+ sc->sc_alts[sc->sc_recchan.altidx].sc_busy = 0;
+
for (mode = AUMODE_RECORD; mode != -1;
mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
if ((setmode & mode) == 0)
continue;
- if ((sc->sc_chan.dir & mode) == 0)
+
+ if ((sc->sc_mode & mode) == 0)
continue;
- p = mode == AUMODE_PLAY ? play : rec;
+ p = (mode == AUMODE_PLAY) ? play : rec;
factor = 1;
swcode = 0;
@@ -2261,6 +2274,9 @@ uaudio_set_params(void *addr, int setmode, int usemode,
for (i = 0; i < sc->sc_nalts; i++) {
struct usb_audio_streaming_type1_descriptor *a1d =
sc->sc_alts[i].asf1desc;
+ if (sc->sc_alts[i].sc_busy)
+ continue;
+
if (p->channels == a1d->bNrChannels &&
precision == a1d->bBitResolution &&
enc == sc->sc_alts[i].encoding &&
@@ -2289,13 +2305,34 @@ uaudio_set_params(void *addr, int setmode, int usemode,
found:
p->sw_code = swcode;
p->factor = factor;
- if (usemode == mode)
- sc->sc_curaltidx = i;
+ if (usemode & mode) {
+ if (mode == AUMODE_PLAY) {
+ paltidx = i;
+ sc->sc_alts[i].sc_busy = 1;
+ } else {
+ raltidx = i;
+ sc->sc_alts[i].sc_busy = 1;
+ }
+ }
+ }
+
+ if ((usemode & AUMODE_PLAY) && paltidx != sc->sc_playchan.altidx) {
+ /* XXX abort transfer if currently happening? */
+ sc->sc_playchan.altidx = paltidx;
+ }
+ if ((usemode & AUMODE_RECORD) && raltidx != sc->sc_recchan.altidx) {
+ /* XXX abort transfer if currently happening? */
+ sc->sc_recchan.altidx = raltidx;
}
- DPRINTF(("uaudio_set_params: use altidx=%d, altno=%d\n",
- sc->sc_curaltidx,
- sc->sc_alts[sc->sc_curaltidx].idesc->bAlternateSetting));
+ DPRINTF(("uaudio_set_params: use altidx=p%d/r%d, altno=p%d/r%d\n",
+ sc->sc_playchan.altidx, sc->sc_recchan.altidx,
+ (sc->sc_playchan.altidx >= 0)
+ ?sc->sc_alts[sc->sc_playchan.altidx].idesc->bAlternateSetting
+ : -1,
+ (sc->sc_recchan.altidx >= 0)
+ ? sc->sc_alts[sc->sc_recchan.altidx].idesc->bAlternateSetting
+ : -1));
return (0);
}
@@ -2316,6 +2353,6 @@ uaudio_set_speed(struct uaudio_softc *sc, int endpt, u_int speed)
data[1] = speed >> 8;
data[2] = speed >> 16;
- return (usbd_do_request(sc->sc_udev, &req, &data));
+ return (usbd_do_request(sc->sc_udev, &req, data));
}