From 14ff3e78304e3f7fe18f950c3aa0686e6800b3fb Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Thu, 10 Dec 2009 20:39:28 +0100 Subject: ALSA: dt019x: merge into the als100 driver The als100 driver is so similar to the dt019x/als007 driver that one driver's source can be used for both drivers with only few changes. Merge the dt019x driver into the als100. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 02fe81c..194af3b0 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -63,15 +63,16 @@ config SND_AD1848 will be called snd-ad1848. config SND_ALS100 - tristate "Avance Logic ALS100/ALS120" + tristate "Diamond Tech. DT-019x and Avance Logic ALSxxx" depends on PNP select ISAPNP select SND_OPL3_LIB select SND_MPU401_UART select SND_SB16_DSP help - Say Y here to include support for soundcards based on Avance - Logic ALS100, ALS110, ALS120 and ALS200 chips. + Say Y here to include support for soundcards based on the + Diamond Technologies DT-019X or Avance Logic chips: ALS007, + ALS100, ALS110, ALS120 and ALS200 chips. To compile this driver as a module, choose M here: the module will be called snd-als100. @@ -127,20 +128,6 @@ config SND_CS4236 To compile this driver as a module, choose M here: the module will be called snd-cs4236. -config SND_DT019X - tristate "Diamond Technologies DT-019X, Avance Logic ALS-007" - depends on PNP - select ISAPNP - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_SB16_DSP - help - Say Y here to include support for soundcards based on the - Diamond Technologies DT-019X or Avance Logic ALS-007 chips. - - To compile this driver as a module, choose M here: the module - will be called snd-dt019x. - config SND_ES968 tristate "Generic ESS ES968 driver" depends on PNP diff --git a/sound/isa/Makefile b/sound/isa/Makefile index b906b9a..c73d30c 100644 --- a/sound/isa/Makefile +++ b/sound/isa/Makefile @@ -7,7 +7,6 @@ snd-adlib-objs := adlib.o snd-als100-objs := als100.o snd-azt2320-objs := azt2320.o snd-cmi8330-objs := cmi8330.o -snd-dt019x-objs := dt019x.o snd-es18xx-objs := es18xx.o snd-opl3sa2-objs := opl3sa2.o snd-sc6000-objs := sc6000.o @@ -19,7 +18,6 @@ obj-$(CONFIG_SND_ADLIB) += snd-adlib.o obj-$(CONFIG_SND_ALS100) += snd-als100.o obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o -obj-$(CONFIG_SND_DT019X) += snd-dt019x.o obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o obj-$(CONFIG_SND_SC6000) += snd-sc6000.o diff --git a/sound/isa/als100.c b/sound/isa/als100.c index 5fd52e4..20becc8 100644 --- a/sound/isa/als100.c +++ b/sound/isa/als100.c @@ -2,9 +2,13 @@ /* card-als100.c - driver for Avance Logic ALS100 based soundcards. Copyright (C) 1999-2000 by Massimo Piccioni + Copyright (C) 1999-2002 by Massimo Piccioni Thanks to Pierfrancesco 'qM2' Passerini. + Generalised for soundcards based on DT-0196 and ALS-007 chips + by Jonathan Woithe : June 2002. + 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 @@ -33,10 +37,10 @@ #define PFX "als100: " -MODULE_AUTHOR("Massimo Piccioni "); -MODULE_DESCRIPTION("Avance Logic ALS1X0"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS100 - PRO16PNP}," +MODULE_DESCRIPTION("Avance Logic ALS007/ALS1X0"); +MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X}," + "{Avance Logic ALS-007}}" + "{{Avance Logic,ALS100 - PRO16PNP}," "{Avance Logic,ALS110}," "{Avance Logic,ALS120}," "{Avance Logic,ALS200}," @@ -45,9 +49,12 @@ MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS100 - PRO16PNP}," "{Avance Logic,ALS120}," "{RTL,RTL3000}}"); +MODULE_AUTHOR("Massimo Piccioni "); +MODULE_LICENSE("GPL"); + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ @@ -57,14 +64,15 @@ static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */ static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */ module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for als100 based soundcard."); +MODULE_PARM_DESC(index, "Index value for Avance Logic based soundcard."); module_param_array(id, charp, NULL, 0444); -MODULE_PARM_DESC(id, "ID string for als100 based soundcard."); +MODULE_PARM_DESC(id, "ID string for Avance Logic based soundcard."); module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable als100 based soundcard."); +MODULE_PARM_DESC(enable, "Enable Avance Logic based soundcard."); + +MODULE_ALIAS("snd-dt019x"); struct snd_card_als100 { - int dev_no; struct pnp_dev *dev; struct pnp_dev *devmpu; struct pnp_dev *devopl; @@ -72,25 +80,43 @@ struct snd_card_als100 { }; static struct pnp_card_device_id snd_als100_pnpids[] = { + /* DT197A30 */ + { .id = "RWB1688", + .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } }, + .driver_data = SB_HW_DT019X }, + /* DT0196 / ALS-007 */ + { .id = "ALS0007", + .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } }, + .driver_data = SB_HW_DT019X }, /* ALS100 - PRO16PNP */ - { .id = "ALS0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } }, + { .id = "ALS0001", + .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } }, + .driver_data = SB_HW_ALS100 }, /* ALS110 - MF1000 - Digimate 3D Sound */ - { .id = "ALS0110", .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } } }, + { .id = "ALS0110", + .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } }, + .driver_data = SB_HW_ALS100 }, /* ALS120 */ - { .id = "ALS0120", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } } }, + { .id = "ALS0120", + .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } }, + .driver_data = SB_HW_ALS100 }, /* ALS200 */ - { .id = "ALS0200", .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } } }, + { .id = "ALS0200", + .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } }, + .driver_data = SB_HW_ALS100 }, /* ALS200 OEM */ - { .id = "ALS0200", .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } } }, + { .id = "ALS0200", + .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } }, + .driver_data = SB_HW_ALS100 }, /* RTL3000 */ - { .id = "RTL3000", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } } }, - { .id = "", } /* end */ + { .id = "RTL3000", + .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } }, + .driver_data = SB_HW_ALS100 }, + { .id = "" } /* end */ }; MODULE_DEVICE_TABLE(pnp_card, snd_als100_pnpids); -#define DRIVER_NAME "snd-card-als100" - static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, struct pnp_card_link *card, const struct pnp_card_device_id *id) @@ -113,8 +139,12 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, return err; } port[dev] = pnp_port_start(pdev, 0); - dma8[dev] = pnp_dma(pdev, 1); - dma16[dev] = pnp_dma(pdev, 0); + if (id->driver_data == SB_HW_DT019X) + dma8[dev] = pnp_dma(pdev, 0); + else { + dma8[dev] = pnp_dma(pdev, 1); + dma16[dev] = pnp_dma(pdev, 0); + } irq[dev] = pnp_irq(pdev, 0); pdev = acard->devmpu; @@ -175,22 +205,33 @@ static int __devinit snd_card_als100_probe(int dev, } snd_card_set_dev(card, &pcard->card->dev); - if ((error = snd_sbdsp_create(card, port[dev], - irq[dev], - snd_sb16dsp_interrupt, - dma8[dev], - dma16[dev], - SB_HW_ALS100, &chip)) < 0) { + if (pid->driver_data == SB_HW_DT019X) + dma16[dev] = -1; + + error = snd_sbdsp_create(card, port[dev], irq[dev], + snd_sb16dsp_interrupt, + dma8[dev], dma16[dev], + pid->driver_data, + &chip); + if (error < 0) { snd_card_free(card); return error; } acard->chip = chip; - strcpy(card->driver, "ALS100"); - strcpy(card->shortname, "Avance Logic ALS100"); - sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d", - card->shortname, chip->name, chip->port, - irq[dev], dma8[dev], dma16[dev]); + if (pid->driver_data == SB_HW_DT019X) { + strcpy(card->driver, "DT-019X"); + strcpy(card->shortname, "Diamond Tech. DT-019X"); + sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d", + card->shortname, chip->name, chip->port, + irq[dev], dma8[dev]); + } else { + strcpy(card->driver, "ALS100"); + strcpy(card->shortname, "Avance Logic ALS100"); + sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d", + card->shortname, chip->name, chip->port, + irq[dev], dma8[dev], dma16[dev]); + } if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) { snd_card_free(card); @@ -203,9 +244,19 @@ static int __devinit snd_card_als100_probe(int dev, } if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { - if (snd_mpu401_uart_new(card, 0, MPU401_HW_ALS100, + int mpu_type = MPU401_HW_ALS100; + + if (mpu_irq[dev] == SNDRV_AUTO_IRQ) + mpu_irq[dev] = -1; + + if (pid->driver_data == SB_HW_DT019X) + mpu_type = MPU401_HW_MPU401; + + if (snd_mpu401_uart_new(card, 0, + mpu_type, mpu_port[dev], 0, - mpu_irq[dev], IRQF_DISABLED, + mpu_irq[dev], + mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0, NULL) < 0) snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]); } @@ -291,7 +342,7 @@ static int snd_als100_pnp_resume(struct pnp_card_link *pcard) static struct pnp_card_driver als100_pnpc_driver = { .flags = PNP_DRIVER_RES_DISABLE, - .name = "als100", + .name = "als100", .id_table = snd_als100_pnpids, .probe = snd_als100_pnp_detect, .remove = __devexit_p(snd_als100_pnp_remove), @@ -312,7 +363,7 @@ static int __init alsa_card_als100_init(void) if (!als100_devices) { pnp_unregister_card_driver(&als100_pnpc_driver); #ifdef MODULE - snd_printk(KERN_ERR "no ALS100 based soundcards found\n"); + snd_printk(KERN_ERR "no Avance Logic based soundcards found\n"); #endif return -ENODEV; } diff --git a/sound/isa/dt019x.c b/sound/isa/dt019x.c deleted file mode 100644 index 80f5b1a..0000000 --- a/sound/isa/dt019x.c +++ /dev/null @@ -1,321 +0,0 @@ - -/* - dt019x.c - driver for Diamond Technologies DT-0197H based soundcards. - Copyright (C) 1999, 2002 by Massimo Piccioni - - Generalised for soundcards based on DT-0196 and ALS-007 chips - by Jonathan Woithe : June 2002. - - 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 - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PFX "dt019x: " - -MODULE_AUTHOR("Massimo Piccioni "); -MODULE_DESCRIPTION("Diamond Technologies DT-019X / Avance Logic ALS-007"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X}," - "{Avance Logic ALS-007}}"); - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ -static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ -static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ -static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ -static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* PnP setup */ -static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* PnP setup */ -static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */ - -module_param_array(index, int, NULL, 0444); -MODULE_PARM_DESC(index, "Index value for DT-019X based soundcard."); -module_param_array(id, charp, NULL, 0444); -MODULE_PARM_DESC(id, "ID string for DT-019X based soundcard."); -module_param_array(enable, bool, NULL, 0444); -MODULE_PARM_DESC(enable, "Enable DT-019X based soundcard."); - -struct snd_card_dt019x { - struct pnp_dev *dev; - struct pnp_dev *devmpu; - struct pnp_dev *devopl; - struct snd_sb *chip; -}; - -static struct pnp_card_device_id snd_dt019x_pnpids[] = { - /* DT197A30 */ - { .id = "RWB1688", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } }, - /* DT0196 / ALS-007 */ - { .id = "ALS0007", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } }, - { .id = "", } -}; - -MODULE_DEVICE_TABLE(pnp_card, snd_dt019x_pnpids); - - -#define DRIVER_NAME "snd-card-dt019x" - - -static int __devinit snd_card_dt019x_pnp(int dev, struct snd_card_dt019x *acard, - struct pnp_card_link *card, - const struct pnp_card_device_id *pid) -{ - struct pnp_dev *pdev; - int err; - - acard->dev = pnp_request_card_device(card, pid->devs[0].id, NULL); - if (acard->dev == NULL) - return -ENODEV; - - acard->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL); - acard->devopl = pnp_request_card_device(card, pid->devs[2].id, NULL); - - pdev = acard->dev; - - err = pnp_activate_dev(pdev); - if (err < 0) { - snd_printk(KERN_ERR PFX "DT-019X AUDIO pnp configure failure\n"); - return err; - } - - port[dev] = pnp_port_start(pdev, 0); - dma8[dev] = pnp_dma(pdev, 0); - irq[dev] = pnp_irq(pdev, 0); - snd_printdd("dt019x: found audio interface: port=0x%lx, irq=0x%x, dma=0x%x\n", - port[dev],irq[dev],dma8[dev]); - - pdev = acard->devmpu; - if (pdev != NULL) { - err = pnp_activate_dev(pdev); - if (err < 0) { - pnp_release_card_device(pdev); - snd_printk(KERN_ERR PFX "DT-019X MPU401 pnp configure failure, skipping\n"); - goto __mpu_error; - } - mpu_port[dev] = pnp_port_start(pdev, 0); - mpu_irq[dev] = pnp_irq(pdev, 0); - snd_printdd("dt019x: found MPU-401: port=0x%lx, irq=0x%x\n", - mpu_port[dev],mpu_irq[dev]); - } else { - __mpu_error: - acard->devmpu = NULL; - mpu_port[dev] = -1; - } - - pdev = acard->devopl; - if (pdev != NULL) { - err = pnp_activate_dev(pdev); - if (err < 0) { - pnp_release_card_device(pdev); - snd_printk(KERN_ERR PFX "DT-019X OPL3 pnp configure failure, skipping\n"); - goto __fm_error; - } - fm_port[dev] = pnp_port_start(pdev, 0); - snd_printdd("dt019x: found OPL3 synth: port=0x%lx\n",fm_port[dev]); - } else { - __fm_error: - acard->devopl = NULL; - fm_port[dev] = -1; - } - - return 0; -} - -static int __devinit snd_card_dt019x_probe(int dev, struct pnp_card_link *pcard, const struct pnp_card_device_id *pid) -{ - int error; - struct snd_sb *chip; - struct snd_card *card; - struct snd_card_dt019x *acard; - struct snd_opl3 *opl3; - - error = snd_card_create(index[dev], id[dev], THIS_MODULE, - sizeof(struct snd_card_dt019x), &card); - if (error < 0) - return error; - acard = card->private_data; - - snd_card_set_dev(card, &pcard->card->dev); - if ((error = snd_card_dt019x_pnp(dev, acard, pcard, pid))) { - snd_card_free(card); - return error; - } - - if ((error = snd_sbdsp_create(card, port[dev], - irq[dev], - snd_sb16dsp_interrupt, - dma8[dev], - -1, - SB_HW_DT019X, - &chip)) < 0) { - snd_card_free(card); - return error; - } - acard->chip = chip; - - strcpy(card->driver, "DT-019X"); - strcpy(card->shortname, "Diamond Tech. DT-019X"); - sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d", - card->shortname, chip->name, chip->port, - irq[dev], dma8[dev]); - - if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) { - snd_card_free(card); - return error; - } - if ((error = snd_sbmixer_new(chip)) < 0) { - snd_card_free(card); - return error; - } - - if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { - if (mpu_irq[dev] == SNDRV_AUTO_IRQ) - mpu_irq[dev] = -1; - if (snd_mpu401_uart_new(card, 0, -/* MPU401_HW_SB,*/ - MPU401_HW_MPU401, - mpu_port[dev], 0, - mpu_irq[dev], - mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0, - NULL) < 0) - snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx ?\n", mpu_port[dev]); - } - - if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { - if (snd_opl3_create(card, - fm_port[dev], - fm_port[dev] + 2, - OPL3_HW_AUTO, 0, &opl3) < 0) { - snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx ?\n", - fm_port[dev], fm_port[dev] + 2); - } else { - if ((error = snd_opl3_timer_new(opl3, 0, 1)) < 0) { - snd_card_free(card); - return error; - } - if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { - snd_card_free(card); - return error; - } - } - } - - if ((error = snd_card_register(card)) < 0) { - snd_card_free(card); - return error; - } - pnp_set_card_drvdata(pcard, card); - return 0; -} - -static unsigned int __devinitdata dt019x_devices; - -static int __devinit snd_dt019x_pnp_probe(struct pnp_card_link *card, - const struct pnp_card_device_id *pid) -{ - static int dev; - int res; - - for ( ; dev < SNDRV_CARDS; dev++) { - if (!enable[dev]) - continue; - res = snd_card_dt019x_probe(dev, card, pid); - if (res < 0) - return res; - dev++; - dt019x_devices++; - return 0; - } - return -ENODEV; -} - -static void __devexit snd_dt019x_pnp_remove(struct pnp_card_link * pcard) -{ - snd_card_free(pnp_get_card_drvdata(pcard)); - pnp_set_card_drvdata(pcard, NULL); -} - -#ifdef CONFIG_PM -static int snd_dt019x_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state) -{ - struct snd_card *card = pnp_get_card_drvdata(pcard); - struct snd_card_dt019x *acard = card->private_data; - struct snd_sb *chip = acard->chip; - - snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); - snd_sbmixer_suspend(chip); - return 0; -} - -static int snd_dt019x_pnp_resume(struct pnp_card_link *pcard) -{ - struct snd_card *card = pnp_get_card_drvdata(pcard); - struct snd_card_dt019x *acard = card->private_data; - struct snd_sb *chip = acard->chip; - - snd_sbdsp_reset(chip); - snd_sbmixer_resume(chip); - snd_power_change_state(card, SNDRV_CTL_POWER_D0); - return 0; -} -#endif - -static struct pnp_card_driver dt019x_pnpc_driver = { - .flags = PNP_DRIVER_RES_DISABLE, - .name = "dt019x", - .id_table = snd_dt019x_pnpids, - .probe = snd_dt019x_pnp_probe, - .remove = __devexit_p(snd_dt019x_pnp_remove), -#ifdef CONFIG_PM - .suspend = snd_dt019x_pnp_suspend, - .resume = snd_dt019x_pnp_resume, -#endif -}; - -static int __init alsa_card_dt019x_init(void) -{ - int err; - - err = pnp_register_card_driver(&dt019x_pnpc_driver); - if (err) - return err; - - if (!dt019x_devices) { - pnp_unregister_card_driver(&dt019x_pnpc_driver); -#ifdef MODULE - snd_printk(KERN_ERR "no DT-019X / ALS-007 based soundcards found\n"); -#endif - return -ENODEV; - } - return 0; -} - -static void __exit alsa_card_dt019x_exit(void) -{ - pnp_unregister_card_driver(&dt019x_pnpc_driver); -} - -module_init(alsa_card_dt019x_init) -module_exit(alsa_card_dt019x_exit) -- cgit v0.10.2 From b2e8d7dab9d82be3851b8cbcc1ab64b1b2575844 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Thu, 10 Dec 2009 20:40:18 +0100 Subject: ALSA: opti93x: move controls definitions to opti93x driver Move OPTi93x controls definitions to the opti93x driver from the common wss-lib library module. These controls are used only by the opti93x driver. Also, fix capture source names. They are the same as opl3sa2 names. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 106be6e..ea4a671 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -546,6 +547,85 @@ __skip_mpu: #ifdef OPTi93X +static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); + +static struct snd_kcontrol_new snd_opti93x_controls[] = { +WSS_DOUBLE("Master Playback Switch", 0, + OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), +WSS_DOUBLE_TLV("Master Playback Volume", 0, + OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1, + db_scale_6bit), +WSS_DOUBLE("PCM Playback Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1), +WSS_DOUBLE("FM Playback Volume", 0, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1), +WSS_DOUBLE("Line Playback Switch", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), +WSS_DOUBLE("Line Playback Volume", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1), +WSS_DOUBLE("Mic Playback Switch", 0, + OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), +WSS_DOUBLE("Mic Playback Volume", 0, + OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), +WSS_DOUBLE("CD Playback Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1), +WSS_DOUBLE("Aux Playback Switch", 0, + OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), +WSS_DOUBLE("Aux Playback Volume", 0, + OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), +}; + +static int __devinit snd_opti93x_mixer(struct snd_wss *chip) +{ + struct snd_card *card; + unsigned int idx; + struct snd_ctl_elem_id id1, id2; + int err; + + if (snd_BUG_ON(!chip || !chip->pcm)) + return -EINVAL; + + card = chip->card; + + strcpy(card->mixername, chip->pcm->name); + + memset(&id1, 0, sizeof(id1)); + memset(&id2, 0, sizeof(id2)); + id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + /* reassign AUX0 switch to CD */ + strcpy(id1.name, "Aux Playback Switch"); + strcpy(id2.name, "CD Playback Switch"); + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) { + snd_printk(KERN_ERR "Cannot rename opti93x control\n"); + return err; + } + /* reassign AUX1 switch to FM */ + strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; + strcpy(id2.name, "FM Playback Switch"); + err = snd_ctl_rename_id(card, &id1, &id2); + if (err < 0) { + snd_printk(KERN_ERR "Cannot rename opti93x control\n"); + return err; + } + /* remove AUX1 volume */ + strcpy(id1.name, "Aux Playback Volume"); id1.index = 1; + snd_ctl_remove_id(card, &id1); + + /* Replace WSS volume controls with OPTi93x volume controls */ + id1.index = 0; + for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { + strcpy(id1.name, snd_opti93x_controls[idx].name); + snd_ctl_remove_id(card, &id1); + + err = snd_ctl_add(card, + snd_ctl_new1(&snd_opti93x_controls[idx], chip)); + if (err < 0) + return err; + } + return 0; +} + static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) { struct snd_wss *codec = dev_id; @@ -752,6 +832,11 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) error = snd_wss_mixer(codec); if (error < 0) return error; +#ifdef OPTi93X + error = snd_opti93x_mixer(codec); + if (error < 0) + return error; +#endif #ifdef CS4231 error = snd_wss_timer(codec, 0, &timer); if (error < 0) diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 5b9d6c1..9191b32 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -2014,6 +2014,7 @@ static int snd_wss_info_mux(struct snd_kcontrol *kcontrol, case WSS_HW_INTERWAVE: ptexts = gusmax_texts; break; + case WSS_HW_OPTI93X: case WSS_HW_OPL3SA2: ptexts = opl3sa_texts; break; @@ -2246,54 +2247,12 @@ WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0), }; -static struct snd_kcontrol_new snd_opti93x_controls[] = { -WSS_DOUBLE("Master Playback Switch", 0, - OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), -WSS_DOUBLE_TLV("Master Playback Volume", 0, - OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1, - db_scale_6bit), -WSS_DOUBLE("PCM Playback Switch", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -WSS_DOUBLE("PCM Playback Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1), -WSS_DOUBLE("FM Playback Switch", 0, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("FM Playback Volume", 0, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1), -WSS_DOUBLE("Line Playback Switch", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -WSS_DOUBLE("Line Playback Volume", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1), -WSS_DOUBLE("Mic Playback Switch", 0, - OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Mic Playback Volume", 0, - OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), -WSS_DOUBLE("Mic Boost", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), -WSS_DOUBLE("CD Playback Switch", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("CD Playback Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1), -WSS_DOUBLE("Aux Playback Switch", 0, - OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Playback Volume", 0, - OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), -WSS_DOUBLE("Capture Volume", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), -{ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = snd_wss_info_mux, - .get = snd_wss_get_mux, - .put = snd_wss_put_mux, -} -}; - int snd_wss_mixer(struct snd_wss *chip) { struct snd_card *card; unsigned int idx; int err; + int count = ARRAY_SIZE(snd_wss_controls); if (snd_BUG_ON(!chip || !chip->pcm)) return -EINVAL; @@ -2302,28 +2261,19 @@ int snd_wss_mixer(struct snd_wss *chip) strcpy(card->mixername, chip->pcm->name); - if (chip->hardware == WSS_HW_OPTI93X) - for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_opti93x_controls[idx], - chip)); - if (err < 0) - return err; - } - else { - int count = ARRAY_SIZE(snd_wss_controls); - - /* Use only the first 11 entries on AD1848 */ - if (chip->hardware & WSS_HW_AD1848_MASK) - count = 11; - - for (idx = 0; idx < count; idx++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_wss_controls[idx], - chip)); - if (err < 0) - return err; - } + /* Use only the first 11 entries on AD1848 */ + if (chip->hardware & WSS_HW_AD1848_MASK) + count = 11; + /* There is no loopback on OPTI93X */ + else if (chip->hardware == WSS_HW_OPTI93X) + count = 9; + + for (idx = 0; idx < count; idx++) { + err = snd_ctl_add(card, + snd_ctl_new1(&snd_wss_controls[idx], + chip)); + if (err < 0) + return err; } return 0; } -- cgit v0.10.2 From e9d0a803c127e2e30afb0df780ccb3af4e2adb28 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sat, 12 Dec 2009 09:51:03 +0100 Subject: ALSA: opti93x: use dB scale for mixer controls Add dB scale for mixer controls. Fix dB scale for Master Volume control. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index ea4a671..b0ea310 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -547,32 +547,40 @@ __skip_mpu: #ifdef OPTi93X -static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_step, -9300, 300, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_4bit_12db_max, -3300, 300, 0); static struct snd_kcontrol_new snd_opti93x_controls[] = { WSS_DOUBLE("Master Playback Switch", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), WSS_DOUBLE_TLV("Master Playback Volume", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1, - db_scale_6bit), -WSS_DOUBLE("PCM Playback Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1), -WSS_DOUBLE("FM Playback Volume", 0, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1), + db_scale_5bit_3db_step), +WSS_DOUBLE_TLV("PCM Playback Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1, + db_scale_5bit), +WSS_DOUBLE_TLV("FM Playback Volume", 0, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1, + db_scale_4bit_12db_max), WSS_DOUBLE("Line Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -WSS_DOUBLE("Line Playback Volume", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1), +WSS_DOUBLE_TLV("Line Playback Volume", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1, + db_scale_4bit_12db_max), WSS_DOUBLE("Mic Playback Switch", 0, OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Mic Playback Volume", 0, - OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), -WSS_DOUBLE("CD Playback Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1), +WSS_DOUBLE_TLV("Mic Playback Volume", 0, + OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1, + db_scale_4bit_12db_max), +WSS_DOUBLE_TLV("CD Playback Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1, + db_scale_4bit_12db_max), WSS_DOUBLE("Aux Playback Switch", 0, OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Playback Volume", 0, - OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), +WSS_DOUBLE_TLV("Aux Playback Volume", 0, + OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1, + db_scale_4bit_12db_max), }; static int __devinit snd_opti93x_mixer(struct snd_wss *chip) -- cgit v0.10.2 From 74c2b45b714e49b427584b4bd8f44f1a24d82d9c Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sun, 13 Dec 2009 21:13:44 +0100 Subject: ALSA: sb_mixer: convert pointer tables to mixer control tables Convert table of pointers to mixer controls into tables of the mixer controls. It saves about 20% of the snd-sb-common module size reported by lsmod. The als4000 uses part of sb16's control table. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index 318ff0c..8cfc41f 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c @@ -528,20 +528,11 @@ int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int ty * SB 2.0 specific mixer elements */ -static struct sbmix_elem snd_sb20_ctl_master_play_vol = - SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7); -static struct sbmix_elem snd_sb20_ctl_pcm_play_vol = - SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3); -static struct sbmix_elem snd_sb20_ctl_synth_play_vol = - SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7); -static struct sbmix_elem snd_sb20_ctl_cd_play_vol = - SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7); - -static struct sbmix_elem *snd_sb20_controls[] = { - &snd_sb20_ctl_master_play_vol, - &snd_sb20_ctl_pcm_play_vol, - &snd_sb20_ctl_synth_play_vol, - &snd_sb20_ctl_cd_play_vol +static struct sbmix_elem snd_sb20_controls[] = { + SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7), + SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3), + SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7), + SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7) }; static unsigned char snd_sb20_init_values[][2] = { @@ -552,41 +543,24 @@ static unsigned char snd_sb20_init_values[][2] = { /* * SB Pro specific mixer elements */ -static struct sbmix_elem snd_sbpro_ctl_master_play_vol = - SB_DOUBLE("Master Playback Volume", SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7); -static struct sbmix_elem snd_sbpro_ctl_pcm_play_vol = - SB_DOUBLE("PCM Playback Volume", SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7); -static struct sbmix_elem snd_sbpro_ctl_pcm_play_filter = - SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1); -static struct sbmix_elem snd_sbpro_ctl_synth_play_vol = - SB_DOUBLE("Synth Playback Volume", SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7); -static struct sbmix_elem snd_sbpro_ctl_cd_play_vol = - SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7); -static struct sbmix_elem snd_sbpro_ctl_line_play_vol = - SB_DOUBLE("Line Playback Volume", SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7); -static struct sbmix_elem snd_sbpro_ctl_mic_play_vol = - SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3); -static struct sbmix_elem snd_sbpro_ctl_capture_source = +static struct sbmix_elem snd_sbpro_controls[] = { + SB_DOUBLE("Master Playback Volume", + SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7), + SB_DOUBLE("PCM Playback Volume", + SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7), + SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1), + SB_DOUBLE("Synth Playback Volume", + SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7), + SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7), + SB_DOUBLE("Line Playback Volume", + SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7), + SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3), { .name = "Capture Source", .type = SB_MIX_CAPTURE_PRO - }; -static struct sbmix_elem snd_sbpro_ctl_capture_filter = - SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1); -static struct sbmix_elem snd_sbpro_ctl_capture_low_filter = - SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1); - -static struct sbmix_elem *snd_sbpro_controls[] = { - &snd_sbpro_ctl_master_play_vol, - &snd_sbpro_ctl_pcm_play_vol, - &snd_sbpro_ctl_pcm_play_filter, - &snd_sbpro_ctl_synth_play_vol, - &snd_sbpro_ctl_cd_play_vol, - &snd_sbpro_ctl_line_play_vol, - &snd_sbpro_ctl_mic_play_vol, - &snd_sbpro_ctl_capture_source, - &snd_sbpro_ctl_capture_filter, - &snd_sbpro_ctl_capture_low_filter + }, + SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1), + SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1) }; static unsigned char snd_sbpro_init_values[][2] = { @@ -598,68 +572,42 @@ static unsigned char snd_sbpro_init_values[][2] = { /* * SB16 specific mixer elements */ -static struct sbmix_elem snd_sb16_ctl_master_play_vol = - SB_DOUBLE("Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31); -static struct sbmix_elem snd_sb16_ctl_3d_enhance_switch = - SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1); -static struct sbmix_elem snd_sb16_ctl_tone_bass = - SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15); -static struct sbmix_elem snd_sb16_ctl_tone_treble = - SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15); -static struct sbmix_elem snd_sb16_ctl_pcm_play_vol = - SB_DOUBLE("PCM Playback Volume", SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31); -static struct sbmix_elem snd_sb16_ctl_synth_capture_route = - SB16_INPUT_SW("Synth Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5); -static struct sbmix_elem snd_sb16_ctl_synth_play_vol = - SB_DOUBLE("Synth Playback Volume", SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31); -static struct sbmix_elem snd_sb16_ctl_cd_capture_route = - SB16_INPUT_SW("CD Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1); -static struct sbmix_elem snd_sb16_ctl_cd_play_switch = - SB_DOUBLE("CD Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1); -static struct sbmix_elem snd_sb16_ctl_cd_play_vol = - SB_DOUBLE("CD Playback Volume", SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31); -static struct sbmix_elem snd_sb16_ctl_line_capture_route = - SB16_INPUT_SW("Line Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3); -static struct sbmix_elem snd_sb16_ctl_line_play_switch = - SB_DOUBLE("Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1); -static struct sbmix_elem snd_sb16_ctl_line_play_vol = - SB_DOUBLE("Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31); -static struct sbmix_elem snd_sb16_ctl_mic_capture_route = - SB16_INPUT_SW("Mic Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0); -static struct sbmix_elem snd_sb16_ctl_mic_play_switch = - SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1); -static struct sbmix_elem snd_sb16_ctl_mic_play_vol = - SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31); -static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol = - SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3); -static struct sbmix_elem snd_sb16_ctl_capture_vol = - SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3); -static struct sbmix_elem snd_sb16_ctl_play_vol = - SB_DOUBLE("Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3); -static struct sbmix_elem snd_sb16_ctl_auto_mic_gain = - SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1); - -static struct sbmix_elem *snd_sb16_controls[] = { - &snd_sb16_ctl_master_play_vol, - &snd_sb16_ctl_3d_enhance_switch, - &snd_sb16_ctl_tone_bass, - &snd_sb16_ctl_tone_treble, - &snd_sb16_ctl_pcm_play_vol, - &snd_sb16_ctl_synth_capture_route, - &snd_sb16_ctl_synth_play_vol, - &snd_sb16_ctl_cd_capture_route, - &snd_sb16_ctl_cd_play_switch, - &snd_sb16_ctl_cd_play_vol, - &snd_sb16_ctl_line_capture_route, - &snd_sb16_ctl_line_play_switch, - &snd_sb16_ctl_line_play_vol, - &snd_sb16_ctl_mic_capture_route, - &snd_sb16_ctl_mic_play_switch, - &snd_sb16_ctl_mic_play_vol, - &snd_sb16_ctl_pc_speaker_vol, - &snd_sb16_ctl_capture_vol, - &snd_sb16_ctl_play_vol, - &snd_sb16_ctl_auto_mic_gain +static struct sbmix_elem snd_sb16_controls[] = { + SB_DOUBLE("Master Playback Volume", + SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31), + SB_DOUBLE("PCM Playback Volume", + SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31), + SB16_INPUT_SW("Synth Capture Route", + SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5), + SB_DOUBLE("Synth Playback Volume", + SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31), + SB16_INPUT_SW("CD Capture Route", + SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1), + SB_DOUBLE("CD Playback Switch", + SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1), + SB_DOUBLE("CD Playback Volume", + SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31), + SB16_INPUT_SW("Mic Capture Route", + SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0), + SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), + SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31), + SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3), + SB_DOUBLE("Capture Volume", + SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3), + SB_DOUBLE("Playback Volume", + SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3), + SB16_INPUT_SW("Line Capture Route", + SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3), + SB_DOUBLE("Line Playback Switch", + SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1), + SB_DOUBLE("Line Playback Volume", + SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31), + SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1), + SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1), + SB_DOUBLE("Tone Control - Bass", + SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15), + SB_DOUBLE("Tone Control - Treble", + SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15) }; static unsigned char snd_sb16_init_values[][2] = { @@ -678,46 +626,34 @@ static unsigned char snd_sb16_init_values[][2] = { /* * DT019x specific mixer elements */ -static struct sbmix_elem snd_dt019x_ctl_master_play_vol = - SB_DOUBLE("Master Playback Volume", SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4,0, 15); -static struct sbmix_elem snd_dt019x_ctl_pcm_play_vol = - SB_DOUBLE("PCM Playback Volume", SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4,0, 15); -static struct sbmix_elem snd_dt019x_ctl_synth_play_vol = - SB_DOUBLE("Synth Playback Volume", SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4,0, 15); -static struct sbmix_elem snd_dt019x_ctl_cd_play_vol = - SB_DOUBLE("CD Playback Volume", SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4,0, 15); -static struct sbmix_elem snd_dt019x_ctl_mic_play_vol = - SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7); -static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol = - SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7); -static struct sbmix_elem snd_dt019x_ctl_line_play_vol = - SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15); -static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch = - SB_DOUBLE("PCM Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2,1, 1); -static struct sbmix_elem snd_dt019x_ctl_synth_play_switch = - SB_DOUBLE("Synth Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4,3, 1); -static struct sbmix_elem snd_dt019x_ctl_capture_source = +static struct sbmix_elem snd_dt019x_controls[] = { + /* ALS4000 below has some parts which we might be lacking, + * e.g. snd_als4000_ctl_mono_playback_switch - check it! */ + SB_DOUBLE("Master Playback Volume", + SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4, 0, 15), + SB_DOUBLE("PCM Playback Switch", + SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1), + SB_DOUBLE("PCM Playback Volume", + SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4, 0, 15), + SB_DOUBLE("Synth Playback Switch", + SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1), + SB_DOUBLE("Synth Playback Volume", + SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4, 0, 15), + SB_DOUBLE("CD Playback Switch", + SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1), + SB_DOUBLE("CD Playback Volume", + SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4, 0, 15), + SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), + SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7), + SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7), + SB_DOUBLE("Line Playback Switch", + SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1), + SB_DOUBLE("Line Playback Volume", + SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4, 0, 15), { .name = "Capture Source", .type = SB_MIX_CAPTURE_DT019X - }; - -static struct sbmix_elem *snd_dt019x_controls[] = { - /* ALS4000 below has some parts which we might be lacking, - * e.g. snd_als4000_ctl_mono_playback_switch - check it! */ - &snd_dt019x_ctl_master_play_vol, - &snd_dt019x_ctl_pcm_play_vol, - &snd_dt019x_ctl_synth_play_vol, - &snd_dt019x_ctl_cd_play_vol, - &snd_dt019x_ctl_mic_play_vol, - &snd_dt019x_ctl_pc_speaker_vol, - &snd_dt019x_ctl_line_play_vol, - &snd_sb16_ctl_mic_play_switch, - &snd_sb16_ctl_cd_play_switch, - &snd_sb16_ctl_line_play_switch, - &snd_dt019x_ctl_pcm_play_switch, - &snd_dt019x_ctl_synth_play_switch, - &snd_dt019x_ctl_capture_source + } }; static unsigned char snd_dt019x_init_values[][2] = { @@ -735,82 +671,37 @@ static unsigned char snd_dt019x_init_values[][2] = { /* * ALS4000 specific mixer elements */ -static struct sbmix_elem snd_als4000_ctl_master_mono_playback_switch = - SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1); -static struct sbmix_elem snd_als4k_ctl_master_mono_capture_route = { +static struct sbmix_elem snd_als4000_controls[] = { + SB_DOUBLE("PCM Playback Switch", + SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1), + SB_DOUBLE("Synth Playback Switch", + SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1), + SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03), + SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1), + { .name = "Master Mono Capture Route", .type = SB_MIX_MONO_CAPTURE_ALS4K - }; -static struct sbmix_elem snd_als4000_ctl_mono_playback_switch = - SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1); -static struct sbmix_elem snd_als4000_ctl_mic_20db_boost = - SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03); -static struct sbmix_elem snd_als4000_ctl_mixer_analog_loopback = - SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01); -static struct sbmix_elem snd_als4000_ctl_mixer_digital_loopback = + }, + SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1), + SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01), + SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01), SB_SINGLE("Digital Loopback Switch", - SB_ALS4000_CR3_CONFIGURATION, 7, 0x01); -/* FIXME: functionality of 3D controls might be swapped, I didn't find - * a description of how to identify what is supposed to be what */ -static struct sbmix_elem snd_als4000_3d_control_switch = - SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01); -static struct sbmix_elem snd_als4000_3d_control_ratio = - SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07); -static struct sbmix_elem snd_als4000_3d_control_freq = + SB_ALS4000_CR3_CONFIGURATION, 7, 0x01), + /* FIXME: functionality of 3D controls might be swapped, I didn't find + * a description of how to identify what is supposed to be what */ + SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07), /* FIXME: maybe there's actually some standard 3D ctrl name for it?? */ - SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03); -static struct sbmix_elem snd_als4000_3d_control_delay = + SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03), /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay, * but what ALSA 3D attribute is that actually? "Center", "Depth", * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */ - SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f); -static struct sbmix_elem snd_als4000_3d_control_poweroff_switch = - SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01); -static struct sbmix_elem snd_als4000_ctl_3db_freq_control_switch = + SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f), + SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01), SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch", - SB_ALS4000_FMDAC, 5, 0x01); + SB_ALS4000_FMDAC, 5, 0x01), #ifdef NOT_AVAILABLE -static struct sbmix_elem snd_als4000_ctl_fmdac = - SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01); -static struct sbmix_elem snd_als4000_ctl_qsound = - SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f); -#endif - -static struct sbmix_elem *snd_als4000_controls[] = { - /* ALS4000a.PDF regs page */ - &snd_sb16_ctl_master_play_vol, /* MX30/31 12 */ - &snd_dt019x_ctl_pcm_play_switch, /* MX4C 16 */ - &snd_sb16_ctl_pcm_play_vol, /* MX32/33 12 */ - &snd_sb16_ctl_synth_capture_route, /* MX3D/3E 14 */ - &snd_dt019x_ctl_synth_play_switch, /* MX4C 16 */ - &snd_sb16_ctl_synth_play_vol, /* MX34/35 12/13 */ - &snd_sb16_ctl_cd_capture_route, /* MX3D/3E 14 */ - &snd_sb16_ctl_cd_play_switch, /* MX3C 14 */ - &snd_sb16_ctl_cd_play_vol, /* MX36/37 13 */ - &snd_sb16_ctl_line_capture_route, /* MX3D/3E 14 */ - &snd_sb16_ctl_line_play_switch, /* MX3C 14 */ - &snd_sb16_ctl_line_play_vol, /* MX38/39 13 */ - &snd_sb16_ctl_mic_capture_route, /* MX3D/3E 14 */ - &snd_als4000_ctl_mic_20db_boost, /* MX4D 16 */ - &snd_sb16_ctl_mic_play_switch, /* MX3C 14 */ - &snd_sb16_ctl_mic_play_vol, /* MX3A 13 */ - &snd_sb16_ctl_pc_speaker_vol, /* MX3B 14 */ - &snd_sb16_ctl_capture_vol, /* MX3F/40 15 */ - &snd_sb16_ctl_play_vol, /* MX41/42 15 */ - &snd_als4000_ctl_master_mono_playback_switch, /* MX4C 16 */ - &snd_als4k_ctl_master_mono_capture_route, /* MX4B 16 */ - &snd_als4000_ctl_mono_playback_switch, /* MX4C 16 */ - &snd_als4000_ctl_mixer_analog_loopback, /* MX4D 16 */ - &snd_als4000_ctl_mixer_digital_loopback, /* CR3 21 */ - &snd_als4000_3d_control_switch, /* MX50 17 */ - &snd_als4000_3d_control_ratio, /* MX50 17 */ - &snd_als4000_3d_control_freq, /* MX50 17 */ - &snd_als4000_3d_control_delay, /* MX51 18 */ - &snd_als4000_3d_control_poweroff_switch, /* MX51 18 */ - &snd_als4000_ctl_3db_freq_control_switch, /* MX4F 17 */ -#ifdef NOT_AVAILABLE - &snd_als4000_ctl_fmdac, - &snd_als4000_ctl_qsound, + SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01), + SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f), #endif }; @@ -829,11 +720,10 @@ static unsigned char snd_als4000_init_values[][2] = { { SB_ALS4000_MIC_IN_GAIN, 0 }, }; - /* */ static int snd_sbmixer_init(struct snd_sb *chip, - struct sbmix_elem **controls, + struct sbmix_elem *controls, int controls_count, unsigned char map[][2], int map_count, @@ -856,7 +746,8 @@ static int snd_sbmixer_init(struct snd_sb *chip, } for (idx = 0; idx < controls_count; idx++) { - if ((err = snd_sbmixer_add_ctl_elem(chip, controls[idx])) < 0) + err = snd_sbmixer_add_ctl_elem(chip, &controls[idx]); + if (err < 0) return err; } snd_component_add(card, name); @@ -908,6 +799,15 @@ int snd_sbmixer_new(struct snd_sb *chip) return err; break; case SB_HW_ALS4000: + /* use only the first 16 controls from SB16 */ + err = snd_sbmixer_init(chip, + snd_sb16_controls, + 16, + snd_sb16_init_values, + ARRAY_SIZE(snd_sb16_init_values), + "ALS4000"); + if (err < 0) + return err; if ((err = snd_sbmixer_init(chip, snd_als4000_controls, ARRAY_SIZE(snd_als4000_controls), -- cgit v0.10.2 From 63978ab3e3e963db28093b53bb4598f2702e1ad7 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 14 Dec 2009 12:48:35 +0100 Subject: sound: add Edirol UA-101 support Add experimental support for the Edirol UA-101 audio/MIDI interface. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 8923597..7a0a4a9 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1791,6 +1791,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. The power-management is supported. + Module snd-ua101 + ---------------- + + Module for the Edirol UA-101 audio/MIDI interface. + + This module supports multiple devices, autoprobe and hotplugging. + Module snd-usb-audio -------------------- diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 73525c0..8c29258 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -21,6 +21,18 @@ config SND_USB_AUDIO To compile this driver as a module, choose M here: the module will be called snd-usb-audio. +config SND_USB_UA101 + tristate "Edirol UA-101 driver (EXPERIMENTAL)" + depends on EXPERIMENTAL + select SND_PCM + select SND_RAWMIDI + help + Say Y here to include support for the Edirol UA-101 audio/MIDI + interface. + + To compile this driver as a module, choose M here: the module + will be called snd-ua101. + config SND_USB_USX2Y tristate "Tascam US-122, US-224 and US-428 USB driver" depends on X86 || PPC || ALPHA diff --git a/sound/usb/Makefile b/sound/usb/Makefile index abb288b..5bf64ae 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -4,9 +4,11 @@ snd-usb-audio-objs := usbaudio.o usbmixer.o snd-usb-lib-objs := usbmidi.o +snd-ua101-objs := ua101.o # Toplevel Module Dependency obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o snd-usb-lib.o +obj-$(CONFIG_SND_USB_UA101) += snd-ua101.o snd-usb-lib.o obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-lib.o obj-$(CONFIG_SND_USB_US122L) += snd-usb-lib.o diff --git a/sound/usb/ua101.c b/sound/usb/ua101.c new file mode 100644 index 0000000..ab9f8a2 --- /dev/null +++ b/sound/usb/ua101.c @@ -0,0 +1,1457 @@ +/* + * Edirol UA-101 driver + * Copyright (c) Clemens Ladisch + * + * This driver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2. + * + * This driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this driver. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "usbaudio.h" + +MODULE_DESCRIPTION("Edirol UA-101 driver"); +MODULE_AUTHOR("Clemens Ladisch "); +MODULE_LICENSE("GPL v2"); +MODULE_SUPPORTED_DEVICE("{{Edirol,UA-101}}"); + +/* I use my UA-1A for testing because I don't have a UA-101 ... */ +#define UA1A_HACK + +/* + * Should not be lower than the minimum scheduling delay of the host + * controller. Some Intel controllers need more than one frame; as long as + * that driver doesn't tell us about this, use 1.5 frames just to be sure. + */ +#define MIN_QUEUE_LENGTH 12 +/* Somewhat random. */ +#define MAX_QUEUE_LENGTH 30 +/* + * This magic value optimizes memory usage efficiency for the UA-101's packet + * sizes at all sample rates, taking into account the stupid cache pool sizes + * that usb_buffer_alloc() uses. + */ +#define DEFAULT_QUEUE_LENGTH 21 + +#define MAX_PACKET_SIZE 672 /* hardware specific */ +#define MAX_MEMORY_BUFFERS DIV_ROUND_UP(MAX_QUEUE_LENGTH, \ + PAGE_SIZE / MAX_PACKET_SIZE) + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; +static unsigned int queue_length = 21; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "card index"); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string"); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "enable card"); +module_param(queue_length, uint, 0644); +MODULE_PARM_DESC(queue_length, "USB queue length in microframes, " + __stringify(MIN_QUEUE_LENGTH)"-"__stringify(MAX_QUEUE_LENGTH)); + +enum { + INTF_PLAYBACK, + INTF_CAPTURE, + INTF_MIDI, + + INTF_COUNT +}; + +/* bits in struct ua101::states */ +enum { + USB_CAPTURE_RUNNING, + USB_PLAYBACK_RUNNING, + ALSA_CAPTURE_OPEN, + ALSA_PLAYBACK_OPEN, + ALSA_CAPTURE_RUNNING, + ALSA_PLAYBACK_RUNNING, + CAPTURE_URB_COMPLETED, + PLAYBACK_URB_COMPLETED, + DISCONNECTED, +}; + +struct ua101 { + struct usb_device *dev; + struct snd_card *card; + struct usb_interface *intf[INTF_COUNT]; + int card_index; + struct snd_pcm *pcm; + struct list_head midi_list; + u64 format_bit; + unsigned int rate; + unsigned int packets_per_second; + spinlock_t lock; + struct mutex mutex; + unsigned long states; + + /* FIFO to synchronize playback rate to capture rate */ + unsigned int rate_feedback_start; + unsigned int rate_feedback_count; + u8 rate_feedback[MAX_QUEUE_LENGTH]; + + struct list_head ready_playback_urbs; + struct tasklet_struct playback_tasklet; + wait_queue_head_t alsa_capture_wait; + wait_queue_head_t rate_feedback_wait; + wait_queue_head_t alsa_playback_wait; + struct ua101_stream { + struct snd_pcm_substream *substream; + unsigned int usb_pipe; + unsigned int channels; + unsigned int frame_bytes; + unsigned int max_packet_bytes; + unsigned int period_pos; + unsigned int buffer_pos; + unsigned int queue_length; + struct ua101_urb { + struct urb urb; + struct usb_iso_packet_descriptor iso_frame_desc[1]; + struct list_head ready_list; + } *urbs[MAX_QUEUE_LENGTH]; + struct { + unsigned int size; + void *addr; + dma_addr_t dma; + } buffers[MAX_MEMORY_BUFFERS]; + } capture, playback; + + unsigned int fps[10]; + unsigned int frame_counter; +}; + +static DEFINE_MUTEX(devices_mutex); +static unsigned int devices_used; +static struct usb_driver ua101_driver; + +static void abort_alsa_playback(struct ua101 *ua); +static void abort_alsa_capture(struct ua101 *ua); + +/* allocate virtual buffer; may be called more than once */ +static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, + size_t size) +{ + struct snd_pcm_runtime *runtime = subs->runtime; + + if (runtime->dma_area) { + if (runtime->dma_bytes >= size) + return 0; /* already large enough */ + vfree(runtime->dma_area); + } + runtime->dma_area = vmalloc_user(size); + if (!runtime->dma_area) + return -ENOMEM; + runtime->dma_bytes = size; + return 0; +} + +/* free virtual buffer; may be called more than once */ +static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs) +{ + struct snd_pcm_runtime *runtime = subs->runtime; + + vfree(runtime->dma_area); + runtime->dma_area = NULL; + return 0; +} + +/* get the physical page pointer at the given offset */ +static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, + unsigned long offset) +{ + void *pageptr = subs->runtime->dma_area + offset; + return vmalloc_to_page(pageptr); +} + +static const char *usb_error_string(int err) +{ + switch (err) { + case -ENODEV: + return "no device"; + case -ENOENT: + return "endpoint not enabled"; + case -EPIPE: + return "endpoint stalled"; + case -ENOSPC: + return "not enough bandwidth"; + case -ESHUTDOWN: + return "device disabled"; + case -EHOSTUNREACH: + return "device suspended"; + case -EINVAL: + case -EAGAIN: + case -EFBIG: + case -EMSGSIZE: + return "internal error"; + default: + return "unknown error"; + } +} + +static void abort_usb_capture(struct ua101 *ua) +{ + if (test_and_clear_bit(USB_CAPTURE_RUNNING, &ua->states)) { + wake_up(&ua->alsa_capture_wait); + wake_up(&ua->rate_feedback_wait); + } +} + +static void abort_usb_playback(struct ua101 *ua) +{ + if (test_and_clear_bit(USB_PLAYBACK_RUNNING, &ua->states)) + wake_up(&ua->alsa_playback_wait); +} + +static void playback_urb_complete(struct urb *usb_urb) +{ + struct ua101_urb *urb = (struct ua101_urb *)usb_urb; + struct ua101 *ua = urb->urb.context; + unsigned long flags; + + if (unlikely(urb->urb.status == -ENOENT || /* unlinked */ + urb->urb.status == -ENODEV || /* device removed */ + urb->urb.status == -ECONNRESET || /* unlinked */ + urb->urb.status == -ESHUTDOWN)) { /* device disabled */ + abort_usb_playback(ua); + abort_alsa_playback(ua); + return; + } + + if (test_bit(USB_PLAYBACK_RUNNING, &ua->states)) { + /* append URB to FIFO */ + spin_lock_irqsave(&ua->lock, flags); + list_add_tail(&urb->ready_list, &ua->ready_playback_urbs); + if (ua->rate_feedback_count > 0) + tasklet_schedule(&ua->playback_tasklet); + ua->playback.substream->runtime->delay -= + urb->urb.iso_frame_desc[0].length / + ua->playback.frame_bytes; + spin_unlock_irqrestore(&ua->lock, flags); + } +} + +static void first_playback_urb_complete(struct urb *urb) +{ + struct ua101 *ua = urb->context; + + urb->complete = playback_urb_complete; + playback_urb_complete(urb); + + set_bit(PLAYBACK_URB_COMPLETED, &ua->states); + wake_up(&ua->alsa_playback_wait); +} + +/* copy data from the ALSA ring buffer into the URB buffer */ +static bool copy_playback_data(struct ua101_stream *stream, struct urb *urb, + unsigned int frames) +{ + struct snd_pcm_runtime *runtime; + unsigned int frame_bytes, frames1; + const u8 *source; + + runtime = stream->substream->runtime; + frame_bytes = stream->frame_bytes; + source = runtime->dma_area + stream->buffer_pos * frame_bytes; + if (stream->buffer_pos + frames <= runtime->buffer_size) { + memcpy(urb->transfer_buffer, source, frames * frame_bytes); + } else { + /* wrap around at end of ring buffer */ + frames1 = runtime->buffer_size - stream->buffer_pos; + memcpy(urb->transfer_buffer, source, frames1 * frame_bytes); + memcpy(urb->transfer_buffer + frames1 * frame_bytes, + runtime->dma_area, (frames - frames1) * frame_bytes); + } + + stream->buffer_pos += frames; + if (stream->buffer_pos >= runtime->buffer_size) + stream->buffer_pos -= runtime->buffer_size; + stream->period_pos += frames; + if (stream->period_pos >= runtime->period_size) { + stream->period_pos -= runtime->period_size; + return true; + } + return false; +} + +static inline void add_with_wraparound(struct ua101 *ua, + unsigned int *value, unsigned int add) +{ + *value += add; + if (*value >= ua->playback.queue_length) + *value -= ua->playback.queue_length; +} + +static void playback_tasklet(unsigned long data) +{ + struct ua101 *ua = (void *)data; + unsigned long flags; + unsigned int frames; + struct ua101_urb *urb; + bool do_period_elapsed = false; + int err; + + if (unlikely(!test_bit(USB_PLAYBACK_RUNNING, &ua->states))) + return; + + /* + * Synchronizing the playback rate to the capture rate is done by using + * the same sequence of packet sizes for both streams. + * Submitting a playback URB therefore requires both a ready URB and + * the size of the corresponding capture packet, i.e., both playback + * and capture URBs must have been completed. Since the USB core does + * not guarantee that playback and capture complete callbacks are + * called alternately, we use two FIFOs for packet sizes and read URBs; + * submitting playback URBs is possible as long as both FIFOs are + * nonempty. + */ + spin_lock_irqsave(&ua->lock, flags); + while (ua->rate_feedback_count > 0 && + !list_empty(&ua->ready_playback_urbs)) { + /* take packet size out of FIFO */ + frames = ua->rate_feedback[ua->rate_feedback_start]; + add_with_wraparound(ua, &ua->rate_feedback_start, 1); + ua->rate_feedback_count--; + + /* take URB out of FIFO */ + urb = list_first_entry(&ua->ready_playback_urbs, + struct ua101_urb, ready_list); + list_del(&urb->ready_list); + + /* fill packet with data or silence */ + urb->urb.iso_frame_desc[0].length = + frames * ua->playback.frame_bytes; + if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) + do_period_elapsed |= copy_playback_data(&ua->playback, + &urb->urb, + frames); + else + memset(urb->urb.transfer_buffer, 0, + urb->urb.iso_frame_desc[0].length); + + /* and off you go ... */ + err = usb_submit_urb(&urb->urb, GFP_ATOMIC); + if (unlikely(err < 0)) { + spin_unlock_irqrestore(&ua->lock, flags); + abort_usb_playback(ua); + abort_alsa_playback(ua); + dev_err(&ua->dev->dev, "USB request error %d: %s\n", + err, usb_error_string(err)); + return; + } + ua->playback.substream->runtime->delay += frames; + } + spin_unlock_irqrestore(&ua->lock, flags); + if (do_period_elapsed) + snd_pcm_period_elapsed(ua->playback.substream); +} + +/* copy data from the URB buffer into the ALSA ring buffer */ +static bool copy_capture_data(struct ua101_stream *stream, struct urb *urb, + unsigned int frames) +{ + struct snd_pcm_runtime *runtime; + unsigned int frame_bytes, frames1; + u8 *dest; + + runtime = stream->substream->runtime; + frame_bytes = stream->frame_bytes; + dest = runtime->dma_area + stream->buffer_pos * frame_bytes; + if (stream->buffer_pos + frames <= runtime->buffer_size) { + memcpy(dest, urb->transfer_buffer, frames * frame_bytes); + } else { + /* wrap around at end of ring buffer */ + frames1 = runtime->buffer_size - stream->buffer_pos; + memcpy(dest, urb->transfer_buffer, frames1 * frame_bytes); + memcpy(runtime->dma_area, + urb->transfer_buffer + frames1 * frame_bytes, + (frames - frames1) * frame_bytes); + } + + stream->buffer_pos += frames; + if (stream->buffer_pos >= runtime->buffer_size) + stream->buffer_pos -= runtime->buffer_size; + stream->period_pos += frames; + if (stream->period_pos >= runtime->period_size) { + stream->period_pos -= runtime->period_size; + return true; + } + return false; +} + +static void capture_urb_complete(struct urb *urb) +{ + struct ua101 *ua = urb->context; + struct ua101_stream *stream = &ua->capture; + unsigned long flags; + unsigned int frames, write_ptr; + bool do_period_elapsed; + int err; + + if (unlikely(urb->status == -ENOENT || /* unlinked */ + urb->status == -ENODEV || /* device removed */ + urb->status == -ECONNRESET || /* unlinked */ + urb->status == -ESHUTDOWN)) /* device disabled */ + goto stream_stopped; + + if (urb->status >= 0 && urb->iso_frame_desc[0].status >= 0) + frames = urb->iso_frame_desc[0].actual_length / + stream->frame_bytes; + else + frames = 0; + + spin_lock_irqsave(&ua->lock, flags); + + if (frames > 0 && test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) + do_period_elapsed = copy_capture_data(stream, urb, frames); + else + do_period_elapsed = false; + + if (test_bit(USB_CAPTURE_RUNNING, &ua->states)) { + err = usb_submit_urb(urb, GFP_ATOMIC); + if (unlikely(err < 0)) { + spin_unlock_irqrestore(&ua->lock, flags); + dev_err(&ua->dev->dev, "USB request error %d: %s\n", + err, usb_error_string(err)); + goto stream_stopped; + } + + /* append packet size to FIFO */ + write_ptr = ua->rate_feedback_start; + add_with_wraparound(ua, &write_ptr, ua->rate_feedback_count); + ua->rate_feedback[write_ptr] = frames; + if (ua->rate_feedback_count < ua->playback.queue_length) { + ua->rate_feedback_count++; + if (ua->rate_feedback_count == + ua->playback.queue_length) + wake_up(&ua->rate_feedback_wait); + } else { + /* + * Ring buffer overflow; this happens when the playback + * stream is not running. Throw away the oldest entry, + * so that the playback stream, when it starts, sees + * the most recent packet sizes. + */ + add_with_wraparound(ua, &ua->rate_feedback_start, 1); + } + if (test_bit(USB_PLAYBACK_RUNNING, &ua->states) && + !list_empty(&ua->ready_playback_urbs)) + tasklet_schedule(&ua->playback_tasklet); + } + + spin_unlock_irqrestore(&ua->lock, flags); + + if (do_period_elapsed) + snd_pcm_period_elapsed(stream->substream); + + /* for debugging: measure the sample rate relative to the USB clock */ + ua->fps[ua->frame_counter++ / ua->packets_per_second] += frames; + if (ua->frame_counter >= ARRAY_SIZE(ua->fps) * ua->packets_per_second) { + printk(KERN_DEBUG "capture rate:"); + for (frames = 0; frames < ARRAY_SIZE(ua->fps); ++frames) + printk(KERN_CONT " %u", ua->fps[frames]); + printk(KERN_CONT "\n"); + memset(ua->fps, 0, sizeof(ua->fps)); + ua->frame_counter = 0; + } + return; + +stream_stopped: + abort_usb_playback(ua); + abort_usb_capture(ua); + abort_alsa_playback(ua); + abort_alsa_capture(ua); +} + +static void first_capture_urb_complete(struct urb *urb) +{ + struct ua101 *ua = urb->context; + + urb->complete = capture_urb_complete; + capture_urb_complete(urb); + + set_bit(CAPTURE_URB_COMPLETED, &ua->states); + wake_up(&ua->alsa_capture_wait); +} + +static int submit_stream_urbs(struct ua101 *ua, struct ua101_stream *stream) +{ + unsigned int i; + + for (i = 0; i < stream->queue_length; ++i) { + int err = usb_submit_urb(&stream->urbs[i]->urb, GFP_KERNEL); + if (err < 0) { + dev_err(&ua->dev->dev, "USB request error %d: %s\n", + err, usb_error_string(err)); + return err; + } + } + return 0; +} + +static void kill_stream_urbs(struct ua101_stream *stream) +{ + unsigned int i; + + for (i = 0; i < stream->queue_length; ++i) + usb_kill_urb(&stream->urbs[i]->urb); +} + +static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index) +{ + struct usb_host_interface *alts; + + alts = ua->intf[intf_index]->cur_altsetting; + if (alts->desc.bAlternateSetting != 1) { + int err = usb_set_interface(ua->dev, + alts->desc.bInterfaceNumber, 1); + if (err < 0) { + dev_err(&ua->dev->dev, + "cannot initialize interface; error %d: %s\n", + err, usb_error_string(err)); + return err; + } + } + return 0; +} + +static void disable_iso_interface(struct ua101 *ua, unsigned int intf_index) +{ + struct usb_host_interface *alts; + + alts = ua->intf[intf_index]->cur_altsetting; + if (alts->desc.bAlternateSetting != 0) { + int err = usb_set_interface(ua->dev, + alts->desc.bInterfaceNumber, 0); + if (err < 0 && !test_bit(DISCONNECTED, &ua->states)) + dev_warn(&ua->dev->dev, + "interface reset failed; error %d: %s\n", + err, usb_error_string(err)); + } +} + +static void stop_usb_capture(struct ua101 *ua) +{ + clear_bit(USB_CAPTURE_RUNNING, &ua->states); + + kill_stream_urbs(&ua->capture); + + disable_iso_interface(ua, INTF_CAPTURE); +} + +static int start_usb_capture(struct ua101 *ua) +{ + int err; + + if (test_bit(DISCONNECTED, &ua->states)) + return -ENODEV; + + if (test_bit(USB_CAPTURE_RUNNING, &ua->states)) + return 0; + + kill_stream_urbs(&ua->capture); + + err = enable_iso_interface(ua, INTF_CAPTURE); + if (err < 0) + return err; + + clear_bit(CAPTURE_URB_COMPLETED, &ua->states); + ua->capture.urbs[0]->urb.complete = first_capture_urb_complete; + ua->rate_feedback_start = 0; + ua->rate_feedback_count = 0; + + set_bit(USB_CAPTURE_RUNNING, &ua->states); + err = submit_stream_urbs(ua, &ua->capture); + if (err < 0) + stop_usb_capture(ua); + return err; +} + +static void stop_usb_playback(struct ua101 *ua) +{ + clear_bit(USB_PLAYBACK_RUNNING, &ua->states); + + kill_stream_urbs(&ua->playback); + + tasklet_kill(&ua->playback_tasklet); + + disable_iso_interface(ua, INTF_PLAYBACK); +} + +static int start_usb_playback(struct ua101 *ua) +{ + unsigned int i, frames; + struct urb *urb; + int err = 0; + + if (test_bit(DISCONNECTED, &ua->states)) + return -ENODEV; + + if (test_bit(USB_PLAYBACK_RUNNING, &ua->states)) + return 0; + + kill_stream_urbs(&ua->playback); + tasklet_kill(&ua->playback_tasklet); + + err = enable_iso_interface(ua, INTF_PLAYBACK); + if (err < 0) + return err; + + clear_bit(PLAYBACK_URB_COMPLETED, &ua->states); + ua->playback.urbs[0]->urb.complete = + first_playback_urb_complete; + spin_lock_irq(&ua->lock); + INIT_LIST_HEAD(&ua->ready_playback_urbs); + spin_unlock_irq(&ua->lock); + + /* + * We submit the initial URBs all at once, so we have to wait for the + * packet size FIFO to be full. + */ + wait_event(ua->rate_feedback_wait, + ua->rate_feedback_count >= ua->playback.queue_length || + !test_bit(USB_CAPTURE_RUNNING, &ua->states) || + test_bit(DISCONNECTED, &ua->states)); + if (test_bit(DISCONNECTED, &ua->states)) { + stop_usb_playback(ua); + return -ENODEV; + } + if (!test_bit(USB_CAPTURE_RUNNING, &ua->states)) { + stop_usb_playback(ua); + return -EIO; + } + + for (i = 0; i < ua->playback.queue_length; ++i) { + /* all initial URBs contain silence */ + spin_lock_irq(&ua->lock); + frames = ua->rate_feedback[ua->rate_feedback_start]; + add_with_wraparound(ua, &ua->rate_feedback_start, 1); + ua->rate_feedback_count--; + spin_unlock_irq(&ua->lock); + urb = &ua->playback.urbs[i]->urb; + urb->iso_frame_desc[0].length = + frames * ua->playback.frame_bytes; + memset(urb->transfer_buffer, 0, + urb->iso_frame_desc[0].length); + } + + set_bit(USB_PLAYBACK_RUNNING, &ua->states); + err = submit_stream_urbs(ua, &ua->playback); + if (err < 0) + stop_usb_playback(ua); + return err; +} + +static void abort_alsa_capture(struct ua101 *ua) +{ + if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) + snd_pcm_stop(ua->capture.substream, SNDRV_PCM_STATE_XRUN); +} + +static void abort_alsa_playback(struct ua101 *ua) +{ + if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) + snd_pcm_stop(ua->playback.substream, SNDRV_PCM_STATE_XRUN); +} + +static int set_stream_hw(struct ua101 *ua, struct snd_pcm_substream *substream, + unsigned int channels) +{ + int err; + + substream->runtime->hw.info = + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_FIFO_IN_FRAMES; + substream->runtime->hw.formats = ua->format_bit; + substream->runtime->hw.rates = snd_pcm_rate_to_rate_bit(ua->rate); + substream->runtime->hw.rate_min = ua->rate; + substream->runtime->hw.rate_max = ua->rate; + substream->runtime->hw.channels_min = channels; + substream->runtime->hw.channels_max = channels; + substream->runtime->hw.buffer_bytes_max = 45000 * 1024; + substream->runtime->hw.period_bytes_min = 1; + substream->runtime->hw.period_bytes_max = UINT_MAX; + substream->runtime->hw.periods_min = 2; + substream->runtime->hw.periods_max = UINT_MAX; + err = snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIOD_TIME, + 1500000 / ua->packets_per_second, + 8192000); + if (err < 0) + return err; + err = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24); + return err; +} + +static int capture_pcm_open(struct snd_pcm_substream *substream) +{ + struct ua101 *ua = substream->private_data; + int err; + + ua->capture.substream = substream; + err = set_stream_hw(ua, substream, ua->capture.channels); + if (err < 0) + return err; + substream->runtime->hw.fifo_size = + DIV_ROUND_CLOSEST(ua->rate, ua->packets_per_second); + substream->runtime->delay = substream->runtime->hw.fifo_size; + + mutex_lock(&ua->mutex); + err = start_usb_capture(ua); + if (err >= 0) + set_bit(ALSA_CAPTURE_OPEN, &ua->states); + mutex_unlock(&ua->mutex); + return err; +} + +static int playback_pcm_open(struct snd_pcm_substream *substream) +{ + struct ua101 *ua = substream->private_data; + int err; + + ua->playback.substream = substream; + err = set_stream_hw(ua, substream, ua->playback.channels); + if (err < 0) + return err; + substream->runtime->hw.fifo_size = + DIV_ROUND_CLOSEST(ua->rate * ua->playback.queue_length, + ua->packets_per_second); + + mutex_lock(&ua->mutex); + err = start_usb_capture(ua); + if (err < 0) + goto error; + err = start_usb_playback(ua); + if (err < 0) { + if (!test_bit(ALSA_CAPTURE_OPEN, &ua->states)) + stop_usb_capture(ua); + goto error; + } + set_bit(ALSA_PLAYBACK_OPEN, &ua->states); +error: + mutex_unlock(&ua->mutex); + return err; +} + +static int capture_pcm_close(struct snd_pcm_substream *substream) +{ + struct ua101 *ua = substream->private_data; + + mutex_lock(&ua->mutex); + clear_bit(ALSA_CAPTURE_OPEN, &ua->states); + if (!test_bit(ALSA_PLAYBACK_OPEN, &ua->states)) + stop_usb_capture(ua); + mutex_unlock(&ua->mutex); + return 0; +} + +static int playback_pcm_close(struct snd_pcm_substream *substream) +{ + struct ua101 *ua = substream->private_data; + + mutex_lock(&ua->mutex); + stop_usb_playback(ua); + clear_bit(ALSA_PLAYBACK_OPEN, &ua->states); + if (!test_bit(ALSA_CAPTURE_OPEN, &ua->states)) + stop_usb_capture(ua); + mutex_unlock(&ua->mutex); + return 0; +} + +static int capture_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct ua101 *ua = substream->private_data; + int err; + + mutex_lock(&ua->mutex); + err = start_usb_capture(ua); + mutex_unlock(&ua->mutex); + if (err < 0) + return err; + + return snd_pcm_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); +} + +static int playback_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct ua101 *ua = substream->private_data; + int err; + + mutex_lock(&ua->mutex); + err = start_usb_capture(ua); + if (err >= 0) + err = start_usb_playback(ua); + mutex_unlock(&ua->mutex); + if (err < 0) + return err; + + return snd_pcm_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); +} + +static int ua101_pcm_hw_free(struct snd_pcm_substream *substream) +{ + snd_pcm_free_vmalloc_buffer(substream); + return 0; +} + +static int capture_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct ua101 *ua = substream->private_data; + int err; + + mutex_lock(&ua->mutex); + err = start_usb_capture(ua); + mutex_unlock(&ua->mutex); + if (err < 0) + return err; + + /* + * The EHCI driver schedules the first packet of an iso stream at 10 ms + * in the future, i.e., no data is actually captured for that long. + * Take the wait here so that the stream is known to be actually + * running when the start trigger has been called. + */ + wait_event(ua->alsa_capture_wait, + test_bit(CAPTURE_URB_COMPLETED, &ua->states) || + !test_bit(USB_CAPTURE_RUNNING, &ua->states)); + if (test_bit(DISCONNECTED, &ua->states)) + return -ENODEV; + if (!test_bit(USB_CAPTURE_RUNNING, &ua->states)) + return -EIO; + + ua->capture.period_pos = 0; + ua->capture.buffer_pos = 0; + return 0; +} + +static int playback_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct ua101 *ua = substream->private_data; + int err; + + mutex_lock(&ua->mutex); + err = start_usb_capture(ua); + if (err >= 0) + err = start_usb_playback(ua); + mutex_unlock(&ua->mutex); + if (err < 0) + return err; + + /* see the comment in capture_pcm_prepare() */ + wait_event(ua->alsa_playback_wait, + test_bit(PLAYBACK_URB_COMPLETED, &ua->states) || + !test_bit(USB_PLAYBACK_RUNNING, &ua->states)); + if (test_bit(DISCONNECTED, &ua->states)) + return -ENODEV; + if (!test_bit(USB_PLAYBACK_RUNNING, &ua->states)) + return -EIO; + + substream->runtime->delay = 0; + ua->playback.period_pos = 0; + ua->playback.buffer_pos = 0; + return 0; +} + +static int capture_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct ua101 *ua = substream->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (!test_bit(USB_CAPTURE_RUNNING, &ua->states)) + return -EIO; + set_bit(ALSA_CAPTURE_RUNNING, &ua->states); + return 0; + case SNDRV_PCM_TRIGGER_STOP: + clear_bit(ALSA_CAPTURE_RUNNING, &ua->states); + return 0; + default: + return -EINVAL; + } +} + +static int playback_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct ua101 *ua = substream->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (!test_bit(USB_PLAYBACK_RUNNING, &ua->states)) + return -EIO; + set_bit(ALSA_PLAYBACK_RUNNING, &ua->states); + return 0; + case SNDRV_PCM_TRIGGER_STOP: + clear_bit(ALSA_PLAYBACK_RUNNING, &ua->states); + return 0; + default: + return -EINVAL; + } +} + +static inline snd_pcm_uframes_t ua101_pcm_pointer(struct ua101 *ua, + struct ua101_stream *stream) +{ + unsigned long flags; + unsigned int pos; + + spin_lock_irqsave(&ua->lock, flags); + pos = stream->buffer_pos; + spin_unlock_irqrestore(&ua->lock, flags); + return pos; +} + +static snd_pcm_uframes_t capture_pcm_pointer(struct snd_pcm_substream *subs) +{ + struct ua101 *ua = subs->private_data; + + return ua101_pcm_pointer(ua, &ua->capture); +} + +static snd_pcm_uframes_t playback_pcm_pointer(struct snd_pcm_substream *subs) +{ + struct ua101 *ua = subs->private_data; + + return ua101_pcm_pointer(ua, &ua->playback); +} + +static struct snd_pcm_ops capture_pcm_ops = { + .open = capture_pcm_open, + .close = capture_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = capture_pcm_hw_params, + .hw_free = ua101_pcm_hw_free, + .prepare = capture_pcm_prepare, + .trigger = capture_pcm_trigger, + .pointer = capture_pcm_pointer, + .page = snd_pcm_get_vmalloc_page, +}; + +static struct snd_pcm_ops playback_pcm_ops = { + .open = playback_pcm_open, + .close = playback_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = playback_pcm_hw_params, + .hw_free = ua101_pcm_hw_free, + .prepare = playback_pcm_prepare, + .trigger = playback_pcm_trigger, + .pointer = playback_pcm_pointer, + .page = snd_pcm_get_vmalloc_page, +}; + +static const struct uac_format_type_i_discrete_descriptor * +find_format_descriptor(struct usb_interface *interface) +{ + struct usb_host_interface *alt; + u8 *extra; + int extralen; + + if (interface->num_altsetting != 2) { + dev_err(&interface->dev, "invalid num_altsetting\n"); + return NULL; + } + + alt = &interface->altsetting[0]; + if (alt->desc.bNumEndpoints != 0) { + dev_err(&interface->dev, "invalid bNumEndpoints\n"); + return NULL; + } + + alt = &interface->altsetting[1]; + if (alt->desc.bNumEndpoints != 1) { + dev_err(&interface->dev, "invalid bNumEndpoints\n"); + return NULL; + } + + extra = alt->extra; + extralen = alt->extralen; + while (extralen >= sizeof(struct usb_descriptor_header)) { + struct uac_format_type_i_discrete_descriptor *desc; + + desc = (struct uac_format_type_i_discrete_descriptor *)extra; + if (desc->bLength > extralen) { + dev_err(&interface->dev, "descriptor overflow\n"); + return NULL; + } + if (desc->bLength == UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1) && + desc->bDescriptorType == USB_DT_CS_INTERFACE && + desc->bDescriptorSubtype == UAC_FORMAT_TYPE) { + if (desc->bFormatType != UAC_FORMAT_TYPE_I_PCM || + desc->bSamFreqType != 1) { + dev_err(&interface->dev, + "invalid format type\n"); + return NULL; + } + return desc; + } + extralen -= desc->bLength; + extra += desc->bLength; + } + dev_err(&interface->dev, "sample format descriptor not found\n"); + return NULL; +} + +static int detect_usb_format(struct ua101 *ua) +{ + const struct uac_format_type_i_discrete_descriptor *fmt_capture; + const struct uac_format_type_i_discrete_descriptor *fmt_playback; + const struct usb_endpoint_descriptor *epd; + unsigned int rate2; + + fmt_capture = find_format_descriptor(ua->intf[INTF_CAPTURE]); + fmt_playback = find_format_descriptor(ua->intf[INTF_PLAYBACK]); + if (!fmt_capture || !fmt_playback) + return -ENXIO; + + switch (fmt_capture->bSubframeSize) { + case 3: + ua->format_bit = SNDRV_PCM_FMTBIT_S24_3LE; + break; + case 4: + ua->format_bit = SNDRV_PCM_FMTBIT_S32_LE; + break; + default: + dev_err(&ua->dev->dev, "sample width is not 24 or 32 bits\n"); + return -ENXIO; + } + if (fmt_capture->bSubframeSize != fmt_playback->bSubframeSize) { + dev_err(&ua->dev->dev, + "playback/capture sample widths do not match\n"); + return -ENXIO; + } + + if (fmt_capture->bBitResolution != 24 || + fmt_playback->bBitResolution != 24) { + dev_err(&ua->dev->dev, "sample width is not 24 bits\n"); + return -ENXIO; + } + + ua->rate = combine_triple(fmt_capture->tSamFreq[0]); + rate2 = combine_triple(fmt_playback->tSamFreq[0]); + if (ua->rate != rate2) { + dev_err(&ua->dev->dev, + "playback/capture rates do not match: %u/%u\n", + rate2, ua->rate); + return -ENXIO; + } + + switch (ua->dev->speed) { + case USB_SPEED_FULL: + ua->packets_per_second = 1000; + break; + case USB_SPEED_HIGH: + ua->packets_per_second = 8000; + break; + default: + dev_err(&ua->dev->dev, "unknown device speed\n"); + return -ENXIO; + } + + ua->capture.channels = fmt_capture->bNrChannels; + ua->playback.channels = fmt_playback->bNrChannels; + ua->capture.frame_bytes = + fmt_capture->bSubframeSize * ua->capture.channels; + ua->playback.frame_bytes = + fmt_playback->bSubframeSize * ua->playback.channels; + + epd = &ua->intf[INTF_CAPTURE]->altsetting[1].endpoint[0].desc; + if (!usb_endpoint_is_isoc_in(epd)) { + dev_err(&ua->dev->dev, "invalid capture endpoint\n"); + return -ENXIO; + } + ua->capture.usb_pipe = usb_rcvisocpipe(ua->dev, usb_endpoint_num(epd)); + ua->capture.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize); + + epd = &ua->intf[INTF_PLAYBACK]->altsetting[1].endpoint[0].desc; + if (!usb_endpoint_is_isoc_out(epd)) { + dev_err(&ua->dev->dev, "invalid playback endpoint\n"); + return -ENXIO; + } + ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, usb_endpoint_num(epd)); + ua->playback.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize); + return 0; +} + +static int alloc_stream_buffers(struct ua101 *ua, struct ua101_stream *stream) +{ + unsigned int remaining_packets, packets, packets_per_page, i; + size_t size; + + stream->queue_length = queue_length; + stream->queue_length = max(stream->queue_length, + (unsigned int)MIN_QUEUE_LENGTH); + stream->queue_length = min(stream->queue_length, + (unsigned int)MAX_QUEUE_LENGTH); + + /* + * The cache pool sizes used by usb_buffer_alloc() (128, 512, 2048) are + * quite bad when used with the packet sizes of this device (e.g. 280, + * 520, 624). Therefore, we allocate and subdivide entire pages, using + * a smaller buffer only for the last chunk. + */ + remaining_packets = stream->queue_length; + packets_per_page = PAGE_SIZE / stream->max_packet_bytes; + for (i = 0; i < ARRAY_SIZE(stream->buffers); ++i) { + packets = min(remaining_packets, packets_per_page); + size = packets * stream->max_packet_bytes; + stream->buffers[i].addr = + usb_buffer_alloc(ua->dev, size, GFP_KERNEL, + &stream->buffers[i].dma); + if (!stream->buffers[i].addr) + return -ENOMEM; + stream->buffers[i].size = size; + remaining_packets -= packets; + if (!remaining_packets) + break; + } + if (remaining_packets) { + dev_err(&ua->dev->dev, "too many packets\n"); + return -ENXIO; + } + return 0; +} + +static void free_stream_buffers(struct ua101 *ua, struct ua101_stream *stream) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(stream->buffers); ++i) + usb_buffer_free(ua->dev, + stream->buffers[i].size, + stream->buffers[i].addr, + stream->buffers[i].dma); +} + +static int alloc_stream_urbs(struct ua101 *ua, struct ua101_stream *stream, + void (*urb_complete)(struct urb *)) +{ + unsigned max_packet_size = stream->max_packet_bytes; + struct ua101_urb *urb; + unsigned int b, u = 0; + + for (b = 0; b < ARRAY_SIZE(stream->buffers); ++b) { + unsigned int size = stream->buffers[b].size; + u8 *addr = stream->buffers[b].addr; + dma_addr_t dma = stream->buffers[b].dma; + + while (size >= max_packet_size) { + if (u >= stream->queue_length) + goto bufsize_error; + urb = kmalloc(sizeof(*urb), GFP_KERNEL); + if (!urb) + return -ENOMEM; + usb_init_urb(&urb->urb); + urb->urb.dev = ua->dev; + urb->urb.pipe = stream->usb_pipe; + urb->urb.transfer_flags = URB_ISO_ASAP | + URB_NO_TRANSFER_DMA_MAP; + urb->urb.transfer_buffer = addr; + urb->urb.transfer_dma = dma; + urb->urb.transfer_buffer_length = max_packet_size; + urb->urb.number_of_packets = 1; + urb->urb.interval = 1; + urb->urb.context = ua; + urb->urb.complete = urb_complete; + urb->urb.iso_frame_desc[0].offset = 0; + urb->urb.iso_frame_desc[0].length = max_packet_size; + stream->urbs[u++] = urb; + size -= max_packet_size; + addr += max_packet_size; + dma += max_packet_size; + } + } + if (u == stream->queue_length) + return 0; +bufsize_error: + dev_err(&ua->dev->dev, "internal buffer size error\n"); + return -ENXIO; +} + +static void free_stream_urbs(struct ua101_stream *stream) +{ + unsigned int i; + + for (i = 0; i < stream->queue_length; ++i) + kfree(stream->urbs[i]); +} + +static void free_usb_related_resources(struct ua101 *ua, + struct usb_interface *interface) +{ + unsigned int i; + + free_stream_urbs(&ua->capture); + free_stream_urbs(&ua->playback); + free_stream_buffers(ua, &ua->capture); + free_stream_buffers(ua, &ua->playback); + + for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) + if (ua->intf[i]) { + usb_set_intfdata(ua->intf[i], NULL); + if (ua->intf[i] != interface) + usb_driver_release_interface(&ua101_driver, + ua->intf[i]); + } +} + +static void ua101_card_free(struct snd_card *card) +{ + struct ua101 *ua = card->private_data; + + mutex_destroy(&ua->mutex); +} + +static int ua101_probe(struct usb_interface *interface, + const struct usb_device_id *usb_id) +{ + static const struct snd_usb_midi_endpoint_info midi_ep = { + .out_cables = 0x0001, + .in_cables = 0x0001 + }; + static const struct snd_usb_audio_quirk midi_quirk = { + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = &midi_ep + }; + struct snd_card *card; + struct ua101 *ua; + unsigned int card_index, i; + char usb_path[32]; + int err; + + if (interface->altsetting->desc.bInterfaceNumber != 0) + return -ENODEV; + + mutex_lock(&devices_mutex); + + for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) + if (enable[card_index] && !(devices_used & (1 << card_index))) + break; + if (card_index >= SNDRV_CARDS) { + mutex_unlock(&devices_mutex); + return -ENOENT; + } + err = snd_card_create(index[card_index], id[card_index], THIS_MODULE, + sizeof(*ua), &card); + if (err < 0) { + mutex_unlock(&devices_mutex); + return err; + } + card->private_free = ua101_card_free; + ua = card->private_data; + ua->dev = interface_to_usbdev(interface); + ua->card = card; + ua->card_index = card_index; + INIT_LIST_HEAD(&ua->midi_list); + spin_lock_init(&ua->lock); + mutex_init(&ua->mutex); + INIT_LIST_HEAD(&ua->ready_playback_urbs); + tasklet_init(&ua->playback_tasklet, + playback_tasklet, (unsigned long)ua); + init_waitqueue_head(&ua->alsa_capture_wait); + init_waitqueue_head(&ua->rate_feedback_wait); + init_waitqueue_head(&ua->alsa_playback_wait); + +#ifdef UA1A_HACK + if (ua->dev->descriptor.idProduct == cpu_to_le16(0x0018)) { + ua->intf[2] = interface; + ua->intf[0] = usb_ifnum_to_if(ua->dev, 1); + ua->intf[1] = usb_ifnum_to_if(ua->dev, 2); + usb_driver_claim_interface(&ua101_driver, ua->intf[0], ua); + usb_driver_claim_interface(&ua101_driver, ua->intf[1], ua); + } else { +#endif + ua->intf[0] = interface; + for (i = 1; i < ARRAY_SIZE(ua->intf); ++i) { + ua->intf[i] = usb_ifnum_to_if(ua->dev, i); + if (!ua->intf[i]) { + dev_err(&ua->dev->dev, "interface %u not found\n", i); + err = -ENXIO; + goto probe_error; + } + err = usb_driver_claim_interface(&ua101_driver, + ua->intf[i], ua); + if (err < 0) { + ua->intf[i] = NULL; + err = -EBUSY; + goto probe_error; + } + } +#ifdef UA1A_HACK + } +#endif + + snd_card_set_dev(card, &interface->dev); + +#ifdef UA1A_HACK + if (ua->dev->descriptor.idProduct == cpu_to_le16(0x0018)) { + ua->format_bit = SNDRV_PCM_FMTBIT_S16_LE; + ua->rate = 44100; + ua->packets_per_second = 1000; + ua->capture.channels = 2; + ua->playback.channels = 2; + ua->capture.frame_bytes = 4; + ua->playback.frame_bytes = 4; + ua->capture.usb_pipe = usb_rcvisocpipe(ua->dev, 2); + ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, 1); + ua->capture.max_packet_bytes = 192; + ua->playback.max_packet_bytes = 192; + } else { +#endif + err = detect_usb_format(ua); + if (err < 0) + goto probe_error; +#ifdef UA1A_HACK + } +#endif + + strcpy(card->driver, "UA-101"); + strcpy(card->shortname, "UA-101"); + usb_make_path(ua->dev, usb_path, sizeof(usb_path)); + snprintf(ua->card->longname, sizeof(ua->card->longname), + "EDIROL UA-101 (serial %s), %u Hz at %s, %s speed", + ua->dev->serial ? ua->dev->serial : "?", ua->rate, usb_path, + ua->dev->speed == USB_SPEED_HIGH ? "high" : "full"); + + err = alloc_stream_buffers(ua, &ua->capture); + if (err < 0) + goto probe_error; + err = alloc_stream_buffers(ua, &ua->playback); + if (err < 0) + goto probe_error; + + err = alloc_stream_urbs(ua, &ua->capture, capture_urb_complete); + if (err < 0) + goto probe_error; + err = alloc_stream_urbs(ua, &ua->playback, playback_urb_complete); + if (err < 0) + goto probe_error; + + err = snd_pcm_new(card, "UA-101", 0, 1, 1, &ua->pcm); + if (err < 0) + goto probe_error; + ua->pcm->private_data = ua; + strcpy(ua->pcm->name, "UA-101"); + snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_pcm_ops); + snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_pcm_ops); + +#ifdef UA1A_HACK + if (ua->dev->descriptor.idProduct != cpu_to_le16(0x0018)) { +#endif + err = snd_usbmidi_create(card, ua->intf[INTF_MIDI], + &ua->midi_list, &midi_quirk); + if (err < 0) + goto probe_error; +#ifdef UA1A_HACK + } +#endif + + err = snd_card_register(card); + if (err < 0) + goto probe_error; + + usb_set_intfdata(interface, ua); + devices_used |= 1 << card_index; + + mutex_unlock(&devices_mutex); + return 0; + +probe_error: + free_usb_related_resources(ua, interface); + snd_card_free(card); + mutex_unlock(&devices_mutex); + return err; +} + +static void ua101_disconnect(struct usb_interface *interface) +{ + struct ua101 *ua = usb_get_intfdata(interface); + struct list_head *midi; + + if (!ua) + return; + + mutex_lock(&devices_mutex); + + set_bit(DISCONNECTED, &ua->states); + wake_up(&ua->rate_feedback_wait); + + /* make sure that userspace cannot create new requests */ + snd_card_disconnect(ua->card); + + /* make sure that there are no pending USB requests */ + __list_for_each(midi, &ua->midi_list) + snd_usbmidi_disconnect(midi); + abort_alsa_playback(ua); + abort_alsa_capture(ua); + mutex_lock(&ua->mutex); + stop_usb_playback(ua); + stop_usb_capture(ua); + mutex_unlock(&ua->mutex); + + free_usb_related_resources(ua, interface); + + devices_used &= ~(1 << ua->card_index); + + snd_card_free_when_closed(ua->card); + + mutex_unlock(&devices_mutex); +} + +static struct usb_device_id ua101_ids[] = { +#ifdef UA1A_HACK + { USB_DEVICE(0x0582, 0x0018) }, +#endif + { USB_DEVICE(0x0582, 0x007d) }, + { USB_DEVICE(0x0582, 0x008d) }, + { } +}; +MODULE_DEVICE_TABLE(usb, ua101_ids); + +static struct usb_driver ua101_driver = { + .name = "snd-ua101", + .id_table = ua101_ids, + .probe = ua101_probe, + .disconnect = ua101_disconnect, +#if 0 + .suspend = ua101_suspend, + .resume = ua101_resume, +#endif +}; + +static int __init alsa_card_ua101_init(void) +{ + return usb_register(&ua101_driver); +} + +static void __exit alsa_card_ua101_exit(void) +{ + usb_deregister(&ua101_driver); + mutex_destroy(&devices_mutex); +} + +module_init(alsa_card_ua101_init); +module_exit(alsa_card_ua101_exit); diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index b074a59..f352141 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -3142,59 +3142,6 @@ static int create_ua1000_quirk(struct snd_usb_audio *chip, return 0; } -/* - * Create a stream for an Edirol UA-101 interface. - * Copy, paste and modify from Edirol UA-1000 - */ -static int create_ua101_quirk(struct snd_usb_audio *chip, - struct usb_interface *iface, - const struct snd_usb_audio_quirk *quirk) -{ - static const struct audioformat ua101_format = { - .format = SNDRV_PCM_FORMAT_S32_LE, - .fmt_type = USB_FORMAT_TYPE_I, - .altsetting = 1, - .altset_idx = 1, - .attributes = 0, - .rates = SNDRV_PCM_RATE_CONTINUOUS, - }; - struct usb_host_interface *alts; - struct usb_interface_descriptor *altsd; - struct audioformat *fp; - int stream, err; - - if (iface->num_altsetting != 2) - return -ENXIO; - alts = &iface->altsetting[1]; - altsd = get_iface_desc(alts); - if (alts->extralen != 18 || alts->extra[1] != USB_DT_CS_INTERFACE || - altsd->bNumEndpoints != 1) - return -ENXIO; - - fp = kmemdup(&ua101_format, sizeof(*fp), GFP_KERNEL); - if (!fp) - return -ENOMEM; - - fp->channels = alts->extra[11]; - fp->iface = altsd->bInterfaceNumber; - fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; - fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; - fp->datainterval = parse_datainterval(chip, alts); - fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); - fp->rate_max = fp->rate_min = combine_triple(&alts->extra[15]); - - stream = (fp->endpoint & USB_DIR_IN) - ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; - err = add_audio_endpoint(chip, stream, fp); - if (err < 0) { - kfree(fp); - return err; - } - /* FIXME: playback must be synchronized to capture */ - usb_set_interface(chip->dev, fp->iface, 0); - return 0; -} - static int snd_usb_create_quirk(struct snd_usb_audio *chip, struct usb_interface *iface, const struct snd_usb_audio_quirk *quirk); @@ -3406,7 +3353,6 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip, [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, - [QUIRK_AUDIO_EDIROL_UA101] = create_ua101_quirk, [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk }; diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 40ba811..9826337 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -159,7 +159,6 @@ enum quirk_type { QUIRK_AUDIO_STANDARD_INTERFACE, QUIRK_AUDIO_FIXED_ENDPOINT, QUIRK_AUDIO_EDIROL_UA1000, - QUIRK_AUDIO_EDIROL_UA101, QUIRK_AUDIO_EDIROL_UAXX, QUIRK_TYPE_COUNT diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index a892bda..bd6706c 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -1266,37 +1266,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, -/* Roland UA-101 in High-Speed Mode only */ -{ - USB_DEVICE(0x0582, 0x007d), - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .vendor_name = "Roland", - .product_name = "UA-101", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_COMPOSITE, - .data = (const struct snd_usb_audio_quirk[]) { - { - .ifnum = 0, - .type = QUIRK_AUDIO_EDIROL_UA101 - }, - { - .ifnum = 1, - .type = QUIRK_AUDIO_EDIROL_UA101 - }, - { - .ifnum = 2, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const struct snd_usb_midi_endpoint_info) { - .out_cables = 0x0001, - .in_cables = 0x0001 - } - }, - { - .ifnum = -1 - } - } - } -}, { /* has ID 0x0081 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0080), -- cgit v0.10.2 From 6c941c8556dd9269be621cd8159fc60e955a91b3 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 16 Dec 2009 16:15:00 +0100 Subject: ALSA: Release v1.0.22 Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai diff --git a/include/sound/version.h b/include/sound/version.h index 2293914..1f5d4872 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h */ -#define CONFIG_SND_VERSION "1.0.21" +#define CONFIG_SND_VERSION "1.0.22" #define CONFIG_SND_DATE "" -- cgit v0.10.2 From 681b84e17747e1c208e8e1acc54cc5e612da84d1 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 18 Dec 2009 09:29:00 +0100 Subject: sound: pcm: add vmalloc buffer helper functions There are now five copies of the code to allocate a PCM buffer using vmalloc(). Add a sixth in the core so that the others can be removed. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/include/sound/pcm.h b/include/sound/pcm.h index c83a4a7..0ad2d28 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -905,6 +905,44 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size); int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream); +int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream, + size_t size, gfp_t gfp_flags); +int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream); +struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream, + unsigned long offset); +#if 0 /* for kernel-doc */ +/** + * snd_pcm_lib_alloc_vmalloc_buffer - allocate virtual DMA buffer + * @substream: the substream to allocate the buffer to + * @size: the requested buffer size, in bytes + * + * Allocates the PCM substream buffer using vmalloc(), i.e., the memory is + * contiguous in kernel virtual space, but not in physical memory. Use this + * if the buffer is accessed by kernel code but not by device DMA. + * + * Returns 1 if the buffer was changed, 0 if not changed, or a negative error + * code. + */ +static int snd_pcm_lib_alloc_vmalloc_buffer + (struct snd_pcm_substream *substream, size_t size); +/** + * snd_pcm_lib_alloc_vmalloc_32_buffer - allocate 32-bit-addressable buffer + * @substream: the substream to allocate the buffer to + * @size: the requested buffer size, in bytes + * + * This function works like snd_pcm_lib_alloc_vmalloc_buffer(), but uses + * vmalloc_32(), i.e., the pages are allocated from 32-bit-addressable memory. + */ +static int snd_pcm_lib_alloc_vmalloc_32_buffer + (struct snd_pcm_substream *substream, size_t size); +#endif +#define snd_pcm_lib_alloc_vmalloc_buffer(subs, size) \ + _snd_pcm_lib_alloc_vmalloc_buffer \ + (subs, size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO) +#define snd_pcm_lib_alloc_vmalloc_32_buffer(subs, size) \ + _snd_pcm_lib_alloc_vmalloc_buffer \ + (subs, size, GFP_KERNEL | GFP_DMA32 | __GFP_ZERO) + #ifdef CONFIG_SND_DMA_SGBUF /* * SG-buffer handling diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index caa7796..d9727c7 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -434,3 +434,57 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream) } EXPORT_SYMBOL(snd_pcm_lib_free_pages); + +int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream, + size_t size, gfp_t gfp_flags) +{ + struct snd_pcm_runtime *runtime; + + if (PCM_RUNTIME_CHECK(substream)) + return -EINVAL; + runtime = substream->runtime; + if (runtime->dma_area) { + if (runtime->dma_bytes >= size) + return 0; /* already large enough */ + vfree(runtime->dma_area); + } + runtime->dma_area = __vmalloc(size, gfp_flags, PAGE_KERNEL); + if (!runtime->dma_area) + return -ENOMEM; + runtime->dma_bytes = size; + return 1; +} +EXPORT_SYMBOL(_snd_pcm_lib_alloc_vmalloc_buffer); + +/** + * snd_pcm_lib_free_vmalloc_buffer - free vmalloc buffer + * @substream: the substream with a buffer allocated by + * snd_pcm_lib_alloc_vmalloc_buffer() + */ +int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime; + + if (PCM_RUNTIME_CHECK(substream)) + return -EINVAL; + runtime = substream->runtime; + vfree(runtime->dma_area); + runtime->dma_area = NULL; + return 0; +} +EXPORT_SYMBOL(snd_pcm_lib_free_vmalloc_buffer); + +/** + * snd_pcm_lib_get_vmalloc_page - map vmalloc buffer offset to page struct + * @substream: the substream with a buffer allocated by + * snd_pcm_lib_alloc_vmalloc_buffer() + * @offset: offset in the buffer + * + * This function is to be used as the page callback in the PCM ops. + */ +struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream, + unsigned long offset) +{ + return vmalloc_to_page(substream->runtime->dma_area + offset); +} +EXPORT_SYMBOL(snd_pcm_lib_get_vmalloc_page); -- cgit v0.10.2 From d20fb5dc076a4cf0fdd00ab5a4e752ea3611e484 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 18 Dec 2009 09:29:49 +0100 Subject: sound: pdaudiocf: use vmalloc buffer helper functions Remove this duplicate of snd_pcm_alloc_vmalloc_buffer and use the equivalent core functions instead. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c index 5cfa608..0afa683 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c @@ -21,7 +21,6 @@ */ #include -#include #include #include #include @@ -29,49 +28,6 @@ /* - * we use a vmalloc'ed (sg-)buffer - */ - -/* get the physical page pointer on the given offset */ -static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, unsigned long offset) -{ - void *pageptr = subs->runtime->dma_area + offset; - return vmalloc_to_page(pageptr); -} - -/* - * hw_params callback - * NOTE: this may be called not only once per pcm open! - */ -static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - if (runtime->dma_area) { - if (runtime->dma_bytes >= size) - return 0; /* already enough large */ - vfree(runtime->dma_area); - } - runtime->dma_area = vmalloc_32_user(size); - if (! runtime->dma_area) - return -ENOMEM; - runtime->dma_bytes = size; - return 0; -} - -/* - * hw_free callback - * NOTE: this may be called not only once per pcm open! - */ -static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - - vfree(runtime->dma_area); - runtime->dma_area = NULL; - return 0; -} - -/* * clear the SRAM contents */ static int pdacf_pcm_clear_sram(struct snd_pdacf *chip) @@ -147,7 +103,8 @@ static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd) static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs, struct snd_pcm_hw_params *hw_params) { - return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params)); + return snd_pcm_lib_alloc_vmalloc_32_buffer + (subs, params_buffer_bytes(hw_params)); } /* @@ -155,7 +112,7 @@ static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs, */ static int pdacf_pcm_hw_free(struct snd_pcm_substream *subs) { - return snd_pcm_free_vmalloc_buffer(subs); + return snd_pcm_lib_free_vmalloc_buffer(subs); } /* @@ -319,7 +276,7 @@ static struct snd_pcm_ops pdacf_pcm_capture_ops = { .prepare = pdacf_pcm_prepare, .trigger = pdacf_pcm_trigger, .pointer = pdacf_pcm_capture_pointer, - .page = snd_pcm_get_vmalloc_page, + .page = snd_pcm_lib_get_vmalloc_page, }; -- cgit v0.10.2 From 6cedf8696d6a01bba391bdae06231243cfe2f48a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 18 Dec 2009 09:30:24 +0100 Subject: sound: sgio2audio: use vmalloc buffer helper functions Remove this duplicate of snd_pcm_alloc_vmalloc_buffer and use the equivalent core functions instead. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index f1d9d16..9b486be 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -603,25 +602,14 @@ static int snd_sgio2audio_pcm_close(struct snd_pcm_substream *substream) static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { - struct snd_pcm_runtime *runtime = substream->runtime; - int size = params_buffer_bytes(hw_params); - - /* alloc virtual 'dma' area */ - if (runtime->dma_area) - vfree(runtime->dma_area); - runtime->dma_area = vmalloc_user(size); - if (runtime->dma_area == NULL) - return -ENOMEM; - runtime->dma_bytes = size; - return 0; + return snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); } /* hw_free callback */ static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream) { - vfree(substream->runtime->dma_area); - substream->runtime->dma_area = NULL; - return 0; + return snd_pcm_lib_free_vmalloc_buffer(substream); } /* prepare callback */ @@ -692,13 +680,6 @@ snd_sgio2audio_pcm_pointer(struct snd_pcm_substream *substream) chip->channel[chan->idx].pos); } -/* get the physical page pointer on the given offset */ -static struct page *snd_sgio2audio_page(struct snd_pcm_substream *substream, - unsigned long offset) -{ - return vmalloc_to_page(substream->runtime->dma_area + offset); -} - /* operators */ static struct snd_pcm_ops snd_sgio2audio_playback1_ops = { .open = snd_sgio2audio_playback1_open, @@ -709,7 +690,7 @@ static struct snd_pcm_ops snd_sgio2audio_playback1_ops = { .prepare = snd_sgio2audio_pcm_prepare, .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, - .page = snd_sgio2audio_page, + .page = snd_pcm_lib_get_vmalloc_page, }; static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { @@ -721,7 +702,7 @@ static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { .prepare = snd_sgio2audio_pcm_prepare, .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, - .page = snd_sgio2audio_page, + .page = snd_pcm_lib_get_vmalloc_page, }; static struct snd_pcm_ops snd_sgio2audio_capture_ops = { @@ -733,7 +714,7 @@ static struct snd_pcm_ops snd_sgio2audio_capture_ops = { .prepare = snd_sgio2audio_pcm_prepare, .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, - .page = snd_sgio2audio_page, + .page = snd_pcm_lib_get_vmalloc_page, }; /* -- cgit v0.10.2 From 149feef54bf543448dd4ec5820ef8ae178021c3a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 18 Dec 2009 09:30:55 +0100 Subject: sound: vx: use vmalloc buffer helper functions Remove this duplicate of snd_pcm_alloc_vmalloc_buffer and use the equivalent core functions instead. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 6644d00..c8385d2 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -46,7 +46,6 @@ */ #include -#include #include #include #include @@ -56,55 +55,6 @@ /* - * we use a vmalloc'ed (sg-)buffer - */ - -/* get the physical page pointer on the given offset */ -static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, - unsigned long offset) -{ - void *pageptr = subs->runtime->dma_area + offset; - return vmalloc_to_page(pageptr); -} - -/* - * allocate a buffer via vmalloc_32(). - * called from hw_params - * NOTE: this may be called not only once per pcm open! - */ -static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - if (runtime->dma_area) { - /* already allocated */ - if (runtime->dma_bytes >= size) - return 0; /* already enough large */ - vfree(runtime->dma_area); - } - runtime->dma_area = vmalloc_32(size); - if (! runtime->dma_area) - return -ENOMEM; - memset(runtime->dma_area, 0, size); - runtime->dma_bytes = size; - return 1; /* changed */ -} - -/* - * free the buffer. - * called from hw_free callback - * NOTE: this may be called not only once per pcm open! - */ -static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - - vfree(runtime->dma_area); - runtime->dma_area = NULL; - return 0; -} - - -/* * read three pending pcm bytes via inb() */ static void vx_pcm_read_per_bytes(struct vx_core *chip, struct snd_pcm_runtime *runtime, @@ -865,7 +815,8 @@ static snd_pcm_uframes_t vx_pcm_playback_pointer(struct snd_pcm_substream *subs) static int vx_pcm_hw_params(struct snd_pcm_substream *subs, struct snd_pcm_hw_params *hw_params) { - return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params)); + return snd_pcm_lib_alloc_vmalloc_32_buffer + (subs, params_buffer_bytes(hw_params)); } /* @@ -873,7 +824,7 @@ static int vx_pcm_hw_params(struct snd_pcm_substream *subs, */ static int vx_pcm_hw_free(struct snd_pcm_substream *subs) { - return snd_pcm_free_vmalloc_buffer(subs); + return snd_pcm_lib_free_vmalloc_buffer(subs); } /* @@ -953,7 +904,7 @@ static struct snd_pcm_ops vx_pcm_playback_ops = { .prepare = vx_pcm_prepare, .trigger = vx_pcm_trigger, .pointer = vx_pcm_playback_pointer, - .page = snd_pcm_get_vmalloc_page, + .page = snd_pcm_lib_get_vmalloc_page, }; @@ -1173,7 +1124,7 @@ static struct snd_pcm_ops vx_pcm_capture_ops = { .prepare = vx_pcm_prepare, .trigger = vx_pcm_trigger, .pointer = vx_pcm_capture_pointer, - .page = snd_pcm_get_vmalloc_page, + .page = snd_pcm_lib_get_vmalloc_page, }; -- cgit v0.10.2 From c55675e348d9630c1ca69a190529bed1108c649d Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 18 Dec 2009 09:31:31 +0100 Subject: sound: usb-audio: use vmalloc buffer helper functions Remove this duplicate of snd_pcm_alloc_vmalloc_buffer and use the equivalent core functions instead. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index af8869a..31b63ea 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include @@ -735,41 +734,6 @@ static void snd_complete_sync_urb(struct urb *urb) } -/* get the physical page pointer at the given offset */ -static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, - unsigned long offset) -{ - void *pageptr = subs->runtime->dma_area + offset; - return vmalloc_to_page(pageptr); -} - -/* allocate virtual buffer; may be called more than once */ -static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - if (runtime->dma_area) { - if (runtime->dma_bytes >= size) - return 0; /* already large enough */ - vfree(runtime->dma_area); - } - runtime->dma_area = vmalloc_user(size); - if (!runtime->dma_area) - return -ENOMEM; - runtime->dma_bytes = size; - return 0; -} - -/* free virtual buffer; may be called more than once */ -static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - - vfree(runtime->dma_area); - runtime->dma_area = NULL; - return 0; -} - - /* * unlink active urbs. */ @@ -1449,8 +1413,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, unsigned int channels, rate, format; int ret, changed; - ret = snd_pcm_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); if (ret < 0) return ret; @@ -1507,7 +1471,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) subs->period_bytes = 0; if (!subs->stream->chip->shutdown) release_substream_urbs(subs, 0); - return snd_pcm_free_vmalloc_buffer(substream); + return snd_pcm_lib_free_vmalloc_buffer(substream); } /* @@ -1973,7 +1937,7 @@ static struct snd_pcm_ops snd_usb_playback_ops = { .prepare = snd_usb_pcm_prepare, .trigger = snd_usb_pcm_playback_trigger, .pointer = snd_usb_pcm_pointer, - .page = snd_pcm_get_vmalloc_page, + .page = snd_pcm_lib_get_vmalloc_page, }; static struct snd_pcm_ops snd_usb_capture_ops = { @@ -1985,7 +1949,7 @@ static struct snd_pcm_ops snd_usb_capture_ops = { .prepare = snd_usb_pcm_prepare, .trigger = snd_usb_pcm_capture_trigger, .pointer = snd_usb_pcm_pointer, - .page = snd_pcm_get_vmalloc_page, + .page = snd_pcm_lib_get_vmalloc_page, }; -- cgit v0.10.2 From 5b4b2a41a1a80f5560364b7ef001486cd8fb5230 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 18 Dec 2009 09:32:00 +0100 Subject: sound: ua101: use vmalloc buffer helper functions Remove this duplicate of snd_pcm_alloc_vmalloc_buffer and use the equivalent core functions instead. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/usb/ua101.c b/sound/usb/ua101.c index ab9f8a2..16dc7bd 100644 --- a/sound/usb/ua101.c +++ b/sound/usb/ua101.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -145,42 +144,6 @@ static struct usb_driver ua101_driver; static void abort_alsa_playback(struct ua101 *ua); static void abort_alsa_capture(struct ua101 *ua); -/* allocate virtual buffer; may be called more than once */ -static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, - size_t size) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - - if (runtime->dma_area) { - if (runtime->dma_bytes >= size) - return 0; /* already large enough */ - vfree(runtime->dma_area); - } - runtime->dma_area = vmalloc_user(size); - if (!runtime->dma_area) - return -ENOMEM; - runtime->dma_bytes = size; - return 0; -} - -/* free virtual buffer; may be called more than once */ -static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - - vfree(runtime->dma_area); - runtime->dma_area = NULL; - return 0; -} - -/* get the physical page pointer at the given offset */ -static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, - unsigned long offset) -{ - void *pageptr = subs->runtime->dma_area + offset; - return vmalloc_to_page(pageptr); -} - static const char *usb_error_string(int err) { switch (err) { @@ -791,8 +754,8 @@ static int capture_pcm_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; - return snd_pcm_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + return snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); } static int playback_pcm_hw_params(struct snd_pcm_substream *substream, @@ -809,14 +772,13 @@ static int playback_pcm_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; - return snd_pcm_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + return snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); } static int ua101_pcm_hw_free(struct snd_pcm_substream *substream) { - snd_pcm_free_vmalloc_buffer(substream); - return 0; + return snd_pcm_lib_free_vmalloc_buffer(substream); } static int capture_pcm_prepare(struct snd_pcm_substream *substream) @@ -948,7 +910,7 @@ static struct snd_pcm_ops capture_pcm_ops = { .prepare = capture_pcm_prepare, .trigger = capture_pcm_trigger, .pointer = capture_pcm_pointer, - .page = snd_pcm_get_vmalloc_page, + .page = snd_pcm_lib_get_vmalloc_page, }; static struct snd_pcm_ops playback_pcm_ops = { @@ -960,7 +922,7 @@ static struct snd_pcm_ops playback_pcm_ops = { .prepare = playback_pcm_prepare, .trigger = playback_pcm_trigger, .pointer = playback_pcm_pointer, - .page = snd_pcm_get_vmalloc_page, + .page = snd_pcm_lib_get_vmalloc_page, }; static const struct uac_format_type_i_discrete_descriptor * -- cgit v0.10.2 From ad8decb7f5dfd556e4a8400e37b127cd20d8e4c5 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sun, 20 Dec 2009 19:01:50 +0100 Subject: ALSA: jazz16: Add support for Media Vision Jazz16 chipset This is one of Sound Blaster Pro compatible chipsets which is supported by Linux OSS driver and was missing native supoort for ALSA. The Jazz16 audio codec is Crystal CS4216 which is capable of playback and recording up to 48 kHz stereo. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai diff --git a/include/sound/sb.h b/include/sound/sb.h index 4e62ee1..9535354 100644 --- a/include/sound/sb.h +++ b/include/sound/sb.h @@ -33,6 +33,7 @@ enum sb_hw_type { SB_HW_20, SB_HW_201, SB_HW_PRO, + SB_HW_JAZZ16, /* Media Vision Jazz16 */ SB_HW_16, SB_HW_16CSP, /* SB16 with CSP chip */ SB_HW_ALS100, /* Avance Logic ALS100 chip */ diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 194af3b0..755a0a5 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -239,6 +239,22 @@ config SND_INTERWAVE_STB To compile this driver as a module, choose M here: the module will be called snd-interwave-stb. +config SND_JAZZ16 + tristate "Media Vision Jazz16 card and compatibles" + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_SB8_DSP + help + Say Y here to include support for soundcards based on the + Media Vision Jazz16 chipset: digital chip MVD1216 (Jazz16), + codec MVA416 (CS4216) and mixer MVA514 (ICS2514). + Media Vision's Jazz16 cards were sold under names Pro Sonic 16, + Premium 3-D and Pro 3-D. There were also OEMs cards with the + Jazz16 chipset. + + To compile this driver as a module, choose M here: the module + will be called snd-jazz16. + config SND_OPL3SA2 tristate "Yamaha OPL3-SA2/SA3" select SND_OPL3_LIB diff --git a/sound/isa/sb/Makefile b/sound/isa/sb/Makefile index faeffceb..af36696 100644 --- a/sound/isa/sb/Makefile +++ b/sound/isa/sb/Makefile @@ -12,6 +12,7 @@ snd-sb16-objs := sb16.o snd-sbawe-objs := sbawe.o emu8000.o snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o snd-es968-objs := es968.o +snd-jazz16-objs := jazz16.o # Toplevel Module Dependency obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o @@ -21,6 +22,7 @@ obj-$(CONFIG_SND_SB8) += snd-sb8.o obj-$(CONFIG_SND_SB16) += snd-sb16.o obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o obj-$(CONFIG_SND_ES968) += snd-es968.o +obj-$(CONFIG_SND_JAZZ16) += snd-jazz16.o ifeq ($(CONFIG_SND_SB16_CSP),y) obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c new file mode 100644 index 0000000..d52966b --- /dev/null +++ b/sound/isa/sb/jazz16.c @@ -0,0 +1,385 @@ + +/* + * jazz16.c - driver for Media Vision Jazz16 based soundcards. + * Copyright (C) 2009 Krzysztof Helt + * Based on patches posted by Rask Ingemann Lambertsen and Rene Herman. + * Based on OSS Sound Blaster driver. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define SNDRV_LEGACY_FIND_FREE_IRQ +#define SNDRV_LEGACY_FIND_FREE_DMA +#include + +#define PFX "jazz16: " + +MODULE_DESCRIPTION("Media Vision Jazz16"); +MODULE_SUPPORTED_DEVICE("{{Media Vision ??? }," + "{RTL,RTL3000}}"); + +MODULE_AUTHOR("Krzysztof Helt "); +MODULE_LICENSE("GPL"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ +static unsigned long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static unsigned long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; +static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; +static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; +static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; + +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for Media Vision Jazz16 based soundcard."); +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for Media Vision Jazz16 based soundcard."); +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable Media Vision Jazz16 based soundcard."); +module_param_array(port, long, NULL, 0444); +MODULE_PARM_DESC(port, "Port # for jazz16 driver."); +module_param_array(mpu_port, long, NULL, 0444); +MODULE_PARM_DESC(mpu_port, "MPU-401 port # for jazz16 driver."); +module_param_array(irq, int, NULL, 0444); +MODULE_PARM_DESC(irq, "IRQ # for jazz16 driver."); +module_param_array(mpu_irq, int, NULL, 0444); +MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for jazz16 driver."); +module_param_array(dma8, int, NULL, 0444); +MODULE_PARM_DESC(dma8, "DMA8 # for jazz16 driver."); +module_param_array(dma16, int, NULL, 0444); +MODULE_PARM_DESC(dma16, "DMA16 # for jazz16 driver."); + +#define SB_JAZZ16_WAKEUP 0xaf +#define SB_JAZZ16_SET_PORTS 0x50 +#define SB_DSP_GET_JAZZ_BRD_REV 0xfa +#define SB_JAZZ16_SET_DMAINTR 0xfb +#define SB_DSP_GET_JAZZ_MODEL 0xfe + +struct snd_card_jazz16 { + struct snd_sb *chip; +}; + +static irqreturn_t jazz16_interrupt(int irq, void *chip) +{ + return snd_sb8dsp_interrupt(chip); +} + +static int __devinit jazz16_configure_ports(unsigned long port, + unsigned long mpu_port, int idx) +{ + unsigned char val; + + if (!request_region(0x201, 1, "jazz16 config")) { + snd_printk(KERN_ERR "config port region is already in use.\n"); + return -EBUSY; + } + outb(SB_JAZZ16_WAKEUP - idx, 0x201); + udelay(100); + outb(SB_JAZZ16_SET_PORTS + idx, 0x201); + udelay(100); + val = port & 0x70; + val |= (mpu_port & 0x30) >> 4; + outb(val, 0x201); + + release_region(0x201, 1); + return 0; +} + +static int __devinit jazz16_detect_board(unsigned long port, + unsigned long mpu_port) +{ + int err; + int val; + struct snd_sb chip; + + if (!request_region(port, 0x10, "jazz16")) { + snd_printk(KERN_ERR "I/O port region is already in use.\n"); + return -EBUSY; + } + /* just to call snd_sbdsp_command/reset/get_byte() */ + chip.port = port; + + err = snd_sbdsp_reset(&chip); + if (err < 0) + for (val = 0; val < 4; val++) { + err = jazz16_configure_ports(port, mpu_port, val); + if (err < 0) + break; + + err = snd_sbdsp_reset(&chip); + if (!err) + break; + } + if (err < 0) { + err = -ENODEV; + goto err_unmap; + } + if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_BRD_REV)) { + err = -EBUSY; + goto err_unmap; + } + val = snd_sbdsp_get_byte(&chip); + if (val >= 0x30) + snd_sbdsp_get_byte(&chip); + + if ((val & 0xf0) != 0x10) { + err = -ENODEV; + goto err_unmap; + } + if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_MODEL)) { + err = -EBUSY; + goto err_unmap; + } + snd_sbdsp_get_byte(&chip); + err = snd_sbdsp_get_byte(&chip); + snd_printd("Media Vision Jazz16 board detected: rev 0x%x, model 0x%x\n", + val, err); + + err = 0; + +err_unmap: + release_region(port, 0x10); + return err; +} + +static int __devinit jazz16_configure_board(struct snd_sb *chip, int mpu_irq) +{ + static unsigned char jazz_irq_bits[] = { 0, 0, 2, 3, 0, 1, 0, 4, + 0, 2, 5, 0, 0, 0, 0, 6 }; + static unsigned char jazz_dma_bits[] = { 0, 1, 0, 2, 0, 3, 0, 4 }; + + if (jazz_dma_bits[chip->dma8] == 0 || + jazz_dma_bits[chip->dma16] == 0 || + jazz_irq_bits[chip->irq] == 0) + return -EINVAL; + + if (!snd_sbdsp_command(chip, SB_JAZZ16_SET_DMAINTR)) + return -EBUSY; + + if (!snd_sbdsp_command(chip, + jazz_dma_bits[chip->dma8] | + (jazz_dma_bits[chip->dma16] << 4))) + return -EBUSY; + + if (!snd_sbdsp_command(chip, + jazz_irq_bits[chip->irq] | + (jazz_irq_bits[mpu_irq] << 4))) + return -EBUSY; + + return 0; +} + +static int __devinit snd_jazz16_match(struct device *devptr, unsigned int dev) +{ + if (!enable[dev]) + return 0; + if (port[dev] == SNDRV_AUTO_PORT) { + snd_printk(KERN_ERR "please specify port\n"); + return 0; + } + if (dma16[dev] != SNDRV_AUTO_DMA && + dma16[dev] != 5 && dma16[dev] != 7) { + snd_printk(KERN_ERR "dma16 must be 5 or 7"); + return 0; + } + return 1; +} + +static int __devinit snd_jazz16_probe(struct device *devptr, unsigned int dev) +{ + struct snd_card *card; + struct snd_card_jazz16 *jazz16; + struct snd_sb *chip; + struct snd_opl3 *opl3; + static int possible_irqs[] = {2, 3, 5, 7, 9, 10, 15, -1}; + static int possible_dmas8[] = {1, 3, -1}; + static int possible_dmas16[] = {5, 7, -1}; + int err, xirq, xdma8, xdma16, xmpu_port, xmpu_irq; + + err = snd_card_create(index[dev], id[dev], THIS_MODULE, + sizeof(struct snd_card_jazz16), &card); + if (err < 0) + return err; + + jazz16 = card->private_data; + + xirq = irq[dev]; + if (xirq == SNDRV_AUTO_IRQ) { + xirq = snd_legacy_find_free_irq(possible_irqs); + if (xirq < 0) { + snd_printk(KERN_ERR "unable to find a free IRQ\n"); + err = -EBUSY; + goto err_free; + } + } + xdma8 = dma8[dev]; + if (xdma8 == SNDRV_AUTO_DMA) { + xdma8 = snd_legacy_find_free_dma(possible_dmas8); + if (xdma8 < 0) { + snd_printk(KERN_ERR "unable to find a free DMA8\n"); + err = -EBUSY; + goto err_free; + } + } + xdma16 = dma16[dev]; + if (xdma16 == SNDRV_AUTO_DMA) { + xdma16 = snd_legacy_find_free_dma(possible_dmas16); + if (xdma16 < 0) { + snd_printk(KERN_ERR "unable to find a free DMA16\n"); + err = -EBUSY; + goto err_free; + } + } + + xmpu_port = mpu_port[dev]; + if (xmpu_port == SNDRV_AUTO_PORT) + xmpu_port = 0; + err = jazz16_detect_board(port[dev], xmpu_port); + if (err < 0) { + printk(KERN_ERR "Media Vision Jazz16 board not detected\n"); + goto err_free; + } + err = snd_sbdsp_create(card, port[dev], irq[dev], + jazz16_interrupt, + dma8[dev], dma16[dev], + SB_HW_JAZZ16, + &chip); + if (err < 0) + goto err_free; + + xmpu_irq = mpu_irq[dev]; + if (xmpu_irq == SNDRV_AUTO_IRQ || mpu_port[dev] == SNDRV_AUTO_PORT) + xmpu_irq = 0; + err = jazz16_configure_board(chip, xmpu_irq); + if (err < 0) { + printk(KERN_ERR "Media Vision Jazz16 configuration failed\n"); + goto err_free; + } + + jazz16->chip = chip; + + strcpy(card->driver, "jazz16"); + strcpy(card->shortname, "Media Vision Jazz16"); + sprintf(card->longname, + "Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d", + port[dev], xirq, xdma8, xdma16); + + err = snd_sb8dsp_pcm(chip, 0, NULL); + if (err < 0) + goto err_free; + err = snd_sbmixer_new(chip); + if (err < 0) + goto err_free; + + err = snd_opl3_create(card, chip->port, chip->port + 2, + OPL3_HW_AUTO, 1, &opl3); + if (err < 0) + snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n", + chip->port, chip->port + 2); + else { + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) + goto err_free; + } + if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { + if (mpu_irq[dev] == SNDRV_AUTO_IRQ) + mpu_irq[dev] = -1; + + if (snd_mpu401_uart_new(card, 0, + MPU401_HW_MPU401, + mpu_port[dev], 0, + mpu_irq[dev], + mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0, + NULL) < 0) + snd_printk(KERN_ERR "no MPU-401 device at 0x%lx\n", + mpu_port[dev]); + } + + snd_card_set_dev(card, devptr); + + err = snd_card_register(card); + if (err < 0) + goto err_free; + + dev_set_drvdata(devptr, card); + return 0; + +err_free: + snd_card_free(card); + return err; +} + +static int __devexit snd_jazz16_remove(struct device *devptr, unsigned int dev) +{ + struct snd_card *card = dev_get_drvdata(devptr); + + dev_set_drvdata(devptr, NULL); + snd_card_free(card); + return 0; +} + +#ifdef CONFIG_PM +static int snd_jazz16_suspend(struct device *pdev, unsigned int n, + pm_message_t state) +{ + struct snd_card *card = dev_get_drvdata(pdev); + struct snd_card_jazz16 *acard = card->private_data; + struct snd_sb *chip = acard->chip; + + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + snd_pcm_suspend_all(chip->pcm); + snd_sbmixer_suspend(chip); + return 0; +} + +static int snd_jazz16_resume(struct device *pdev, unsigned int n) +{ + struct snd_card *card = dev_get_drvdata(pdev); + struct snd_card_jazz16 *acard = card->private_data; + struct snd_sb *chip = acard->chip; + + snd_sbdsp_reset(chip); + snd_sbmixer_resume(chip); + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + return 0; +} +#endif + +static struct isa_driver snd_jazz16_driver = { + .match = snd_jazz16_match, + .probe = snd_jazz16_probe, + .remove = __devexit_p(snd_jazz16_remove), +#ifdef CONFIG_PM + .suspend = snd_jazz16_suspend, + .resume = snd_jazz16_resume, +#endif + .driver = { + .name = "jazz16" + }, +}; + +static int __init alsa_card_jazz16_init(void) +{ + return isa_register_driver(&snd_jazz16_driver, SNDRV_CARDS); +} + +static void __exit alsa_card_jazz16_exit(void) +{ + isa_unregister_driver(&snd_jazz16_driver); +} + +module_init(alsa_card_jazz16_init) +module_exit(alsa_card_jazz16_exit) diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index 658d557..3222aed 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c @@ -106,9 +106,21 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) struct snd_sb *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int mixreg, rate, size, count; + unsigned char format; + unsigned char stereo = runtime->channels > 1; + int dma; rate = runtime->rate; switch (chip->hardware) { + case SB_HW_JAZZ16: + if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) { + if (chip->mode & SB_MODE_CAPTURE_16) + return -EBUSY; + else + chip->mode |= SB_MODE_PLAYBACK_16; + } + chip->playback_format = SB_DSP_LO_OUTPUT_AUTO; + break; case SB_HW_PRO: if (runtime->channels > 1) { if (snd_BUG_ON(rate != SB8_RATE(11025) && @@ -133,11 +145,21 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) default: return -EINVAL; } + if (chip->mode & SB_MODE_PLAYBACK_16) { + format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT; + dma = chip->dma16; + } else { + format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT; + chip->mode |= SB_MODE_PLAYBACK_8; + dma = chip->dma8; + } size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream); count = chip->p_period_size = snd_pcm_lib_period_bytes(substream); spin_lock_irqsave(&chip->reg_lock, flags); snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); - if (runtime->channels > 1) { + if (chip->hardware == SB_HW_JAZZ16) + snd_sbdsp_command(chip, format); + else if (stereo) { /* set playback stereo mode */ spin_lock(&chip->mixer_lock); mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW); @@ -147,15 +169,14 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) /* Soundblaster hardware programming reference guide, 3-23 */ snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT); runtime->dma_area[0] = 0x80; - snd_dma_program(chip->dma8, runtime->dma_addr, 1, DMA_MODE_WRITE); + snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE); /* force interrupt */ - chip->mode = SB_MODE_HALT; snd_sbdsp_command(chip, SB_DSP_OUTPUT); snd_sbdsp_command(chip, 0); snd_sbdsp_command(chip, 0); } snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); - if (runtime->channels > 1) { + if (stereo) { snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); spin_lock(&chip->mixer_lock); /* save output filter status and turn it off */ @@ -168,13 +189,15 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) snd_sbdsp_command(chip, 256 - runtime->rate_den); } if (chip->playback_format != SB_DSP_OUTPUT) { + if (chip->mode & SB_MODE_PLAYBACK_16) + count /= 2; count--; snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); snd_sbdsp_command(chip, count & 0xff); snd_sbdsp_command(chip, count >> 8); } spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_dma_program(chip->dma8, runtime->dma_addr, + snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); return 0; } @@ -212,7 +235,6 @@ static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream, snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); } spin_unlock_irqrestore(&chip->reg_lock, flags); - chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_PLAYBACK_8 : SB_MODE_HALT; return 0; } @@ -234,9 +256,21 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) struct snd_sb *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int mixreg, rate, size, count; + unsigned char format; + unsigned char stereo = runtime->channels > 1; + int dma; rate = runtime->rate; switch (chip->hardware) { + case SB_HW_JAZZ16: + if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) { + if (chip->mode & SB_MODE_PLAYBACK_16) + return -EBUSY; + else + chip->mode |= SB_MODE_CAPTURE_16; + } + chip->capture_format = SB_DSP_LO_INPUT_AUTO; + break; case SB_HW_PRO: if (runtime->channels > 1) { if (snd_BUG_ON(rate != SB8_RATE(11025) && @@ -262,14 +296,24 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) default: return -EINVAL; } + if (chip->mode & SB_MODE_CAPTURE_16) { + format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT; + dma = chip->dma16; + } else { + format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT; + chip->mode |= SB_MODE_CAPTURE_8; + dma = chip->dma8; + } size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream); count = chip->c_period_size = snd_pcm_lib_period_bytes(substream); spin_lock_irqsave(&chip->reg_lock, flags); snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); - if (runtime->channels > 1) + if (chip->hardware == SB_HW_JAZZ16) + snd_sbdsp_command(chip, format); + else if (stereo) snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT); snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); - if (runtime->channels > 1) { + if (stereo) { snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); spin_lock(&chip->mixer_lock); /* save input filter status and turn it off */ @@ -282,13 +326,15 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) snd_sbdsp_command(chip, 256 - runtime->rate_den); } if (chip->capture_format != SB_DSP_INPUT) { + if (chip->mode & SB_MODE_PLAYBACK_16) + count /= 2; count--; snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); snd_sbdsp_command(chip, count & 0xff); snd_sbdsp_command(chip, count >> 8); } spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_dma_program(chip->dma8, runtime->dma_addr, + snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); return 0; } @@ -328,7 +374,6 @@ static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream, snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); } spin_unlock_irqrestore(&chip->reg_lock, flags); - chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_CAPTURE_8 : SB_MODE_HALT; return 0; } @@ -339,13 +384,21 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip) snd_sb_ack_8bit(chip); switch (chip->mode) { - case SB_MODE_PLAYBACK_8: /* ok.. playback is active */ + case SB_MODE_PLAYBACK_16: /* ok.. playback is active */ + if (chip->hardware != SB_HW_JAZZ16) + break; + /* fallthru */ + case SB_MODE_PLAYBACK_8: substream = chip->playback_substream; runtime = substream->runtime; if (chip->playback_format == SB_DSP_OUTPUT) snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START); snd_pcm_period_elapsed(substream); break; + case SB_MODE_CAPTURE_16: + if (chip->hardware != SB_HW_JAZZ16) + break; + /* fallthru */ case SB_MODE_CAPTURE_8: substream = chip->capture_substream; runtime = substream->runtime; @@ -361,10 +414,15 @@ static snd_pcm_uframes_t snd_sb8_playback_pointer(struct snd_pcm_substream *subs { struct snd_sb *chip = snd_pcm_substream_chip(substream); size_t ptr; + int dma; - if (chip->mode != SB_MODE_PLAYBACK_8) + if (chip->mode & SB_MODE_PLAYBACK_8) + dma = chip->dma8; + else if (chip->mode & SB_MODE_PLAYBACK_16) + dma = chip->dma16; + else return 0; - ptr = snd_dma_pointer(chip->dma8, chip->p_dma_size); + ptr = snd_dma_pointer(dma, chip->p_dma_size); return bytes_to_frames(substream->runtime, ptr); } @@ -372,10 +430,15 @@ static snd_pcm_uframes_t snd_sb8_capture_pointer(struct snd_pcm_substream *subst { struct snd_sb *chip = snd_pcm_substream_chip(substream); size_t ptr; + int dma; - if (chip->mode != SB_MODE_CAPTURE_8) + if (chip->mode & SB_MODE_CAPTURE_8) + dma = chip->dma8; + else if (chip->mode & SB_MODE_CAPTURE_16) + dma = chip->dma16; + else return 0; - ptr = snd_dma_pointer(chip->dma8, chip->c_dma_size); + ptr = snd_dma_pointer(dma, chip->c_dma_size); return bytes_to_frames(substream->runtime, ptr); } @@ -446,6 +509,13 @@ static int snd_sb8_open(struct snd_pcm_substream *substream) runtime->hw = snd_sb8_capture; } switch (chip->hardware) { + case SB_HW_JAZZ16: + runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE; + runtime->hw.rates |= SNDRV_PCM_RATE_8000_48000; + runtime->hw.rate_min = 4000; + runtime->hw.rate_max = 50000; + runtime->hw.channels_max = 2; + break; case SB_HW_PRO: runtime->hw.rate_max = 44100; runtime->hw.channels_max = 2; @@ -468,6 +538,14 @@ static int snd_sb8_open(struct snd_pcm_substream *substream) } snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_clock); + if (chip->dma8 > 3 || chip->dma16 >= 0) { + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2); + snd_pcm_hw_constraint_step(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2); + runtime->hw.buffer_bytes_max = 128 * 1024 * 1024; + runtime->hw.period_bytes_max = 128 * 1024 * 1024; + } return 0; } @@ -480,6 +558,10 @@ static int snd_sb8_close(struct snd_pcm_substream *substream) chip->capture_substream = NULL; spin_lock_irqsave(&chip->open_lock, flags); chip->open &= ~SB_OPEN_PCM; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + chip->mode &= ~SB_MODE_PLAYBACK; + else + chip->mode &= ~SB_MODE_CAPTURE; spin_unlock_irqrestore(&chip->open_lock, flags); return 0; } @@ -515,6 +597,7 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm) struct snd_card *card = chip->card; struct snd_pcm *pcm; int err; + size_t max_prealloc = 64 * 1024; if (rpcm) *rpcm = NULL; @@ -527,9 +610,11 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops); + if (chip->dma8 > 3 || chip->dma16 >= 0) + max_prealloc = 128 * 1024; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), - 64*1024, 64*1024); + 64*1024, max_prealloc); if (rpcm) *rpcm = pcm; diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c index 27a6515..eae6c1c 100644 --- a/sound/isa/sb/sb_common.c +++ b/sound/isa/sb/sb_common.c @@ -170,6 +170,9 @@ static int snd_sbdsp_probe(struct snd_sb * chip) case SB_HW_CS5530: str = "16 (CS5530)"; break; + case SB_HW_JAZZ16: + str = "Pro (Jazz16)"; + break; default: return -ENODEV; } diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index 8cfc41f..6496822 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c @@ -779,6 +779,7 @@ int snd_sbmixer_new(struct snd_sb *chip) return err; break; case SB_HW_PRO: + case SB_HW_JAZZ16: if ((err = snd_sbmixer_init(chip, snd_sbpro_controls, ARRAY_SIZE(snd_sbpro_controls), @@ -929,6 +930,7 @@ void snd_sbmixer_suspend(struct snd_sb *chip) save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); break; case SB_HW_PRO: + case SB_HW_JAZZ16: save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); break; case SB_HW_16: @@ -955,6 +957,7 @@ void snd_sbmixer_resume(struct snd_sb *chip) restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); break; case SB_HW_PRO: + case SB_HW_JAZZ16: restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); break; case SB_HW_16: -- cgit v0.10.2 From ee7c343c0134bf126b4235e65c407711b77174da Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 21 Dec 2009 12:41:37 +0100 Subject: ALSA: pcm - Add missing inclusion of linux/vmalloc.h Signed-off-by: Takashi Iwai diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index d9727c7..d6d49d6 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include -- cgit v0.10.2 From 8374e24c23448cabf6e78db2c83841c56c5df1e1 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Mon, 21 Dec 2009 17:07:08 +0100 Subject: ALSA: refine rate selection in snd_interval_ratnum() Refine the rate selection by choosing the rate closer to the requested one in case of selecting single frequency. Previously, the higher rate was always selected. Also, fix problem with the best_diff unsigned int value wrapping (turning negative). Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index a27545b2..b07cc36 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -745,10 +745,13 @@ int snd_interval_ratnum(struct snd_interval *i, unsigned int rats_count, struct snd_ratnum *rats, unsigned int *nump, unsigned int *denp) { - unsigned int best_num, best_diff, best_den; + unsigned int best_num, best_den; + int best_diff; unsigned int k; struct snd_interval t; int err; + unsigned int result_num, result_den; + int result_diff; best_num = best_den = best_diff = 0; for (k = 0; k < rats_count; ++k) { @@ -770,6 +773,8 @@ int snd_interval_ratnum(struct snd_interval *i, den -= r; } diff = num - q * den; + if (diff < 0) + diff = -diff; if (best_num == 0 || diff * best_den < best_diff * den) { best_diff = diff; @@ -784,6 +789,9 @@ int snd_interval_ratnum(struct snd_interval *i, t.min = div_down(best_num, best_den); t.openmin = !!(best_num % best_den); + result_num = best_num; + result_diff = best_diff; + result_den = best_den; best_num = best_den = best_diff = 0; for (k = 0; k < rats_count; ++k) { unsigned int num = rats[k].num; @@ -806,6 +814,8 @@ int snd_interval_ratnum(struct snd_interval *i, den += rats[k].den_step - r; } diff = q * den - num; + if (diff < 0) + diff = -diff; if (best_num == 0 || diff * best_den < best_diff * den) { best_diff = diff; @@ -825,10 +835,14 @@ int snd_interval_ratnum(struct snd_interval *i, return err; if (snd_interval_single(i)) { + if (best_diff * result_den < result_diff * best_den) { + result_num = best_num; + result_den = best_den; + } if (nump) - *nump = best_num; + *nump = result_num; if (denp) - *denp = best_den; + *denp = result_den; } return err; } -- cgit v0.10.2 From 41116e926cb92292fa4fcbe888ae8133fa0038e6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 22 Dec 2009 09:00:14 +0100 Subject: ALSA: cs46xx - Fix suspend/resume with new DSP Fix the basic suspend/resume of snd-cs46xx drivers with new DSP. References: https://bugzilla.redhat.com/show_bug.cgi?id=498287 https://bugzilla.redhat.com/show_bug.cgi?id=160751 Tested-by: Florian Zumbiehl Signed-off-by: Takashi Iwai diff --git a/include/sound/cs46xx_dsp_spos.h b/include/sound/cs46xx_dsp_spos.h index 7c44667..49b03c9 100644 --- a/include/sound/cs46xx_dsp_spos.h +++ b/include/sound/cs46xx_dsp_spos.h @@ -118,9 +118,11 @@ struct dsp_scb_descriptor { struct snd_info_entry *proc_info; int ref_count; - spinlock_t lock; - int deleted; + u16 volume[2]; + unsigned int deleted :1; + unsigned int updated :1; + unsigned int volume_set :1; }; struct dsp_task_descriptor { diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 1be96ea..e6b4a87 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -3597,7 +3597,7 @@ static struct cs_card_type __devinitdata cards[] = { #ifdef CONFIG_PM static unsigned int saved_regs[] = { BA0_ACOSV, - BA0_ASER_FADDR, + /*BA0_ASER_FADDR,*/ BA0_ASER_MASTER, BA1_PVOL, BA1_CVOL, diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index f4f0c8f..3e5ca8f 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c @@ -298,6 +298,9 @@ void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip) if (ins->scbs[i].deleted) continue; cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) ); +#ifdef CONFIG_PM + kfree(ins->scbs[i].data); +#endif } kfree(ins->code.data); @@ -974,13 +977,11 @@ static struct dsp_scb_descriptor * _map_scb (struct snd_cs46xx *chip, char * nam index = find_free_scb_index (ins); + memset(&ins->scbs[index], 0, sizeof(ins->scbs[index])); strcpy(ins->scbs[index].scb_name, name); ins->scbs[index].address = dest; ins->scbs[index].index = index; - ins->scbs[index].proc_info = NULL; ins->scbs[index].ref_count = 1; - ins->scbs[index].deleted = 0; - spin_lock_init(&ins->scbs[index].lock); desc = (ins->scbs + index); ins->scbs[index].scb_symbol = add_symbol (chip, name, dest, SYMBOL_PARAMETER); @@ -1022,17 +1023,29 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size) return desc; } +#define SCB_BYTES (0x10 * 4) + struct dsp_scb_descriptor * cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest) { struct dsp_scb_descriptor * desc; +#ifdef CONFIG_PM + /* copy the data for resume */ + scb_data = kmemdup(scb_data, SCB_BYTES, GFP_KERNEL); + if (!scb_data) + return NULL; +#endif + desc = _map_scb (chip,name,dest); if (desc) { desc->data = scb_data; _dsp_create_scb(chip,scb_data,dest); } else { snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n"); +#ifdef CONFIG_PM + kfree(scb_data); +#endif } return desc; @@ -1988,7 +2001,28 @@ int cs46xx_dsp_resume(struct snd_cs46xx * chip) continue; _dsp_create_scb(chip, s->data, s->address); } - + for (i = 0; i < ins->nscb; i++) { + struct dsp_scb_descriptor *s = &ins->scbs[i]; + if (s->deleted) + continue; + if (s->updated) + cs46xx_dsp_spos_update_scb(chip, s); + if (s->volume_set) + cs46xx_dsp_scb_set_volume(chip, s, + s->volume[0], s->volume[1]); + } + if (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) { + cs46xx_dsp_enable_spdif_hw(chip); + snd_cs46xx_poke(chip, (ins->ref_snoop_scb->address + 2) << 2, + (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10); + if (ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) + cs46xx_poke_via_dsp(chip, SP_SPDOUT_CSUV, + ins->spdif_csuv_stream); + } + if (chip->dsp_spos_instance->spdif_status_in) { + cs46xx_poke_via_dsp(chip, SP_ASER_COUNTDOWN, 0x80000005); + cs46xx_poke_via_dsp(chip, SP_SPDIN_CONTROL, 0x800003ff); + } return 0; } #endif diff --git a/sound/pci/cs46xx/dsp_spos.h b/sound/pci/cs46xx/dsp_spos.h index f9e169d..ca47a81 100644 --- a/sound/pci/cs46xx/dsp_spos.h +++ b/sound/pci/cs46xx/dsp_spos.h @@ -212,6 +212,7 @@ static inline void cs46xx_dsp_spos_update_scb (struct snd_cs46xx * chip, (scb->address + SCBsubListPtr) << 2, (scb->sub_list_ptr->address << 0x10) | (scb->next_scb_ptr->address)); + scb->updated = 1; } static inline void cs46xx_dsp_scb_set_volume (struct snd_cs46xx * chip, @@ -222,6 +223,9 @@ static inline void cs46xx_dsp_scb_set_volume (struct snd_cs46xx * chip, snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl) << 2, val); snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl + 1) << 2, val); + scb->volume_set = 1; + scb->volume[0] = left; + scb->volume[1] = right; } #endif /* __DSP_SPOS_H__ */ #endif /* CONFIG_SND_CS46XX_NEW_DSP */ diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index dd7c41b..00b148a 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c @@ -115,7 +115,6 @@ static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry, static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb) { struct dsp_spos_instance * ins = chip->dsp_spos_instance; - unsigned long flags; if ( scb->parent_scb_ptr ) { /* unlink parent SCB */ @@ -153,8 +152,6 @@ static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor scb->next_scb_ptr = ins->the_null_scb; } - spin_lock_irqsave(&chip->reg_lock, flags); - /* update parent first entry in DSP RAM */ cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr); @@ -162,7 +159,6 @@ static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor cs46xx_dsp_spos_update_scb(chip,scb); scb->parent_scb_ptr = NULL; - spin_unlock_irqrestore(&chip->reg_lock, flags); } } @@ -197,9 +193,9 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * goto _end; #endif - spin_lock_irqsave(&scb->lock, flags); + spin_lock_irqsave(&chip->reg_lock, flags); _dsp_unlink_scb (chip,scb); - spin_unlock_irqrestore(&scb->lock, flags); + spin_unlock_irqrestore(&chip->reg_lock, flags); cs46xx_dsp_proc_free_scb_desc(scb); if (snd_BUG_ON(!scb->scb_symbol)) @@ -207,6 +203,10 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * remove_symbol (chip,scb->scb_symbol); ins->scbs[scb->index].deleted = 1; +#ifdef CONFIG_PM + kfree(ins->scbs[scb->index].data); + ins->scbs[scb->index].data = NULL; +#endif if (scb->index < ins->scb_highest_frag_index) ins->scb_highest_frag_index = scb->index; @@ -1508,20 +1508,17 @@ int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip, chip->dsp_spos_instance->npcm_channels <= 0)) return -EIO; - spin_lock(&pcm_channel->src_scb->lock); - + spin_lock_irqsave(&chip->reg_lock, flags); if (pcm_channel->unlinked) { - spin_unlock(&pcm_channel->src_scb->lock); + spin_unlock_irqrestore(&chip->reg_lock, flags); return -EIO; } - spin_lock_irqsave(&chip->reg_lock, flags); pcm_channel->unlinked = 1; - spin_unlock_irqrestore(&chip->reg_lock, flags); _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb); + spin_unlock_irqrestore(&chip->reg_lock, flags); - spin_unlock(&pcm_channel->src_scb->lock); return 0; } @@ -1533,10 +1530,10 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip, struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb; unsigned long flags; - spin_lock(&pcm_channel->src_scb->lock); + spin_lock_irqsave(&chip->reg_lock, flags); if (pcm_channel->unlinked == 0) { - spin_unlock(&pcm_channel->src_scb->lock); + spin_unlock_irqrestore(&chip->reg_lock, flags); return -EIO; } @@ -1552,8 +1549,6 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip, snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr); pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb; - spin_lock_irqsave(&chip->reg_lock, flags); - /* update SCB entry in DSP RAM */ cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb); @@ -1562,8 +1557,6 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip, pcm_channel->unlinked = 0; spin_unlock_irqrestore(&chip->reg_lock, flags); - - spin_unlock(&pcm_channel->src_scb->lock); return 0; } @@ -1596,13 +1589,17 @@ cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * s int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src) { + unsigned long flags; + if (snd_BUG_ON(!src->parent_scb_ptr)) return -EINVAL; /* mute SCB */ cs46xx_dsp_scb_set_volume (chip,src,0,0); + spin_lock_irqsave(&chip->reg_lock, flags); _dsp_unlink_scb (chip,src); + spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } -- cgit v0.10.2 From 44eba3e82b35ae796826a65d8040001582adc10a Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Wed, 23 Dec 2009 18:02:41 +0100 Subject: ALSA: jazz16: refine dma and irq selection Narrow the dma and irq selection after the DOS driver. Add ALSA configuration description as well. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 7a0a4a9..c540637 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1123,6 +1123,21 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. This module supports multiple cards, autoprobe and ISA PnP. + Module snd-jazz16 + ------------------- + + Module for Media Vision Jazz16 chipset. The chipset consists of 3 chips: + MVD1216 + MVA416 + MVA514. + + port - port # for SB DSP chip (0x210,0x220,0x230,0x240,0x250,0x260) + irq - IRQ # for SB DSP chip (3,5,7,9,10,15) + dma8 - DMA # for SB DSP chip (1,3) + dma16 - DMA # for SB DSP chip (5,7) + mpu_port - MPU-401 port # (0x300,0x310,0x320,0x330) + mpu_irq - MPU-401 irq # (2,3,5,7) + + This module supports multiple cards. + Module snd-korg1212 ------------------- diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c index d52966b..8d21a3f 100644 --- a/sound/isa/sb/jazz16.c +++ b/sound/isa/sb/jazz16.c @@ -189,10 +189,29 @@ static int __devinit snd_jazz16_match(struct device *devptr, unsigned int dev) if (port[dev] == SNDRV_AUTO_PORT) { snd_printk(KERN_ERR "please specify port\n"); return 0; + } else if (port[dev] == 0x200 || (port[dev] & ~0x270)) { + snd_printk(KERN_ERR "incorrect port specified\n"); + return 0; + } + if (dma8[dev] != SNDRV_AUTO_DMA && + dma8[dev] != 1 && dma8[dev] != 3) { + snd_printk(KERN_ERR "dma8 must be 1 or 3\n"); + return 0; } if (dma16[dev] != SNDRV_AUTO_DMA && dma16[dev] != 5 && dma16[dev] != 7) { - snd_printk(KERN_ERR "dma16 must be 5 or 7"); + snd_printk(KERN_ERR "dma16 must be 5 or 7\n"); + return 0; + } + if (mpu_port[dev] != SNDRV_AUTO_PORT && + (mpu_port[dev] & ~0x030) != 0x300) { + snd_printk(KERN_ERR "incorrect mpu_port specified\n"); + return 0; + } + if (mpu_irq[dev] != SNDRV_AUTO_DMA && + mpu_irq[dev] != 2 && mpu_irq[dev] != 3 && + mpu_irq[dev] != 5 && mpu_irq[dev] != 7) { + snd_printk(KERN_ERR "mpu_irq must be 2, 3, 5 or 7\n"); return 0; } return 1; diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index 3222aed..7d84c9f 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c @@ -510,7 +510,8 @@ static int snd_sb8_open(struct snd_pcm_substream *substream) } switch (chip->hardware) { case SB_HW_JAZZ16: - runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE; + if (chip->dma16 == 5 || chip->dma16 == 7) + runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE; runtime->hw.rates |= SNDRV_PCM_RATE_8000_48000; runtime->hw.rate_min = 4000; runtime->hw.rate_max = 50000; -- cgit v0.10.2 From 7d2b451e65d255427c108e990507964ac39c13ee Mon Sep 17 00:00:00 2001 From: Sergiy Kovalchuk Date: Sun, 27 Dec 2009 09:13:41 -0800 Subject: ALSA: usb-audio - Added functionality for E-mu 0404USB/0202USB/TrackerPre Added functionality: 1) Extension Units support (all XU settings now available at alsamixer, kmix, etc): - "AnalogueIn soft limiter" switch; - "Sample rate" selector (values 0,1,2,3,4,5 corresponds to 44.1 48 ... 192 kHz); - "DigitalIn CLK source" selector (internal/external) (**); - "DigitalOut format SPDIF/AC3" switch (**); (**)E-mu-0404usb only. 2) Automatic device sample rate adjustment depending on substream samplerate for both capture and playback substream. [minor coding-style fixes by tiwai] Signed-off-by: Sergiy Kovalchuk Signed-off-by: Takashi Iwai diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 31b63ea..286fa14 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -1271,6 +1271,47 @@ static int init_usb_sample_rate(struct usb_device *dev, int iface, } /* + * For E-Mu 0404USB/0202USB/TrackerPre sample rate should be set for device, + * not for interface. + */ +static void set_format_emu_quirk(struct snd_usb_substream *subs, + struct audioformat *fmt) +{ + unsigned char emu_samplerate_id = 0; + + /* When capture is active + * sample rate shouldn't be changed + * by playback substream + */ + if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { + if (subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE].interface != -1) + return; + } + + switch (fmt->rate_min) { + case 48000: + emu_samplerate_id = EMU_QUIRK_SR_48000HZ; + break; + case 88200: + emu_samplerate_id = EMU_QUIRK_SR_88200HZ; + break; + case 96000: + emu_samplerate_id = EMU_QUIRK_SR_96000HZ; + break; + case 176400: + emu_samplerate_id = EMU_QUIRK_SR_176400HZ; + break; + case 192000: + emu_samplerate_id = EMU_QUIRK_SR_192000HZ; + break; + default: + emu_samplerate_id = EMU_QUIRK_SR_44100HZ; + break; + } + snd_emuusb_set_samplerate(subs->stream->chip, emu_samplerate_id); +} + +/* * find a matching format and set up the interface */ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) @@ -1383,6 +1424,14 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) subs->cur_audiofmt = fmt; + switch (subs->stream->chip->usb_id) { + case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */ + case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */ + case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */ + set_format_emu_quirk(subs, fmt); + break; + } + #if 0 printk(KERN_DEBUG "setting done: format = %d, rate = %d..%d, channels = %d\n", diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 9826337..1522167 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -208,6 +208,16 @@ struct snd_usb_midi_endpoint_info { /* */ +/*E-mu USB samplerate control quirk*/ +enum { + EMU_QUIRK_SR_44100HZ = 0, + EMU_QUIRK_SR_48000HZ, + EMU_QUIRK_SR_88200HZ, + EMU_QUIRK_SR_96000HZ, + EMU_QUIRK_SR_176400HZ, + EMU_QUIRK_SR_192000HZ +}; + #define combine_word(s) ((*(s)) | ((unsigned int)(s)[1] << 8)) #define combine_triple(s) (combine_word(s) | ((unsigned int)(s)[2] << 16)) #define combine_quad(s) (combine_triple(s) | ((unsigned int)(s)[3] << 24)) @@ -233,6 +243,9 @@ void snd_usbmidi_input_stop(struct list_head* p); void snd_usbmidi_input_start(struct list_head* p); void snd_usbmidi_disconnect(struct list_head *p); +void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, + unsigned char samplerate_id); + /* * retrieve usb_interface descriptor from the host interface * (conditional for compatibility with the older API) diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index c998220..f5596cf 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -186,6 +186,21 @@ enum { USB_PROC_DCR_RELEASE = 6, }; +/*E-mu 0202(0404) eXtension Unit(XU) control*/ +enum { + USB_XU_CLOCK_RATE = 0xe301, + USB_XU_CLOCK_SOURCE = 0xe302, + USB_XU_DIGITAL_IO_STATUS = 0xe303, + USB_XU_DEVICE_OPTIONS = 0xe304, + USB_XU_DIRECT_MONITORING = 0xe305, + USB_XU_METERING = 0xe306 +}; +enum { + USB_XU_CLOCK_SOURCE_SELECTOR = 0x02, /* clock source*/ + USB_XU_CLOCK_RATE_SELECTOR = 0x03, /* clock rate */ + USB_XU_DIGITAL_FORMAT_SELECTOR = 0x01, /* the spdif format */ + USB_XU_SOFT_LIMIT_SELECTOR = 0x03 /* soft limiter */ +}; /* * manual mapping of mixer names @@ -1330,7 +1345,32 @@ static struct procunit_info procunits[] = { { USB_PROC_DCR, "DCR", dcr_proc_info }, { 0 }, }; - +/* + * predefined data for extension units + */ +static struct procunit_value_info clock_rate_xu_info[] = { + { USB_XU_CLOCK_RATE_SELECTOR, "Selector", USB_MIXER_U8, 0 }, + { 0 } +}; +static struct procunit_value_info clock_source_xu_info[] = { + { USB_XU_CLOCK_SOURCE_SELECTOR, "External", USB_MIXER_BOOLEAN }, + { 0 } +}; +static struct procunit_value_info spdif_format_xu_info[] = { + { USB_XU_DIGITAL_FORMAT_SELECTOR, "SPDIF/AC3", USB_MIXER_BOOLEAN }, + { 0 } +}; +static struct procunit_value_info soft_limit_xu_info[] = { + { USB_XU_SOFT_LIMIT_SELECTOR, " ", USB_MIXER_BOOLEAN }, + { 0 } +}; +static struct procunit_info extunits[] = { + { USB_XU_CLOCK_RATE, "Clock rate", clock_rate_xu_info }, + { USB_XU_CLOCK_SOURCE, "DigitalIn CLK source", clock_source_xu_info }, + { USB_XU_DIGITAL_IO_STATUS, "DigitalOut format:", spdif_format_xu_info }, + { USB_XU_DEVICE_OPTIONS, "AnalogueIn Soft Limit", soft_limit_xu_info }, + { 0 } +}; /* * build a processing/extension unit */ @@ -1391,8 +1431,18 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned cval->max = dsc[15]; cval->res = 1; cval->initialized = 1; - } else - get_min_max(cval, valinfo->min_value); + } else { + if (type == USB_XU_CLOCK_RATE) { + /* E-Mu USB 0404/0202/TrackerPre + * samplerate control quirk + */ + cval->min = 0; + cval->max = 5; + cval->res = 1; + cval->initialized = 1; + } else + get_min_max(cval, valinfo->min_value); + } kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); if (! kctl) { @@ -1433,7 +1483,7 @@ static int parse_audio_processing_unit(struct mixer_build *state, int unitid, un static int parse_audio_extension_unit(struct mixer_build *state, int unitid, unsigned char *desc) { - return build_audio_procunit(state, unitid, desc, NULL, "Extension Unit"); + return build_audio_procunit(state, unitid, desc, extunits, "Extension Unit"); } @@ -2109,6 +2159,23 @@ static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) return 0; } +void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, + unsigned char samplerate_id) +{ + struct usb_mixer_interface *mixer; + struct usb_mixer_elem_info *cval; + int unitid = 12; /* SamleRate ExtensionUnit ID */ + + list_for_each_entry(mixer, &chip->mixer_list, list) { + cval = mixer->id_elems[unitid]; + if (cval) { + set_cur_ctl_value(cval, cval->control << 8, samplerate_id); + snd_usb_mixer_notify_id(mixer, unitid); + } + break; + } +} + int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, int ignore_error) { -- cgit v0.10.2 From adc8d31326c32a2a1e145ab80accbc3c6570b117 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sun, 27 Dec 2009 12:19:57 -0500 Subject: ALSA: usb-audio: make buffer pointer based on bytes instead on frames Since there are devices that do not align the size of their data packets to frame boundaries, the driver needs to be able to keep track of partial frames. This patch prepares for support for such devices by changing the hwptr_done variable from a frame counter to a byte counter. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 286fa14..8fcb5d5 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -173,7 +173,7 @@ struct snd_usb_substream { unsigned int running: 1; /* running status */ - unsigned int hwptr_done; /* processed frame position in the buffer */ + unsigned int hwptr_done; /* processed byte position in the buffer */ unsigned int transfer_done; /* processed frames since last period update */ unsigned long active_mask; /* bitmask of active urbs */ unsigned long unlink_mask; /* bitmask of unlinked urbs */ @@ -342,7 +342,7 @@ static int retire_capture_urb(struct snd_usb_substream *subs, unsigned long flags; unsigned char *cp; int i; - unsigned int stride, len, oldptr; + unsigned int stride, frames, bytes, oldptr; int period_elapsed = 0; stride = runtime->frame_bits >> 3; @@ -353,29 +353,28 @@ static int retire_capture_urb(struct snd_usb_substream *subs, snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); // continue; } - len = urb->iso_frame_desc[i].actual_length / stride; - if (! len) - continue; + frames = urb->iso_frame_desc[i].actual_length / stride; + bytes = frames * stride; /* update the current pointer */ spin_lock_irqsave(&subs->lock, flags); oldptr = subs->hwptr_done; - subs->hwptr_done += len; - if (subs->hwptr_done >= runtime->buffer_size) - subs->hwptr_done -= runtime->buffer_size; - subs->transfer_done += len; + subs->hwptr_done += bytes; + if (subs->hwptr_done >= runtime->buffer_size * stride) + subs->hwptr_done -= runtime->buffer_size * stride; + subs->transfer_done += frames; if (subs->transfer_done >= runtime->period_size) { subs->transfer_done -= runtime->period_size; period_elapsed = 1; } spin_unlock_irqrestore(&subs->lock, flags); /* copy a data chunk */ - if (oldptr + len > runtime->buffer_size) { - unsigned int cnt = runtime->buffer_size - oldptr; - unsigned int blen = cnt * stride; - memcpy(runtime->dma_area + oldptr * stride, cp, blen); - memcpy(runtime->dma_area, cp + blen, len * stride - blen); + if (oldptr + bytes > runtime->buffer_size * stride) { + unsigned int bytes1 = + runtime->buffer_size * stride - oldptr; + memcpy(runtime->dma_area + oldptr, cp, bytes1); + memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1); } else { - memcpy(runtime->dma_area + oldptr * stride, cp, len * stride); + memcpy(runtime->dma_area + oldptr, cp, bytes); } } if (period_elapsed) @@ -562,24 +561,24 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *urb) { - int i, stride, offs; - unsigned int counts; + int i, stride; + unsigned int counts, frames, bytes; unsigned long flags; int period_elapsed = 0; struct snd_urb_ctx *ctx = urb->context; stride = runtime->frame_bits >> 3; - offs = 0; + frames = 0; urb->dev = ctx->subs->dev; /* we need to set this at each time */ urb->number_of_packets = 0; spin_lock_irqsave(&subs->lock, flags); for (i = 0; i < ctx->packets; i++) { counts = snd_usb_audio_next_packet_size(subs); /* set up descriptor */ - urb->iso_frame_desc[i].offset = offs * stride; + urb->iso_frame_desc[i].offset = frames * stride; urb->iso_frame_desc[i].length = counts * stride; - offs += counts; + frames += counts; urb->number_of_packets++; subs->transfer_done += counts; if (subs->transfer_done >= runtime->period_size) { @@ -589,7 +588,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, if (subs->transfer_done > 0) { /* FIXME: fill-max mode is not * supported yet */ - offs -= subs->transfer_done; + frames -= subs->transfer_done; counts -= subs->transfer_done; urb->iso_frame_desc[i].length = counts * stride; @@ -599,7 +598,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, if (i < ctx->packets) { /* add a transfer delimiter */ urb->iso_frame_desc[i].offset = - offs * stride; + frames * stride; urb->iso_frame_desc[i].length = 0; urb->number_of_packets++; } @@ -609,26 +608,25 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, if (period_elapsed) /* finish at the period boundary */ break; } - if (subs->hwptr_done + offs > runtime->buffer_size) { + bytes = frames * stride; + if (subs->hwptr_done + bytes > runtime->buffer_size * stride) { /* err, the transferred area goes over buffer boundary. */ - unsigned int len = runtime->buffer_size - subs->hwptr_done; + unsigned int bytes1 = + runtime->buffer_size * stride - subs->hwptr_done; memcpy(urb->transfer_buffer, - runtime->dma_area + subs->hwptr_done * stride, - len * stride); - memcpy(urb->transfer_buffer + len * stride, - runtime->dma_area, - (offs - len) * stride); + runtime->dma_area + subs->hwptr_done, bytes1); + memcpy(urb->transfer_buffer + bytes1, + runtime->dma_area, bytes - bytes1); } else { memcpy(urb->transfer_buffer, - runtime->dma_area + subs->hwptr_done * stride, - offs * stride); + runtime->dma_area + subs->hwptr_done, bytes); } - subs->hwptr_done += offs; - if (subs->hwptr_done >= runtime->buffer_size) - subs->hwptr_done -= runtime->buffer_size; - runtime->delay += offs; + subs->hwptr_done += bytes; + if (subs->hwptr_done >= runtime->buffer_size * stride) + subs->hwptr_done -= runtime->buffer_size * stride; + runtime->delay += frames; spin_unlock_irqrestore(&subs->lock, flags); - urb->transfer_buffer_length = offs * stride; + urb->transfer_buffer_length = bytes; if (period_elapsed) snd_pcm_period_elapsed(subs->pcm_substream); return 0; @@ -901,18 +899,18 @@ static int wait_clear_urbs(struct snd_usb_substream *subs) /* - * return the current pcm pointer. just return the hwptr_done value. + * return the current pcm pointer. just based on the hwptr_done value. */ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream) { struct snd_usb_substream *subs; - snd_pcm_uframes_t hwptr_done; + unsigned int hwptr_done; subs = (struct snd_usb_substream *)substream->runtime->private_data; spin_lock(&subs->lock); hwptr_done = subs->hwptr_done; spin_unlock(&subs->lock); - return hwptr_done; + return hwptr_done / (substream->runtime->frame_bits >> 3); } -- cgit v0.10.2 From 98e89f606c38a310a20342f90e0c453e6afadf18 Mon Sep 17 00:00:00 2001 From: "John S. Gruber" Date: Sun, 27 Dec 2009 12:19:58 -0500 Subject: ALSA: usb-audio: relax urb data align. restriction HVR-950Q and HVR-850 only Addressing audio quality problem. In sound/usb/usbaudio.c, for the Hauppage HVR-950Q and HVR-850 only, change retire_capture_urb to allow transfers on audio sub-slot boundaries rather than audio slots boundaries. With these devices the left and right channel samples can be split between two different urbs. Throwing away extra channel samples causes a sound quality problem for stereo streams as the left and right channels are swapped repeatedly, perhaps many times per second. Urbs unaligned on sub-slot boundaries are still truncated to the next lowest stride (audio slot) to retain synchronization on samples even though left/right channel synchronization may be lost in this case. Detect the quirk using a case statement in snd_usb_audio_probe. BugLink: https://bugs.launchpad.net/ubuntu/+bug/495745 Signed-off-by: John S. Gruber Signed-off-by: Takashi Iwai diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 8fcb5d5..617515f 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -169,6 +169,7 @@ struct snd_usb_substream { unsigned int curpacksize; /* current packet size in bytes (for capture) */ unsigned int curframesize; /* current packet size in frames (for capture) */ unsigned int fill_max: 1; /* fill max packet size always */ + unsigned int txfr_quirk:1; /* allow sub-frame alignment */ unsigned int fmt_type; /* USB audio format type (1-3) */ unsigned int running: 1; /* running status */ @@ -353,14 +354,25 @@ static int retire_capture_urb(struct snd_usb_substream *subs, snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); // continue; } - frames = urb->iso_frame_desc[i].actual_length / stride; - bytes = frames * stride; + bytes = urb->iso_frame_desc[i].actual_length; + frames = bytes / stride; + if (!subs->txfr_quirk) + bytes = frames * stride; + if (bytes % (runtime->sample_bits >> 3) != 0) { +#ifdef CONFIG_SND_DEBUG_VERBOSE + int oldbytes = bytes; +#endif + bytes = frames * stride; + snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n", + oldbytes, bytes); + } /* update the current pointer */ spin_lock_irqsave(&subs->lock, flags); oldptr = subs->hwptr_done; subs->hwptr_done += bytes; if (subs->hwptr_done >= runtime->buffer_size * stride) subs->hwptr_done -= runtime->buffer_size * stride; + frames = (bytes + (oldptr % stride)) / stride; subs->transfer_done += frames; if (subs->transfer_done >= runtime->period_size) { subs->transfer_done -= runtime->period_size; @@ -2238,6 +2250,7 @@ static void init_substream(struct snd_usb_stream *as, int stream, struct audiofo subs->stream = as; subs->direction = stream; subs->dev = as->chip->dev; + subs->txfr_quirk = as->chip->txfr_quirk; if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) { subs->ops = audio_urb_ops[stream]; } else { @@ -3618,6 +3631,20 @@ static void *snd_usb_audio_probe(struct usb_device *dev, } } + switch (chip->usb_id) { + case USB_ID(0x2040, 0x7200): /* Hauppage hvr950Q */ + case USB_ID(0x2040, 0x7221): /* Hauppage hvr950Q */ + case USB_ID(0x2040, 0x7222): /* Hauppage hvr950Q */ + case USB_ID(0x2040, 0x7223): /* Hauppage hvr950Q */ + case USB_ID(0x2040, 0x7224): /* Hauppage hvr950Q */ + case USB_ID(0x2040, 0x7225): /* Hauppage hvr950Q */ + case USB_ID(0x2040, 0x7230): /* Hauppage hvr850 */ + case USB_ID(0x2040, 0x7250): /* Hauppage hvr950Q */ + chip->txfr_quirk = 1; + break; + default: + chip->txfr_quirk = 0; + } err = 1; /* continue */ if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { /* need some special handlings */ diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 1522167..d180554b8 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -125,6 +125,7 @@ struct snd_usb_audio { struct snd_card *card; u32 usb_id; int shutdown; + unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */ int num_interfaces; int num_suspended_intf; -- cgit v0.10.2 From 52a7a5835173af61b9f6c3038212370d9717526f Mon Sep 17 00:00:00 2001 From: "John S. Gruber" Date: Sun, 27 Dec 2009 12:19:59 -0500 Subject: ALSA: usb-audio: use usbquirk.h for detection of HVR-950Q/850 Detect the HVR-950Q HVR-850 urb data alignment quirk using usbquirk.h rather than using a case statement in snd_usb_audio_probe. Signed-off-by: John S. Gruber Signed-off-by: Takashi Iwai diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 617515f..4ada98e 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -3203,6 +3203,18 @@ static int ignore_interface_quirk(struct snd_usb_audio *chip, return 0; } +/* + * Allow alignment on audio sub-slot (channel samples) rather than + * on audio slots (audio frames) + */ +static int create_align_transfer_quirk(struct snd_usb_audio *chip, + struct usb_interface *iface, + const struct snd_usb_audio_quirk *quirk) +{ + chip->txfr_quirk = 1; + return 1; /* Continue with creating streams and mixer */ +} + /* * boot quirks @@ -3377,7 +3389,8 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip, [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, - [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk + [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, + [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk }; if (quirk->type < QUIRK_TYPE_COUNT) { @@ -3631,20 +3644,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev, } } - switch (chip->usb_id) { - case USB_ID(0x2040, 0x7200): /* Hauppage hvr950Q */ - case USB_ID(0x2040, 0x7221): /* Hauppage hvr950Q */ - case USB_ID(0x2040, 0x7222): /* Hauppage hvr950Q */ - case USB_ID(0x2040, 0x7223): /* Hauppage hvr950Q */ - case USB_ID(0x2040, 0x7224): /* Hauppage hvr950Q */ - case USB_ID(0x2040, 0x7225): /* Hauppage hvr950Q */ - case USB_ID(0x2040, 0x7230): /* Hauppage hvr850 */ - case USB_ID(0x2040, 0x7250): /* Hauppage hvr950Q */ - chip->txfr_quirk = 1; - break; - default: - chip->txfr_quirk = 0; - } + chip->txfr_quirk = 0; err = 1; /* continue */ if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { /* need some special handlings */ diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index d180554b8..9d8cea4 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -161,6 +161,7 @@ enum quirk_type { QUIRK_AUDIO_FIXED_ENDPOINT, QUIRK_AUDIO_EDIROL_UA1000, QUIRK_AUDIO_EDIROL_UAXX, + QUIRK_AUDIO_ALIGN_TRANSFER, QUIRK_TYPE_COUNT }; diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index bd6706c..65bbd22 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -2074,6 +2074,120 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +/* Hauppauge HVR-950Q and HVR-850 */ +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7200), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7201), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7202), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7203), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7204), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7205), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7250), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-950Q", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x2040, 0x7230), + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS, + .bInterfaceClass = USB_CLASS_AUDIO, + .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Hauppauge", + .product_name = "HVR-850", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_AUDIO_ALIGN_TRANSFER, + } +}, + { /* * Some USB MIDI devices don't have an audio control interface, -- cgit v0.10.2 From 6b98515a620592636d2f8e0d3e2942d1cb4847ec Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 4 Jan 2010 16:22:59 +0000 Subject: sound_oss: remove use of old BKL ioctl path Signed-off-by: Alan Cox Signed-off-by: Takashi Iwai diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index 61aaeda..6c3267b 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c @@ -328,11 +328,11 @@ static int sound_mixer_ioctl(int mixdev, unsigned int cmd, void __user *arg) return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg); } -static int sound_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int len = 0, dtype; - int dev = iminor(inode); + int dev = iminor(file->f_dentry->d_inode); + long ret = -EINVAL; void __user *p = (void __user *)arg; if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) { @@ -353,6 +353,7 @@ static int sound_ioctl(struct inode *inode, struct file *file, if (cmd == OSS_GETVERSION) return __put_user(SOUND_VERSION, (int __user *)p); + lock_kernel(); if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ (dev & 0x0f) != SND_DEV_CTL) { dtype = dev & 0x0f; @@ -360,24 +361,31 @@ static int sound_ioctl(struct inode *inode, struct file *file, case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: - return sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev, + ret = sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev, cmd, p); - + break; default: - return sound_mixer_ioctl(dev >> 4, cmd, p); + ret = sound_mixer_ioctl(dev >> 4, cmd, p); + break; } + unlock_kernel(); + return ret; } + switch (dev & 0x0f) { case SND_DEV_CTL: if (cmd == SOUND_MIXER_GETLEVELS) - return get_mixer_levels(p); - if (cmd == SOUND_MIXER_SETLEVELS) - return set_mixer_levels(p); - return sound_mixer_ioctl(dev >> 4, cmd, p); + ret = get_mixer_levels(p); + else if (cmd == SOUND_MIXER_SETLEVELS) + ret = set_mixer_levels(p); + else + ret = sound_mixer_ioctl(dev >> 4, cmd, p); + break; case SND_DEV_SEQ: case SND_DEV_SEQ2: - return sequencer_ioctl(dev, file, cmd, p); + ret = sequencer_ioctl(dev, file, cmd, p); + break; case SND_DEV_DSP: case SND_DEV_DSP16: @@ -390,7 +398,8 @@ static int sound_ioctl(struct inode *inode, struct file *file, break; } - return -EINVAL; + unlock_kernel(); + return ret; } static unsigned int sound_poll(struct file *file, poll_table * wait) @@ -490,7 +499,7 @@ const struct file_operations oss_sound_fops = { .read = sound_read, .write = sound_write, .poll = sound_poll, - .ioctl = sound_ioctl, + .unlocked_ioctl = sound_ioctl, .mmap = sound_mmap, .open = sound_open, .release = sound_release, -- cgit v0.10.2 From d1458279bf9c575a52fd22818ca19c463f380aba Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 14 Jan 2010 09:16:52 +0100 Subject: ALSA: Add snd_pci_quirk_lookup_id() Added a new function to look up a quirk entry with the given PCI SSID instead of a pci device pointer. This can be used when the searched ID is overridden for debugging or such a purpose. Signed-off-by: Takashi Iwai diff --git a/include/sound/core.h b/include/sound/core.h index a61499c..89e0ac1 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -458,5 +458,8 @@ struct snd_pci_quirk { const struct snd_pci_quirk * snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list); +const struct snd_pci_quirk * +snd_pci_quirk_lookup_id(u16 vendor, u16 device, + const struct snd_pci_quirk *list); #endif /* __SOUND_CORE_H */ diff --git a/sound/core/misc.c b/sound/core/misc.c index 23a032c..3da4f92 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -101,8 +101,9 @@ EXPORT_SYMBOL_GPL(__snd_printk); #ifdef CONFIG_PCI #include /** - * snd_pci_quirk_lookup - look up a PCI SSID quirk list - * @pci: pci_dev handle + * snd_pci_quirk_lookup_id - look up a PCI SSID quirk list + * @vendor: PCI SSV id + * @device: PCI SSD id * @list: quirk list, terminated by a null entry * * Look through the given quirk list and finds a matching entry @@ -112,18 +113,39 @@ EXPORT_SYMBOL_GPL(__snd_printk); * Returns the matched entry pointer, or NULL if nothing matched. */ const struct snd_pci_quirk * -snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list) +snd_pci_quirk_lookup_id(u16 vendor, u16 device, + const struct snd_pci_quirk *list) { const struct snd_pci_quirk *q; for (q = list; q->subvendor; q++) { - if (q->subvendor != pci->subsystem_vendor) + if (q->subvendor != vendor) continue; if (!q->subdevice || - (pci->subsystem_device & q->subdevice_mask) == q->subdevice) + (device & q->subdevice_mask) == q->subdevice) return q; } return NULL; } +EXPORT_SYMBOL(snd_pci_quirk_lookup_id); + +/** + * snd_pci_quirk_lookup - look up a PCI SSID quirk list + * @pci: pci_dev handle + * @list: quirk list, terminated by a null entry + * + * Look through the given quirk list and finds a matching entry + * with the same PCI SSID. When subdevice is 0, all subdevice + * values may match. + * + * Returns the matched entry pointer, or NULL if nothing matched. + */ +const struct snd_pci_quirk * +snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list) +{ + return snd_pci_quirk_lookup_id(pci->subsystem_vendor, + pci->subsystem_device, + list); +} EXPORT_SYMBOL(snd_pci_quirk_lookup); #endif -- cgit v0.10.2 From 408bffd01cfcda2907b07fb86b3666e3db86fd82 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 14 Jan 2010 09:19:46 +0100 Subject: ALSA: ctxfi - Add subsystem option Added a new option "subsystem" to override the PCI SSID for identifying the card type. Signed-off-by: Takashi Iwai diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index c540637..c83fd7b 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -482,6 +482,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. reference_rate - reference sample rate, 44100 or 48000 (default) multiple - multiple to ref. sample rate, 1 or 2 (default) + subsystem - override the PCI SSID for probing; the value + consists of SSVID << 16 | SSDID. The default is + zero, which means no override. This module supports multiple cards. diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index cb65bd0..903594e 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -1225,10 +1225,11 @@ static int atc_dev_free(struct snd_device *dev) return ct_atc_destroy(atc); } -static int __devinit atc_identify_card(struct ct_atc *atc) +static int __devinit atc_identify_card(struct ct_atc *atc, unsigned int ssid) { const struct snd_pci_quirk *p; const struct snd_pci_quirk *list; + u16 vendor_id, device_id; switch (atc->chip_type) { case ATC20K1: @@ -1242,13 +1243,19 @@ static int __devinit atc_identify_card(struct ct_atc *atc) default: return -ENOENT; } - p = snd_pci_quirk_lookup(atc->pci, list); + if (ssid) { + vendor_id = ssid >> 16; + device_id = ssid & 0xffff; + } else { + vendor_id = atc->pci->subsystem_vendor; + device_id = atc->pci->subsystem_device; + } + p = snd_pci_quirk_lookup_id(vendor_id, device_id, list); if (p) { if (p->value < 0) { printk(KERN_ERR "ctxfi: " "Device %04x:%04x is black-listed\n", - atc->pci->subsystem_vendor, - atc->pci->subsystem_device); + vendor_id, device_id); return -ENOENT; } atc->model = p->value; @@ -1261,8 +1268,7 @@ static int __devinit atc_identify_card(struct ct_atc *atc) atc->model_name = ct_subsys_name[atc->model]; snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n", atc->chip_name, atc->model_name, - atc->pci->subsystem_vendor, - atc->pci->subsystem_device); + vendor_id, device_id); return 0; } @@ -1636,7 +1642,8 @@ static struct ct_atc atc_preset __devinitdata = { int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, unsigned int rsr, unsigned int msr, - int chip_type, struct ct_atc **ratc) + int chip_type, unsigned int ssid, + struct ct_atc **ratc) { struct ct_atc *atc; static struct snd_device_ops ops = { @@ -1662,7 +1669,7 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, mutex_init(&atc->atc_mutex); /* Find card model */ - err = atc_identify_card(atc); + err = atc_identify_card(atc, ssid); if (err < 0) { printk(KERN_ERR "ctatc: Card not recognised\n"); goto error1; diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h index 9fd8a57..7167c01 100644 --- a/sound/pci/ctxfi/ctatc.h +++ b/sound/pci/ctxfi/ctatc.h @@ -148,7 +148,7 @@ struct ct_atc { int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, unsigned int rsr, unsigned int msr, int chip_type, - struct ct_atc **ratc); + unsigned int subsysid, struct ct_atc **ratc); int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc); #endif /* CTATC_H */ diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index 7654174..ed44ed7 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c @@ -32,6 +32,7 @@ module_param(multiple, uint, S_IRUGO); static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; +static unsigned int subsystem[SNDRV_CARDS]; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for Creative X-Fi driver"); @@ -39,6 +40,8 @@ module_param_array(id, charp, NULL, 0444); MODULE_PARM_DESC(id, "ID string for Creative X-Fi driver"); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver"); +module_param_array(subsystem, int, NULL, 0444); +MODULE_PARM_DESC(subsystem, "Override subsystem ID for Creative X-Fi driver"); static struct pci_device_id ct_pci_dev_ids[] = { /* only X-Fi is supported, so... */ @@ -85,7 +88,7 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) multiple = 2; } err = ct_atc_create(card, pci, reference_rate, multiple, - pci_id->driver_data, &atc); + pci_id->driver_data, subsystem[dev], &atc); if (err < 0) goto error; -- cgit v0.10.2 From 3e879d7bac705be4813a0ec9560cbe31db4b269f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 18 Jan 2010 14:49:50 +0100 Subject: ALSA: pcm - Remove unneeded ifdef pgprot_noncached Signed-off-by: Takashi Iwai diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index a870fe69..5df0d21 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3162,9 +3162,7 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, long size; unsigned long offset; -#ifdef pgprot_noncached area->vm_page_prot = pgprot_noncached(area->vm_page_prot); -#endif area->vm_flags |= VM_IO; size = area->vm_end - area->vm_start; offset = area->vm_pgoff << PAGE_SHIFT; -- cgit v0.10.2 From c32d977b8157bf67cdf47729ce7dd054a26eb534 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 18 Jan 2010 14:58:57 +0100 Subject: ALSA: pcm - Call pgprot_noncached() for vmalloc'ed buffers pgprot_noncached() can be set for vmalloc'ed buffers safely, and we'd need non-cached behavior more or less, even for the intermediate ring- buffers. Now snd_pcm_lib_mmap_vmalloc() is added as the common PCM mmap callback that is coupled with snd_pcm_lib_alloc_vmalloc_buffer() & co. Signed-off-by: Takashi Iwai diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 1d4ca2a..aabf48b 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -1021,6 +1021,10 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_s #define snd_pcm_lib_mmap_iomem NULL #endif +int snd_pcm_lib_mmap_noncached(struct snd_pcm_substream *substream, + struct vm_area_struct *area); +#define snd_pcm_lib_mmap_vmalloc snd_pcm_lib_mmap_noncached + static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max) { *max = dma < 4 ? 64 * 1024 : 128 * 1024; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 5df0d21..88fff44 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3176,6 +3176,15 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); #endif /* SNDRV_PCM_INFO_MMAP */ +/* mmap callback with pgprot_noncached */ +int snd_pcm_lib_mmap_noncached(struct snd_pcm_substream *substream, + struct vm_area_struct *area) +{ + area->vm_page_prot = pgprot_noncached(area->vm_page_prot); + return snd_pcm_default_mmap(substream, area); +} +EXPORT_SYMBOL(snd_pcm_lib_mmap_noncached); + /* * mmap DMA buffer */ diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index c8385d2..35a2f71 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -905,6 +905,7 @@ static struct snd_pcm_ops vx_pcm_playback_ops = { .trigger = vx_pcm_trigger, .pointer = vx_pcm_playback_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; @@ -1125,6 +1126,7 @@ static struct snd_pcm_ops vx_pcm_capture_ops = { .trigger = vx_pcm_trigger, .pointer = vx_pcm_capture_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index 9b486be..6aff217 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -691,6 +691,7 @@ static struct snd_pcm_ops snd_sgio2audio_playback1_ops = { .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { @@ -703,6 +704,7 @@ static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; static struct snd_pcm_ops snd_sgio2audio_capture_ops = { @@ -715,6 +717,7 @@ static struct snd_pcm_ops snd_sgio2audio_capture_ops = { .trigger = snd_sgio2audio_pcm_trigger, .pointer = snd_sgio2audio_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; /* diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c index 0afa683..0d668f4 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c @@ -277,6 +277,7 @@ static struct snd_pcm_ops pdacf_pcm_capture_ops = { .trigger = pdacf_pcm_trigger, .pointer = pdacf_pcm_capture_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; diff --git a/sound/usb/ua101.c b/sound/usb/ua101.c index 16dc7bd..4f4ccdf 100644 --- a/sound/usb/ua101.c +++ b/sound/usb/ua101.c @@ -911,6 +911,7 @@ static struct snd_pcm_ops capture_pcm_ops = { .trigger = capture_pcm_trigger, .pointer = capture_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; static struct snd_pcm_ops playback_pcm_ops = { @@ -923,6 +924,7 @@ static struct snd_pcm_ops playback_pcm_ops = { .trigger = playback_pcm_trigger, .pointer = playback_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; static const struct uac_format_type_i_discrete_descriptor * diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 4ada98e..b8e0b8f 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -1997,6 +1997,7 @@ static struct snd_pcm_ops snd_usb_playback_ops = { .trigger = snd_usb_pcm_playback_trigger, .pointer = snd_usb_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; static struct snd_pcm_ops snd_usb_capture_ops = { @@ -2009,6 +2010,7 @@ static struct snd_pcm_ops snd_usb_capture_ops = { .trigger = snd_usb_pcm_capture_trigger, .pointer = snd_usb_pcm_pointer, .page = snd_pcm_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, }; -- cgit v0.10.2 From cf944ee55cc318bdb1d4b2f3f5cce3257f7c07b3 Mon Sep 17 00:00:00 2001 From: Florian Zumbiehl Date: Tue, 26 Jan 2010 09:06:14 +0100 Subject: ALSA: cs46xx: Fix cpu idling with resume Make sure that capture DMA doesn't stay enabled after system resume as that potentially prevents the processor from entering deep sleep states. Signed-off-by: Florian Zumbiehl Signed-off-by: Takashi Iwai diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index e6b4a87..56fcf00 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -3644,6 +3644,7 @@ int snd_cs46xx_resume(struct pci_dev *pci) #ifdef CONFIG_SND_CS46XX_NEW_DSP int i; #endif + unsigned int tmp; pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); @@ -3685,6 +3686,15 @@ int snd_cs46xx_resume(struct pci_dev *pci) snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]); snd_ac97_resume(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]); + /* + * Stop capture DMA. + */ + tmp = snd_cs46xx_peek(chip, BA1_CCTL); + chip->capt.ctl = tmp & 0x0000ffff; + snd_cs46xx_poke(chip, BA1_CCTL, tmp & 0xffff0000); + + mdelay(5); + /* reset playback/capture */ snd_cs46xx_set_play_sample_rate(chip, 8000); snd_cs46xx_set_capture_sample_rate(chip, 8000); -- cgit v0.10.2 From c85a400499093b2025238413198e48e4d825723e Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Mon, 1 Feb 2010 16:17:01 -0200 Subject: ALSA: trivial: sound seq ioctl dbg: print hexadecimal value padded with 0s Instead of padding with blanks and printing "number=0x a", print "number=0x0a". Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Takashi Iwai diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 8ca2be3..48eca9f 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -2190,7 +2190,7 @@ static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd, if (p->cmd == cmd) return p->func(client, arg); } - snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%2x)\n", + snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n", cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); return -ENOTTY; } -- cgit v0.10.2 From 350a514787a4516746f738f69bff6aa0d4ac70e9 Mon Sep 17 00:00:00 2001 From: Sebastien Alaiwan Date: Fri, 5 Feb 2010 08:58:20 +0100 Subject: ALSA: ice1712: fix: lock samplerate when samplerate locking is enabled I found that the sampling rate locking setting of the ice1712 sound driver was only half-respected : when the driver was locked to, let's say, 44100Hz, and a usermode app was requesting 48000Hz playback, the request was succesful although the soundcard would continue to run at 44100Hz. Here's a patch that will make those requests to fail. Signed-off-by: Sebastien Alaiwan Signed-off-by: Takashi Iwai diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index c7cff6f..fb61943 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -1180,6 +1180,10 @@ static int snd_ice1712_playback_pro_open(struct snd_pcm_substream *substream) snd_pcm_set_sync(substream); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); + if (is_pro_rate_locked(ice)) { + runtime->hw.rate_min = PRO_RATE_DEFAULT; + runtime->hw.rate_max = PRO_RATE_DEFAULT; + } if (ice->spdif.ops.open) ice->spdif.ops.open(ice, substream); @@ -1197,6 +1201,11 @@ static int snd_ice1712_capture_pro_open(struct snd_pcm_substream *substream) snd_pcm_set_sync(substream); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); + if (is_pro_rate_locked(ice)) { + runtime->hw.rate_min = PRO_RATE_DEFAULT; + runtime->hw.rate_max = PRO_RATE_DEFAULT; + } + return 0; } -- cgit v0.10.2 From cebe41d4b8f8092359de31e241815fcb4b4dc0be Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 6 Feb 2010 00:21:03 +0200 Subject: sound: use DEFINE_PCI_DEVICE_TABLE Use DEFINE_PCI_DEVICE_TABLE() to make PCI device ids go to .devinit.rodata section, so they can be discarded in some cases, and make them const. Signed-off-by: Alexey Dobriyan Signed-off-by: Takashi Iwai diff --git a/sound/oss/kahlua.c b/sound/oss/kahlua.c index 89466b0..24d152c 100644 --- a/sound/oss/kahlua.c +++ b/sound/oss/kahlua.c @@ -198,7 +198,7 @@ MODULE_LICENSE("GPL"); * 5530 only. The 5510/5520 decode is different. */ -static struct pci_device_id id_tbl[] = { +static DEFINE_PCI_DEVICE_TABLE(id_tbl) = { { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO), 0 }, { } }; diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 8f5098f..4382d0f 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -1048,7 +1048,7 @@ snd_ad1889_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_device_id snd_ad1889_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_ad1889_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS) }, { 0, }, }; diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index aaf4da6..5c6e322 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -275,7 +275,7 @@ struct snd_ali { #endif }; -static struct pci_device_id snd_ali_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_ali_ids) = { {PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5451), 0, 0, 0}, {0, } }; diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 3aa35af..d7653cb 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -145,7 +145,7 @@ struct snd_als300_substream_data { int block_counter_register; }; -static struct pci_device_id snd_als300_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_als300_ids) = { { 0x4005, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300 }, { 0x4005, 0x0308, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300_PLUS }, { 0, } diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 3dbacde..d75cf7b 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -117,7 +117,7 @@ struct snd_card_als4000 { #endif }; -static struct pci_device_id snd_als4000_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_als4000_ids) = { { 0x4005, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* ALS4000 */ { 0, } }; diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index d6752df..81e2bfc 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -286,7 +286,7 @@ struct atiixp { /* */ -static struct pci_device_id snd_atiixp_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_atiixp_ids) = { { PCI_VDEVICE(ATI, 0x4341), 0 }, /* SB200 */ { PCI_VDEVICE(ATI, 0x4361), 0 }, /* SB300 */ { PCI_VDEVICE(ATI, 0x4370), 0 }, /* SB400 */ diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index e7e147b..91d7036 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -261,7 +261,7 @@ struct atiixp_modem { /* */ -static struct pci_device_id snd_atiixp_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_atiixp_ids) = { { PCI_VDEVICE(ATI, 0x434d), 0 }, /* SB200 */ { PCI_VDEVICE(ATI, 0x4378), 0 }, /* SB400 */ { 0, } diff --git a/sound/pci/au88x0/au8810.c b/sound/pci/au88x0/au8810.c index c0e8c6b..aa51cc7 100644 --- a/sound/pci/au88x0/au8810.c +++ b/sound/pci/au88x0/au8810.c @@ -1,6 +1,6 @@ #include "au8810.h" #include "au88x0.h" -static struct pci_device_id snd_vortex_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = { {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE), 1,}, {0,} }; diff --git a/sound/pci/au88x0/au8820.c b/sound/pci/au88x0/au8820.c index a652733..2f321e7 100644 --- a/sound/pci/au88x0/au8820.c +++ b/sound/pci/au88x0/au8820.c @@ -1,6 +1,6 @@ #include "au8820.h" #include "au88x0.h" -static struct pci_device_id snd_vortex_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = { {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1), 0,}, {0,} }; diff --git a/sound/pci/au88x0/au8830.c b/sound/pci/au88x0/au8830.c index 6c702ad..279b78f 100644 --- a/sound/pci/au88x0/au8830.c +++ b/sound/pci/au88x0/au8830.c @@ -1,6 +1,6 @@ #include "au8830.h" #include "au88x0.h" -static struct pci_device_id snd_vortex_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = { {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2), 0,}, {0,} }; diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index 4d34bb0..67921f9 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c @@ -164,7 +164,7 @@ MODULE_PARM_DESC(id, "ID string for the Audiowerk2 soundcard."); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard."); -static struct pci_device_id snd_aw2_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_aw2_ids) = { {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, 0, 0, 0, 0, 0}, {0} diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 69867ac..4679ed8 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -350,7 +350,7 @@ struct snd_azf3328 { #endif }; -static const struct pci_device_id snd_azf3328_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_azf3328_ids) = { { 0x122D, 0x50DC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* PCI168/3328 */ { 0x122D, 0x80DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 3328 */ { 0, } diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 4e2b925..37e1b5d 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -795,7 +795,7 @@ fail: .driver_data = SND_BT87X_BOARD_ ## id } /* driver_data is the card id for that device */ -static struct pci_device_id snd_bt87x_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_ids) = { /* Hauppauge WinTV series */ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, GENERIC), /* Hauppauge WinTV series */ @@ -964,7 +964,7 @@ static void __devexit snd_bt87x_remove(struct pci_dev *pci) /* default entries for all Bt87x cards - it's not exported */ /* driver_data is set to 0 to call detection */ -static struct pci_device_id snd_bt87x_default_ids[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = { BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), { } diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 15e4138..0a3d3d6 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -1875,7 +1875,7 @@ static int snd_ca0106_resume(struct pci_dev *pci) #endif // PCI IDs -static struct pci_device_id snd_ca0106_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_ca0106_ids) = { { PCI_VDEVICE(CREATIVE, 0x0007), 0 }, /* Audigy LS or Live 24bit */ { 0, } }; diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index a312bae..1ded64e 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -2796,7 +2796,7 @@ static inline void snd_cmipci_proc_init(struct cmipci *cm) {} #endif -static struct pci_device_id snd_cmipci_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_cmipci_ids) = { {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A), 0}, {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B), 0}, {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738), 0}, @@ -3018,7 +3018,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc int integrated_midi = 0; char modelstr[16]; int pcm_index, pcm_spdif_index; - static struct pci_device_id intel_82437vx[] = { + static DEFINE_PCI_DEVICE_TABLE(intel_82437vx) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX) }, { }, }; diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index e2e0359..9edc650 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -494,7 +494,7 @@ struct cs4281 { static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id); -static struct pci_device_id snd_cs4281_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_cs4281_ids) = { { PCI_VDEVICE(CIRRUS, 0x6005), 0, }, /* CS4281 */ { 0, } }; diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 033aec4..767fa7f 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c @@ -64,7 +64,7 @@ MODULE_PARM_DESC(thinkpad, "Force to enable Thinkpad's CLKRUN control."); module_param_array(mmap_valid, bool, NULL, 0444); MODULE_PARM_DESC(mmap_valid, "Support OSS mmap."); -static struct pci_device_id snd_cs46xx_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_cs46xx_ids) = { { PCI_VDEVICE(CIRRUS, 0x6001), 0, }, /* CS4280 */ { PCI_VDEVICE(CIRRUS, 0x6003), 0, }, /* CS4612 */ { PCI_VDEVICE(CIRRUS, 0x6004), 0, }, /* CS4615 */ diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c index dc46432..207479a 100644 --- a/sound/pci/cs5530.c +++ b/sound/pci/cs5530.c @@ -58,7 +58,7 @@ struct snd_cs5530 { unsigned long pci_base; }; -static struct pci_device_id snd_cs5530_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_cs5530_ids) = { {PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0}, {0,} diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 91e7faf..afb8037 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -66,7 +66,7 @@ MODULE_PARM_DESC(id, "ID string for " DRIVER_NAME); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable " DRIVER_NAME); -static struct pci_device_id snd_cs5535audio_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_cs5535audio_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO) }, {} diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index ed44ed7..f42e7e1 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c @@ -43,7 +43,7 @@ MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver"); module_param_array(subsystem, int, NULL, 0444); MODULE_PARM_DESC(subsystem, "Override subsystem ID for Creative X-Fi driver"); -static struct pci_device_id ct_pci_dev_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(ct_pci_dev_ids) = { /* only X-Fi is supported, so... */ { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K1), .driver_data = ATC20K1, diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c index 8c6db3a..a65bafe 100644 --- a/sound/pci/echoaudio/darla20.c +++ b/sound/pci/echoaudio/darla20.c @@ -63,7 +63,7 @@ static const struct firmware card_fw[] = { {0, "darla20_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x1801, 0xECC0, 0x0010, 0, 0, 0}, /* DSP 56301 Darla20 rev.0 */ {0,} }; diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c index 04cbf3e..0a6c50b 100644 --- a/sound/pci/echoaudio/darla24.c +++ b/sound/pci/echoaudio/darla24.c @@ -67,7 +67,7 @@ static const struct firmware card_fw[] = { {0, "darla24_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x1801, 0xECC0, 0x0040, 0, 0, 0}, /* DSP 56301 Darla24 rev.0 */ {0x1057, 0x1801, 0xECC0, 0x0041, 0, 0, 0}, /* DSP 56301 Darla24 rev.1 */ {0,} diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c index 4022e43..f514279 100644 --- a/sound/pci/echoaudio/echo3g.c +++ b/sound/pci/echoaudio/echo3g.c @@ -81,7 +81,7 @@ static const struct firmware card_fw[] = { {0, "3g_asic.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x3410, 0xECC0, 0x0100, 0, 0, 0}, /* Echo 3G */ {0,} }; diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c index c0e64b8..2364f8a 100644 --- a/sound/pci/echoaudio/gina20.c +++ b/sound/pci/echoaudio/gina20.c @@ -67,7 +67,7 @@ static const struct firmware card_fw[] = { {0, "gina20_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x1801, 0xECC0, 0x0020, 0, 0, 0}, /* DSP 56301 Gina20 rev.0 */ {0,} }; diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c index c36a78d..616b558 100644 --- a/sound/pci/echoaudio/gina24.c +++ b/sound/pci/echoaudio/gina24.c @@ -85,7 +85,7 @@ static const struct firmware card_fw[] = { {0, "gina24_361_asic.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x1801, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56301 Gina24 rev.0 */ {0x1057, 0x1801, 0xECC0, 0x0051, 0, 0, 0}, /* DSP 56301 Gina24 rev.1 */ {0x1057, 0x3410, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56361 Gina24 rev.0 */ diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c index 0a58a7c..776175c 100644 --- a/sound/pci/echoaudio/indigo.c +++ b/sound/pci/echoaudio/indigo.c @@ -68,7 +68,7 @@ static const struct firmware card_fw[] = { {0, "indigo_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x3410, 0xECC0, 0x0090, 0, 0, 0}, /* Indigo */ {0,} }; diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c index 2db24d2..8816b0b 100644 --- a/sound/pci/echoaudio/indigodj.c +++ b/sound/pci/echoaudio/indigodj.c @@ -68,7 +68,7 @@ static const struct firmware card_fw[] = { {0, "indigo_dj_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x3410, 0xECC0, 0x00B0, 0, 0, 0}, /* Indigo DJ*/ {0,} }; diff --git a/sound/pci/echoaudio/indigodjx.c b/sound/pci/echoaudio/indigodjx.c index 2e44316..b1e3652 100644 --- a/sound/pci/echoaudio/indigodjx.c +++ b/sound/pci/echoaudio/indigodjx.c @@ -68,7 +68,7 @@ static const struct firmware card_fw[] = { {0, "indigo_djx_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x3410, 0xECC0, 0x00E0, 0, 0, 0}, /* Indigo DJx*/ {0,} }; diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c index a60c0a0..1035125 100644 --- a/sound/pci/echoaudio/indigoio.c +++ b/sound/pci/echoaudio/indigoio.c @@ -69,7 +69,7 @@ static const struct firmware card_fw[] = { {0, "indigo_io_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x3410, 0xECC0, 0x00A0, 0, 0, 0}, /* Indigo IO*/ {0,} }; diff --git a/sound/pci/echoaudio/indigoiox.c b/sound/pci/echoaudio/indigoiox.c index eb3819f..60b7cb2 100644 --- a/sound/pci/echoaudio/indigoiox.c +++ b/sound/pci/echoaudio/indigoiox.c @@ -69,7 +69,7 @@ static const struct firmware card_fw[] = { {0, "indigo_iox_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x3410, 0xECC0, 0x00D0, 0, 0, 0}, /* Indigo IOx */ {0,} }; diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c index 5061946..8c3f5c5 100644 --- a/sound/pci/echoaudio/layla20.c +++ b/sound/pci/echoaudio/layla20.c @@ -76,7 +76,7 @@ static const struct firmware card_fw[] = { {0, "layla20_asic.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x1801, 0xECC0, 0x0030, 0, 0, 0}, /* DSP 56301 Layla20 rev.0 */ {0x1057, 0x1801, 0xECC0, 0x0031, 0, 0, 0}, /* DSP 56301 Layla20 rev.1 */ {0,} diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c index e09e3ea..ed1cc0a 100644 --- a/sound/pci/echoaudio/layla24.c +++ b/sound/pci/echoaudio/layla24.c @@ -87,7 +87,7 @@ static const struct firmware card_fw[] = { {0, "layla24_2S_asic.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x3410, 0xECC0, 0x0060, 0, 0, 0}, /* DSP 56361 Layla24 rev.0 */ {0,} }; diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c index f05c8c0..cc2bbfc 100644 --- a/sound/pci/echoaudio/mia.c +++ b/sound/pci/echoaudio/mia.c @@ -77,7 +77,7 @@ static const struct firmware card_fw[] = { {0, "mia_dsp.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x3410, 0xECC0, 0x0080, 0, 0, 0}, /* DSP 56361 Mia rev.0 */ {0x1057, 0x3410, 0xECC0, 0x0081, 0, 0, 0}, /* DSP 56361 Mia rev.1 */ {0,} diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c index b05bad9..3e7e018 100644 --- a/sound/pci/echoaudio/mona.c +++ b/sound/pci/echoaudio/mona.c @@ -92,7 +92,7 @@ static const struct firmware card_fw[] = { {0, "mona_2_asic.fw"} }; -static struct pci_device_id snd_echo_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { {0x1057, 0x1801, 0xECC0, 0x0070, 0, 0, 0}, /* DSP 56301 Mona rev.0 */ {0x1057, 0x1801, 0xECC0, 0x0071, 0, 0, 0}, /* DSP 56301 Mona rev.1 */ {0x1057, 0x1801, 0xECC0, 0x0072, 0, 0, 0}, /* DSP 56301 Mona rev.2 */ diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 168af67..4203782 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -76,7 +76,7 @@ MODULE_PARM_DESC(subsystem, "Force card subsystem model."); /* * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400 */ -static struct pci_device_id snd_emu10k1_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_emu10k1_ids) = { { PCI_VDEVICE(CREATIVE, 0x0002), 0 }, /* EMU10K1 */ { PCI_VDEVICE(CREATIVE, 0x0004), 1 }, /* Audigy */ { PCI_VDEVICE(CREATIVE, 0x0008), 1 }, /* Audigy 2 Value SB0400 */ diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 1d369ff..df47f73 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -1605,7 +1605,7 @@ static void __devexit snd_emu10k1x_remove(struct pci_dev *pci) } // PCI IDs -static struct pci_device_id snd_emu10k1x_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_emu10k1x_ids) = { { PCI_VDEVICE(CREATIVE, 0x0006), 0 }, /* Dell OEM version (EMU10K1) */ { 0, } }; diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 2b82c5c..c7fba53 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -443,7 +443,7 @@ struct ensoniq { static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id); -static struct pci_device_id snd_audiopci_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_audiopci_ids) = { #ifdef CHIP1370 { PCI_VDEVICE(ENSONIQ, 0x5000), 0, }, /* ES1370 */ #endif diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index fb83e1f..553b752 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -243,7 +243,7 @@ struct es1938 { static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id); -static struct pci_device_id snd_es1938_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_es1938_ids) = { { PCI_VDEVICE(ESS, 0x1969), 0, }, /* Solo-1 */ { 0, } }; diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index a11f453..ecaea9f 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -551,7 +551,7 @@ struct es1968 { static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id); -static struct pci_device_id snd_es1968_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_es1968_ids) = { /* Maestro 1 */ { 0x1285, 0x0100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TYPE_MAESTRO }, /* Maestro 2 */ diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 83508b3..e1baad7 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -205,7 +205,7 @@ struct fm801 { #endif }; -static struct pci_device_id snd_fm801_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_fm801_ids) = { { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* FM801 */ { 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* Gallant Odyssey Sound 4 */ { 0, } diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 1f516e6..ac05bef 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2664,7 +2664,7 @@ static void __devexit azx_remove(struct pci_dev *pci) } /* PCI IDs */ -static struct pci_device_id azx_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { /* ICH 6..10 */ { PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH }, { PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH }, diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index fb61943..4fc6d8b 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -106,7 +106,7 @@ module_param_array(dxr_enable, int, NULL, 0444); MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE."); -static const struct pci_device_id snd_ice1712_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_ice1712_ids) = { { PCI_VDEVICE(ICE, PCI_DEVICE_ID_ICE_1712), 0 }, /* ICE1712 */ { 0, } }; diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index ae29073..c1498fa 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -94,7 +94,7 @@ MODULE_PARM_DESC(model, "Use the given board model."); /* Both VT1720 and VT1724 have the same PCI IDs */ -static const struct pci_device_id snd_vt1724_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_vt1724_ids) = { { PCI_VDEVICE(ICE, PCI_DEVICE_ID_VT1724), 0 }, { 0, } }; diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index b990143..6433e65 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -420,7 +420,7 @@ struct intel8x0 { u32 int_sta_mask; /* interrupt status mask */ }; -static struct pci_device_id snd_intel8x0_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0_ids) = { { PCI_VDEVICE(INTEL, 0x2415), DEVICE_INTEL }, /* 82801AA */ { PCI_VDEVICE(INTEL, 0x2425), DEVICE_INTEL }, /* 82901AB */ { PCI_VDEVICE(INTEL, 0x2445), DEVICE_INTEL }, /* 82801BA */ diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 9e7d12e..13cec1e 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -219,7 +219,7 @@ struct intel8x0m { unsigned int pcm_pos_shift; }; -static struct pci_device_id snd_intel8x0m_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0m_ids) = { { PCI_VDEVICE(INTEL, 0x2416), DEVICE_INTEL }, /* 82801AA */ { PCI_VDEVICE(INTEL, 0x2426), DEVICE_INTEL }, /* 82901AB */ { PCI_VDEVICE(INTEL, 0x2446), DEVICE_INTEL }, /* 82801BA */ diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 7cc38a1..6d79570 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -418,7 +418,7 @@ module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable Korg 1212 soundcard."); MODULE_AUTHOR("Haroldo Gamal "); -static struct pci_device_id snd_korg1212_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_korg1212_ids) = { { .vendor = 0x10b5, .device = 0x906d, diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index 11b8c65..0cca560 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c @@ -55,7 +55,7 @@ static const char card_name[] = "LX6464ES"; #define PCI_DEVICE_ID_PLX_LX6464ES PCI_DEVICE_ID_PLX_9056 -static struct pci_device_id snd_lx6464es_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_lx6464es_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), .subvendor = PCI_VENDOR_ID_DIGIGRAM, .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 75283fbb..b64e781 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -861,7 +861,7 @@ struct snd_m3 { /* * pci ids */ -static struct pci_device_id snd_m3_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_m3_ids) = { {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO_1, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO, PCI_ANY_ID, PCI_ANY_ID, diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index a83d196..7e8e7da 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -60,7 +60,7 @@ MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard."); /* */ -static struct pci_device_id snd_mixart_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_mixart_ids) = { { PCI_VDEVICE(MOTOROLA, 0x0003), 0, }, /* MC8240 */ { 0, } }; diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 97a0731..5a60492 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -262,7 +262,7 @@ struct nm256 { /* * PCI ids */ -static struct pci_device_id snd_nm256_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_nm256_ids) = { {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO), 0}, {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO), 0}, {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO), 0}, diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c index e3c229b..5a87d68 100644 --- a/sound/pci/oxygen/hifier.c +++ b/sound/pci/oxygen/hifier.c @@ -48,7 +48,7 @@ MODULE_PARM_DESC(id, "ID string"); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "enable card"); -static struct pci_device_id hifier_ids[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(hifier_ids) = { { OXYGEN_PCI_SUBID(0x14c3, 0x1710) }, { OXYGEN_PCI_SUBID(0x14c3, 0x1711) }, { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index acbedeb..289cb4d 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -72,7 +72,7 @@ enum { MODEL_CLARO_HALO, /* HT-Omega Claro halo */ }; -static struct pci_device_id oxygen_ids[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { { OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF }, { OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF }, diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 563b6f5..f03a2f2 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -40,7 +40,7 @@ MODULE_PARM_DESC(id, "ID string"); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "enable card"); -static struct pci_device_id xonar_ids[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = { { OXYGEN_PCI_SUBID(0x1043, 0x8269) }, { OXYGEN_PCI_SUBID(0x1043, 0x8275) }, { OXYGEN_PCI_SUBID(0x1043, 0x82b7) }, diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 833e9c7..95cfde2 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -94,7 +94,7 @@ enum { PCI_ID_LAST }; -static struct pci_device_id pcxhr_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(pcxhr_ids) = { { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, }, { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, }, { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, }, diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index b5ca02e..bb08a28 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -506,7 +506,7 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip); /* */ -static struct pci_device_id snd_riptide_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_riptide_ids) = { { PCI_DEVICE(0x127a, 0x4310) }, { PCI_DEVICE(0x127a, 0x4320) }, { PCI_DEVICE(0x127a, 0x4330) }, @@ -515,7 +515,7 @@ static struct pci_device_id snd_riptide_ids[] = { }; #ifdef SUPPORT_JOYSTICK -static struct pci_device_id snd_riptide_joystick_ids[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(snd_riptide_joystick_ids) = { { PCI_DEVICE(0x127a, 0x4312) }, { PCI_DEVICE(0x127a, 0x4322) }, { PCI_DEVICE(0x127a, 0x4332) }, diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index f977dba..d5e1c6e 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -226,7 +226,7 @@ struct rme32 { struct snd_kcontrol *spdif_ctl; }; -static struct pci_device_id snd_rme32_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_rme32_ids) = { {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32), 0,}, {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_8), 0,}, {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_PRO), 0,}, diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 2ba5c0f..9d5252b 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -231,7 +231,7 @@ struct rme96 { struct snd_kcontrol *spdif_ctl; }; -static struct pci_device_id snd_rme96_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_rme96_ids) = { { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96), 0, }, { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8), 0, }, { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PRO), 0, }, diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 7bb827c..52c6eb5 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -585,7 +585,7 @@ static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_d } -static struct pci_device_id snd_hdsp_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_hdsp_ids) = { { .vendor = PCI_VENDOR_ID_XILINX, .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP, diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index a1b10d1..3d72c1e 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -512,7 +512,7 @@ static char channel_map_madi_ss[HDSPM_MAX_CHANNELS] = { }; -static struct pci_device_id snd_hdspm_ids[] __devinitdata = { +static DEFINE_PCI_DEVICE_TABLE(snd_hdspm_ids) = { { .vendor = PCI_VENDOR_ID_XILINX, .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI, diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index bc539ab..44a3e2d 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -314,7 +314,7 @@ static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_d } -static struct pci_device_id snd_rme9652_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_rme9652_ids) = { { .vendor = 0x10ee, .device = 0x3fc4, diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 1a5ff06..7e3e8fb 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -48,7 +48,7 @@ MODULE_PARM_DESC(id, "ID string for SiS7019 Audio Accelerator."); module_param(enable, bool, 0444); MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator."); -static struct pci_device_id snd_sis7019_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_sis7019_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) }, { 0, } }; diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 1f6406c..337b9fa 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -242,7 +242,7 @@ struct sonicvibes { #endif }; -static struct pci_device_id snd_sonic_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_sonic_ids) = { { PCI_VDEVICE(S3, 0xca00), 0, }, { 0, } }; diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 21cef97..6d05818 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -62,7 +62,7 @@ MODULE_PARM_DESC(pcm_channels, "Number of hardware channels assigned for PCM."); module_param_array(wavetable_size, int, NULL, 0444); MODULE_PARM_DESC(wavetable_size, "Maximum memory size in kB for wavetable synth."); -static struct pci_device_id snd_trident_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_trident_ids) = { {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX), PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX), diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 8a332d2..9595b5b 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -401,7 +401,7 @@ struct via82xx { #endif }; -static struct pci_device_id snd_via82xx_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_via82xx_ids) = { /* 0x1106, 0x3058 */ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C686_5), TYPE_CARD_VIA686, }, /* 686A */ /* 0x1106, 0x3059 */ diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 47eb615..f7e8bbbe 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -260,7 +260,7 @@ struct via82xx_modem { struct snd_info_entry *proc_entry; }; -static struct pci_device_id snd_via82xx_modem_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_via82xx_modem_ids) = { { PCI_VDEVICE(VIA, 0x3068), TYPE_CARD_VIA82XX_MODEM, }, { 0, } }; diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index fc9136c..99a9a81 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -60,7 +60,7 @@ enum { VX_PCI_VX222_NEW }; -static struct pci_device_id snd_vx222_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_vx222_ids) = { { 0x10b5, 0x9050, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_OLD, }, /* PLX */ { 0x10b5, 0x9030, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_NEW, }, /* PLX */ { 0, } diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index e6b18b9..80c6821 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -66,7 +66,7 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address"); module_param_array(rear_switch, bool, NULL, 0444); MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch"); -static struct pci_device_id snd_ymfpci_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(snd_ymfpci_ids) = { { PCI_VDEVICE(YAMAHA, 0x0004), 0, }, /* YMF724 */ { PCI_VDEVICE(YAMAHA, 0x000d), 0, }, /* YMF724F */ { PCI_VDEVICE(YAMAHA, 0x000a), 0, }, /* YMF740 */ -- cgit v0.10.2 From 19b50063780953563e3c3a2867c39aad7b9e64cf Mon Sep 17 00:00:00 2001 From: Giuliano Pochini Date: Sun, 14 Feb 2010 18:15:34 +0100 Subject: ALSA: Echoaudio - Add firmware cache #1 Changes the way the firmware is passed through functions. When CONFIG_PM is enabled the firmware cannot be released because the driver will need it again to resume the card. With this patch the firmware is passed as an index of the struct firmware card_fw[] in place of a pointer. That same index is then used to locate the firmware in the firmware cache. Signed-off-by: Giuliano Pochini Signed-off-by: Takashi Iwai diff --git a/sound/pci/echoaudio/darla20_dsp.c b/sound/pci/echoaudio/darla20_dsp.c index 2904330..a44135d 100644 --- a/sound/pci/echoaudio/darla20_dsp.c +++ b/sound/pci/echoaudio/darla20_dsp.c @@ -45,7 +45,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_DARLA20_DSP]; + chip->dsp_code_to_load = FW_DARLA20_DSP; chip->spdif_status = GD_SPDIF_STATUS_UNDEF; chip->clock_state = GD_CLOCK_UNDEF; /* Since this card has no ASIC, mark it as loaded so everything diff --git a/sound/pci/echoaudio/darla24_dsp.c b/sound/pci/echoaudio/darla24_dsp.c index 6022873..d681da1 100644 --- a/sound/pci/echoaudio/darla24_dsp.c +++ b/sound/pci/echoaudio/darla24_dsp.c @@ -45,7 +45,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_DARLA24_DSP]; + chip->dsp_code_to_load = FW_DARLA24_DSP; /* Since this card has no ASIC, mark it as loaded so everything works OK */ chip->asic_loaded = TRUE; diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c index 57967e5..f007193 100644 --- a/sound/pci/echoaudio/echo3g_dsp.c +++ b/sound/pci/echoaudio/echo3g_dsp.c @@ -61,7 +61,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; chip->has_midi = TRUE; - chip->dsp_code_to_load = &card_fw[FW_ECHO3G_DSP]; + chip->dsp_code_to_load = FW_ECHO3G_DSP; /* Load the DSP code and the ASIC on the PCI card and get what type of external box is attached */ diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 1305f7c..78fc263 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -36,11 +36,15 @@ MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard."); static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999}; static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1); + + static int get_firmware(const struct firmware **fw_entry, - const struct firmware *frm, struct echoaudio *chip) + struct echoaudio *chip, const short fw_index) { int err; char name[30]; + const struct firmware *frm = &card_fw[fw_index]; + DE_ACT(("firmware requested: %s\n", frm->data)); snprintf(name, sizeof(name), "ea/%s", frm->data); if ((err = request_firmware(fw_entry, name, pci_device(chip))) < 0) @@ -48,6 +52,8 @@ static int get_firmware(const struct firmware **fw_entry, return err; } + + static void free_firmware(const struct firmware *fw_entry) { release_firmware(fw_entry); diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h index f9490ae..be76ef3 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h @@ -442,8 +442,8 @@ struct echoaudio { u16 device_id, subdevice_id; u16 *dsp_code; /* Current DSP code loaded, * NULL if nothing loaded */ - const struct firmware *dsp_code_to_load;/* DSP code to load */ - const struct firmware *asic_code; /* Current ASIC code */ + short dsp_code_to_load; /* DSP code to load */ + short asic_code; /* Current ASIC code */ u32 comm_page_phys; /* Physical address of the * memory seen by DSP */ volatile u32 __iomem *dsp_registers; /* DSP's register base */ @@ -464,7 +464,7 @@ static int load_firmware(struct echoaudio *chip); static int wait_handshake(struct echoaudio *chip); static int send_vector(struct echoaudio *chip, u32 command); static int get_firmware(const struct firmware **fw_entry, - const struct firmware *frm, struct echoaudio *chip); + struct echoaudio *chip, const short fw_index); static void free_firmware(const struct firmware *fw_entry); #ifdef ECHOCARD_HAS_MIDI diff --git a/sound/pci/echoaudio/echoaudio_3g.c b/sound/pci/echoaudio/echoaudio_3g.c index e32a748..658db44 100644 --- a/sound/pci/echoaudio/echoaudio_3g.c +++ b/sound/pci/echoaudio/echoaudio_3g.c @@ -227,12 +227,11 @@ static int load_asic(struct echoaudio *chip) /* Give the DSP a few milliseconds to settle down */ mdelay(2); - err = load_asic_generic(chip, DSP_FNC_LOAD_3G_ASIC, - &card_fw[FW_3G_ASIC]); + err = load_asic_generic(chip, DSP_FNC_LOAD_3G_ASIC, FW_3G_ASIC); if (err < 0) return err; - chip->asic_code = &card_fw[FW_3G_ASIC]; + chip->asic_code = FW_3G_ASIC; /* Now give the new ASIC some time to set up */ msleep(1000); diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c index 4df51ef..031ef7e 100644 --- a/sound/pci/echoaudio/echoaudio_dsp.c +++ b/sound/pci/echoaudio/echoaudio_dsp.c @@ -175,15 +175,15 @@ static inline int check_asic_status(struct echoaudio *chip) #ifdef ECHOCARD_HAS_ASIC /* Load ASIC code - done after the DSP is loaded */ -static int load_asic_generic(struct echoaudio *chip, u32 cmd, - const struct firmware *asic) +static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic) { const struct firmware *fw; int err; u32 i, size; u8 *code; - if ((err = get_firmware(&fw, asic, chip)) < 0) { + err = get_firmware(&fw, chip, asic); + if (err < 0) { snd_printk(KERN_WARNING "Firmware not found !\n"); return err; } @@ -245,7 +245,8 @@ static int install_resident_loader(struct echoaudio *chip) return 0; } - if ((i = get_firmware(&fw, &card_fw[FW_361_LOADER], chip)) < 0) { + i = get_firmware(&fw, chip, FW_361_LOADER); + if (i < 0) { snd_printk(KERN_WARNING "Firmware not found !\n"); return i; } @@ -485,7 +486,8 @@ static int load_firmware(struct echoaudio *chip) chip->dsp_code = NULL; } - if ((err = get_firmware(&fw, chip->dsp_code_to_load, chip)) < 0) + err = get_firmware(&fw, chip, chip->dsp_code_to_load); + if (err < 0) return err; err = load_dsp(chip, (u16 *)fw->data); free_firmware(fw); diff --git a/sound/pci/echoaudio/gina20_dsp.c b/sound/pci/echoaudio/gina20_dsp.c index 3f1e747..c5de88b 100644 --- a/sound/pci/echoaudio/gina20_dsp.c +++ b/sound/pci/echoaudio/gina20_dsp.c @@ -49,7 +49,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_GINA20_DSP]; + chip->dsp_code_to_load = FW_GINA20_DSP; chip->spdif_status = GD_SPDIF_STATUS_UNDEF; chip->clock_state = GD_CLOCK_UNDEF; /* Since this card has no ASIC, mark it as loaded so everything diff --git a/sound/pci/echoaudio/gina24_dsp.c b/sound/pci/echoaudio/gina24_dsp.c index 2fef37a..093dd7b 100644 --- a/sound/pci/echoaudio/gina24_dsp.c +++ b/sound/pci/echoaudio/gina24_dsp.c @@ -33,8 +33,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force); static int set_input_clock(struct echoaudio *chip, u16 clock); static int set_professional_spdif(struct echoaudio *chip, char prof); static int set_digital_mode(struct echoaudio *chip, u8 mode); -static int load_asic_generic(struct echoaudio *chip, u32 cmd, - const struct firmware *asic); +static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic); static int check_asic_status(struct echoaudio *chip); @@ -64,13 +63,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) /* Gina24 comes in both '301 and '361 flavors */ if (chip->device_id == DEVICE_ID_56361) { - chip->dsp_code_to_load = &card_fw[FW_GINA24_361_DSP]; + chip->dsp_code_to_load = FW_GINA24_361_DSP; chip->digital_modes = ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; } else { - chip->dsp_code_to_load = &card_fw[FW_GINA24_301_DSP]; + chip->dsp_code_to_load = FW_GINA24_301_DSP; chip->digital_modes = ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | @@ -125,7 +124,7 @@ static int load_asic(struct echoaudio *chip) { u32 control_reg; int err; - const struct firmware *fw; + short asic; if (chip->asic_loaded) return 1; @@ -135,14 +134,15 @@ static int load_asic(struct echoaudio *chip) /* Pick the correct ASIC for '301 or '361 Gina24 */ if (chip->device_id == DEVICE_ID_56361) - fw = &card_fw[FW_GINA24_361_ASIC]; + asic = FW_GINA24_361_ASIC; else - fw = &card_fw[FW_GINA24_301_ASIC]; + asic = FW_GINA24_301_ASIC; - if ((err = load_asic_generic(chip, DSP_FNC_LOAD_GINA24_ASIC, fw)) < 0) + err = load_asic_generic(chip, DSP_FNC_LOAD_GINA24_ASIC, asic); + if (err < 0) return err; - chip->asic_code = fw; + chip->asic_code = asic; /* Now give the new ASIC a little time to set up */ mdelay(10); diff --git a/sound/pci/echoaudio/indigo_dsp.c b/sound/pci/echoaudio/indigo_dsp.c index 0b2cd9c..8799d2e 100644 --- a/sound/pci/echoaudio/indigo_dsp.c +++ b/sound/pci/echoaudio/indigo_dsp.c @@ -50,7 +50,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_INDIGO_DSP]; + chip->dsp_code_to_load = FW_INDIGO_DSP; /* Since this card has no ASIC, mark it as loaded so everything works OK */ chip->asic_loaded = TRUE; diff --git a/sound/pci/echoaudio/indigodj_dsp.c b/sound/pci/echoaudio/indigodj_dsp.c index 0839291..cb1c92c 100644 --- a/sound/pci/echoaudio/indigodj_dsp.c +++ b/sound/pci/echoaudio/indigodj_dsp.c @@ -50,7 +50,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_INDIGO_DJ_DSP]; + chip->dsp_code_to_load = FW_INDIGO_DJ_DSP; /* Since this card has no ASIC, mark it as loaded so everything works OK */ chip->asic_loaded = TRUE; diff --git a/sound/pci/echoaudio/indigodjx_dsp.c b/sound/pci/echoaudio/indigodjx_dsp.c index f591fc2..91dbfeb 100644 --- a/sound/pci/echoaudio/indigodjx_dsp.c +++ b/sound/pci/echoaudio/indigodjx_dsp.c @@ -48,7 +48,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_INDIGO_DJX_DSP]; + chip->dsp_code_to_load = FW_INDIGO_DJX_DSP; /* Since this card has no ASIC, mark it as loaded so everything works OK */ chip->asic_loaded = TRUE; diff --git a/sound/pci/echoaudio/indigoio_dsp.c b/sound/pci/echoaudio/indigoio_dsp.c index 0604c8a..134e783 100644 --- a/sound/pci/echoaudio/indigoio_dsp.c +++ b/sound/pci/echoaudio/indigoio_dsp.c @@ -50,7 +50,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_INDIGO_IO_DSP]; + chip->dsp_code_to_load = FW_INDIGO_IO_DSP; /* Since this card has no ASIC, mark it as loaded so everything works OK */ chip->asic_loaded = TRUE; diff --git a/sound/pci/echoaudio/indigoiox_dsp.c b/sound/pci/echoaudio/indigoiox_dsp.c index f357521..766cf50 100644 --- a/sound/pci/echoaudio/indigoiox_dsp.c +++ b/sound/pci/echoaudio/indigoiox_dsp.c @@ -48,7 +48,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_INDIGO_IOX_DSP]; + chip->dsp_code_to_load = FW_INDIGO_IOX_DSP; /* Since this card has no ASIC, mark it as loaded so everything works OK */ chip->asic_loaded = TRUE; diff --git a/sound/pci/echoaudio/layla20_dsp.c b/sound/pci/echoaudio/layla20_dsp.c index 83750e9..07f3245 100644 --- a/sound/pci/echoaudio/layla20_dsp.c +++ b/sound/pci/echoaudio/layla20_dsp.c @@ -31,8 +31,7 @@ static int read_dsp(struct echoaudio *chip, u32 *data); static int set_professional_spdif(struct echoaudio *chip, char prof); -static int load_asic_generic(struct echoaudio *chip, u32 cmd, - const struct firmware *asic); +static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic); static int check_asic_status(struct echoaudio *chip); static int update_flags(struct echoaudio *chip); @@ -54,7 +53,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; chip->has_midi = TRUE; - chip->dsp_code_to_load = &card_fw[FW_LAYLA20_DSP]; + chip->dsp_code_to_load = FW_LAYLA20_DSP; chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER; @@ -144,7 +143,7 @@ static int load_asic(struct echoaudio *chip) return 0; err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA_ASIC, - &card_fw[FW_LAYLA20_ASIC]); + FW_LAYLA20_ASIC); if (err < 0) return err; diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c index d61b5cb..12dc00a 100644 --- a/sound/pci/echoaudio/layla24_dsp.c +++ b/sound/pci/echoaudio/layla24_dsp.c @@ -32,8 +32,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force); static int set_input_clock(struct echoaudio *chip, u16 clock); static int set_professional_spdif(struct echoaudio *chip, char prof); static int set_digital_mode(struct echoaudio *chip, u8 mode); -static int load_asic_generic(struct echoaudio *chip, u32 cmd, - const struct firmware *asic); +static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic); static int check_asic_status(struct echoaudio *chip); @@ -54,7 +53,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; chip->has_midi = TRUE; - chip->dsp_code_to_load = &card_fw[FW_LAYLA24_DSP]; + chip->dsp_code_to_load = FW_LAYLA24_DSP; chip->input_clock_types = ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_ADAT; @@ -123,18 +122,18 @@ static int load_asic(struct echoaudio *chip) /* Load the ASIC for the PCI card */ err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_PCI_CARD_ASIC, - &card_fw[FW_LAYLA24_1_ASIC]); + FW_LAYLA24_1_ASIC); if (err < 0) return err; - chip->asic_code = &card_fw[FW_LAYLA24_2S_ASIC]; + chip->asic_code = FW_LAYLA24_2S_ASIC; /* Now give the new ASIC a little time to set up */ mdelay(10); /* Do the external one */ err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC, - &card_fw[FW_LAYLA24_2S_ASIC]); + FW_LAYLA24_2S_ASIC); if (err < 0) return FALSE; @@ -299,7 +298,7 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) /* Depending on what digital mode you want, Layla24 needs different ASICs loaded. This function checks the ASIC needed for the new mode and sees if it matches the one already loaded. */ -static int switch_asic(struct echoaudio *chip, const struct firmware *asic) +static int switch_asic(struct echoaudio *chip, short asic) { s8 *monitors; @@ -335,7 +334,7 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) { u32 control_reg; int err, incompatible_clock; - const struct firmware *asic; + short asic; /* Set clock to "internal" if it's not compatible with the new mode */ incompatible_clock = FALSE; @@ -344,12 +343,12 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) case DIGITAL_MODE_SPDIF_RCA: if (chip->input_clock == ECHO_CLOCK_ADAT) incompatible_clock = TRUE; - asic = &card_fw[FW_LAYLA24_2S_ASIC]; + asic = FW_LAYLA24_2S_ASIC; break; case DIGITAL_MODE_ADAT: if (chip->input_clock == ECHO_CLOCK_SPDIF) incompatible_clock = TRUE; - asic = &card_fw[FW_LAYLA24_2A_ASIC]; + asic = FW_LAYLA24_2A_ASIC; break; default: DE_ACT(("Digital mode not supported: %d\n", mode)); diff --git a/sound/pci/echoaudio/mia_dsp.c b/sound/pci/echoaudio/mia_dsp.c index 5514051..d0302f2 100644 --- a/sound/pci/echoaudio/mia_dsp.c +++ b/sound/pci/echoaudio/mia_dsp.c @@ -53,7 +53,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->device_id = device_id; chip->subdevice_id = subdevice_id; chip->bad_board = TRUE; - chip->dsp_code_to_load = &card_fw[FW_MIA_DSP]; + chip->dsp_code_to_load = FW_MIA_DSP; /* Since this card has no ASIC, mark it as loaded so everything works OK */ chip->asic_loaded = TRUE; diff --git a/sound/pci/echoaudio/mona_dsp.c b/sound/pci/echoaudio/mona_dsp.c index eaa619b..b28b8e4 100644 --- a/sound/pci/echoaudio/mona_dsp.c +++ b/sound/pci/echoaudio/mona_dsp.c @@ -33,8 +33,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force); static int set_input_clock(struct echoaudio *chip, u16 clock); static int set_professional_spdif(struct echoaudio *chip, char prof); static int set_digital_mode(struct echoaudio *chip, u8 mode); -static int load_asic_generic(struct echoaudio *chip, u32 cmd, - const struct firmware *asic); +static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic); static int check_asic_status(struct echoaudio *chip); @@ -64,9 +63,9 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) /* Mona comes in both '301 and '361 flavors */ if (chip->device_id == DEVICE_ID_56361) - chip->dsp_code_to_load = &card_fw[FW_MONA_361_DSP]; + chip->dsp_code_to_load = FW_MONA_361_DSP; else - chip->dsp_code_to_load = &card_fw[FW_MONA_301_DSP]; + chip->dsp_code_to_load = FW_MONA_301_DSP; chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; chip->professional_spdif = FALSE; @@ -120,7 +119,7 @@ static int load_asic(struct echoaudio *chip) { u32 control_reg; int err; - const struct firmware *asic; + short asic; if (chip->asic_loaded) return 0; @@ -128,9 +127,9 @@ static int load_asic(struct echoaudio *chip) mdelay(10); if (chip->device_id == DEVICE_ID_56361) - asic = &card_fw[FW_MONA_361_1_ASIC48]; + asic = FW_MONA_361_1_ASIC48; else - asic = &card_fw[FW_MONA_301_1_ASIC48]; + asic = FW_MONA_301_1_ASIC48; err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_PCI_CARD_ASIC, asic); if (err < 0) @@ -141,7 +140,7 @@ static int load_asic(struct echoaudio *chip) /* Do the external one */ err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_EXTERNAL_ASIC, - &card_fw[FW_MONA_2_ASIC]); + FW_MONA_2_ASIC); if (err < 0) return err; @@ -165,22 +164,22 @@ loaded. This function checks the ASIC needed for the new mode and sees if it matches the one already loaded. */ static int switch_asic(struct echoaudio *chip, char double_speed) { - const struct firmware *asic; int err; + short asic; /* Check the clock detect bits to see if this is a single-speed clock or a double-speed clock; load a new ASIC if necessary. */ if (chip->device_id == DEVICE_ID_56361) { if (double_speed) - asic = &card_fw[FW_MONA_361_1_ASIC96]; + asic = FW_MONA_361_1_ASIC96; else - asic = &card_fw[FW_MONA_361_1_ASIC48]; + asic = FW_MONA_361_1_ASIC48; } else { if (double_speed) - asic = &card_fw[FW_MONA_301_1_ASIC96]; + asic = FW_MONA_301_1_ASIC96; else - asic = &card_fw[FW_MONA_301_1_ASIC48]; + asic = FW_MONA_301_1_ASIC48; } if (asic != chip->asic_code) { @@ -200,7 +199,7 @@ static int switch_asic(struct echoaudio *chip, char double_speed) static int set_sample_rate(struct echoaudio *chip, u32 rate) { u32 control_reg, clock; - const struct firmware *asic; + short asic; char force_write; /* Only set the clock for internal mode. */ @@ -218,14 +217,14 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) if (chip->digital_mode == DIGITAL_MODE_ADAT) return -EINVAL; if (chip->device_id == DEVICE_ID_56361) - asic = &card_fw[FW_MONA_361_1_ASIC96]; + asic = FW_MONA_361_1_ASIC96; else - asic = &card_fw[FW_MONA_301_1_ASIC96]; + asic = FW_MONA_301_1_ASIC96; } else { if (chip->device_id == DEVICE_ID_56361) - asic = &card_fw[FW_MONA_361_1_ASIC48]; + asic = FW_MONA_361_1_ASIC48; else - asic = &card_fw[FW_MONA_301_1_ASIC48]; + asic = FW_MONA_301_1_ASIC48; } force_write = 0; @@ -410,8 +409,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) case DIGITAL_MODE_ADAT: /* If the current ASIC is the 96KHz ASIC, switch the ASIC and set to 48 KHz */ - if (chip->asic_code == &card_fw[FW_MONA_361_1_ASIC96] || - chip->asic_code == &card_fw[FW_MONA_301_1_ASIC96]) { + if (chip->asic_code == FW_MONA_361_1_ASIC96 || + chip->asic_code == FW_MONA_301_1_ASIC96) { set_sample_rate(chip, 48000); } control_reg |= GML_ADAT_MODE; -- cgit v0.10.2 From 4f8ada444cc7a7ea70cdc81f098b34c5f1f2df41 Mon Sep 17 00:00:00 2001 From: Giuliano Pochini Date: Sun, 14 Feb 2010 18:15:51 +0100 Subject: ALSA: Echoaudio - Add firmware cache #2 This patch implements a simple cache for the firmware files when CONFIG_PM is defined. This patch changes get_firmware(), free_firmware() and adds free_firmware_cache(). The first two functions implement a very simple cache and the latter is used to actually release all the stored firmwares when the module is unloaded. When CONFIG_PM is not enabled those functions act as before, that is free_firmware() releases the firmware immediately and free_firmware_cache() does nothing. Signed-off-by: Giuliano Pochini Signed-off-by: Takashi Iwai diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 78fc263..79dde95 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -43,12 +43,24 @@ static int get_firmware(const struct firmware **fw_entry, { int err; char name[30]; - const struct firmware *frm = &card_fw[fw_index]; - DE_ACT(("firmware requested: %s\n", frm->data)); - snprintf(name, sizeof(name), "ea/%s", frm->data); - if ((err = request_firmware(fw_entry, name, pci_device(chip))) < 0) +#ifdef CONFIG_PM + if (chip->fw_cache[fw_index]) { + DE_ACT(("firmware requested: %s is cached\n", card_fw[fw_index].data)); + *fw_entry = chip->fw_cache[fw_index]; + return 0; + } +#endif + + DE_ACT(("firmware requested: %s\n", card_fw[fw_index].data)); + snprintf(name, sizeof(name), "ea/%s", card_fw[fw_index].data); + err = request_firmware(fw_entry, name, pci_device(chip)); + if (err < 0) snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err); +#ifdef CONFIG_PM + else + chip->fw_cache[fw_index] = *fw_entry; +#endif return err; } @@ -56,8 +68,29 @@ static int get_firmware(const struct firmware **fw_entry, static void free_firmware(const struct firmware *fw_entry) { +#ifdef CONFIG_PM + DE_ACT(("firmware not released (kept in cache)\n")); +#else release_firmware(fw_entry); DE_ACT(("firmware released\n")); +#endif +} + + + +static void free_firmware_cache(struct echoaudio *chip) +{ +#ifdef CONFIG_PM + int i; + + for (i = 0; i < 8 ; i++) + if (chip->fw_cache[i]) { + release_firmware(chip->fw_cache[i]); + DE_ACT(("release_firmware(%d)\n", i)); + } + + DE_ACT(("firmware_cache released\n")); +#endif } @@ -1880,6 +1913,7 @@ static int snd_echo_free(struct echoaudio *chip) pci_disable_device(chip->pci); /* release chip data */ + free_firmware_cache(chip); kfree(chip); DE_INIT(("Chip freed.\n")); return 0; diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h index be76ef3..a84c0d1 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h @@ -449,6 +449,9 @@ struct echoaudio { volatile u32 __iomem *dsp_registers; /* DSP's register base */ u32 active_mask; /* Chs. active mask or * punks out */ +#ifdef CONFIG_PM + const struct firmware *fw_cache[8]; /* Cached firmwares */ +#endif #ifdef ECHOCARD_HAS_MIDI u16 mtc_state; /* State for MIDI input parsing state machine */ -- cgit v0.10.2 From ad3499f4668f684ef6e5d0222ae14d5e4ade1fdd Mon Sep 17 00:00:00 2001 From: Giuliano Pochini Date: Sun, 14 Feb 2010 18:15:59 +0100 Subject: ALSA: Echoaudio - Add suspend support #1 Move the controls init code outside the init_hw() function because is must not be called during resume. This patch moves the code that initializes the card's controls with default valued from the init_hw() function into a separated set_mixer_defaults() function (one for each of the 16 supported cards). This change is necessary because during resume we must resurrect the hardware without losing the previous settings. set_mixer_defaults() must be called only once when the module is loaded. Signed-off-by: Giuliano Pochini Signed-off-by: Takashi Iwai diff --git a/sound/pci/echoaudio/darla20_dsp.c b/sound/pci/echoaudio/darla20_dsp.c index a44135d..20c7cbc 100644 --- a/sound/pci/echoaudio/darla20_dsp.c +++ b/sound/pci/echoaudio/darla20_dsp.c @@ -57,15 +57,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + return init_line_levels(chip); +} + + + /* The Darla20 has no external clock sources */ static u32 detect_input_clocks(const struct echoaudio *chip) { diff --git a/sound/pci/echoaudio/darla24_dsp.c b/sound/pci/echoaudio/darla24_dsp.c index d681da1..6da6663 100644 --- a/sound/pci/echoaudio/darla24_dsp.c +++ b/sound/pci/echoaudio/darla24_dsp.c @@ -56,15 +56,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { u32 clocks_from_dsp, clock_bits; diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c index f007193..3cdc2ee 100644 --- a/sound/pci/echoaudio/echo3g_dsp.c +++ b/sound/pci/echoaudio/echo3g_dsp.c @@ -97,20 +97,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) chip->digital_modes = ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; - chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; - chip->professional_spdif = FALSE; - chip->non_audio_spdif = FALSE; - chip->bad_board = FALSE; - - if ((err = init_line_levels(chip)) < 0) - return err; - err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA); - if (err < 0) - return err; - err = set_phantom_power(chip, 0); - if (err < 0) - return err; - err = set_professional_spdif(chip, TRUE); DE_INIT(("init_hw done\n")); return err; @@ -118,6 +104,18 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) +static int set_mixer_defaults(struct echoaudio *chip) +{ + chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; + chip->professional_spdif = FALSE; + chip->non_audio_spdif = FALSE; + chip->bad_board = FALSE; + chip->phantom_power = FALSE; + return init_line_levels(chip); +} + + + static int set_phantom_power(struct echoaudio *chip, char on) { u32 control_reg = le32_to_cpu(chip->comm_page->control_register); diff --git a/sound/pci/echoaudio/gina20_dsp.c b/sound/pci/echoaudio/gina20_dsp.c index c5de88b..d1615a0 100644 --- a/sound/pci/echoaudio/gina20_dsp.c +++ b/sound/pci/echoaudio/gina20_dsp.c @@ -62,17 +62,20 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - - err = set_professional_spdif(chip, TRUE); - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + chip->professional_spdif = FALSE; + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { u32 clocks_from_dsp, clock_bits; diff --git a/sound/pci/echoaudio/gina24_dsp.c b/sound/pci/echoaudio/gina24_dsp.c index 093dd7b..98f7cfa 100644 --- a/sound/pci/echoaudio/gina24_dsp.c +++ b/sound/pci/echoaudio/gina24_dsp.c @@ -57,9 +57,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | ECHO_CLOCK_BIT_ESYNC | ECHO_CLOCK_BIT_ESYNC96 | ECHO_CLOCK_BIT_ADAT; - chip->professional_spdif = FALSE; - chip->digital_in_automute = TRUE; - chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; /* Gina24 comes in both '301 and '361 flavors */ if (chip->device_id == DEVICE_ID_56361) { @@ -81,19 +78,22 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA); - if (err < 0) - return err; - err = set_professional_spdif(chip, TRUE); - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; + chip->professional_spdif = FALSE; + chip->digital_in_automute = TRUE; + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { u32 clocks_from_dsp, clock_bits; diff --git a/sound/pci/echoaudio/indigo_dsp.c b/sound/pci/echoaudio/indigo_dsp.c index 8799d2e..5e85f14 100644 --- a/sound/pci/echoaudio/indigo_dsp.c +++ b/sound/pci/echoaudio/indigo_dsp.c @@ -60,15 +60,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { return ECHO_CLOCK_BIT_INTERNAL; diff --git a/sound/pci/echoaudio/indigo_express_dsp.c b/sound/pci/echoaudio/indigo_express_dsp.c index 9ab625e..2e4ab3e 100644 --- a/sound/pci/echoaudio/indigo_express_dsp.c +++ b/sound/pci/echoaudio/indigo_express_dsp.c @@ -61,6 +61,7 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) control_reg |= clock; if (control_reg != old_control_reg) { + DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock)); chip->comm_page->control_register = cpu_to_le32(control_reg); chip->sample_rate = rate; clear_handshake(chip); diff --git a/sound/pci/echoaudio/indigodj_dsp.c b/sound/pci/echoaudio/indigodj_dsp.c index cb1c92c..68f3c8c 100644 --- a/sound/pci/echoaudio/indigodj_dsp.c +++ b/sound/pci/echoaudio/indigodj_dsp.c @@ -60,15 +60,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { return ECHO_CLOCK_BIT_INTERNAL; diff --git a/sound/pci/echoaudio/indigodjx_dsp.c b/sound/pci/echoaudio/indigodjx_dsp.c index 91dbfeb..bb9632c7 100644 --- a/sound/pci/echoaudio/indigodjx_dsp.c +++ b/sound/pci/echoaudio/indigodjx_dsp.c @@ -59,10 +59,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - err = init_line_levels(chip); - if (err < 0) - return err; - DE_INIT(("init_hw done\n")); return err; } + + + +static int set_mixer_defaults(struct echoaudio *chip) +{ + return init_line_levels(chip); +} diff --git a/sound/pci/echoaudio/indigoio_dsp.c b/sound/pci/echoaudio/indigoio_dsp.c index 134e783..beb9a5b 100644 --- a/sound/pci/echoaudio/indigoio_dsp.c +++ b/sound/pci/echoaudio/indigoio_dsp.c @@ -60,15 +60,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { return ECHO_CLOCK_BIT_INTERNAL; diff --git a/sound/pci/echoaudio/indigoiox_dsp.c b/sound/pci/echoaudio/indigoiox_dsp.c index 766cf50..394c6e76 100644 --- a/sound/pci/echoaudio/indigoiox_dsp.c +++ b/sound/pci/echoaudio/indigoiox_dsp.c @@ -59,10 +59,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - err = init_line_levels(chip); - if (err < 0) - return err; - DE_INIT(("init_hw done\n")); return err; } + + + +static int set_mixer_defaults(struct echoaudio *chip) +{ + return init_line_levels(chip); +} diff --git a/sound/pci/echoaudio/layla20_dsp.c b/sound/pci/echoaudio/layla20_dsp.c index 07f3245..53ce946 100644 --- a/sound/pci/echoaudio/layla20_dsp.c +++ b/sound/pci/echoaudio/layla20_dsp.c @@ -64,17 +64,20 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - - err = set_professional_spdif(chip, TRUE); - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + chip->professional_spdif = FALSE; + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { u32 clocks_from_dsp, clock_bits; diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c index 12dc00a..8c04164 100644 --- a/sound/pci/echoaudio/layla24_dsp.c +++ b/sound/pci/echoaudio/layla24_dsp.c @@ -61,9 +61,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; - chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; - chip->professional_spdif = FALSE; - chip->digital_in_automute = TRUE; if ((err = load_firmware(chip)) < 0) return err; @@ -72,17 +69,22 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) if ((err = init_line_levels(chip)) < 0) return err; - err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA); - if (err < 0) - return err; - err = set_professional_spdif(chip, TRUE); - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; + chip->professional_spdif = FALSE; + chip->digital_in_automute = TRUE; + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { u32 clocks_from_dsp, clock_bits; diff --git a/sound/pci/echoaudio/mia_dsp.c b/sound/pci/echoaudio/mia_dsp.c index d0302f2..6ebfa6e 100644 --- a/sound/pci/echoaudio/mia_dsp.c +++ b/sound/pci/echoaudio/mia_dsp.c @@ -66,15 +66,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip))) - return err; - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { u32 clocks_from_dsp, clock_bits; diff --git a/sound/pci/echoaudio/mona_dsp.c b/sound/pci/echoaudio/mona_dsp.c index b28b8e4..6e6a7eb 100644 --- a/sound/pci/echoaudio/mona_dsp.c +++ b/sound/pci/echoaudio/mona_dsp.c @@ -67,28 +67,26 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) else chip->dsp_code_to_load = FW_MONA_301_DSP; - chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; - chip->professional_spdif = FALSE; - chip->digital_in_automute = TRUE; - if ((err = load_firmware(chip)) < 0) return err; chip->bad_board = FALSE; - if ((err = init_line_levels(chip)) < 0) - return err; - - err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA); - if (err < 0) - return err; - err = set_professional_spdif(chip, TRUE); - DE_INIT(("init_hw done\n")); return err; } +static int set_mixer_defaults(struct echoaudio *chip) +{ + chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; + chip->professional_spdif = FALSE; + chip->digital_in_automute = TRUE; + return init_line_levels(chip); +} + + + static u32 detect_input_clocks(const struct echoaudio *chip) { u32 clocks_from_dsp, clock_bits; -- cgit v0.10.2 From 47b5d028fdce8f809bf22852ac900338fb90e8aa Mon Sep 17 00:00:00 2001 From: Giuliano Pochini Date: Sun, 14 Feb 2010 18:16:10 +0100 Subject: ALSA: Echoaudio - Add suspend support #2 This patch adds rearranges parts of the initialization code and adds suspend and resume callbacks. This patch adds suspend and resume callbacks. It also rearranges parts of the initialization code so it can be used in both the first initialization (when the module is loaded we also have to load default settings) and the resume callback (where we have to restore the previous settings). Signed-off-by: Giuliano Pochini Signed-off-by: Takashi Iwai diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 79dde95..2783ce6 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -753,6 +753,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) spin_lock(&chip->lock); switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + DE_ACT(("pcm_trigger resume\n")); case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: DE_ACT(("pcm_trigger start\n")); @@ -776,6 +778,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) err = start_transport(chip, channelmask, chip->pipe_cyclic_mask); break; + case SNDRV_PCM_TRIGGER_SUSPEND: + DE_ACT(("pcm_trigger suspend\n")); case SNDRV_PCM_TRIGGER_STOP: DE_ACT(("pcm_trigger stop\n")); for (i = 0; i < DSP_MAXPIPES; i++) { @@ -1951,18 +1955,27 @@ static __devinit int snd_echo_create(struct snd_card *card, return err; pci_set_master(pci); - /* allocate a chip-specific data */ - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) { - pci_disable_device(pci); - return -ENOMEM; + /* Allocate chip if needed */ + if (!*rchip) { + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) { + pci_disable_device(pci); + return -ENOMEM; + } + DE_INIT(("chip=%p\n", chip)); + spin_lock_init(&chip->lock); + chip->card = card; + chip->pci = pci; + chip->irq = -1; + atomic_set(&chip->opencount, 0); + mutex_init(&chip->mode_mutex); + chip->can_set_rate = 1; + } else { + /* If this was called from the resume function, chip is + * already allocated and it contains current card settings. + */ + chip = *rchip; } - DE_INIT(("chip=%p\n", chip)); - - spin_lock_init(&chip->lock); - chip->card = card; - chip->pci = pci; - chip->irq = -1; /* PCI resource allocation */ chip->dsp_registers_phys = pci_resource_start(pci, 0); @@ -2002,7 +2015,9 @@ static __devinit int snd_echo_create(struct snd_card *card, chip->comm_page = (struct comm_page *)chip->commpage_dma_buf.area; err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device); - if (err) { + if (err >= 0) + err = set_mixer_defaults(chip); + if (err < 0) { DE_INIT(("init_hw err=%d\n", err)); snd_echo_free(chip); return err; @@ -2013,9 +2028,6 @@ static __devinit int snd_echo_create(struct snd_card *card, snd_echo_free(chip); return err; } - atomic_set(&chip->opencount, 0); - mutex_init(&chip->mode_mutex); - chip->can_set_rate = 1; *rchip = chip; /* Init done ! */ return 0; @@ -2048,6 +2060,7 @@ static int __devinit snd_echo_probe(struct pci_dev *pci, snd_card_set_dev(card, &pci->dev); + chip = NULL; /* Tells snd_echo_create to allocate chip */ if ((err = snd_echo_create(card, pci, &chip)) < 0) { snd_card_free(card); return err; @@ -2187,6 +2200,112 @@ ctl_error: +#if defined(CONFIG_PM) + +static int snd_echo_suspend(struct pci_dev *pci, pm_message_t state) +{ + struct echoaudio *chip = pci_get_drvdata(pci); + + DE_INIT(("suspend start\n")); + snd_pcm_suspend_all(chip->analog_pcm); + snd_pcm_suspend_all(chip->digital_pcm); + +#ifdef ECHOCARD_HAS_MIDI + /* This call can sleep */ + if (chip->midi_out) + snd_echo_midi_output_trigger(chip->midi_out, 0); +#endif + spin_lock_irq(&chip->lock); + if (wait_handshake(chip)) { + spin_unlock_irq(&chip->lock); + return -EIO; + } + clear_handshake(chip); + if (send_vector(chip, DSP_VC_GO_COMATOSE) < 0) { + spin_unlock_irq(&chip->lock); + return -EIO; + } + spin_unlock_irq(&chip->lock); + + chip->dsp_code = NULL; + free_irq(chip->irq, chip); + chip->irq = -1; + pci_save_state(pci); + pci_disable_device(pci); + + DE_INIT(("suspend done\n")); + return 0; +} + + + +static int snd_echo_resume(struct pci_dev *pci) +{ + struct echoaudio *chip = pci_get_drvdata(pci); + struct comm_page *commpage, *commpage_bak; + u32 pipe_alloc_mask; + int err; + + DE_INIT(("resume start\n")); + pci_restore_state(pci); + commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL); + commpage = chip->comm_page; + memcpy(commpage_bak, commpage, sizeof(struct comm_page)); + + err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device); + if (err < 0) { + kfree(commpage_bak); + DE_INIT(("resume init_hw err=%d\n", err)); + snd_echo_free(chip); + return err; + } + DE_INIT(("resume init OK\n")); + + /* Temporarily set chip->pipe_alloc_mask=0 otherwise + * restore_dsp_settings() fails. + */ + pipe_alloc_mask = chip->pipe_alloc_mask; + chip->pipe_alloc_mask = 0; + err = restore_dsp_rettings(chip); + chip->pipe_alloc_mask = pipe_alloc_mask; + if (err < 0) { + kfree(commpage_bak); + return err; + } + DE_INIT(("resume restore OK\n")); + + memcpy(&commpage->audio_format, &commpage_bak->audio_format, + sizeof(commpage->audio_format)); + memcpy(&commpage->sglist_addr, &commpage_bak->sglist_addr, + sizeof(commpage->sglist_addr)); + memcpy(&commpage->midi_output, &commpage_bak->midi_output, + sizeof(commpage->midi_output)); + kfree(commpage_bak); + + if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED, + ECHOCARD_NAME, chip)) { + snd_echo_free(chip); + snd_printk(KERN_ERR "cannot grab irq\n"); + return -EBUSY; + } + chip->irq = pci->irq; + DE_INIT(("resume irq=%d\n", chip->irq)); + +#ifdef ECHOCARD_HAS_MIDI + if (chip->midi_input_enabled) + enable_midi_input(chip, TRUE); + if (chip->midi_out) + snd_echo_midi_output_trigger(chip->midi_out, 1); +#endif + + DE_INIT(("resume done\n")); + return 0; +} + +#endif /* CONFIG_PM */ + + + static void __devexit snd_echo_remove(struct pci_dev *pci) { struct echoaudio *chip; @@ -2209,6 +2328,10 @@ static struct pci_driver driver = { .id_table = snd_echo_ids, .probe = snd_echo_probe, .remove = __devexit_p(snd_echo_remove), +#ifdef CONFIG_PM + .suspend = snd_echo_suspend, + .resume = snd_echo_resume, +#endif /* CONFIG_PM */ }; diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h index a84c0d1..1df974d 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h @@ -472,6 +472,8 @@ static void free_firmware(const struct firmware *fw_entry); #ifdef ECHOCARD_HAS_MIDI static int enable_midi_input(struct echoaudio *chip, char enable); +static void snd_echo_midi_output_trigger( + struct snd_rawmidi_substream *substream, int up); static int midi_service_irq(struct echoaudio *chip); static int __devinit snd_echo_midi_create(struct snd_card *card, struct echoaudio *chip); diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c index 031ef7e..64417a7 100644 --- a/sound/pci/echoaudio/echoaudio_dsp.c +++ b/sound/pci/echoaudio/echoaudio_dsp.c @@ -497,9 +497,6 @@ static int load_firmware(struct echoaudio *chip) if ((box_type = load_asic(chip)) < 0) return box_type; /* error */ - if ((err = restore_dsp_rettings(chip)) < 0) - return err; - return box_type; } @@ -659,51 +656,106 @@ static void get_audio_meters(struct echoaudio *chip, long *meters) static int restore_dsp_rettings(struct echoaudio *chip) { - int err; + int i, o, err; DE_INIT(("restore_dsp_settings\n")); if ((err = check_asic_status(chip)) < 0) return err; - /* @ Gina20/Darla20 only. Should be harmless for other cards. */ + /* Gina20/Darla20 only. Should be harmless for other cards. */ chip->comm_page->gd_clock_state = GD_CLOCK_UNDEF; chip->comm_page->gd_spdif_status = GD_SPDIF_STATUS_UNDEF; chip->comm_page->handshake = 0xffffffff; - if ((err = set_sample_rate(chip, chip->sample_rate)) < 0) + /* Restore output busses */ + for (i = 0; i < num_busses_out(chip); i++) { + err = set_output_gain(chip, i, chip->output_gain[i]); + if (err < 0) + return err; + } + +#ifdef ECHOCARD_HAS_VMIXER + for (i = 0; i < num_pipes_out(chip); i++) + for (o = 0; o < num_busses_out(chip); o++) { + err = set_vmixer_gain(chip, o, i, + chip->vmixer_gain[o][i]); + if (err < 0) + return err; + } + if (update_vmixer_level(chip) < 0) + return -EIO; +#endif /* ECHOCARD_HAS_VMIXER */ + +#ifdef ECHOCARD_HAS_MONITOR + for (o = 0; o < num_busses_out(chip); o++) + for (i = 0; i < num_busses_in(chip); i++) { + err = set_monitor_gain(chip, o, i, + chip->monitor_gain[o][i]); + if (err < 0) + return err; + } +#endif /* ECHOCARD_HAS_MONITOR */ + +#ifdef ECHOCARD_HAS_INPUT_GAIN + for (i = 0; i < num_busses_in(chip); i++) { + err = set_input_gain(chip, i, chip->input_gain[i]); + if (err < 0) + return err; + } +#endif /* ECHOCARD_HAS_INPUT_GAIN */ + + err = update_output_line_level(chip); + if (err < 0) return err; - if (chip->meters_enabled) - if (send_vector(chip, DSP_VC_METERS_ON) < 0) - return -EIO; + err = update_input_line_level(chip); + if (err < 0) + return err; -#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK - if (set_input_clock(chip, chip->input_clock) < 0) + err = set_sample_rate(chip, chip->sample_rate); + if (err < 0) + return err; + + if (chip->meters_enabled) { + err = send_vector(chip, DSP_VC_METERS_ON); + if (err < 0) + return err; + } + +#ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH + if (set_digital_mode(chip, chip->digital_mode) < 0) return -EIO; #endif -#ifdef ECHOCARD_HAS_OUTPUT_CLOCK_SWITCH - if (set_output_clock(chip, chip->output_clock) < 0) +#ifdef ECHOCARD_HAS_DIGITAL_IO + if (set_professional_spdif(chip, chip->professional_spdif) < 0) return -EIO; #endif - if (update_output_line_level(chip) < 0) +#ifdef ECHOCARD_HAS_PHANTOM_POWER + if (set_phantom_power(chip, chip->phantom_power) < 0) return -EIO; +#endif - if (update_input_line_level(chip) < 0) +#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK + /* set_input_clock() also restores automute setting */ + if (set_input_clock(chip, chip->input_clock) < 0) return -EIO; +#endif -#ifdef ECHOCARD_HAS_VMIXER - if (update_vmixer_level(chip) < 0) +#ifdef ECHOCARD_HAS_OUTPUT_CLOCK_SWITCH + if (set_output_clock(chip, chip->output_clock) < 0) return -EIO; #endif if (wait_handshake(chip) < 0) return -EIO; clear_handshake(chip); + if (send_vector(chip, DSP_VC_UPDATE_FLAGS) < 0) + return -EIO; DE_INIT(("restore_dsp_rettings done\n")); - return send_vector(chip, DSP_VC_UPDATE_FLAGS); + return 0; } @@ -920,9 +972,6 @@ static int init_dsp_comm_page(struct echoaudio *chip) chip->card_name = ECHOCARD_NAME; chip->bad_board = TRUE; /* Set TRUE until DSP loaded */ chip->dsp_code = NULL; /* Current DSP code not loaded */ - chip->digital_mode = DIGITAL_MODE_NONE; - chip->input_clock = ECHO_CLOCK_INTERNAL; - chip->output_clock = ECHO_CLOCK_WORD; chip->asic_loaded = FALSE; memset(chip->comm_page, 0, sizeof(struct comm_page)); @@ -933,7 +982,6 @@ static int init_dsp_comm_page(struct echoaudio *chip) chip->comm_page->midi_out_free_count = cpu_to_le32(DSP_MIDI_OUT_FIFO_SIZE); chip->comm_page->sample_rate = cpu_to_le32(44100); - chip->sample_rate = 44100; /* Set line levels so we don't blast any inputs on startup */ memset(chip->comm_page->monitors, ECHOGAIN_MUTED, MONITOR_ARRAY_SIZE); @@ -944,50 +992,21 @@ static int init_dsp_comm_page(struct echoaudio *chip) -/* This function initializes the several volume controls for busses and pipes. -This MUST be called after the DSP is up and running ! */ +/* This function initializes the chip structure with default values, ie. all + * muted and internal clock source. Then it copies the settings to the DSP. + * This MUST be called after the DSP is up and running ! + */ static int init_line_levels(struct echoaudio *chip) { - int st, i, o; - DE_INIT(("init_line_levels\n")); - - /* Mute output busses */ - for (i = 0; i < num_busses_out(chip); i++) - if ((st = set_output_gain(chip, i, ECHOGAIN_MUTED))) - return st; - if ((st = update_output_line_level(chip))) - return st; - -#ifdef ECHOCARD_HAS_VMIXER - /* Mute the Vmixer */ - for (i = 0; i < num_pipes_out(chip); i++) - for (o = 0; o < num_busses_out(chip); o++) - if ((st = set_vmixer_gain(chip, o, i, ECHOGAIN_MUTED))) - return st; - if ((st = update_vmixer_level(chip))) - return st; -#endif /* ECHOCARD_HAS_VMIXER */ - -#ifdef ECHOCARD_HAS_MONITOR - /* Mute the monitor mixer */ - for (o = 0; o < num_busses_out(chip); o++) - for (i = 0; i < num_busses_in(chip); i++) - if ((st = set_monitor_gain(chip, o, i, ECHOGAIN_MUTED))) - return st; - if ((st = update_output_line_level(chip))) - return st; -#endif /* ECHOCARD_HAS_MONITOR */ - -#ifdef ECHOCARD_HAS_INPUT_GAIN - for (i = 0; i < num_busses_in(chip); i++) - if ((st = set_input_gain(chip, i, ECHOGAIN_MUTED))) - return st; - if ((st = update_input_line_level(chip))) - return st; -#endif /* ECHOCARD_HAS_INPUT_GAIN */ - - return 0; + memset(chip->output_gain, ECHOGAIN_MUTED, sizeof(chip->output_gain)); + memset(chip->input_gain, ECHOGAIN_MUTED, sizeof(chip->input_gain)); + memset(chip->monitor_gain, ECHOGAIN_MUTED, sizeof(chip->monitor_gain)); + memset(chip->vmixer_gain, ECHOGAIN_MUTED, sizeof(chip->vmixer_gain)); + chip->input_clock = ECHO_CLOCK_INTERNAL; + chip->output_clock = ECHO_CLOCK_WORD; + chip->sample_rate = 44100; + return restore_dsp_rettings(chip); } -- cgit v0.10.2