diff options
author | Jaroslav Kysela <perex@perex.cz> | 2010-02-16 11:25:03 +0100 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2010-02-16 11:25:03 +0100 |
commit | b8f1f5983fbe751aa3d07d9ce7ebb0c23bf4b7e4 (patch) | |
tree | e9f11863f683a9f4eb03d76008740a36d6b4ff3c /sound | |
parent | ba9341dfef6b0201cd30e3904dcd0a47d3dc35e0 (diff) | |
parent | 47b5d028fdce8f809bf22852ac900338fb90e8aa (diff) | |
download | op-kernel-dev-b8f1f5983fbe751aa3d07d9ce7ebb0c23bf4b7e4.zip op-kernel-dev-b8f1f5983fbe751aa3d07d9ce7ebb0c23bf4b7e4.tar.gz |
Merge branch 'topic/misc' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6 into devel
Diffstat (limited to 'sound')
119 files changed, 3364 insertions, 1321 deletions
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 <linux/pci.h> /** - * 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 diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index aa54195..b546ac2 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -766,10 +766,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) { @@ -791,6 +794,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; @@ -805,6 +810,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; @@ -827,6 +835,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; @@ -846,10 +856,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; } diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index caa7796..d6d49d6 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -23,6 +23,7 @@ #include <linux/time.h> #include <linux/init.h> #include <linux/moduleparam.h> +#include <linux/vmalloc.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/info.h> @@ -434,3 +435,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); diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 053c6d6..1793574 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3200,9 +3200,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; @@ -3216,6 +3214,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/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; } diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 6644d00..35a2f71 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -46,7 +46,6 @@ */ #include <linux/slab.h> -#include <linux/vmalloc.h> #include <linux/delay.h> #include <sound/core.h> #include <sound/asoundef.h> @@ -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,8 @@ 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, + .mmap = snd_pcm_lib_mmap_vmalloc, }; @@ -1173,7 +1125,8 @@ 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, + .mmap = snd_pcm_lib_mmap_vmalloc, }; diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 02fe81c..755a0a5 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 @@ -252,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/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 <dafastidio@libero.it> + Copyright (C) 1999-2002 by Massimo Piccioni <dafastidio@libero.it> Thanks to Pierfrancesco 'qM2' Passerini. + Generalised for soundcards based on DT-0196 and ALS-007 chips + by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>: 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 <dafastidio@libero.it>"); -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 <dafastidio@libero.it>"); +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 <dafastidio@libero.it> - - Generalised for soundcards based on DT-0196 and ALS-007 chips - by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>: 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 <linux/init.h> -#include <linux/wait.h> -#include <linux/pnp.h> -#include <linux/moduleparam.h> -#include <sound/core.h> -#include <sound/initval.h> -#include <sound/mpu401.h> -#include <sound/opl3.h> -#include <sound/sb.h> - -#define PFX "dt019x: " - -MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>"); -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) diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index c8a8da0..a4af53b 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -33,6 +33,7 @@ #include <asm/io.h> #include <asm/dma.h> #include <sound/core.h> +#include <sound/tlv.h> #include <sound/wss.h> #include <sound/mpu401.h> #include <sound/opl3.h> @@ -546,6 +547,93 @@ __skip_mpu: #ifdef OPTi93X +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_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_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_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_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) +{ + 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_opti9xx *chip = dev_id; @@ -754,6 +842,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/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..8d21a3f --- /dev/null +++ b/sound/isa/sb/jazz16.c @@ -0,0 +1,404 @@ + +/* + * jazz16.c - driver for Media Vision Jazz16 based soundcards. + * Copyright (C) 2009 Krzysztof Helt <krzysztof.h1@wp.pl> + * 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 <linux/init.h> +#include <linux/module.h> +#include <linux/io.h> +#include <asm/dma.h> +#include <linux/isa.h> +#include <sound/core.h> +#include <sound/mpu401.h> +#include <sound/opl3.h> +#include <sound/sb.h> +#define SNDRV_LEGACY_FIND_FREE_IRQ +#define SNDRV_LEGACY_FIND_FREE_DMA +#include <sound/initval.h> + +#define PFX "jazz16: " + +MODULE_DESCRIPTION("Media Vision Jazz16"); +MODULE_SUPPORTED_DEVICE("{{Media Vision ??? }," + "{RTL,RTL3000}}"); + +MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>"); +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; + } 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\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; +} + +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..7d84c9f 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,14 @@ static int snd_sb8_open(struct snd_pcm_substream *substream) runtime->hw = snd_sb8_capture; } switch (chip->hardware) { + case SB_HW_JAZZ16: + 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; + runtime->hw.channels_max = 2; + break; case SB_HW_PRO: runtime->hw.rate_max = 44100; runtime->hw.channels_max = 2; @@ -468,6 +539,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 +559,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 +598,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 +611,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 318ff0c..6496822 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); @@ -888,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), @@ -908,6 +800,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), @@ -1029,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: @@ -1055,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: 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; } diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index f1d9d16..6aff217 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -26,7 +26,6 @@ #include <linux/delay.h> #include <linux/spinlock.h> #include <linux/gfp.h> -#include <linux/vmalloc.h> #include <linux/interrupt.h> #include <linux/dma-mapping.h> #include <linux/platform_device.h> @@ -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,8 @@ 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, + .mmap = snd_pcm_lib_mmap_vmalloc, }; static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { @@ -721,7 +703,8 @@ 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, + .mmap = snd_pcm_lib_mmap_vmalloc, }; static struct snd_pcm_ops snd_sgio2audio_capture_ops = { @@ -733,7 +716,8 @@ 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, + .mmap = snd_pcm_lib_mmap_vmalloc, }; /* 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/oss/soundcard.c b/sound/oss/soundcard.c index c625309..fde7c12 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, 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/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 1be96ea..56fcf00 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, @@ -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); 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; } 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/ctatc.c b/sound/pci/ctxfi/ctatc.c index 459c1f6..480cb1e 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -1214,10 +1214,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: @@ -1231,13 +1232,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; @@ -1250,8 +1257,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; } @@ -1625,7 +1631,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 = { @@ -1651,7 +1658,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..f42e7e1 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,8 +40,10 @@ 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[] = { +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, @@ -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; 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/darla20_dsp.c b/sound/pci/echoaudio/darla20_dsp.c index 2904330..20c7cbc 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 @@ -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.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/darla24_dsp.c b/sound/pci/echoaudio/darla24_dsp.c index 6022873..6da6663 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; @@ -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.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/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c index 57967e5..3cdc2ee 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 */ @@ -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/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 1305f7c..2783ce6 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -36,22 +36,61 @@ 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]; - 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; } + + 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 } @@ -714,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")); @@ -737,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++) { @@ -1874,6 +1917,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; @@ -1911,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); @@ -1962,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; @@ -1973,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; @@ -2008,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; @@ -2147,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; @@ -2169,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 f9490ae..1df974d 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h @@ -442,13 +442,16 @@ 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 */ 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 */ @@ -464,11 +467,13 @@ 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 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_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..64417a7 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); @@ -495,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; } @@ -657,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; } @@ -918,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)); @@ -931,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); @@ -942,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); } 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/gina20_dsp.c b/sound/pci/echoaudio/gina20_dsp.c index 3f1e747..d1615a0 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 @@ -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.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/gina24_dsp.c b/sound/pci/echoaudio/gina24_dsp.c index 2fef37a..98f7cfa 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); @@ -58,19 +57,16 @@ 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) { - 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 | @@ -82,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; @@ -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.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/indigo_dsp.c b/sound/pci/echoaudio/indigo_dsp.c index 0b2cd9c..5e85f14 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; @@ -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.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/indigodj_dsp.c b/sound/pci/echoaudio/indigodj_dsp.c index 0839291..68f3c8c 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; @@ -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.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/indigodjx_dsp.c b/sound/pci/echoaudio/indigodjx_dsp.c index f591fc2..bb9632c7 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; @@ -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.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/indigoio_dsp.c b/sound/pci/echoaudio/indigoio_dsp.c index 0604c8a..beb9a5b6 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; @@ -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.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/indigoiox_dsp.c b/sound/pci/echoaudio/indigoiox_dsp.c index f357521..394c6e76 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; @@ -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.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/layla20_dsp.c b/sound/pci/echoaudio/layla20_dsp.c index 83750e9..53ce946 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; @@ -65,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; @@ -144,7 +146,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.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/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c index d61b5cb..8c04164 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; @@ -62,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; @@ -73,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; @@ -123,18 +124,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 +300,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 +336,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 +345,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.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/mia_dsp.c b/sound/pci/echoaudio/mia_dsp.c index 5514051..6ebfa6e 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; @@ -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.c b/sound/pci/echoaudio/mona.c index b05bad9..3e7e0182 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/echoaudio/mona_dsp.c b/sound/pci/echoaudio/mona_dsp.c index eaa619b..6e6a7eb 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,32 +63,30 @@ 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->digital_mode = DIGITAL_MODE_SPDIF_RCA; - chip->professional_spdif = FALSE; - chip->digital_in_automute = TRUE; + chip->dsp_code_to_load = FW_MONA_301_DSP; 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; @@ -120,7 +117,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 +125,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 +138,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 +162,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 +197,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 +215,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 +407,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; 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 c7cff6f..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, } }; @@ -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; } 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 <gamal@alternex.com.br>"); -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 */ diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c index 5cfa608..0d668f4 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c @@ -21,7 +21,6 @@ */ #include <linux/slab.h> -#include <linux/vmalloc.h> #include <linux/delay.h> #include <sound/core.h> #include <sound/asoundef.h> @@ -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,8 @@ 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, + .mmap = snd_pcm_lib_mmap_vmalloc, }; 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..4f4ccdf --- /dev/null +++ b/sound/usb/ua101.c @@ -0,0 +1,1421 @@ +/* + * Edirol UA-101 driver + * Copyright (c) Clemens Ladisch <clemens@ladisch.de> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <linux/usb/audio.h> +#include <sound/core.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include "usbaudio.h" + +MODULE_DESCRIPTION("Edirol UA-101 driver"); +MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); +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); + +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_lib_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_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); +} + +static int ua101_pcm_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_vmalloc_buffer(substream); +} + +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_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, +}; + +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_lib_get_vmalloc_page, + .mmap = snd_pcm_lib_mmap_vmalloc, +}; + +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 d01ec18..8a8f6251 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -44,7 +44,6 @@ #include <linux/slab.h> #include <linux/string.h> #include <linux/usb.h> -#include <linux/vmalloc.h> #include <linux/moduleparam.h> #include <linux/mutex.h> #include <sound/core.h> @@ -170,11 +169,12 @@ 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 */ - 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 */ @@ -343,7 +343,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; @@ -354,29 +354,39 @@ 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; + 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 += 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; + frames = (bytes + (oldptr % stride)) / 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) @@ -563,24 +573,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) { @@ -590,7 +600,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; @@ -600,7 +610,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++; } @@ -610,26 +620,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; @@ -735,41 +744,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. */ @@ -937,18 +911,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); } @@ -1307,6 +1281,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) @@ -1419,6 +1434,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", @@ -1449,8 +1472,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 +1530,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 +1996,8 @@ 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, + .mmap = snd_pcm_lib_mmap_vmalloc, }; static struct snd_pcm_ops snd_usb_capture_ops = { @@ -1985,7 +2009,8 @@ 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, + .mmap = snd_pcm_lib_mmap_vmalloc, }; @@ -2227,6 +2252,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 { @@ -3142,59 +3168,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); @@ -3232,6 +3205,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 @@ -3432,8 +3417,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_UA101] = create_ua101_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) { @@ -3693,6 +3678,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev, } } + 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 40ba811..9d8cea4 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; @@ -159,8 +160,8 @@ enum quirk_type { QUIRK_AUDIO_STANDARD_INTERFACE, QUIRK_AUDIO_FIXED_ENDPOINT, QUIRK_AUDIO_EDIROL_UA1000, - QUIRK_AUDIO_EDIROL_UA101, QUIRK_AUDIO_EDIROL_UAXX, + QUIRK_AUDIO_ALIGN_TRANSFER, QUIRK_TYPE_COUNT }; @@ -209,6 +210,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)) @@ -234,6 +245,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 c72ad0c..dd0c1d7 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -187,6 +187,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 @@ -1352,7 +1367,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 */ @@ -1415,8 +1455,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) { @@ -1458,7 +1508,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"); } @@ -2136,6 +2186,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) { diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index 406b74b..e691eba 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), @@ -2132,6 +2101,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, |