From bb92b7c4ed4f7d5102bb1623cc8a1a9960ddfc08 Mon Sep 17 00:00:00 2001 From: Raymond Yau Date: Tue, 17 Jan 2012 11:32:17 +0800 Subject: ALSA: Au88x0 - Implement subdevice volume controls - add "PCM Playback Volume" controls for 16 playback subdevices This allow application to change the volume of each subdevice by using hardware mixer of au88x0 and default is zero gain/attenunation. Signed-off-by: Raymond Yau Signed-off-by: Takashi Iwai --- sound/pci/au88x0/au88x0.h | 13 ++++- sound/pci/au88x0/au88x0_core.c | 18 +++--- sound/pci/au88x0/au88x0_pcm.c | 127 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 145 insertions(+), 13 deletions(-) diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h index bb938153a964..466a5c8e8354 100644 --- a/sound/pci/au88x0/au88x0.h +++ b/sound/pci/au88x0/au88x0.h @@ -26,7 +26,7 @@ #include #include #include - +#include #endif #ifndef CHIP_AU8820 @@ -107,6 +107,14 @@ #define NR_WTPB 0x20 /* WT channels per each bank. */ #define NR_PCM 0x10 +struct pcm_vol { + struct snd_kcontrol *kctl; + int active; + int dma; + int mixin[4]; + int vol[4]; +}; + /* Structs */ typedef struct { //int this_08; /* Still unknown */ @@ -168,6 +176,7 @@ struct snd_vortex { /* Xtalk canceler */ int xt_mode; /* 1: speakers, 0:headphones. */ #endif + struct pcm_vol pcm_vol[NR_PCM]; int isquad; /* cache of extended ID codec flag. */ @@ -239,7 +248,7 @@ static int vortex_alsafmt_aspfmt(int alsafmt); /* Connection stuff. */ static void vortex_connect_default(vortex_t * vortex, int en); static int vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, - int dir, int type); + int dir, int type, int subdev); static char vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype); #ifndef CHIP_AU8810 diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index 6933a27a5d76..1181c5ec2d4f 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -2050,8 +2050,6 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype) } /* Default Connections */ -static int -vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type); static void vortex_connect_default(vortex_t * vortex, int en) { @@ -2111,15 +2109,13 @@ static void vortex_connect_default(vortex_t * vortex, int en) Return: Return allocated DMA or same DMA passed as "dma" when dma >= 0. */ static int -vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type) +vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir, + int type, int subdev) { stream_t *stream; int i, en; + struct pcm_vol *p; - if ((nr_ch == 3) - || ((dir == SNDRV_PCM_STREAM_CAPTURE) && (nr_ch > 2))) - return -EBUSY; - if (dma >= 0) { en = 0; vortex_adb_checkinout(vortex, @@ -2250,6 +2246,14 @@ vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type) MIX_DEFIGAIN); #endif } + if (stream->type == VORTEX_PCM_ADB && en) { + p = &vortex->pcm_vol[subdev]; + p->dma = dma; + for (i = 0; i < nr_ch; i++) + p->mixin[i] = mix[i]; + for (i = 0; i < ch_top; i++) + p->vol[i] = 0; + } } #ifndef CHIP_AU8820 else { diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index 0ef2f9712208..e59f120742a4 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c @@ -122,6 +122,18 @@ static struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = { .mask = 0, }; #endif + +static void vortex_notify_pcm_vol_change(struct snd_card *card, + struct snd_kcontrol *kctl, int activate) +{ + if (activate) + kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + else + kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE | + SNDRV_CTL_EVENT_MASK_INFO, &(kctl->id)); +} + /* open callback */ static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) { @@ -230,12 +242,14 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream, if (stream != NULL) vortex_adb_allocroute(chip, stream->dma, stream->nr_ch, stream->dir, - stream->type); + stream->type, + substream->number); /* Alloc routes. */ dma = vortex_adb_allocroute(chip, -1, params_channels(hw_params), - substream->stream, type); + substream->stream, type, + substream->number); if (dma < 0) { spin_unlock_irq(&chip->lock); return dma; @@ -246,6 +260,11 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream, vortex_adbdma_setbuffers(chip, dma, params_period_bytes(hw_params), params_periods(hw_params)); + if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { + chip->pcm_vol[substream->number].active = 1; + vortex_notify_pcm_vol_change(chip->card, + chip->pcm_vol[substream->number].kctl, 1); + } } #ifndef CHIP_AU8810 else { @@ -275,10 +294,18 @@ static int snd_vortex_pcm_hw_free(struct snd_pcm_substream *substream) spin_lock_irq(&chip->lock); // Delete audio routes. if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { - if (stream != NULL) + if (stream != NULL) { + if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { + chip->pcm_vol[substream->number].active = 0; + vortex_notify_pcm_vol_change(chip->card, + chip->pcm_vol[substream->number].kctl, + 0); + } vortex_adb_allocroute(chip, stream->dma, stream->nr_ch, stream->dir, - stream->type); + stream->type, + substream->number); + } } #ifndef CHIP_AU8810 else { @@ -506,6 +533,83 @@ static struct snd_kcontrol_new snd_vortex_mixer_spdif[] __devinitdata = { }, }; +/* subdevice PCM Volume control */ + +static int snd_vortex_pcm_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + vortex_t *vortex = snd_kcontrol_chip(kcontrol); + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = (VORTEX_IS_QUAD(vortex) ? 4 : 2); + uinfo->value.integer.min = -128; + uinfo->value.integer.max = 32; + return 0; +} + +static int snd_vortex_pcm_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int i; + vortex_t *vortex = snd_kcontrol_chip(kcontrol); + int subdev = kcontrol->id.subdevice; + struct pcm_vol *p = &vortex->pcm_vol[subdev]; + int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2); + for (i = 0; i < max_chn; i++) + ucontrol->value.integer.value[i] = p->vol[i]; + return 0; +} + +static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int i; + int changed = 0; + int mixin; + unsigned char vol; + vortex_t *vortex = snd_kcontrol_chip(kcontrol); + int subdev = kcontrol->id.subdevice; + struct pcm_vol *p = &vortex->pcm_vol[subdev]; + int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2); + for (i = 0; i < max_chn; i++) { + if (p->vol[i] != ucontrol->value.integer.value[i]) { + p->vol[i] = ucontrol->value.integer.value[i]; + if (p->active) { + switch (vortex->dma_adb[p->dma].nr_ch) { + case 1: + mixin = p->mixin[0]; + break; + case 2: + default: + mixin = p->mixin[(i < 2) ? i : (i - 2)]; + break; + case 4: + mixin = p->mixin[i]; + break; + }; + vol = p->vol[i]; + vortex_mix_setinputvolumebyte(vortex, + vortex->mixplayb[i], mixin, vol); + } + changed = 1; + } + } + return changed; +} + +static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400); + +static struct snd_kcontrol_new snd_vortex_pcm_vol __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "PCM Playback Volume", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_INACTIVE, + .info = snd_vortex_pcm_vol_info, + .get = snd_vortex_pcm_vol_get, + .put = snd_vortex_pcm_vol_put, + .tlv = { .p = vortex_pcm_vol_db_scale }, +}; + /* create a pcm device */ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) { @@ -555,5 +659,20 @@ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) return err; } } + if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_ADB) { + for (i = 0; i < NR_PCM; i++) { + chip->pcm_vol[i].active = 0; + chip->pcm_vol[i].dma = -1; + kctl = snd_ctl_new1(&snd_vortex_pcm_vol, chip); + if (!kctl) + return -ENOMEM; + chip->pcm_vol[i].kctl = kctl; + kctl->id.device = 0; + kctl->id.subdevice = i; + err = snd_ctl_add(chip->card, kctl); + if (err < 0) + return err; + } + } return 0; } -- cgit v1.2.2 From 8a3e53732c5695669bfb9e23ae7dfd8504a37256 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 25 Jan 2012 08:56:30 +0100 Subject: ALSA: Release v1.0.25 Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- include/sound/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/version.h b/include/sound/version.h index 8fc5321e1ecc..cc75024c1089 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h */ -#define CONFIG_SND_VERSION "1.0.24" +#define CONFIG_SND_VERSION "1.0.25" #define CONFIG_SND_DATE "" -- cgit v1.2.2 From 98654d3fa2e6983378e3510131c5c45be97c4906 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 27 Jan 2012 15:23:51 +0800 Subject: ALSA: aoa: Convert onyx and tas codec drivers to module_i2c_driver This patch converts onyx and tas codec drivers to use the module_i2c_driver() macro which makes the code smaller and a bit simpler. Signed-off-by: Axel Lin Signed-off-by: Takashi Iwai --- sound/aoa/codecs/onyx.c | 13 +------------ sound/aoa/codecs/tas.c | 13 +------------ 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c index 762af68c8996..270790d384e2 100644 --- a/sound/aoa/codecs/onyx.c +++ b/sound/aoa/codecs/onyx.c @@ -1132,15 +1132,4 @@ static struct i2c_driver onyx_driver = { .id_table = onyx_i2c_id, }; -static int __init onyx_init(void) -{ - return i2c_add_driver(&onyx_driver); -} - -static void __exit onyx_exit(void) -{ - i2c_del_driver(&onyx_driver); -} - -module_init(onyx_init); -module_exit(onyx_exit); +module_i2c_driver(onyx_driver); diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c index fd2188c3df2b..8e63d1f35ce1 100644 --- a/sound/aoa/codecs/tas.c +++ b/sound/aoa/codecs/tas.c @@ -1026,15 +1026,4 @@ static struct i2c_driver tas_driver = { .id_table = tas_i2c_id, }; -static int __init tas_init(void) -{ - return i2c_add_driver(&tas_driver); -} - -static void __exit tas_exit(void) -{ - i2c_del_driver(&tas_driver); -} - -module_init(tas_init); -module_exit(tas_exit); +module_i2c_driver(tas_driver); -- cgit v1.2.2 From f443ac935a2fd80f177c6b5a580cc54ef18c552d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 27 Jan 2012 15:29:13 +0800 Subject: ALSA: Convert at73c213 to module_spi_driver This patch converts at73c213 to use the module_spi_driver() macro which makes the code smaller and a bit simpler. Signed-off-by: Axel Lin Signed-off-by: Takashi Iwai --- sound/spi/at73c213.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index 4dd051bdf4fd..c6500d00053b 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c @@ -1112,17 +1112,7 @@ static struct spi_driver at73c213_driver = { .remove = __devexit_p(snd_at73c213_remove), }; -static int __init at73c213_init(void) -{ - return spi_register_driver(&at73c213_driver); -} -module_init(at73c213_init); - -static void __exit at73c213_exit(void) -{ - spi_unregister_driver(&at73c213_driver); -} -module_exit(at73c213_exit); +module_spi_driver(at73c213_driver); MODULE_AUTHOR("Hans-Christian Egtvedt "); MODULE_DESCRIPTION("Sound driver for AT73C213 with Atmel SSC"); -- cgit v1.2.2 From 6e8d5d2f17e707ecfabd33fd5fa167ac7739326e Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 15 Feb 2012 00:38:55 +0900 Subject: ALSA: usx2y: Fix typo in usbusx2yaudio.c and usx2yhwdeppcm.c Correct spelling "propably" to "probably" and "activ" to "active" in sound/usb/usx2y/usbusx2yaudio.c and usx2yhwdeppcm.c Signed-off-by: Masanari Iida Signed-off-by: Takashi Iwai --- sound/usb/usx2y/usbusx2yaudio.c | 4 ++-- sound/usb/usx2y/usx2yhwdeppcm.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 6ffb3713b60c..520ef96d7c75 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -80,7 +80,7 @@ static int usX2Y_urb_capt_retire(struct snd_usX2Y_substream *subs) cp = (unsigned char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset; if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */ snd_printk(KERN_ERR "active frame status %i. " - "Most propably some hardware problem.\n", + "Most probably some hardware problem.\n", urb->iso_frame_desc[i].status); return urb->iso_frame_desc[i].status; } @@ -300,7 +300,7 @@ static void usX2Y_error_sequence(struct usX2Ydev *usX2Y, { snd_printk(KERN_ERR "Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n" -"Most propably some urb of usb-frame %i is still missing.\n" +"Most probably some urb of usb-frame %i is still missing.\n" "Cause could be too long delays in usb-hcd interrupt handling.\n", usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index a51340f6f2db..8e40b6e67e9e 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -74,7 +74,7 @@ static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream *subs) } for (i = 0; i < nr_of_packs(); i++) { if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */ - snd_printk(KERN_ERR "activ frame status %i. Most propably some hardware problem.\n", urb->iso_frame_desc[i].status); + snd_printk(KERN_ERR "active frame status %i. Most probably some hardware problem.\n", urb->iso_frame_desc[i].status); return urb->iso_frame_desc[i].status; } lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride; -- cgit v1.2.2 From 7913a49963ffa8849c14c805c26d9e63bb27ccaa Mon Sep 17 00:00:00 2001 From: Jeffrin Jose Date: Thu, 16 Feb 2012 21:50:49 +0530 Subject: ALSA: Fixed a trailing white space error This is a patch to the sound/core/misc.c file that fixes up a trailing white space issue found by the checkpatch.pl tool. Signed-off-by: Jeffrin Jose Signed-off-by: Takashi Iwai --- sound/core/misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/misc.c b/sound/core/misc.c index 465f0ce772cb..768167925409 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -72,7 +72,7 @@ void __snd_printk(unsigned int level, const char *path, int line, char verbose_fmt[] = KERN_DEFAULT "ALSA %s:%d %pV"; #endif -#ifdef CONFIG_SND_DEBUG +#ifdef CONFIG_SND_DEBUG if (debug < level) return; #endif -- cgit v1.2.2 From c596758f57aa33e5e89c006867ae66fa2f9c357c Mon Sep 17 00:00:00 2001 From: Torsten Schenk Date: Wed, 22 Feb 2012 15:20:45 +0100 Subject: ALSA: snd-usb-6fire: remove driver version information Remove unused driver version information from the individual files. Signed-off-by: Torsten Schenk Signed-off-by: Takashi Iwai --- sound/usb/6fire/chip.c | 3 +-- sound/usb/6fire/chip.h | 1 - sound/usb/6fire/comm.c | 1 - sound/usb/6fire/comm.h | 1 - sound/usb/6fire/common.h | 1 - sound/usb/6fire/control.c | 1 - sound/usb/6fire/control.h | 1 - sound/usb/6fire/firmware.c | 1 - sound/usb/6fire/midi.c | 1 - sound/usb/6fire/midi.h | 1 - sound/usb/6fire/pcm.c | 1 - sound/usb/6fire/pcm.h | 1 - 12 files changed, 1 insertion(+), 13 deletions(-) diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c index 8af92e3e9c18..fc8cc823e438 100644 --- a/sound/usb/6fire/chip.c +++ b/sound/usb/6fire/chip.c @@ -5,7 +5,6 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify @@ -29,7 +28,7 @@ #include MODULE_AUTHOR("Torsten Schenk "); -MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver, version 0.3.0"); +MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver"); MODULE_LICENSE("GPL v2"); MODULE_SUPPORTED_DEVICE("{{TerraTec, DMX 6Fire USB}}"); diff --git a/sound/usb/6fire/chip.h b/sound/usb/6fire/chip.h index d11e5cb520f0..bde02d105a51 100644 --- a/sound/usb/6fire/chip.h +++ b/sound/usb/6fire/chip.h @@ -3,7 +3,6 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/comm.c b/sound/usb/6fire/comm.c index c994daa57af2..6c3d531a250e 100644 --- a/sound/usb/6fire/comm.c +++ b/sound/usb/6fire/comm.c @@ -5,7 +5,6 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/comm.h b/sound/usb/6fire/comm.h index edc5dc84b888..d2af0a5ddcf3 100644 --- a/sound/usb/6fire/comm.h +++ b/sound/usb/6fire/comm.h @@ -3,7 +3,6 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/common.h b/sound/usb/6fire/common.h index 7dbeb4a37831..b6eb03ed1c2c 100644 --- a/sound/usb/6fire/common.h +++ b/sound/usb/6fire/common.h @@ -3,7 +3,6 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c index ac828eff1a63..8111844c4b16 100644 --- a/sound/usb/6fire/control.c +++ b/sound/usb/6fire/control.c @@ -5,7 +5,6 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h index 8f5aeead2e3d..0dcb1d2f522c 100644 --- a/sound/usb/6fire/control.h +++ b/sound/usb/6fire/control.h @@ -3,7 +3,6 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c index 3b5f517a3972..6f9715ab32fe 100644 --- a/sound/usb/6fire/firmware.c +++ b/sound/usb/6fire/firmware.c @@ -5,7 +5,6 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/midi.c b/sound/usb/6fire/midi.c index 13f4509dce2b..f0e5179b242b 100644 --- a/sound/usb/6fire/midi.c +++ b/sound/usb/6fire/midi.c @@ -5,7 +5,6 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/midi.h b/sound/usb/6fire/midi.h index 97a7bf669135..5114eccc1d8e 100644 --- a/sound/usb/6fire/midi.h +++ b/sound/usb/6fire/midi.h @@ -3,7 +3,6 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index d144cdb2f159..c97d05f0e966 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c @@ -5,7 +5,6 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify diff --git a/sound/usb/6fire/pcm.h b/sound/usb/6fire/pcm.h index 2bee81374002..3104301b257d 100644 --- a/sound/usb/6fire/pcm.h +++ b/sound/usb/6fire/pcm.h @@ -3,7 +3,6 @@ * * Author: Torsten Schenk * Created: Jan 01, 2011 - * Version: 0.3.0 * Copyright: (C) Torsten Schenk * * This program is free software; you can redistribute it and/or modify -- cgit v1.2.2 From 8e247a9c90e65b25b5b064e2159d9c4c2c173a5e Mon Sep 17 00:00:00 2001 From: Torsten Schenk Date: Wed, 22 Feb 2012 15:20:54 +0100 Subject: ALSA: snd-usb-6fire: add tlv to controls Remove the soft log-conversion and add a dB scale according to the DAC documentation instead. Signed-off-by: Torsten Schenk Signed-off-by: Takashi Iwai --- sound/usb/6fire/control.c | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c index 8111844c4b16..b00b8bb88c63 100644 --- a/sound/usb/6fire/control.c +++ b/sound/usb/6fire/control.c @@ -15,6 +15,7 @@ #include #include +#include #include "control.h" #include "comm.h" @@ -23,26 +24,6 @@ static char *opt_coax_texts[2] = { "Optical", "Coax" }; static char *line_phono_texts[2] = { "Line", "Phono" }; -/* - * calculated with $value\[i\] = 128 \cdot sqrt[3]{\frac{i}{128}}$ - * this is done because the linear values cause rapid degredation - * of volume in the uppermost region. - */ -static const u8 log_volume_table[128] = { - 0x00, 0x19, 0x20, 0x24, 0x28, 0x2b, 0x2e, 0x30, 0x32, 0x34, - 0x36, 0x38, 0x3a, 0x3b, 0x3d, 0x3e, 0x40, 0x41, 0x42, 0x43, - 0x44, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, - 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x53, 0x54, 0x55, 0x56, - 0x56, 0x57, 0x58, 0x58, 0x59, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, - 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62, - 0x63, 0x63, 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x68, - 0x68, 0x69, 0x69, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, - 0x6d, 0x6d, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71, - 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75, - 0x75, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, - 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, - 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f }; - /* * data that needs to be sent to device. sets up card internal stuff. * values dumped from windows driver and filtered by trial'n'error. @@ -69,6 +50,8 @@ static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 }; static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}; static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00}; +static DECLARE_TLV_DB_MINMAX(tlv_output, -9000, 0); + enum { DIGITAL_THRU_ONLY_SAMPLERATE = 3 }; @@ -78,8 +61,7 @@ static void usb6fire_control_master_vol_update(struct control_runtime *rt) struct comm_runtime *comm_rt = rt->chip->comm; if (comm_rt) { /* set volume */ - comm_rt->write8(comm_rt, 0x12, 0x0f, 0x7f - - log_volume_table[rt->master_vol]); + comm_rt->write8(comm_rt, 0x12, 0x0f, 180 - rt->master_vol); /* unmute */ comm_rt->write8(comm_rt, 0x12, 0x0e, 0x00); } @@ -170,7 +152,7 @@ static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol, uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; - uinfo->value.integer.max = 127; + uinfo->value.integer.max = 180; return 0; } @@ -291,10 +273,12 @@ static struct __devinitdata snd_kcontrol_new elements[] = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Volume", .index = 0, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = usb6fire_control_master_vol_info, .get = usb6fire_control_master_vol_get, - .put = usb6fire_control_master_vol_put + .put = usb6fire_control_master_vol_put, + .tlv = { .p = tlv_output } }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, -- cgit v1.2.2 From f90ffbf3c68a69714b4273b203d4deb5ae81d8d6 Mon Sep 17 00:00:00 2001 From: Torsten Schenk Date: Wed, 22 Feb 2012 15:21:12 +0100 Subject: ALSA: snd-usb-6fire: add individual volume control for analog channels Add a stereo volume control for every analog output pair 1/2, 3/4, 5/6. Signed-off-by: Torsten Schenk Signed-off-by: Takashi Iwai --- sound/usb/6fire/control.c | 146 +++++++++++++++++++++++++++++++++++++++------- sound/usb/6fire/control.h | 3 +- 2 files changed, 126 insertions(+), 23 deletions(-) diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c index b00b8bb88c63..c22cc29e33d7 100644 --- a/sound/usb/6fire/control.c +++ b/sound/usb/6fire/control.c @@ -7,6 +7,10 @@ * Created: Jan 01, 2011 * Copyright: (C) Torsten Schenk * + * Thanks to: + * - Holger Ruckdeschel: he found out how to control individual channel + * volumes and introduced mute switch + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -39,7 +43,7 @@ init_data[] = { { 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 }, { 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 }, { 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 }, - { 0x12, 0x0d, 0x78 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 }, + { 0x12, 0x0d, 0x38 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 }, { 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 }, { 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 }, { 0 } /* TERMINATING ENTRY */ @@ -56,15 +60,18 @@ enum { DIGITAL_THRU_ONLY_SAMPLERATE = 3 }; -static void usb6fire_control_master_vol_update(struct control_runtime *rt) +static void usb6fire_control_output_vol_update(struct control_runtime *rt) { struct comm_runtime *comm_rt = rt->chip->comm; - if (comm_rt) { - /* set volume */ - comm_rt->write8(comm_rt, 0x12, 0x0f, 180 - rt->master_vol); - /* unmute */ - comm_rt->write8(comm_rt, 0x12, 0x0e, 0x00); - } + int i; + + if (comm_rt) + for (i = 0; i < 6; i++) + if (!(rt->ovol_updated & (1 << i))) { + comm_rt->write8(comm_rt, 0x12, 0x0f + i, + 180 - rt->output_vol[i]); + rt->ovol_updated |= 1 << i; + } } static void usb6fire_control_line_phono_update(struct control_runtime *rt) @@ -146,34 +153,58 @@ static int usb6fire_control_streaming_update(struct control_runtime *rt) return -EINVAL; } -static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol, +static int usb6fire_control_output_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; + uinfo->count = 2; uinfo->value.integer.min = 0; uinfo->value.integer.max = 180; return 0; } -static int usb6fire_control_master_vol_put(struct snd_kcontrol *kcontrol, +static int usb6fire_control_output_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct control_runtime *rt = snd_kcontrol_chip(kcontrol); + unsigned int ch = kcontrol->private_value; int changed = 0; - if (rt->master_vol != ucontrol->value.integer.value[0]) { - rt->master_vol = ucontrol->value.integer.value[0]; - usb6fire_control_master_vol_update(rt); + + if (ch > 4) { + snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); + return -EINVAL; + } + + if (rt->output_vol[ch] != ucontrol->value.integer.value[0]) { + rt->output_vol[ch] = ucontrol->value.integer.value[0]; + rt->ovol_updated &= ~(1 << ch); changed = 1; } + if (rt->output_vol[ch + 1] != ucontrol->value.integer.value[1]) { + rt->output_vol[ch + 1] = ucontrol->value.integer.value[1]; + rt->ovol_updated &= ~(2 << ch); + changed = 1; + } + + if (changed) + usb6fire_control_output_vol_update(rt); + return changed; } -static int usb6fire_control_master_vol_get(struct snd_kcontrol *kcontrol, +static int usb6fire_control_output_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct control_runtime *rt = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = rt->master_vol; + unsigned int ch = kcontrol->private_value; + + if (ch > 4) { + snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = rt->output_vol[ch]; + ucontrol->value.integer.value[1] = rt->output_vol[ch + 1]; return 0; } @@ -268,18 +299,47 @@ static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol, return 0; } -static struct __devinitdata snd_kcontrol_new elements[] = { +static struct __devinitdata snd_kcontrol_new vol_elements[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", + .name = "Analog Playback Volume", .index = 0, + .private_value = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = usb6fire_control_output_vol_info, + .get = usb6fire_control_output_vol_get, + .put = usb6fire_control_output_vol_put, + .tlv = { .p = tlv_output } + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Playback Volume", + .index = 1, + .private_value = 2, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = usb6fire_control_output_vol_info, + .get = usb6fire_control_output_vol_get, + .put = usb6fire_control_output_vol_put, + .tlv = { .p = tlv_output } + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Playback Volume", + .index = 2, + .private_value = 4, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .info = usb6fire_control_master_vol_info, - .get = usb6fire_control_master_vol_get, - .put = usb6fire_control_master_vol_put, + .info = usb6fire_control_output_vol_info, + .get = usb6fire_control_output_vol_get, + .put = usb6fire_control_output_vol_put, .tlv = { .p = tlv_output } }, + {} +}; + +static struct __devinitdata snd_kcontrol_new elements[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line/Phono Capture Route", @@ -310,6 +370,40 @@ static struct __devinitdata snd_kcontrol_new elements[] = { {} }; +static int usb6fire_control_add_virtual( + struct control_runtime *rt, + struct snd_card *card, + char *name, + struct snd_kcontrol_new *elems) +{ + int ret; + int i; + struct snd_kcontrol *vmaster = + snd_ctl_make_virtual_master(name, tlv_output); + struct snd_kcontrol *control; + + if (!vmaster) + return -ENOMEM; + ret = snd_ctl_add(card, vmaster); + if (ret < 0) + return ret; + + i = 0; + while (elems[i].name) { + control = snd_ctl_new1(&elems[i], rt); + if (!control) + return -ENOMEM; + ret = snd_ctl_add(card, control); + if (ret < 0) + return ret; + ret = snd_ctl_add_slave(vmaster, control); + if (ret < 0) + return ret; + i++; + } + return 0; +} + int __devinit usb6fire_control_init(struct sfire_chip *chip) { int i; @@ -335,9 +429,17 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip) usb6fire_control_opt_coax_update(rt); usb6fire_control_line_phono_update(rt); - usb6fire_control_master_vol_update(rt); + usb6fire_control_output_vol_update(rt); usb6fire_control_streaming_update(rt); + ret = usb6fire_control_add_virtual(rt, chip->card, + "Master Playback Volume", vol_elements); + if (ret) { + kfree(rt); + snd_printk(KERN_ERR PREFIX "cannot add control.\n"); + return ret; + } + i = 0; while (elements[i].name) { ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt)); diff --git a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h index 0dcb1d2f522c..ce024113c98f 100644 --- a/sound/usb/6fire/control.h +++ b/sound/usb/6fire/control.h @@ -43,7 +43,8 @@ struct control_runtime { bool line_phono_switch; bool digital_thru_switch; bool usb_streaming; - u8 master_vol; + u8 output_vol[6]; + u8 ovol_updated; }; int __devinit usb6fire_control_init(struct sfire_chip *chip); -- cgit v1.2.2 From d97c735a1047fa06165e55da32154cf0e6b9419c Mon Sep 17 00:00:00 2001 From: Torsten Schenk Date: Wed, 22 Feb 2012 15:21:23 +0100 Subject: ALSA: snd-usb-6fire: add mute control for analog outputs Add a mute control for every analog output channel. Signed-off-by: Torsten Schenk Signed-off-by: Takashi Iwai --- sound/usb/6fire/control.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++ sound/usb/6fire/control.h | 1 + 2 files changed, 96 insertions(+) diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c index c22cc29e33d7..a2bbf48c6413 100644 --- a/sound/usb/6fire/control.c +++ b/sound/usb/6fire/control.c @@ -74,6 +74,14 @@ static void usb6fire_control_output_vol_update(struct control_runtime *rt) } } +static void usb6fire_control_output_mute_update(struct control_runtime *rt) +{ + struct comm_runtime *comm_rt = rt->chip->comm; + + if (comm_rt) + comm_rt->write8(comm_rt, 0x12, 0x0e, ~rt->output_mute); +} + static void usb6fire_control_line_phono_update(struct control_runtime *rt) { struct comm_runtime *comm_rt = rt->chip->comm; @@ -208,6 +216,51 @@ static int usb6fire_control_output_vol_get(struct snd_kcontrol *kcontrol, return 0; } +static int usb6fire_control_output_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct control_runtime *rt = snd_kcontrol_chip(kcontrol); + unsigned int ch = kcontrol->private_value; + u8 old = rt->output_mute; + u8 value = 0; + + if (ch > 4) { + snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); + return -EINVAL; + } + + rt->output_mute &= ~(3 << ch); + if (ucontrol->value.integer.value[0]) + value |= 1; + if (ucontrol->value.integer.value[1]) + value |= 2; + rt->output_mute |= value << ch; + + if (rt->output_mute != old) + usb6fire_control_output_mute_update(rt); + + return rt->output_mute != old; +} + +static int usb6fire_control_output_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct control_runtime *rt = snd_kcontrol_chip(kcontrol); + unsigned int ch = kcontrol->private_value; + u8 value = rt->output_mute >> ch; + + if (ch > 4) { + snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); + return -EINVAL; + } + + ucontrol->value.integer.value[0] = 1 & value; + value >>= 1; + ucontrol->value.integer.value[1] = 1 & value; + + return 0; +} + static int usb6fire_control_line_phono_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -339,6 +392,40 @@ static struct __devinitdata snd_kcontrol_new vol_elements[] = { {} }; +static struct __devinitdata snd_kcontrol_new mute_elements[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Playback Switch", + .index = 0, + .private_value = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_ctl_boolean_stereo_info, + .get = usb6fire_control_output_mute_get, + .put = usb6fire_control_output_mute_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Playback Switch", + .index = 1, + .private_value = 2, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_ctl_boolean_stereo_info, + .get = usb6fire_control_output_mute_get, + .put = usb6fire_control_output_mute_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Playback Switch", + .index = 2, + .private_value = 4, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_ctl_boolean_stereo_info, + .get = usb6fire_control_output_mute_get, + .put = usb6fire_control_output_mute_put, + }, + {} +}; + static struct __devinitdata snd_kcontrol_new elements[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -430,13 +517,21 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip) usb6fire_control_opt_coax_update(rt); usb6fire_control_line_phono_update(rt); usb6fire_control_output_vol_update(rt); + usb6fire_control_output_mute_update(rt); usb6fire_control_streaming_update(rt); ret = usb6fire_control_add_virtual(rt, chip->card, "Master Playback Volume", vol_elements); if (ret) { + snd_printk(KERN_ERR PREFIX "cannot add control.\n"); kfree(rt); + return ret; + } + ret = usb6fire_control_add_virtual(rt, chip->card, + "Master Playback Switch", mute_elements); + if (ret) { snd_printk(KERN_ERR PREFIX "cannot add control.\n"); + kfree(rt); return ret; } diff --git a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h index ce024113c98f..9f9eb647bc6b 100644 --- a/sound/usb/6fire/control.h +++ b/sound/usb/6fire/control.h @@ -45,6 +45,7 @@ struct control_runtime { bool usb_streaming; u8 output_vol[6]; u8 ovol_updated; + u8 output_mute; }; int __devinit usb6fire_control_init(struct sfire_chip *chip); -- cgit v1.2.2 From 06bb4e7435019ff9b6dbc9b1d02d8babb36d8177 Mon Sep 17 00:00:00 2001 From: Torsten Schenk Date: Wed, 22 Feb 2012 15:21:30 +0100 Subject: ALSA: snd-usb-6fire: add analog input volume control Add a stereo volume control for analog input channel pair 1/2. Signed-off-by: Torsten Schenk Signed-off-by: Takashi Iwai --- sound/usb/6fire/control.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++ sound/usb/6fire/control.h | 2 ++ 2 files changed, 73 insertions(+) diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c index a2bbf48c6413..07ed914d5e71 100644 --- a/sound/usb/6fire/control.c +++ b/sound/usb/6fire/control.c @@ -55,6 +55,7 @@ static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}; static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00}; static DECLARE_TLV_DB_MINMAX(tlv_output, -9000, 0); +static DECLARE_TLV_DB_MINMAX(tlv_input, -1500, 1500); enum { DIGITAL_THRU_ONLY_SAMPLERATE = 3 @@ -82,6 +83,20 @@ static void usb6fire_control_output_mute_update(struct control_runtime *rt) comm_rt->write8(comm_rt, 0x12, 0x0e, ~rt->output_mute); } +static void usb6fire_control_input_vol_update(struct control_runtime *rt) +{ + struct comm_runtime *comm_rt = rt->chip->comm; + int i; + + if (comm_rt) + for (i = 0; i < 2; i++) + if (!(rt->ivol_updated & (1 << i))) { + comm_rt->write8(comm_rt, 0x12, 0x1c + i, + rt->input_vol[i] & 0x3f); + rt->ivol_updated |= 1 << i; + } +} + static void usb6fire_control_line_phono_update(struct control_runtime *rt) { struct comm_runtime *comm_rt = rt->chip->comm; @@ -261,6 +276,50 @@ static int usb6fire_control_output_mute_get(struct snd_kcontrol *kcontrol, return 0; } +static int usb6fire_control_input_vol_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 30; + return 0; +} + +static int usb6fire_control_input_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct control_runtime *rt = snd_kcontrol_chip(kcontrol); + int changed = 0; + + if (rt->input_vol[0] != ucontrol->value.integer.value[0]) { + rt->input_vol[0] = ucontrol->value.integer.value[0] - 15; + rt->ivol_updated &= ~(1 << 0); + changed = 1; + } + if (rt->input_vol[1] != ucontrol->value.integer.value[1]) { + rt->input_vol[1] = ucontrol->value.integer.value[1] - 15; + rt->ivol_updated &= ~(1 << 1); + changed = 1; + } + + if (changed) + usb6fire_control_input_vol_update(rt); + + return changed; +} + +static int usb6fire_control_input_vol_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct control_runtime *rt = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = rt->input_vol[0] + 15; + ucontrol->value.integer.value[1] = rt->input_vol[1] + 15; + + return 0; +} + static int usb6fire_control_line_phono_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -454,6 +513,17 @@ static struct __devinitdata snd_kcontrol_new elements[] = { .get = usb6fire_control_digital_thru_get, .put = usb6fire_control_digital_thru_put }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Capture Volume", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = usb6fire_control_input_vol_info, + .get = usb6fire_control_input_vol_get, + .put = usb6fire_control_input_vol_put, + .tlv = { .p = tlv_input } + }, {} }; @@ -518,6 +588,7 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip) usb6fire_control_line_phono_update(rt); usb6fire_control_output_vol_update(rt); usb6fire_control_output_mute_update(rt); + usb6fire_control_input_vol_update(rt); usb6fire_control_streaming_update(rt); ret = usb6fire_control_add_virtual(rt, chip->card, diff --git a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h index 9f9eb647bc6b..9a596d95474a 100644 --- a/sound/usb/6fire/control.h +++ b/sound/usb/6fire/control.h @@ -46,6 +46,8 @@ struct control_runtime { u8 output_vol[6]; u8 ovol_updated; u8 output_mute; + s8 input_vol[2]; + u8 ivol_updated; }; int __devinit usb6fire_control_init(struct sfire_chip *chip); -- cgit v1.2.2 From 8a236f3f1a0e65de526c5e169eb8d7a758ffde9e Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Thu, 23 Feb 2012 23:23:06 +0900 Subject: ALSA: ctxfi: Fix typo in ctvmem.c Correct spelling "virtural" to "virtual" in sound/pci/ctxfi/ctvmem.c Signed-off-by: Masanari Iida Signed-off-by: Takashi Iwai --- sound/pci/ctxfi/ctvmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index b78f3fc3c33c..6109490b83e8 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c @@ -36,7 +36,7 @@ get_vm_block(struct ct_vm *vm, unsigned int size) size = CT_PAGE_ALIGN(size); if (size > vm->size) { - printk(KERN_ERR "ctxfi: Fail! No sufficient device virtural " + printk(KERN_ERR "ctxfi: Fail! No sufficient device virtual " "memory space available!\n"); return NULL; } -- cgit v1.2.2 From adef39c0ea2e5deae5c4f2917b23694b68535e45 Mon Sep 17 00:00:00 2001 From: Torsten Schenk Date: Fri, 24 Feb 2012 21:34:22 +0100 Subject: ALSA: snd-usb-6fire: Select missing SND_VMASTER option in Kconfig Signed-off-by: Torsten Schenk Signed-off-by: Takashi Iwai --- sound/usb/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 3efc21c3d67c..ff77b28f3da1 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -106,6 +106,7 @@ config SND_USB_6FIRE select BITREVERSE select SND_RAWMIDI select SND_PCM + select SND_VMASTER help Say Y here to include support for TerraTec 6fire DMX USB interface. -- cgit v1.2.2 From db05828aadbcc71aeea1c0b33ffadc8655dec600 Mon Sep 17 00:00:00 2001 From: Pavel Hofman Date: Fri, 2 Mar 2012 22:09:39 +0100 Subject: ALSA: ice1724 - constrain runtime rates for locked internal rate The driver already defines control "Multi Track Rate Locking" which locks the card at current rate if switched to internal clock. This patch limits the runtime rates to this rate only, allowing proper reporting of the card capabilities, and e.g. automatic rate conversion by the plug plugin to the currently locked rate. Signed-off-by: Pavel Hofman Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1724.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 92362973764d..812d10e43ae0 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -1013,6 +1013,25 @@ static int set_rate_constraints(struct snd_ice1712 *ice, ice->hw_rates); } +/* if the card has the internal rate locked (is_pro_locked), limit runtime + hw rates to the current internal rate only. +*/ +static void constrain_rate_if_locked(struct snd_pcm_substream *substream) +{ + struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int rate; + if (is_pro_rate_locked(ice)) { + rate = ice->get_rate(ice); + if (rate >= runtime->hw.rate_min + && rate <= runtime->hw.rate_max) { + runtime->hw.rate_min = rate; + runtime->hw.rate_max = rate; + } + } +} + + /* multi-channel playback needs alignment 8x32bit regardless of the channels * actually used */ @@ -1046,6 +1065,7 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream) VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, VT1724_BUFFER_ALIGN); + constrain_rate_if_locked(substream); if (ice->pro_open) ice->pro_open(ice, substream); return 0; @@ -1066,6 +1086,7 @@ static int snd_vt1724_capture_pro_open(struct snd_pcm_substream *substream) VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, VT1724_BUFFER_ALIGN); + constrain_rate_if_locked(substream); if (ice->pro_open) ice->pro_open(ice, substream); return 0; @@ -1215,6 +1236,7 @@ static int snd_vt1724_playback_spdif_open(struct snd_pcm_substream *substream) VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, VT1724_BUFFER_ALIGN); + constrain_rate_if_locked(substream); if (ice->spdif.ops.open) ice->spdif.ops.open(ice, substream); return 0; @@ -1251,6 +1273,7 @@ static int snd_vt1724_capture_spdif_open(struct snd_pcm_substream *substream) VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, VT1724_BUFFER_ALIGN); + constrain_rate_if_locked(substream); if (ice->spdif.ops.open) ice->spdif.ops.open(ice, substream); return 0; -- cgit v1.2.2 From e7df2a3ae569ed6d178510f58b22308edac7a4c7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 9 Mar 2012 17:41:53 +0100 Subject: ALSA: core - Refactor card id string creation code The code to handle the card id string is fairly messy, so here is a tidy up. Signed-off-by: Takashi Iwai --- sound/core/init.c | 169 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 100 insertions(+), 69 deletions(-) diff --git a/sound/core/init.c b/sound/core/init.c index 3ac49b1b7cb8..068cf08d3ffb 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -480,74 +480,104 @@ int snd_card_free(struct snd_card *card) EXPORT_SYMBOL(snd_card_free); -static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid) +/* retrieve the last word of shortname or longname */ +static const char *retrieve_id_from_card_name(const char *name) { - int i, len, idx_flag = 0, loops = SNDRV_CARDS; - const char *spos, *src; - char *id; - - if (nid == NULL) { - id = card->shortname; - spos = src = id; - while (*id != '\0') { - if (*id == ' ') - spos = id + 1; - id++; - } - } else { - spos = src = nid; + const char *spos = name; + + while (*name) { + if (isspace(*name) && isalnum(name[1])) + spos = name + 1; + name++; } - id = card->id; - while (*spos != '\0' && !isalnum(*spos)) - spos++; - if (isdigit(*spos)) - *id++ = isalpha(src[0]) ? src[0] : 'D'; - while (*spos != '\0' && (size_t)(id - card->id) < sizeof(card->id) - 1) { - if (isalnum(*spos)) - *id++ = *spos; - spos++; + return spos; +} + +/* return true if the given id string doesn't conflict any other card ids */ +static bool card_id_ok(struct snd_card *card, const char *id) +{ + int i; + if (!snd_info_check_reserved_words(id)) + return false; + for (i = 0; i < snd_ecards_limit; i++) { + if (snd_cards[i] && snd_cards[i] != card && + !strcmp(snd_cards[i]->id, id)) + return false; } - *id = '\0'; + return true; +} - id = card->id; +/* copy to card->id only with valid letters from nid */ +static void copy_valid_id_string(struct snd_card *card, const char *src, + const char *nid) +{ + char *id = card->id; + + while (*nid && !isalnum(*nid)) + nid++; + if (isdigit(*nid)) + *id++ = isalpha(*src) ? *src : 'D'; + while (*nid && (size_t)(id - card->id) < sizeof(card->id) - 1) { + if (isalnum(*nid)) + *id++ = *nid; + nid++; + } + *id = 0; +} + +/* Set card->id from the given string + * If the string conflicts with other ids, add a suffix to make it unique. + */ +static void snd_card_set_id_no_lock(struct snd_card *card, const char *src, + const char *nid) +{ + int len, loops; + bool with_suffix; + bool is_default = false; + char *id; - if (*id == '\0') + copy_valid_id_string(card, src, nid); + id = card->id; + + again: + /* use "Default" for obviously invalid strings + * ("card" conflicts with proc directories) + */ + if (!*id || !strncmp(id, "card", 4)) { strcpy(id, "Default"); + is_default = true; + } - while (1) { - if (loops-- == 0) { - snd_printk(KERN_ERR "unable to set card id (%s)\n", id); - strcpy(card->id, card->proc_root->name); - return; - } - if (!snd_info_check_reserved_words(id)) - goto __change; - for (i = 0; i < snd_ecards_limit; i++) { - if (snd_cards[i] && !strcmp(snd_cards[i]->id, id)) - goto __change; - } - break; + with_suffix = false; + for (loops = 0; loops < SNDRV_CARDS; loops++) { + if (card_id_ok(card, id)) + return; /* OK */ - __change: len = strlen(id); - if (idx_flag) { - if (id[len-1] != '9') - id[len-1]++; - else - id[len-1] = 'A'; - } else if ((size_t)len <= sizeof(card->id) - 3) { - strcat(id, "_1"); - idx_flag++; + if (!with_suffix) { + /* add the "_X" suffix */ + char *spos = id + len; + if (len > sizeof(card->id) - 3) + spos = id + sizeof(card->id) - 3; + strcpy(spos, "_1"); + with_suffix = true; } else { - spos = id + len - 2; - if ((size_t)len <= sizeof(card->id) - 2) - spos++; - *(char *)spos++ = '_'; - *(char *)spos++ = '1'; - *(char *)spos++ = '\0'; - idx_flag++; + /* modify the existing suffix */ + if (id[len - 1] != '9') + id[len - 1]++; + else + id[len - 1] = 'A'; } } + /* fallback to the default id */ + if (!is_default) { + *id = 0; + goto again; + } + /* last resort... */ + snd_printk(KERN_ERR "unable to set card id (%s)\n", id); + if (card->proc_root->name) + strcpy(card->id, card->proc_root->name); } /** @@ -564,7 +594,7 @@ void snd_card_set_id(struct snd_card *card, const char *nid) if (card->id[0] != '\0') return; mutex_lock(&snd_card_mutex); - snd_card_set_id_no_lock(card, nid); + snd_card_set_id_no_lock(card, nid, nid); mutex_unlock(&snd_card_mutex); } EXPORT_SYMBOL(snd_card_set_id); @@ -596,22 +626,12 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr, memcpy(buf1, buf, copy); buf1[copy] = '\0'; mutex_lock(&snd_card_mutex); - if (!snd_info_check_reserved_words(buf1)) { - __exist: + if (!card_id_ok(NULL, buf1)) { mutex_unlock(&snd_card_mutex); return -EEXIST; } - for (idx = 0; idx < snd_ecards_limit; idx++) { - if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) { - if (card == snd_cards[idx]) - goto __ok; - else - goto __exist; - } - } strcpy(card->id, buf1); snd_info_card_id_change(card); -__ok: mutex_unlock(&snd_card_mutex); return count; @@ -665,7 +685,18 @@ int snd_card_register(struct snd_card *card) mutex_unlock(&snd_card_mutex); return 0; } - snd_card_set_id_no_lock(card, card->id[0] == '\0' ? NULL : card->id); + if (*card->id) { + /* make a unique id name from the given string */ + char tmpid[sizeof(card->id)]; + memcpy(tmpid, card->id, sizeof(card->id)); + snd_card_set_id_no_lock(card, tmpid, tmpid); + } else { + /* create an id from either shortname or longname */ + const char *src; + src = *card->shortname ? card->shortname : card->longname; + snd_card_set_id_no_lock(card, src, + retrieve_id_from_card_name(src)); + } snd_cards[card->number] = card; mutex_unlock(&snd_card_mutex); init_info_for_card(card); -- cgit v1.2.2 From bd483d4c6c65c1c48483f2f81c603d42b39ce83b Mon Sep 17 00:00:00 2001 From: Jeffrin Jose Date: Wed, 7 Mar 2012 22:57:39 +0530 Subject: ALSA: control - Fixe a trailing white space error Fixed a trailing white space error detected in sound/core/control.c by checkpatch.pl script. Signed-off-by: Jeffrin Jose Signed-off-by: Takashi Iwai --- sound/core/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/control.c b/sound/core/control.c index 819a5c579a39..2487a6bb1c54 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1313,7 +1313,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, err = -EPERM; goto __kctl_end; } - err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); + err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); if (err > 0) { up_read(&card->controls_rwsem); snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id); -- cgit v1.2.2 From 28aa165cc52fa686a55a2a2052fdddad0fbde5eb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 13 Mar 2012 08:07:41 +0100 Subject: ALSA: ymfpci - Fix legacy registers on S3/S4 resume We need to resume two legacy registers to recover MIDI/FM functionality on S3/S4 resume, too. Signed-off-by: Takashi Iwai --- include/sound/ymfpci.h | 2 ++ sound/pci/ymfpci/ymfpci_main.c | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/include/sound/ymfpci.h b/include/sound/ymfpci.h index 444cd6ba0ba7..41199664666b 100644 --- a/include/sound/ymfpci.h +++ b/include/sound/ymfpci.h @@ -366,6 +366,8 @@ struct snd_ymfpci { #ifdef CONFIG_PM u32 *saved_regs; u32 saved_ydsxgr_mode; + u16 saved_dsxg_legacy; + u16 saved_dsxg_elegacy; #endif }; diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 03ee4e365311..a3a2eababc01 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -2310,6 +2310,10 @@ int snd_ymfpci_suspend(struct pci_dev *pci, pm_message_t state) for (i = 0; i < YDSXGR_NUM_SAVED_REGS; i++) chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]); chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE); + pci_read_config_word(chip->pci, PCIR_DSXG_LEGACY, + &chip->saved_dsxg_legacy); + pci_read_config_word(chip->pci, PCIR_DSXG_ELEGACY, + &chip->saved_dsxg_elegacy); snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0); snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0); snd_ymfpci_disable_dsp(chip); @@ -2344,6 +2348,11 @@ int snd_ymfpci_resume(struct pci_dev *pci) snd_ac97_resume(chip->ac97); + pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY, + chip->saved_dsxg_legacy); + pci_write_config_word(chip->pci, PCIR_DSXG_ELEGACY, + chip->saved_dsxg_elegacy); + /* start hw again */ if (chip->start_count > 0) { spin_lock_irq(&chip->reg_lock); -- cgit v1.2.2 From 4af87a939ef7092fdca267fba473cf8407d6d8e2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 14 Mar 2012 19:48:43 +0000 Subject: ALSA: pcm: Constify the list in snd_pcm_hw_constraint_list Allows the constraint lists to be declared const by drivers which seems reasonable; there's plenty of other constification we could do if we were being complete but this was easy and quick. Signed-off-by: Mark Brown Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 5 +++-- sound/core/pcm_lib.c | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 0cf91b2f08ca..4ae9e22c4827 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -264,7 +264,7 @@ struct snd_pcm_hw_constraint_ratdens { struct snd_pcm_hw_constraint_list { unsigned int count; - unsigned int *list; + const unsigned int *list; unsigned int mask; }; @@ -781,7 +781,8 @@ void snd_interval_muldivk(const struct snd_interval *a, const struct snd_interva unsigned int k, struct snd_interval *c); void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k, const struct snd_interval *b, struct snd_interval *c); -int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *list, unsigned int mask); +int snd_interval_list(struct snd_interval *i, unsigned int count, + const unsigned int *list, unsigned int mask); int snd_interval_ratnum(struct snd_interval *i, unsigned int rats_count, struct snd_ratnum *rats, unsigned int *nump, unsigned int *denp); diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 3420bd3da5d7..4d18941178e6 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1029,7 +1029,8 @@ static int snd_interval_ratden(struct snd_interval *i, * * Returns non-zero if the value is changed, zero if not changed. */ -int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *list, unsigned int mask) +int snd_interval_list(struct snd_interval *i, unsigned int count, + const unsigned int *list, unsigned int mask) { unsigned int k; struct snd_interval list_range; -- cgit v1.2.2 From 1662591b2e6876b8bc041cd48837ccd297c2028f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 13 Mar 2012 15:55:43 +0100 Subject: ALSA: pcm - Avoid GFP_ATOMIC in snd_pcm_link() GFP_ATOMIC is used in snd_pcm_link() just because the kmalloc is called inside a lock. Since this function isn't too critical for speed and is rarely called in practice, better to allocate the chunk at first before spinlock and free it in error paths, so that GFP_KERNEL can be used. Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 25ed9fe41b89..3fe99e644eb8 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -1586,12 +1586,18 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) struct file *file; struct snd_pcm_file *pcm_file; struct snd_pcm_substream *substream1; + struct snd_pcm_group *group; file = snd_pcm_file_fd(fd); if (!file) return -EBADFD; pcm_file = file->private_data; substream1 = pcm_file->substream; + group = kmalloc(sizeof(*group), GFP_KERNEL); + if (!group) { + res = -ENOMEM; + goto _nolock; + } down_write(&snd_pcm_link_rwsem); write_lock_irq(&snd_pcm_link_rwlock); if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || @@ -1604,11 +1610,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) goto _end; } if (!snd_pcm_stream_linked(substream)) { - substream->group = kmalloc(sizeof(struct snd_pcm_group), GFP_ATOMIC); - if (substream->group == NULL) { - res = -ENOMEM; - goto _end; - } + substream->group = group; spin_lock_init(&substream->group->lock); INIT_LIST_HEAD(&substream->group->substreams); list_add_tail(&substream->link_list, &substream->group->substreams); @@ -1620,7 +1622,10 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) _end: write_unlock_irq(&snd_pcm_link_rwlock); up_write(&snd_pcm_link_rwsem); + _nolock: fput(file); + if (res < 0) + kfree(group); return res; } -- cgit v1.2.2 From 0717d0f5d2737a63650a8d928360769e0d411bd5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 15 Mar 2012 16:14:38 +0100 Subject: ALSA: usb-audio - Fix build error by consitification of rate list Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 0220b0f335b9..0eed6115c2d4 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -695,6 +695,7 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs) { struct audioformat *fp; + int *rate_list; int count = 0, needs_knot = 0; int err; @@ -708,7 +709,8 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, if (!needs_knot) return 0; - subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL); + subs->rate_list.list = rate_list = + kmalloc(sizeof(int) * count, GFP_KERNEL); if (!subs->rate_list.list) return -ENOMEM; subs->rate_list.count = count; @@ -717,7 +719,7 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, list_for_each_entry(fp, &subs->fmt_list, list) { int i; for (i = 0; i < fp->nr_rates; i++) - subs->rate_list.list[count++] = fp->rate_table[i]; + rate_list[count++] = fp->rate_table[i]; } err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &subs->rate_list); -- cgit v1.2.2 From c6b76d1f02e2ab1109d8549877a3a24c6a2b4587 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 16 Mar 2012 09:54:00 +0100 Subject: ALSA: au88x0 - Avoid possible Oops at unbinding The irq handler must check whether the MPU401 instance is still alive. Signed-off-by: Takashi Iwai --- sound/pci/au88x0/au88x0_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index 1181c5ec2d4f..525f881f0409 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -2477,7 +2477,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id) hwread(vortex->mmio, VORTEX_IRQ_STAT); handled = 1; } - if (source & IRQ_MIDI) { + if ((source & IRQ_MIDI) && vortex->rmidi) { snd_mpu401_uart_interrupt(vortex->irq, vortex->rmidi->private_data); handled = 1; -- cgit v1.2.2