patch-2.4.0-test1 linux/drivers/usb/audio.c
Next file: linux/drivers/usb/ibmcam.c
Previous file: linux/drivers/sound/sonicvibes.c
Back to the patch index
Back to the overall index
- Lines: 326
- Date:
Wed May 24 14:01:44 2000
- Orig file:
v2.3.99-pre9/linux/drivers/usb/audio.c
- Orig date:
Tue May 23 15:31:35 2000
diff -u --recursive --new-file v2.3.99-pre9/linux/drivers/usb/audio.c linux/drivers/usb/audio.c
@@ -52,14 +52,17 @@
* decent headphones!
* "Let's make things better" -> but please Philips start with your
* own stuff!!!!
- * 1999-11-02: It takes the Philips boxes several seconds to acquire synchronisation
+ * 1999-11-02: Thomas Sailer
+ * It takes the Philips boxes several seconds to acquire synchronisation
* that means they won't play short sounds. Should probably maintain
* the ISO datastream even if there's nothing to play.
* Fix counting the total_bytes counter, RealPlayer G2 depends on it.
- * 1999-12-20: Fix bad bug in conversion to per interface probing.
+ * 1999-12-20: Thomas Sailer
+ * Fix bad bug in conversion to per interface probing.
* disconnect was called multiple times for the audio device,
* leading to a premature freeing of the audio structures
- * 2000-05-13: I don't remember who changed the find_format routine,
+ * 2000-05-13: Thomas Sailer
+ * I don't remember who changed the find_format routine,
* but the change was completely broken for the Dallas
* chip. Anyway taking sampling rate into account in find_format
* is bad and should not be done unless there are devices with
@@ -72,8 +75,20 @@
* for the Dallas chip.
* Also fix a rather long standing problem with applications that
* use "small" writes producing no sound at all.
- * 2000-05-15: My fears came true, the Philips camera indeed has pretty stupid
+ * 2000-05-15: Thomas Sailer
+ * My fears came true, the Philips camera indeed has pretty stupid
* audio descriptors.
+ * 2000-05-17: Thomas Sailer
+ * Nemsoft spotted my stupid last minute change, thanks
+ * 2000-05-19: Thomas Sailer
+ * Fixed FEATURE_UNIT thinkos found thanks to the KC Technology
+ * Xtend device. Basically the driver treated FEATURE_UNIT's sourced
+ * by mono terminals as stereo.
+ * 2000-05-20: Thomas Sailer
+ * SELECTOR support (and thus selecting record channels from the mixer).
+ * Somewhat peculiar due to OSS interface limitations. Only works
+ * for channels where a "slider" is already in front of it (i.e.
+ * a MIXER unit or a FEATURE unit with volume capability).
*
*/
@@ -211,6 +226,7 @@
__u16 value;
__u16 osschannel; /* number of the OSS channel */
__s16 minval, maxval;
+ __u16 slctunitid;
__u8 unitid;
__u8 selector;
__u8 chnum;
@@ -988,7 +1004,7 @@
}
spin_lock_irqsave(&as->lock, flags);
}
- if (u->dma.count <= 0 && !u->dma.mapped)
+ if (u->dma.count >= u->dma.dmasize && !u->dma.mapped)
return 0;
u->flags |= FLG_RUNNING;
if (!(u->flags & FLG_URB0RUNNING)) {
@@ -1719,7 +1735,7 @@
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
(ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 2, HZ) < 0)
goto err;
- if (ch->chnum == 0)
+ if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
return 0;
data[0] = v2;
data[1] = v2 >> 8;
@@ -1735,7 +1751,7 @@
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
(ch->selector << 8) | ch->chnum, ms->iface | (ch->unitid << 8), data, 1, HZ) < 0)
goto err;
- if (ch->chnum == 0)
+ if (!(ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)))
return 0;
data[0] = v2 >> 8;
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
@@ -1754,6 +1770,89 @@
return -1;
}
+static int get_rec_src(struct usb_mixerdev *ms)
+{
+ struct usb_device *dev = ms->state->usbdev;
+ unsigned int mask = 0, retmask = 0;
+ unsigned int i, j;
+ unsigned char buf;
+ int err = 0;
+
+ for (i = 0; i < ms->numch; i++) {
+ if (!ms->ch[i].slctunitid || (mask & (1 << i)))
+ continue;
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ 0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, HZ) < 0) {
+ err = -EIO;
+ printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n",
+ dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
+ continue;
+ }
+ for (j = i; j < ms->numch; i++) {
+ if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
+ continue;
+ mask |= 1 << j;
+ if (buf == (ms->ch[j].slctunitid >> 8))
+ retmask |= 1 << ms->ch[j].osschannel;
+ }
+ }
+ if (err)
+ return -EIO;
+ return retmask;
+}
+
+static int set_rec_src(struct usb_mixerdev *ms, int srcmask)
+{
+ struct usb_device *dev = ms->state->usbdev;
+ unsigned int mask = 0, smask, bmask;
+ unsigned int i, j;
+ unsigned char buf;
+ int err = 0;
+
+ for (i = 0; i < ms->numch; i++) {
+ if (!ms->ch[i].slctunitid || (mask & (1 << i)))
+ continue;
+ if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ 0, ms->iface | (ms->ch[i].slctunitid << 8), &buf, 1, HZ) < 0) {
+ err = -EIO;
+ printk(KERN_ERR "usbaudio: selector read request device %u if %u unit %u failed\n",
+ dev->devnum, ms->iface, ms->ch[i].slctunitid & 0xff);
+ continue;
+ }
+ /* first generate smask */
+ smask = bmask = 0;
+ for (j = i; j < ms->numch; i++) {
+ if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
+ continue;
+ smask |= 1 << ms->ch[j].osschannel;
+ if (buf == (ms->ch[j].slctunitid >> 8))
+ bmask |= 1 << ms->ch[j].osschannel;
+ mask |= 1 << j;
+ }
+ /* check for multiple set sources */
+ j = hweight32(srcmask & smask);
+ if (j == 0)
+ continue;
+ if (j > 1)
+ srcmask &= ~bmask;
+ for (j = i; j < ms->numch; i++) {
+ if ((ms->ch[i].slctunitid ^ ms->ch[j].slctunitid) & 0xff)
+ continue;
+ if (!(srcmask & (1 << ms->ch[j].osschannel)))
+ continue;
+ buf = ms->ch[j].slctunitid >> 8;
+ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ 0, ms->iface | (ms->ch[j].slctunitid << 8), &buf, 1, HZ) < 0) {
+ err = -EIO;
+ printk(KERN_ERR "usbaudio: selector write request device %u if %u unit %u failed\n",
+ dev->devnum, ms->iface, ms->ch[j].slctunitid & 0xff);
+ continue;
+ }
+ }
+ }
+ return err ? -EIO : 0;
+}
+
/* --------------------------------------------------------------------- */
/*
@@ -1886,8 +1985,10 @@
if (_IOC_DIR(cmd) == _IOC_READ) {
switch (_IOC_NR(cmd)) {
case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- /* don't know how to handle this yet */
- return put_user(0, (int *)arg);
+ val = get_rec_src(ms);
+ if (val < 0)
+ return val;
+ return put_user(val, (int *)arg);
case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
for (val = i = 0; i < ms->numch; i++)
@@ -1895,9 +1996,11 @@
return put_user(val, (int *)arg);
case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
- /* don't know how to handle this yet */
- return put_user(0, (int *)arg);
-
+ for (val = i = 0; i < ms->numch; i++)
+ if (ms->ch[i].slctunitid)
+ val |= 1 << ms->ch[i].osschannel;
+ return put_user(val, (int *)arg);
+
case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
for (val = i = 0; i < ms->numch; i++)
if (ms->ch[i].flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT))
@@ -1905,7 +2008,7 @@
return put_user(val, (int *)arg);
case SOUND_MIXER_CAPS:
- return put_user(0, (int *)arg);
+ return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg);
default:
i = _IOC_NR(cmd);
@@ -1925,8 +2028,7 @@
switch (_IOC_NR(cmd)) {
case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
get_user_ret(val, (int *)arg, -EFAULT);
- /* set recording source: val */
- return 0;
+ return set_rec_src(ms, val);
default:
i = _IOC_NR(cmd);
@@ -2852,7 +2954,7 @@
{
unsigned int u;
- if ((state->termtype & 0xff00) == 0x0000 && !(state->mixchmask & SOUND_MASK_VOLUME))
+ if ((state->termtype & 0xff00) == 0x0000 && (state->mixchmask & SOUND_MASK_VOLUME))
return SOUND_MIXER_VOLUME;
if ((state->termtype & 0xff00) == 0x0100) {
if (state->mixchmask & SOUND_MASK_PCM)
@@ -2864,8 +2966,6 @@
return SOUND_MIXER_MIC;
if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER))
return SOUND_MIXER_SPEAKER;
- if ((state->termtype & 0xff00) == 0x0300 && (state->mixchmask & SOUND_MASK_SPEAKER))
- return SOUND_MIXER_SPEAKER;
if ((state->termtype & 0xff00) == 0x0500) {
if (state->mixchmask & SOUND_MASK_PHONEIN)
return SOUND_MIXER_PHONEIN;
@@ -2950,7 +3050,7 @@
if (v3 > 100)
v3 = 100;
ch->value = v3;
- if (ch->chnum != 0) {
+ if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
(ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 2, HZ) < 0)
goto err;
@@ -2986,7 +3086,7 @@
if (v3 > 100)
v3 = 100;
ch->value = v3;
- if (ch->chnum != 0) {
+ if (ch->flags & (MIXFLG_STEREOIN | MIXFLG_STEREOOUT)) {
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
(ch->selector << 8) | (ch->chnum + 1), state->ctrlif | (ch->unitid << 8), buf, 1, HZ) < 0)
goto err;
@@ -3095,15 +3195,24 @@
static void usb_audio_selectorunit(struct consmixstate *state, unsigned char *selector)
{
- unsigned int chnum, i;
+ unsigned int chnum, i, mixch;
+ struct mixerchannel *mch;
if (!selector[4]) {
printk(KERN_ERR "usbaudio: unit %u invalid SELECTOR_UNIT descriptor\n", selector[3]);
return;
}
+ mixch = state->nrmixch;
usb_audio_recurseunit(state, selector[5]);
+ if (state->nrmixch != mixch) {
+ mch = &state->mixch[state->nrmixch-1];
+ mch->slctunitid = selector[5] | (1 << 8);
+ } else {
+ printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel 1\n", selector[3]);
+ }
chnum = state->nrchannels;
for (i = 1; i < selector[4]; i++) {
+ mixch = state->nrmixch;
usb_audio_recurseunit(state, selector[5+i]);
if (chnum != state->nrchannels) {
printk(KERN_ERR "usbaudio: selector unit %u: input pins with varying channel numbers\n", selector[3]);
@@ -3112,6 +3221,12 @@
state->nrchannels = 0;
return;
}
+ if (state->nrmixch != mixch) {
+ mch = &state->mixch[state->nrmixch-1];
+ mch->slctunitid = selector[5] | ((i + 1) << 8);
+ } else {
+ printk(KERN_INFO "usbaudio: selector unit %u: ignoring channel %u\n", selector[3], i+1);
+ }
}
state->termtype = 0;
state->chconfig = 0;
@@ -3167,7 +3282,7 @@
ch->unitid = ftr[3];
ch->selector = VOLUME_CONTROL;
ch->chnum = 1;
- ch->flags = MIXFLG_STEREOIN | MIXFLG_STEREOOUT;
+ ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
prepmixch(state);
}
} else if (mchftr & 2) {
@@ -3187,7 +3302,7 @@
ch->unitid = ftr[3];
ch->selector = BASS_CONTROL;
ch->chnum = 1;
- ch->flags = MIXFLG_STEREOIN | MIXFLG_STEREOOUT;
+ ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
prepmixch(state);
}
} else if (mchftr & 4) {
@@ -3207,7 +3322,7 @@
ch->unitid = ftr[3];
ch->selector = TREBLE_CONTROL;
ch->chnum = 1;
- ch->flags = MIXFLG_STEREOIN | MIXFLG_STEREOOUT;
+ ch->flags = (state->nrchannels > 1) ? (MIXFLG_STEREOIN | MIXFLG_STEREOOUT) : 0;
prepmixch(state);
}
} else if (mchftr & 16) {
@@ -3239,7 +3354,7 @@
unsigned int i, j;
if (test_and_set_bit(unitid, &state->unitbitmap)) {
- printk(KERN_ERR "usbaudio: mixer path recursion detected, unit %d!\n", unitid);
+ printk(KERN_INFO "usbaudio: mixer path revisits unit %d\n", unitid);
return;
}
p1 = find_audiocontrol_unit(state->buffer, state->buflen, NULL, unitid, state->ctrlif);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)