diff -Nru a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt --- a/Documentation/sound/alsa/ALSA-Configuration.txt Mon Feb 2 22:07:55 2004 +++ b/Documentation/sound/alsa/ALSA-Configuration.txt Mon Feb 2 22:07:55 2004 @@ -55,9 +55,10 @@ major - major # for sound driver - default is 116 cards_limit - - specifies card limit # (1-8) - - good for kmod support if you do not want to search - for soundcards which are not installed in your system + - specifies card limit # for auto-loading (1-8) + - default is 1 + - for auto-loading more than 1 card, specify this option + together with snd-card-X aliases. device_mode - specifies permission mask for dynamic sound device filesystem (available only when DEVFS is enabled) @@ -173,8 +174,7 @@ Module for soundcards based on Avance Logic ALS4000 PCI chip. joystick_port - port # for legacy joystick support. - default: 0x200 for the 1st card. - 0 = disabled + 0 = disabled (default), 1 = auto-detect Module supports up to 8 cards, autoprobe and PnP. @@ -199,6 +199,8 @@ Module for soundcards based on Aztech AZF3328 PCI chip. + joystick - Enable joystick (default off) + Module supports up to 8 cards. Module snd-cmi8330 @@ -221,10 +223,11 @@ Module for C-Media CMI8338 and 8738 PCI soundcards. - mpu_port - 0x300 (default),0x310,0x320,0x330, -1 (diable) - fm_port - 0x388 (default), -1 (disable) + mpu_port - 0x300,0x310,0x320,0x330, 0 = disable (default) + fm_port - 0x388 (default), 0 = disable (default) soft_ac3 - Sofware-conversion of raw SPDIF packets (model 033 only) (default = 1) + joystick_port - Joystick port address (0 = disable, 1 = auto-detect) Module supports autoprobe and multiple chips (max 8). @@ -377,6 +380,8 @@ * SoundBlaster PCI 64 * SoundBlaster PCI 128 + joystick - Enable joystick (default off) + Module supports up to 8 cards and autoprobe. Module snd-ens1371 @@ -387,6 +392,9 @@ * SoundBlaster PCI 128 * SoundBlaster Vibra PCI + joystick_port - port # for joystick (0x200,0x208,0x210,0x218), + 0 = disable (default), 1 = auto-detect + Module supports up to 8 cards and autoprobe. Module snd-es968 @@ -451,6 +459,7 @@ use_pm - support the power-management (0 = off, 1 = on, 2 = auto (default)) enable_mpu - enable MPU401 (0 = off, 1 = on, 2 = auto (default)) + joystick - enable joystick (default off) Module supports up to 8 cards and autoprobe. @@ -527,7 +536,7 @@ Module supports up to 8 cards. Note: you need to load the firmware via hdsploader utility included - in alsa-tools package. + in alsa-tools and alsa-firmware packages. Note: snd-page-alloc module does the job which snd-hammerfall-mem module did formerly. It will allocate the buffers in advance @@ -581,7 +590,7 @@ * ALi m5455 ac97_clock - AC'97 codec clock base (0 = auto-detect) - joystick_port - Joystick port # (0 = disabled, 0x200) + joystick - Enable joystick (default off) mpu_port - MPU401 port # (0 = disabled, 0x330,0x300) Module supports autoprobe and multiple bus-master chips (max 8). @@ -991,10 +1000,11 @@ mpu_port - 0x300,0x310,0x320,0x330, otherwise obtain BIOS setup [VIA686A/686B only] + joystick - Enable joystick (default off) [VIA686A/686B only] ac97_clock - AC'97 codec clock base (default 48000Hz) dxs_support - support DXS channels, 0 = auto (defalut), 1 = enable, 2 = disable, - 3 = 48k only + 3 = 48k only, 4 = no VRA [VIA8233/C,8235 only] Module supports autoprobe and multiple bus-master chips (max 8). @@ -1008,13 +1018,20 @@ Note: VIA8233/5 (not VIA8233A) can support DXS (direct sound) channels as the first PCM. On these channels, up to 4 streams can be played at the same time. - As default (dxs_support = 0), 48k fixed rate is chosen since - the output is often noisy except for 48k on some mother - boards due to the bug of BIOS. + As default (dxs_support = 0), 48k fixed rate is chosen + except for the known devices since the output is often + noisy except for 48k on some mother boards due to the + bug of BIOS. Please try once dxs_support=1 and if it works on other - sample rates, please let us know the PCI subsystem - vendor/device id's (output of "lspci -nv"). - If it doesn't work, use dxs_support=3 or dxs_support=2. + sample rates (e.g. 44.1kHz of mp3 playback), please let us + know the PCI subsystem vendor/device id's (output of + "lspci -nv"). + If it doesn't work, try dxs_support=4. If it still doesn't + work and the default setting is ok, dxs_support=3 is the + right choice. If the default setting doesn't work at all, + try dxs_support=2 to disable the DXS channels. + In any cases, please let us know the result and the + subsystem vendor/device ids. Note: for the MPU401 on VIA823x, use snd-mpu401 driver additonally. The mpu_port option is for VIA686 chips only. @@ -1041,11 +1058,13 @@ Module supports up to 8 cards. For loading the firmware, use vxloader utility in alsa-tools - package. You can load the firmware automatically by adding - the following to /etc/modules.conf + and alsa-firmware packages. You can load the firmware automatically + by adding the following to /etc/modprobe.conf - post-install snd-vx222 "/usr/bin/vxload" + install snd-vx222 /sbin/modprobe --first-time -i snd-vx222 && /usr/bin/vxloader + (for 2.2/2.4 kernels, add "post-install /usr/bin/vxloader" to + /etc/modules.conf, instead.) IBL size defines the interrupts period for PCM. The smaller size gives smaller latency but leads to more CPU consumption, too. The size is usually aligned to 126. As default (=0), the smallest @@ -1060,6 +1079,7 @@ irq_mask - IRQ bitmask, specifies the available IRQs as bits (default = 0xffff, all available) irq_list - List of available interrupts (default = -1, not specified) + 4 numbers must be given (if specified). ibl - Capture IBL size. (default = 0, minimum size) Module supports up to 8 cards. The module is compiled only when @@ -1069,13 +1089,15 @@ up /etc/pcmcia/vxpocket.conf. See the sound/pcmcia/vx/vxpocket.c. For loading the firmware, use vxloader utility in alsa-tools - package. + and alsa-firmware packages. The irq_mask and irq_list are provided to avoid allocation of specific IRQs. Usually you don't need to specify them. About capture IBL, see the description of snd-vx222 module. + Note: the driver is build only when CONFIG_ISA is set. + Module snd-vxp440 ----------------- @@ -1083,6 +1105,7 @@ irq_mask - IRQ bitmask, specifies the available IRQs as bits irq_list - List of available interrupts (default = -1, not specified) + 4 numbers must be given (if specified). ibl - Capture IBL size. (default = 0, minimum size) Module supports up to 8 cards. The module is compiled only when @@ -1092,24 +1115,30 @@ up /etc/pcmcia/vxp440.conf. See the sound/pcmcia/vx/vxp440.c. For loading the firmware, use vxloader utility in alsa-tools - package. + and alsa-firmware packages. The irq_mask and irq_list are provided to avoid allocation of specific IRQs. Usually you don't need to specify them. About capture IBL, see the description of snd-vx222 module. + Note: the driver is build only when CONFIG_ISA is set. + Module snd-ymfpci ----------------- Module for Yamaha PCI chips (YMF72x, YMF74x & YMF75x). - mpu_port - 0x300,0x330,0x332,0x334, -1 (disable) by default - fm_port - 0x388,0x398,0x3a0,0x3a8, -1 (disable) by default - rear_switch - enable shared rear/line-in switch (bool) + mpu_port - 0x300,0x330,0x332,0x334, 0 (disable) by default, + 1 (auto-detect for YMF744/754 only) + fm_port - 0x388,0x398,0x3a0,0x3a8, 0 (disable) by default + 1 (auto-detect for YMF744/754 only) + joystick_port - 0x201,0x202,0x204,0x205, 0 (disable) by default, + 1 (auto-detect) + rear_switch - enable shared rear/line-in switch (bool) Module supports autoprobe and multiple chips (max 8). - + The power-management is supported. @@ -1126,160 +1155,49 @@ will be not built in. -modprobe/kmod support -===================== - -The modprobe program must know which modules are used for the -device major numbers. -Native ALSA devices have got default number 116. Thus a line like -'alias char-major-116 snd' must be added to /etc/modules.conf. If you have -compiled the ALSA driver with the OSS/Free emulation code, then you -will need to add lines as explained below: - -The ALSA driver uses soundcore multiplexer for 2.2+ kernels and OSS compatible -devices. You should add line like 'alias char-major-14 soundcore'. - -Example with OSS/Free emulation turned on: - ------ /etc/modules.conf +Module Autoloading Support +========================== -# ALSA portion -alias char-major-116 snd -# OSS/Free portion -alias char-major-14 soundcore - ------ /etc/modules.conf +The ALSA drivers can be loaded automatically on demand by defining +module aliases. The string 'snd-card-%1' is requested for ALSA native +devices where %i is soundcard number from zero to seven. + +To auto-load an ALSA driver for OSS services, define the string +'sound-slot-%i' where %i means the slot number for OSS, which +corresponds to the card index of ALSA. Usually, define this +as the the same card module. + +An example configuration for a single emu10k1 card is like below: +----- /etc/modprobe.conf +alias snd-card-0 snd-emu10k1 +alias sound-slot-0 snd-emu10k1 +----- /etc/modprobe.conf + +The available number of auto-loaded soundcards depends on the module +option "cards_limit" of snd module. As default it's set to 1. +To enable the auto-loading of multiple cards, specify the number of +soundcards in that option. + +When multiple cards are available, it'd better to specify the index +number for each card via module option, too, so that the order of +cards is kept consistent. -After the main multiplexer is loaded, its code requests top-level soundcard -module. String 'snd-card-%i' is requested for native devices where %i is -soundcard number from zero to seven. String 'sound-slot-%i' is requested -for native devices where %i is slot number (for ALSA owner this means soundcard -number). - ------ /etc/modules.conf +An example configuration for two soundcards is like below: +----- /etc/modprobe.conf # ALSA portion +options snd cards_limit=2 alias snd-card-0 snd-interwave alias snd-card-1 snd-ens1371 +options snd-interwave index=0 +options snd-ens1371 index=1 # OSS/Free portion -alias sound-slot-0 snd-card-0 -alias sound-slot-1 snd-card-1 - ------ /etc/modules.conf - -We are finished at this point with the configuration for ALSA native devices, -but you may also need autoloading for ALSA's add-on OSS/Free emulation -modules. At this time only one module does not depend on any others, thus -must be loaded separately - snd-pcm-oss. String 'sound-service-%i-%i' -is requested for OSS/Free service where first %i means slot number -(e.g. card number) and second %i means service number. - ------ /etc/modules.conf - -# OSS/Free portion - card #1 -alias sound-service-0-0 snd-mixer-oss -alias sound-service-0-1 snd-seq-oss -alias sound-service-0-3 snd-pcm-oss -alias sound-service-0-8 snd-seq-oss -alias sound-service-0-12 snd-pcm-oss -# OSS/Free portion - card #2 -alias sound-service-1-0 snd-mixer-oss -alias sound-service-1-3 snd-pcm-oss -alias sound-service-1-12 snd-pcm-oss - ------ /etc/modules.conf - -A complete example for Gravis UltraSound PnP soundcard: - ------ /etc/modules.conf - -# ISA PnP support (don't use IRQs 9,10,11,12,13) -options isapnp isapnp_reserve_irq=9,10,11,12,13 - -# ALSA native device support -alias char-major-116 snd -options snd major=116 cards_limit=1 -alias snd-card-0 snd-interwave -options snd-interwave index=0 id="GusPnP" - -# OSS/Free setup -alias char-major-14 soundcore -alias sound-slot-0 snd-card-0 -alias sound-service-0-0 snd-mixer-oss -alias sound-service-0-1 snd-seq-oss -alias sound-service-0-3 snd-pcm-oss -alias sound-service-0-8 snd-seq-oss -alias sound-service-0-12 snd-pcm-oss - ------ - -A complete example if you want to use more soundcards in one machine -(the configuration below is for Sound Blaster 16 and Gravis UltraSound Classic): - ------ /etc/modules.conf - -# ISA PnP support (don't use IRQs 9,10,11,12,13) -# it's only an example to reserve some IRQs for another hardware -options isapnp isapnp_reserve_irq=9,10,11,12,13 - -# ALSA native device support -alias char-major-116 snd -options snd major=116 cards_limit=2 -alias snd-card-0 snd-gusclassic -alias snd-card-1 snd-sb16 -options snd-gusclassic index=0 id="Gus" \ - port=0x220 irq=5 dma1=6 dma2=7 -options snd-sb16 index=1 id="SB16" - -# OSS/Free setup -alias char-major-14 soundcore -alias sound-slot-0 snd-card-0 -alias sound-service-0-0 snd-mixer-oss -alias sound-service-0-1 snd-seq-oss -alias sound-service-0-3 snd-pcm-oss -alias sound-service-0-8 snd-seq-oss -alias sound-service-0-12 snd-pcm-oss -alias sound-slot-1 snd-card-1 -alias sound-service-1-0 snd-mixer-oss -alias sound-service-1-3 snd-pcm-oss -alias sound-service-1-12 snd-pcm-oss - ------ - -A complete example, two Gravis UltraSound Classic soundcards are installed -in the system: - ------ /etc/modules.conf - -# ALSA native device support -alias char-major-116 snd -options snd major=116 cards_limit=2 -alias snd-card-0 snd-gusclassic -alias snd-card-1 snd-gusclassic -options snd-gusclassic index=0,1 id="Gus1","Gus2" \ - port=0x220,0x240 irq=5,7 dma1=1,5 dma2=3,6 - -# OSS/Free setup -alias char-major-14 soundcore -alias sound-slot-0 snd-card-0 -alias sound-service-0-0 snd-mixer-oss -alias sound-service-0-1 snd-seq-oss -alias sound-service-0-3 snd-pcm-oss -alias sound-service-0-8 snd-seq-oss -alias sound-service-0-12 snd-pcm-oss -alias sound-slot-1 snd-card-1 -alias sound-service-1-0 snd-mixer-oss -alias sound-service-1-3 snd-pcm-oss -alias sound-service-1-12 snd-pcm-oss - ------ - -If you want to autoclean your modules, you should put below line to your -/etc/crontab: - -*/10 * * * * root /sbin/modprobe -rs snd-card-0 snd-card-1; /sbin/rmmod -as +alias sound-slot-0 snd-interwave +alias sound-slot-1 snd-ens1371 +----- /etc/moprobe.conf -You may also want to extend the soundcard list to follow your requirements. +In this example, the interwave card is always loaded as the first card +(index 0) and ens1371 as the second (index 1). ALSA PCM devices to OSS devices mapping diff -Nru a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl Mon Feb 2 22:07:56 2004 +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl Mon Feb 2 22:07:56 2004 @@ -341,10 +341,6 @@ drivers will be on pci directory, because its API is identical with the standard PCI cards. - - - At this moment, only VX-pocket driver exists. -
@@ -500,14 +496,14 @@ } // (4) - // implemented later - - // (5) strcpy(card->driver, "My Chip"); strcpy(card->shortname, "My Own Chip 123"); sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->ioport, chip->irq); + // (5) + // implemented later + // (6) if ((err = snd_card_register(card)) < 0) { snd_card_free(card); @@ -626,21 +622,8 @@
-
- 4) Create other components, such as mixer, MIDI, etc. - - Here you define the basic components such as - PCM, - mixer (e.g. AC97), - MIDI (e.g. MPU-401), - and other interfaces. - Also, if you want a proc - file, define it here, too. - -
-
- 5) Set the driver ID and name strings. + 4) Set the driver ID and name strings. @@ -667,6 +650,19 @@
+
+ 5) Create other components, such as mixer, MIDI, etc. + + Here you define the basic components such as + PCM, + mixer (e.g. AC97), + MIDI (e.g. MPU-401), + and other interfaces. + Also, if you want a proc + file, define it here, too. + +
+
6) Register the card instance. @@ -1295,11 +1291,11 @@ // check PCI availability (28bit DMA) if ((err = pci_enable_device(pci)) < 0) return err; - if (!pci_dma_supported(pci, 0x0fffffff)) { + if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || + pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { printk(KERN_ERR "error to set 28bit mask DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x0fffffff); chip = snd_magic_kcalloc(mychip_t, 0, GFP_KERNEL); if (chip == NULL) @@ -1413,11 +1409,12 @@ @@ -1914,8 +1911,27 @@ .periods_max = 1024, }; + /* hardware definition */ + static snd_pcm_hardware_t snd_mychip_capture_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_8000_48000, + .rate_min = 8000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 32768, + .period_bytes_min = 4096, + .period_bytes_max = 32768, + .periods_min = 1, + .periods_max = 1024, + }; + /* open callback */ - static int snd_mychip_pcm_open(snd_pcm_substream_t *substream) + static int snd_mychip_playback_open(snd_pcm_substream_t *substream) { mychip_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; @@ -1926,7 +1942,27 @@ } /* close callback */ - static int snd_mychip_pcm_close(snd_pcm_substream_t *substream) + static int snd_mychip_playback_close(snd_pcm_substream_t *substream) + { + mychip_t *chip = snd_pcm_substream_chip(substream); + // the hardware-specific codes will be here + return 0; + + } + + /* open callback */ + static int snd_mychip_capture_open(snd_pcm_substream_t *substream) + { + mychip_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + + runtime->hw = snd_mychip_capture_hw; + // more hardware-initialization will be done here + return 0; + } + + /* close callback */ + static int snd_mychip_capture_close(snd_pcm_substream_t *substream) { mychip_t *chip = snd_pcm_substream_chip(substream); // the hardware-specific codes will be here @@ -2005,6 +2041,18 @@ .pointer = snd_mychip_pcm_pointer, }; + /* operators */ + static snd_pcm_ops_t snd_mychip_capture_ops = { + .open = snd_mychip_capture_open, + .close = snd_mychip_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_mychip_pcm_hw_params, + .hw_free = snd_mychip_pcm_hw_free, + .prepare = snd_mychip_pcm_prepare, + .trigger = snd_mychip_pcm_trigger, + .pointer = snd_mychip_pcm_pointer, + }; + /* * definitions of capture are omitted here... */ @@ -3982,13 +4030,18 @@ static int snd_mychip_ac97(mychip_t *chip) { + ac97_bus_t bus, *pbus; ac97_t ac97; + int err; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_mychip_ac97_write; + bus.read = snd_mychip_ac97_read; + if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0) + return err; memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_mychip_ac97_write; - ac97.read = snd_mychip_ac97_read; ac97.private_data = chip; - return snd_ac97_mixer(card, &ac97, &chip->ac97); + return snd_ac97_mixer(pbus, &ac97, &chip->ac97); } ]]> @@ -4000,9 +4053,29 @@
Constructor - For creating an ac97 instance, call - snd_ac97_mixer() with an ac97_t - record, in which the callbacks and the private_data is set. + For creating an ac97 instance, first call snd_ac97_bus + with ac97_bus_t record including callback functions. + + + + + + + + The bus record is shared among all belonging ac97 instances. + + + + And then call snd_ac97_mixer() with an ac97_t + record together with the bus pointer created above. @@ -4011,16 +4084,16 @@ int err; memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_mychip_ac97_write; - ac97.read = snd_mychip_ac97_read; ac97.private_data = chip; - snd_ac97_mixer(card, &ac97, &chip->ac97); + snd_ac97_mixer(bus, &ac97, &chip->ac97); ]]> where chip->ac97 is the pointer of a newly created ac97_t instance. + In this case, the chip pointer is set as the private data, so that + the read/write callback functions can refer to this chip instance. This instance is not necessarily stored in the chip record. When you need to change the register values from the driver, or need the suspend/resume of ac97 codecs, keep this @@ -4094,14 +4167,11 @@ The wait callback is used for a certain wait at the standard initialization of the codec. If the chip requires the extra wait-time, define this callback. - This callback is always non-atomic, because it's never called - in the resume mode. The init callback is used for - additional initialization of the codec. This callback is called - after the reset, and should be atomic in the resume mode. + additional initialization of the codec.
@@ -4674,10 +4744,7 @@ - Note that you have to pre-allocate to use this function - (i.e. you cannot use this function for - - a scatter-gather buffer). + Note that you have to pre-allocate to use this function.
@@ -4905,6 +4972,8 @@ When a SG-handler is used, you need to set snd_pcm_sgbuf_ops_page as the page callback. + (See + page callback section.) @@ -4999,13 +5068,14 @@ where the second argument (chip) is the - private data to be used in the callbacks and the third + private data to be used in the callbacks. The third parameter + specifies the read buffer size and the fourth (my_proc_read) is the callback function, which is defined like diff -Nru a/Documentation/sound/alsa/Joystick.txt b/Documentation/sound/alsa/Joystick.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/sound/alsa/Joystick.txt Mon Feb 2 22:07:58 2004 @@ -0,0 +1,87 @@ +Analog Joystick Support on ALSA Drivers +======================================= + Oct. 14, 2003 + Takashi Iwai + +General +------- + +First of all, you need to enable GAMEPORT support on Linux kernel for +using a joystick with the ALSA driver. For the details of gameport +support, refer to Documentation/input/joystick.txt. + +The joystick support of ALSA drivers is different between ISA and PCI +cards. In the case of ISA (PnP) cards, it's usually handled by the +independent module (ns558). Meanwhile, the ALSA PCI drivers have the +built-in gameport support. Hence, when the ALSA PCI driver is built +in the kernel, CONFIG_GAMEPORT must be 'y', too. Otherwise, the +gameport support on that card will be (silently) disabled. + +Some adapter modules probe the physical connection of the device at +the load time. It'd be safer to plug in the joystick device before +loading the module. + + +PCI Cards +--------- + +For PCI cards, the joystick is enabled when the appropriate module +option is specified. Some drivers don't need options, and the +joystick support is always enabled. In the former ALSA version, there +was a dynamic control API for the joystick activation. It was +changed, however, to the static module options because of the system +stability and the resource management. + +The following PCI drivers support the joystick natively. + + Driver Module Option Available Values + --------------------------------------------------------------------------- + als4000 joystick_port 0 = disable (default), 1 = auto-detect, + manual: any address (e.g. 0x200) + au88x0 N/A N/A + azf3328 joystick 0 = disable, 1 = enable, -1 = auto (default) + ens1370 joystick 0 = disable (default), 1 = enable + ens1371 joystick_port 0 = disable (default), 1 = auto-detect, + manual: 0x200, 0x208, 0x210, 0x218 + cmipci joystick 0 = disable (default), 1 = enable + cs4281 N/A N/A + cs46xx N/A N/A + es1938 N/A N/A + es1968 joystick 0 = disable (default), 1 = enable + intel8x0(*1)joystick 0 = disable (default), 1 = enable + sonicvibes N/A N/A + trident N/A N/A + via82xx(*2) joystick 0 = disable (default), 1 = enable + ymfpci joystick_port 0 = disable (default), 1 = auto-detect, + manual: 0x201, 0x202, 0x204, 0x205(*3) + --------------------------------------------------------------------------- + + *1) not all chips support joystick + *2) VIA686A/B only + *3) With YMF744/754 chips, the port address can be chosen arbitrarily + +The following drivers don't support gameport natively, but there are +additional modules. Load the corresponding module to add the gameport +support. + + Driver Additional Module + ----------------------------- + emu10k1 emu10k1-gp + fm801 fm801-gp + ----------------------------- + +Note: the "pcigame" and "cs461x" modules are for the OSS drivers only. + These ALSA drivers (cs46xx, trident and au88x0) have the + built-in gameport support. + +As mentioned above, ALSA PCI drivers have the built-in gameport +support, so you don't have to load ns558 module. Just load "joydev" +and the appropriate adapter module (e.g. "analog"). + + +ISA Cards +--------- + +ALSA ISA drivers don't have the built-in gameport support. +Instead, you need to load "ns558" module in addition to "joydev" and +the adapter module (e.g. "analog"). diff -Nru a/Documentation/sound/alsa/OSS-Emulation.txt b/Documentation/sound/alsa/OSS-Emulation.txt --- a/Documentation/sound/alsa/OSS-Emulation.txt Mon Feb 2 22:07:57 2004 +++ b/Documentation/sound/alsa/OSS-Emulation.txt Mon Feb 2 22:07:57 2004 @@ -1,7 +1,7 @@ NOTES ON KERNEL OSS-EMULATION ============================= - Jan. 9, 2003 Takashi Iwai + Jan. 22, 2004 Takashi Iwai Modules @@ -13,32 +13,20 @@ When you need to access the OSS PCM, mixer or sequencer devices, the corresponding module has to be loaded. -For loading these modules automatically, define the aliases in -/etc/modules.conf like below: - - alias sound-service-0-0 snd-mixer-oss - alias sound-service-0-1 snd-seq-oss - alias sound-service-0-3 snd-pcm-oss - alias sound-service-0-8 snd-seq-oss - alias sound-service-0-12 snd-pcm-oss - -Then the access to an OSS device file such as /dev/dsp0 triggers to -load the necessary module via KMOD. - -For auto-loading the secondary card device like /dev/dsp1, the -following aliases are necessary in addition: - - alias sound-service-1-0 snd-mixer-oss - alias sound-service-1-3 snd-pcm-oss - alias sound-service-1-12 snd-pcm-oss - -Here you don't need to define service-1-1 and service-1-8 because -there is only one sequencer device. -Similarly, you can add definitions for the third or later cards as -sound-service-X-Y. - -The OSS-MIDI is emulated directly in the ALSA rawmidi module, -therefore no extra module exists for that purpose. +These modules are loaded automatically when the corresponding service +is called. The alias is defined sound-service-x-y, where x and y are +the card number and the minor unit number. Usually you don't have to +define these aliases by yourself. + +Only necessary step for auto-loading of OSS modules is to define the +card alias in /etc/modprobe.conf, such as + + alias sound-slot-0 snd-emu10k1 + +As the second card, define sound-slot-1 as well. +Note that you can't use the aliased name as the target name (i.e. +"alias sound-slot-0 snd-card-0" doesn't work any more like the old +modutils). The currently available OSS configuration is shown in /proc/asound/oss/sndstat. This shows in the same syntax of @@ -152,8 +140,7 @@ direct don't use plugins block force block open mode non-block force non-block open mode - whole-frag write only whole fragments (optimization affecting - playback only) + partial-frag write also partial fragments (affects playback only) no-silence do not fill silence ahead to avoid clicks The disable option is useful when one stream direction (playback or @@ -188,7 +175,7 @@ options snd-pcm-oss nonblock_open=1 -The whole-frag and no-silence commands have been added recently. +The partial-frag and no-silence commands have been added recently. Both commands are for optimization use only. The former command specifies to invoke the write transfer only when the whole fragment is filled. The latter stops writing the silence data ahead diff -Nru a/Documentation/sound/alsa/SB-Live-mixer.txt b/Documentation/sound/alsa/SB-Live-mixer.txt --- a/Documentation/sound/alsa/SB-Live-mixer.txt Mon Feb 2 22:07:55 2004 +++ b/Documentation/sound/alsa/SB-Live-mixer.txt Mon Feb 2 22:07:55 2004 @@ -101,15 +101,15 @@ The result is forwarded to the ADC capture FIFO (thus to the standard capture PCM device). -name='Surround Digital Playback Volume',index=0 +name='Surround Playback Volume',index=0 This control is used to attenuate samples for left and right rear PCM FX-bus accumulators. ALSA uses accumulators 2 and 3 for left and right rear PCM samples. The result samples are forwarded to the rear I2S DACs. These DACs operate separately (they are not inside the AC97 codec). -name='Surround Digital Capture Volume',index=0 -name='Surround Digital Capture Switch',index=0 +name='Surround Capture Volume',index=0 +name='Surround Capture Switch',index=0 These controls are used to attenuate samples for left and right rear PCM FX-bus accumulators. ALSA uses accumulators 2 and 3 for left and right rear PCM samples. @@ -172,13 +172,13 @@ digital inputs (usually used by a CDROM drive). The result samples are forwarded to the ADC capture FIFO (thus to the standard capture PCM device). -name='IEC958 Optical Playback Volume',index=0 +name='IEC958 LiveDrive Playback Volume',index=0 This control is used to attenuate samples from left and right IEC958 optical digital input. The result samples are forwarded to the front DAC PCM slots of the AC97 codec. -name='IEC958 Optical Capture Volume',index=0 +name='IEC958 LiveDrive Capture Volume',index=0 This control is used to attenuate samples from left and right IEC958 optical digital inputs. The result samples are forwarded to the ADC capture FIFO diff -Nru a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h --- a/include/sound/ac97_codec.h Mon Feb 2 22:07:56 2004 +++ b/include/sound/ac97_codec.h Mon Feb 2 22:07:57 2004 @@ -83,6 +83,33 @@ #define AC97_VENDOR_ID1 0x7c /* Vendor ID1 */ #define AC97_VENDOR_ID2 0x7e /* Vendor ID2 / revision */ +/* slot allocation */ +#define AC97_SLOT_TAG 0 +#define AC97_SLOT_CMD_ADDR 1 +#define AC97_SLOT_CMD_DATA 2 +#define AC97_SLOT_PCM_LEFT 3 +#define AC97_SLOT_PCM_RIGHT 4 +#define AC97_SLOT_MODEM_LINE1 5 +#define AC97_SLOT_PCM_CENTER 6 +#define AC97_SLOT_MIC 6 /* input */ +#define AC97_SLOT_SPDIF_LEFT1 6 +#define AC97_SLOT_PCM_SLEFT 7 /* surround left */ +#define AC97_SLOT_PCM_LEFT_0 7 /* double rate operation */ +#define AC97_SLOT_SPDIF_LEFT 7 +#define AC97_SLOT_PCM_SRIGHT 8 /* surround right */ +#define AC97_SLOT_PCM_RIGHT_0 8 /* double rate operation */ +#define AC97_SLOT_SPDIF_RIGHT 8 +#define AC97_SLOT_LFE 9 +#define AC97_SLOT_SPDIF_RIGHT1 9 +#define AC97_SLOT_MODEM_LINE2 10 +#define AC97_SLOT_PCM_LEFT_1 10 /* double rate operation */ +#define AC97_SLOT_SPDIF_LEFT2 10 +#define AC97_SLOT_HANDSET 11 /* output */ +#define AC97_SLOT_PCM_RIGHT_1 11 /* double rate operation */ +#define AC97_SLOT_SPDIF_RIGHT2 11 +#define AC97_SLOT_MODEM_GPIO 12 /* modem GPIO */ +#define AC97_SLOT_PCM_CENTER_1 12 /* double rate operation */ + /* basic capabilities (reset register) */ #define AC97_BC_DEDICATED_MIC 0x0001 /* Dedicated Mic PCM In Channel */ #define AC97_BC_RESERVED1 0x0002 /* Reserved (was Modem Line Codec support) */ @@ -180,6 +207,24 @@ #define AC97_MEA_PRG 0x4000 /* HADC power down (high) */ #define AC97_MEA_PRH 0x8000 /* HDAC power down (high) */ +/* modem gpio status defines */ +#define AC97_GPIO_LINE1_OH 0x0001 /* Off Hook Line1 */ +#define AC97_GPIO_LINE1_RI 0x0002 /* Ring Detect Line1 */ +#define AC97_GPIO_LINE1_CID 0x0004 /* Caller ID path enable Line1 */ +#define AC97_GPIO_LINE1_LCS 0x0008 /* Loop Current Sense Line1 */ +#define AC97_GPIO_LINE1_PULSE 0x0010 /* Opt./ Pulse Dial Line1 (out) */ +#define AC97_GPIO_LINE1_HL1R 0x0020 /* Opt./ Handset to Line1 relay control (out) */ +#define AC97_GPIO_LINE1_HOHD 0x0040 /* Opt./ Handset off hook detect Line1 (in) */ +#define AC97_GPIO_LINE12_AC 0x0080 /* Opt./ Int.bit 1 / Line1/2 AC (out) */ +#define AC97_GPIO_LINE12_DC 0x0100 /* Opt./ Int.bit 2 / Line1/2 DC (out) */ +#define AC97_GPIO_LINE12_RS 0x0200 /* Opt./ Int.bit 3 / Line1/2 RS (out) */ +#define AC97_GPIO_LINE2_OH 0x0400 /* Off Hook Line2 */ +#define AC97_GPIO_LINE2_RI 0x0800 /* Ring Detect Line2 */ +#define AC97_GPIO_LINE2_CID 0x1000 /* Caller ID path enable Line2 */ +#define AC97_GPIO_LINE2_LCS 0x2000 /* Loop Current Sense Line2 */ +#define AC97_GPIO_LINE2_PULSE 0x4000 /* Opt./ Pulse Dial Line2 (out) */ +#define AC97_GPIO_LINE2_HL1R 0x8000 /* Opt./ Handset to Line2 relay control (out) */ + /* specific - SigmaTel */ #define AC97_SIGMATEL_ANALOG 0x6c /* Analog Special */ #define AC97_SIGMATEL_DAC2INVERT 0x6e @@ -274,10 +319,13 @@ /* ac97->scaps */ -#define AC97_SCAP_AUDIO (1<<0) /* audio AC'97 codec */ -#define AC97_SCAP_MODEM (1<<1) /* modem AC'97 codec */ +#define AC97_SCAP_AUDIO (1<<0) /* audio codec 97 */ +#define AC97_SCAP_MODEM (1<<1) /* modem codec 97 */ #define AC97_SCAP_SURROUND_DAC (1<<2) /* surround L&R DACs are present */ #define AC97_SCAP_CENTER_LFE_DAC (1<<3) /* center and LFE DACs are present */ +#define AC97_SCAP_SKIP_AUDIO (1<<4) /* skip audio part of codec */ +#define AC97_SCAP_SKIP_MODEM (1<<5) /* skip modem part of codec */ +#define AC97_SCAP_INDEP_SDIN (1<<6) /* independent SDIN */ /* ac97->flags */ #define AC97_HAS_PC_BEEP (1<<0) /* force PC Speaker usage */ @@ -298,8 +346,36 @@ * */ +typedef struct _snd_ac97_bus ac97_bus_t; typedef struct _snd_ac97 ac97_t; +enum ac97_pcm_cfg { + AC97_PCM_CFG_FRONT = 2, + AC97_PCM_CFG_REAR = 10, /* alias surround */ + AC97_PCM_CFG_LFE = 11, /* center + lfe */ + AC97_PCM_CFG_40 = 4, /* front + rear */ + AC97_PCM_CFG_51 = 6, /* front + rear + center/lfe */ + AC97_PCM_CFG_SPDIF = 20 +}; + +/* PCM allocation */ +struct ac97_pcm { + ac97_bus_t *bus; + unsigned int stream: 1, /* stream type: 1 = capture */ + exclusive: 1, /* exclusive mode, don't override with other pcms */ + copy_flag: 1, /* lowlevel driver must fill all entries */ + spdif: 1; /* spdif pcm */ + unsigned short aslots; /* active slots */ + unsigned int rates; /* available rates */ + struct { + unsigned short slots; /* driver input: requested AC97 slot numbers */ + unsigned short rslots[4]; /* allocated slots per codecs */ + unsigned char rate_table[4]; + ac97_t *codec[4]; /* allocated codecs */ + } r[2]; /* 0 = standard rates, 1 = double rates */ + unsigned long private_value; /* used by the hardware driver */ +}; + struct snd_ac97_build_ops { int (*build_3d) (ac97_t *ac97); int (*build_specific) (ac97_t *ac97); @@ -307,18 +383,39 @@ int (*build_post_spdif) (ac97_t *ac97); }; -struct _snd_ac97 { +struct _snd_ac97_bus { + /* -- lowlevel (hardware) driver specific -- */ void (*reset) (ac97_t *ac97); void (*write) (ac97_t *ac97, unsigned short reg, unsigned short val); unsigned short (*read) (ac97_t *ac97, unsigned short reg); void (*wait) (ac97_t *ac97); void (*init) (ac97_t *ac97); + void *private_data; + void (*private_free) (ac97_bus_t *bus); + /* --- */ + snd_card_t *card; + unsigned short num; /* bus number */ + unsigned short vra: 1, /* bridge supports VRA */ + isdin: 1;/* independent SDIN */ + unsigned int clock; /* AC'97 base clock (usually 48000Hz) */ + spinlock_t bus_lock; /* used mainly for slot allocation */ + unsigned short used_slots[2][4]; /* actually used PCM slots */ + unsigned short pcms_count; /* count of PCMs */ + struct ac97_pcm *pcms; + ac97_t *codec[4]; + snd_info_entry_t *proc; +}; + +struct _snd_ac97 { + /* -- lowlevel (hardware) driver specific -- */ struct snd_ac97_build_ops * build_ops; void *private_data; void (*private_free) (ac97_t *ac97); /* --- */ - snd_card_t *card; + ac97_bus_t *bus; struct pci_dev *pci; /* assigned PCI device - used for quirks */ + snd_info_entry_t *proc; + snd_info_entry_t *proc_regs; unsigned short subsystem_vendor; unsigned short subsystem_device; spinlock_t reg_lock; @@ -330,7 +427,6 @@ unsigned short ext_mid; /* extended modem ID (register 3C) */ unsigned int scaps; /* driver capabilities */ unsigned int flags; /* specific code */ - unsigned int clock; /* AC'97 clock (usually 48000Hz) */ unsigned int rates[6]; /* see AC97_RATES_* defines */ unsigned int spdif_status; unsigned short regs[0x80]; /* register cache */ @@ -368,15 +464,14 @@ } /* functions */ -int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97); /* create mixer controls */ -int snd_ac97_modem(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97); /* create modem controls */ +int snd_ac97_bus(snd_card_t * card, ac97_bus_t * _bus, ac97_bus_t ** rbus); /* create new AC97 bus */ +int snd_ac97_mixer(ac97_bus_t * bus, ac97_t * _ac97, ac97_t ** rac97); /* create mixer controls */ void snd_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short value); unsigned short snd_ac97_read(ac97_t *ac97, unsigned short reg); void snd_ac97_write_cache(ac97_t *ac97, unsigned short reg, unsigned short value); int snd_ac97_update(ac97_t *ac97, unsigned short reg, unsigned short value); int snd_ac97_update_bits(ac97_t *ac97, unsigned short reg, unsigned short mask, unsigned short value); -int snd_ac97_set_rate(ac97_t *ac97, int reg, unsigned short rate); #ifdef CONFIG_PM void snd_ac97_suspend(ac97_t *ac97); void snd_ac97_resume(ac97_t *ac97); @@ -399,5 +494,13 @@ }; int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk); +int snd_ac97_set_rate(ac97_t *ac97, int reg, unsigned short rate); + +int snd_ac97_pcm_assign(ac97_bus_t *ac97, + unsigned short pcms_count, + const struct ac97_pcm *pcms); +int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate, + enum ac97_pcm_cfg cfg, unsigned short slots); +int snd_ac97_pcm_close(struct ac97_pcm *pcm); #endif /* __SOUND_AC97_CODEC_H */ diff -Nru a/include/sound/asequencer.h b/include/sound/asequencer.h --- a/include/sound/asequencer.h Mon Feb 2 22:07:57 2004 +++ b/include/sound/asequencer.h Mon Feb 2 22:07:57 2004 @@ -1,6 +1,6 @@ /* * Main header file for the ALSA sequencer - * Copyright (c) 1998-1999 by Frank van de Pol + * Copyright (c) 1998-1999 by Frank van de Pol * (c) 1998-1999 by Jaroslav Kysela * * diff -Nru a/include/sound/asound.h b/include/sound/asound.h --- a/include/sound/asound.h Mon Feb 2 22:07:57 2004 +++ b/include/sound/asound.h Mon Feb 2 22:07:57 2004 @@ -107,9 +107,10 @@ SNDRV_HWDEP_IFACE_VX, /* Digigram VX cards */ SNDRV_HWDEP_IFACE_MIXART, /* Digigram miXart cards */ SNDRV_HWDEP_IFACE_USX2Y, /* Tascam US122, US224 & US428 usb */ + SNDRV_HWDEP_IFACE_EMUX_WAVETABLE, /* EmuX wavetable */ /* Don't forget to change the following: */ - SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_USX2Y, + SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE, }; struct sndrv_hwdep_info { @@ -272,6 +273,7 @@ #define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 /* only half duplex */ #define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 /* playback and capture stream are somewhat correlated */ #define SNDRV_PCM_INFO_SYNC_START 0x00400000 /* pcm support some kind of sync go */ +#define SNDRV_PCM_INFO_NONATOMIC_OPS 0x00800000 /* non-atomic prepare callback */ enum sndrv_pcm_state { SNDRV_PCM_STATE_OPEN = 0, /* stream is open */ @@ -282,7 +284,8 @@ SNDRV_PCM_STATE_DRAINING, /* stream is draining */ SNDRV_PCM_STATE_PAUSED, /* stream is paused */ SNDRV_PCM_STATE_SUSPENDED, /* hardware is suspended */ - SNDRV_PCM_STATE_LAST = SNDRV_PCM_STATE_SUSPENDED, + SNDRV_PCM_STATE_DISCONNECTED, /* hardware is disconnected */ + SNDRV_PCM_STATE_LAST = SNDRV_PCM_STATE_DISCONNECTED, }; enum { @@ -683,7 +686,7 @@ * * ****************************************************************************/ -#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 2) +#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 3) struct sndrv_ctl_card_info { int card; /* card number */ @@ -728,6 +731,7 @@ #define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8) /* control does actually nothing, but may be updated */ #define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9) /* write lock */ #define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10) /* write lock owner */ +#define SNDRV_CTL_ELEM_ACCESS_USER (1<<29) /* user space element */ #define SNDRV_CTL_ELEM_ACCESS_DINDIRECT (1<<30) /* indirect access for matrix dimensions in the info structure */ #define SNDRV_CTL_ELEM_ACCESS_INDIRECT (1<<31) /* indirect access for element value in the value structure */ @@ -824,6 +828,9 @@ SNDRV_CTL_IOCTL_ELEM_LOCK = _IOW('U', 0x14, struct sndrv_ctl_elem_id), SNDRV_CTL_IOCTL_ELEM_UNLOCK = _IOW('U', 0x15, struct sndrv_ctl_elem_id), SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS = _IOWR('U', 0x16, int), + SNDRV_CTL_IOCTL_ELEM_ADD = _IOWR('U', 0x17, struct sndrv_ctl_elem_info), + SNDRV_CTL_IOCTL_ELEM_REPLACE = _IOWR('U', 0x18, struct sndrv_ctl_elem_info), + SNDRV_CTL_IOCTL_ELEM_REMOVE = _IOWR('U', 0x19, struct sndrv_ctl_elem_id), SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE = _IOWR('U', 0x20, int), SNDRV_CTL_IOCTL_HWDEP_INFO = _IOR('U', 0x21, struct sndrv_hwdep_info), SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE = _IOR('U', 0x30, int), diff -Nru a/include/sound/asound_fm.h b/include/sound/asound_fm.h --- a/include/sound/asound_fm.h Mon Feb 2 22:07:58 2004 +++ b/include/sound/asound_fm.h Mon Feb 2 22:07:58 2004 @@ -105,15 +105,11 @@ /* for OPL3 only */ #define SNDRV_DM_FM_IOCTL_SET_CONNECTION _IOW('H', 0x26, int) -#ifdef __SND_OSS_COMPAT__ - #define SNDRV_DM_FM_OSS_IOCTL_RESET 0x20 #define SNDRV_DM_FM_OSS_IOCTL_PLAY_NOTE 0x21 #define SNDRV_DM_FM_OSS_IOCTL_SET_VOICE 0x22 #define SNDRV_DM_FM_OSS_IOCTL_SET_PARAMS 0x23 #define SNDRV_DM_FM_OSS_IOCTL_SET_MODE 0x24 #define SNDRV_DM_FM_OSS_IOCTL_SET_OPL 0x25 - -#endif #endif /* __SOUND_ASOUND_FM_H */ diff -Nru a/include/sound/core.h b/include/sound/core.h --- a/include/sound/core.h Mon Feb 2 22:07:58 2004 +++ b/include/sound/core.h Mon Feb 2 22:07:58 2004 @@ -308,6 +308,10 @@ int snd_card_file_add(snd_card_t *card, struct file *file); int snd_card_file_remove(snd_card_t *card, struct file *file); +#ifndef snd_card_set_dev +#define snd_card_set_dev(card,devptr) ((card)->dev = (devptr)) +#endif + /* device.c */ int snd_device_new(snd_card_t *card, snd_device_type_t type, @@ -331,10 +335,12 @@ int snd_task_name(struct task_struct *task, char *name, size_t size); #ifdef CONFIG_SND_VERBOSE_PRINTK -void snd_verbose_printk(const char *file, int line, const char *format, ...); +void snd_verbose_printk(const char *file, int line, const char *format, ...) + __attribute__ ((format (printf, 3, 4))); #endif #if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK) -void snd_verbose_printd(const char *file, int line, const char *format, ...); +void snd_verbose_printd(const char *file, int line, const char *format, ...) + __attribute__ ((format (printf, 3, 4))); #endif /* --- */ diff -Nru a/include/sound/cs46xx.h b/include/sound/cs46xx.h --- a/include/sound/cs46xx.h Mon Feb 2 22:07:56 2004 +++ b/include/sound/cs46xx.h Mon Feb 2 22:07:56 2004 @@ -1712,6 +1712,7 @@ int nr_ac97_codecs; + ac97_bus_t *ac97_bus; ac97_t *ac97[MAX_NR_AC97]; struct pci_dev *pci; diff -Nru a/include/sound/emu10k1.h b/include/sound/emu10k1.h --- a/include/sound/emu10k1.h Mon Feb 2 22:07:56 2004 +++ b/include/sound/emu10k1.h Mon Feb 2 22:07:56 2004 @@ -679,6 +679,9 @@ #define A_ADCIDX 0x63 #define A_ADCIDX_IDX 0x10000063 +#define A_MICIDX 0x64 +#define A_MICIDX_IDX 0x10000064 + #define FXIDX 0x65 /* FX recording buffer index register */ #define FXIDX_MASK 0x0000ffff /* 16-bit value */ #define FXIDX_IDX 0x10000065 @@ -1049,7 +1052,7 @@ snd_util_memblk_t *snd_emu10k1_synth_alloc(emu10k1_t *emu, unsigned int size); int snd_emu10k1_synth_free(emu10k1_t *emu, snd_util_memblk_t *blk); int snd_emu10k1_synth_bzero(emu10k1_t *emu, snd_util_memblk_t *blk, int offset, int size); -int snd_emu10k1_synth_copy_from_user(emu10k1_t *emu, snd_util_memblk_t *blk, int offset, const char *data, int size); +int snd_emu10k1_synth_copy_from_user(emu10k1_t *emu, snd_util_memblk_t *blk, int offset, const char __user *data, int size); int snd_emu10k1_memblk_map(emu10k1_t *emu, emu10k1_memblk_t *blk); /* voice allocation */ @@ -1152,10 +1155,12 @@ #define FXBUS_MIDI_RIGHT 0x05 #define FXBUS_PCM_CENTER 0x06 #define FXBUS_PCM_LFE 0x07 -#define FXBUS_PT_LEFT 20 -#define FXBUS_PT_RIGHT 21 +#define FXBUS_PCM_LEFT_FRONT 0x08 +#define FXBUS_PCM_RIGHT_FRONT 0x09 #define FXBUS_MIDI_REVERB 0x0c #define FXBUS_MIDI_CHORUS 0x0d +#define FXBUS_PT_LEFT 0x14 +#define FXBUS_PT_RIGHT 0x15 /* Inputs */ #define EXTIN_AC97_L 0x00 /* AC'97 capture channel - left */ @@ -1199,8 +1204,8 @@ #define A_EXTIN_OPT_SPDIF_R 0x05 /* right */ #define A_EXTIN_LINE2_L 0x08 /* audigy drive line2/mic2 - left */ #define A_EXTIN_LINE2_R 0x09 /* right */ -#define A_EXTIN_RCA_SPDIF_L 0x0a /* audigy drive RCA SPDIF - left */ -#define A_EXTIN_RCA_SPDIF_R 0x0b /* right */ +#define A_EXTIN_ADC_L 0x0a /* Philips ADC - left */ +#define A_EXTIN_ADC_R 0x0b /* right */ #define A_EXTIN_AUX2_L 0x0c /* audigy drive aux2 - left */ #define A_EXTIN_AUX2_R 0x0d /* - right */ @@ -1225,6 +1230,7 @@ #define A_EXTOUT_AC97_R 0x11 /* right */ #define A_EXTOUT_ADC_CAP_L 0x16 /* ADC capture buffer left */ #define A_EXTOUT_ADC_CAP_R 0x17 /* right */ +#define A_EXTOUT_MIC_CAP 0x18 /* Mic capture buffer */ /* Audigy constants */ #define A_C_00000000 0xc0 @@ -1249,8 +1255,8 @@ #define A_C_4f1bbcdc 0xd3 #define A_C_5a7ef9db 0xd4 #define A_C_00100000 0xd5 -/* 0xd6 = 0x7fffffff (?) ACCUM? */ -/* 0xd7 = 0x0000000 CCR */ +#define A_GPR_ACCU 0xd6 /* ACCUM, accumulator */ +#define A_GPR_COND 0xd7 /* CCR, condition register */ /* 0xd8 = noise1 */ /* 0xd9 = noise2 */ diff -Nru a/include/sound/emu8000.h b/include/sound/emu8000.h --- a/include/sound/emu8000.h Mon Feb 2 22:07:56 2004 +++ b/include/sound/emu8000.h Mon Feb 2 22:07:56 2004 @@ -114,7 +114,7 @@ void snd_emu8000_update_chorus_mode(emu8000_t *emu); void snd_emu8000_update_reverb_mode(emu8000_t *emu); void snd_emu8000_update_equalizer(emu8000_t *emu); -int snd_emu8000_load_chorus_fx(emu8000_t *emu, int mode, const void *buf, long len); -int snd_emu8000_load_reverb_fx(emu8000_t *emu, int mode, const void *buf, long len); +int snd_emu8000_load_chorus_fx(emu8000_t *emu, int mode, const void __user *buf, long len); +int snd_emu8000_load_reverb_fx(emu8000_t *emu, int mode, const void __user *buf, long len); #endif /* __SOUND_EMU8000_H */ diff -Nru a/include/sound/emux_synth.h b/include/sound/emux_synth.h --- a/include/sound/emux_synth.h Mon Feb 2 22:07:58 2004 +++ b/include/sound/emux_synth.h Mon Feb 2 22:07:58 2004 @@ -63,7 +63,7 @@ int (*sample_new)(snd_emux_t *emu, snd_sf_sample_t *sp, snd_util_memhdr_t *hdr, const void *data, long count); int (*sample_free)(snd_emux_t *emu, snd_sf_sample_t *sp, snd_util_memhdr_t *hdr); void (*sample_reset)(snd_emux_t *emu); - int (*load_fx)(snd_emux_t *emu, int type, int arg, const void *data, long count); + int (*load_fx)(snd_emux_t *emu, int type, int arg, const void __user *data, long count); void (*sysex)(snd_emux_t *emu, char *buf, int len, int parsed, snd_midi_channel_set_t *chset); #ifdef CONFIG_SND_SEQUENCER_OSS int (*oss_ioctl)(snd_emux_t *emu, int cmd, int p1, int p2); @@ -103,6 +103,8 @@ int midi_ports; /* number of virtual midi devices */ int midi_devidx; /* device offset of virtual midi */ unsigned int linear_panning: 1; /* panning is linear (sbawe = 1, emu10k1 = 0) */ + int hwdep_idx; /* hwdep device index */ + snd_hwdep_t *hwdep; /* hwdep device */ /* private */ int num_voices; /* current number of voices */ @@ -113,6 +115,7 @@ struct semaphore register_mutex; int client; /* For the sequencer client */ int ports[SNDRV_EMUX_MAX_PORTS]; /* The ports for this device */ + snd_emux_port_t *portptrs[SNDRV_EMUX_MAX_PORTS]; int used; /* use counter */ char *name; /* name of the device (internal) */ snd_rawmidi_t **vmidi; diff -Nru a/include/sound/hdsp.h b/include/sound/hdsp.h --- a/include/sound/hdsp.h Mon Feb 2 22:07:58 2004 +++ b/include/sound/hdsp.h Mon Feb 2 22:07:58 2004 @@ -25,17 +25,20 @@ Digiface, Multiface, H9652, + H9632, Undefined, } HDSP_IO_Type; typedef struct _snd_hdsp_peak_rms hdsp_peak_rms_t; struct _snd_hdsp_peak_rms { - unsigned int playback_peaks[26]; unsigned int input_peaks[26]; + unsigned int playback_peaks[26]; unsigned int output_peaks[28]; - unsigned long long playback_rms[26]; unsigned long long input_rms[26]; + unsigned long long playback_rms[26]; + /* These are only used for H96xx cards */ + unsigned long long output_rms[26]; }; #define SNDRV_HDSP_IOCTL_GET_PEAK_RMS _IOR('H', 0x40, hdsp_peak_rms_t) @@ -61,6 +64,11 @@ unsigned char autosync_ref; unsigned char line_out; unsigned char passthru; + unsigned char da_gain; + unsigned char ad_gain; + unsigned char phone_gain; + unsigned char xlr_breakout_cable; + unsigned char analog_extension_board; }; #define SNDRV_HDSP_IOCTL_GET_CONFIG_INFO _IOR('H', 0x41, hdsp_config_info_t) @@ -89,5 +97,14 @@ }; #define SNDRV_HDSP_IOCTL_GET_MIXER _IOR('H', 0x44, hdsp_mixer_t) + +typedef struct _snd_hdsp_9632_aeb hdsp_9632_aeb_t; + +struct _snd_hdsp_9632_aeb { + int aebi; + int aebo; +}; + +#define SNDRV_HDSP_IOCTL_GET_9632_AEB _IOR('H', 0x45, hdsp_9632_aeb_t) #endif /* __SOUND_HDSP_H */ diff -Nru a/include/sound/i2c.h b/include/sound/i2c.h --- a/include/sound/i2c.h Mon Feb 2 22:07:55 2004 +++ b/include/sound/i2c.h Mon Feb 2 22:07:55 2004 @@ -58,7 +58,7 @@ snd_card_t *card; /* card which I2C belongs to */ char name[32]; /* some useful label */ - spinlock_t lock; + struct semaphore lock_mutex; snd_i2c_bus_t *master; /* master bus when SCK/SCL is shared */ struct list_head buses; /* master: slave buses sharing SCK/SCL, slave: link list */ @@ -84,15 +84,15 @@ static inline void snd_i2c_lock(snd_i2c_bus_t *bus) { if (bus->master) - spin_lock(&bus->master->lock); + down(&bus->master->lock_mutex); else - spin_lock(&bus->lock); + down(&bus->lock_mutex); } static inline void snd_i2c_unlock(snd_i2c_bus_t *bus) { if (bus->master) - spin_unlock(&bus->master->lock); + up(&bus->master->lock_mutex); else - spin_unlock(&bus->lock); + up(&bus->lock_mutex); } int snd_i2c_sendbytes(snd_i2c_device_t *device, unsigned char *bytes, int count); diff -Nru a/include/sound/info.h b/include/sound/info.h --- a/include/sound/info.h Mon Feb 2 22:07:58 2004 +++ b/include/sound/info.h Mon Feb 2 22:07:58 2004 @@ -134,12 +134,13 @@ /* for card drivers */ int snd_card_proc_new(snd_card_t *card, const char *name, snd_info_entry_t **entryp); -inline static void snd_info_set_text_ops(snd_info_entry_t *entry, +static inline void snd_info_set_text_ops(snd_info_entry_t *entry, void *private_data, + long read_size, void (*read)(snd_info_entry_t *, snd_info_buffer_t *)) { entry->private_data = private_data; - entry->c.text.read_size = 1024; + entry->c.text.read_size = read_size; entry->c.text.read = read; } diff -Nru a/include/sound/initval.h b/include/sound/initval.h --- a/include/sound/initval.h Mon Feb 2 22:07:55 2004 +++ b/include/sound/initval.h Mon Feb 2 22:07:55 2004 @@ -35,7 +35,7 @@ #define MODULE_DEVICES(val) MODULE_GENERIC_STRING(info_devices, val) #define MODULE_PARM_SYNTAX(id, val) MODULE_GENERIC_STRING(info_parm_##id, val) -#define SNDRV_AUTO_PORT 0xffff +#define SNDRV_AUTO_PORT 1 #define SNDRV_AUTO_IRQ 0xffff #define SNDRV_AUTO_DMA 0xffff #define SNDRV_AUTO_DMA_SIZE (0x7fffffff) @@ -58,7 +58,7 @@ #else #define SNDRV_DEFAULT_ENABLE_ISAPNP SNDRV_DEFAULT_ENABLE #endif -#define SNDRV_DEFAULT_PORT { SNDRV_AUTO_PORT, [1 ... (SNDRV_CARDS-1)] = -1 } +#define SNDRV_DEFAULT_PORT { [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_PORT } #define SNDRV_DEFAULT_IRQ { [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_IRQ } #define SNDRV_DEFAULT_DMA { [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_DMA } #define SNDRV_DEFAULT_DMA_SIZE { [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_DMA_SIZE } @@ -136,31 +136,41 @@ #if defined(SNDRV_GET_ID) && !defined(MODULE) #include #include +#include static int __init get_id(char **str, char **dst) { - char *s, *d; + char *s; if (!(*str) || !(**str)) return 0; for (s = *str; isalpha(*s) || isdigit(*s) || *s == '_'; s++); if (s != *str) { - *dst = (char *)kmalloc((s - *str) + 1, GFP_KERNEL); - s = *str; d = *dst; - while (isalpha(*s) || isdigit(*s) || *s == '_') { - if (d != NULL) - *d++ = *s; - s++; + int len = s - *str; + char *d = (char *)alloc_bootmem(len + 1); + if (d != NULL) { + memcpy(*dst = d, *str, len); + d[len] = '\0'; } - if (d != NULL) - *d = '\0'; } - *str = s; if (*s == ',') { - (*str)++; + *str = s + 1; return 2; } + *str = s; return 1; } #endif + +/* simple wrapper for long variable. + * the value more than 32bit won't work! + */ +inline static int get_option_long(char **str, long *valp) +{ + int val, ret; + ret = get_option(str, &val); + if (ret) + *valp = val; + return ret; +} #endif /* __SOUND_INITVAL_H */ diff -Nru a/include/sound/minors.h b/include/sound/minors.h --- a/include/sound/minors.h Mon Feb 2 22:07:55 2004 +++ b/include/sound/minors.h Mon Feb 2 22:07:55 2004 @@ -81,6 +81,9 @@ #define SNDRV_OSS_DEVICE_TYPE_SNDSTAT 5 #define SNDRV_OSS_DEVICE_TYPE_MUSIC 6 +#define MODULE_ALIAS_SNDRV_MINOR(type) \ + MODULE_ALIAS("sound-service-?-" __stringify(type)) + #endif #endif /* __SOUND_MINORS_H */ diff -Nru a/include/sound/pcm.h b/include/sound/pcm.h --- a/include/sound/pcm.h Mon Feb 2 22:07:56 2004 +++ b/include/sound/pcm.h Mon Feb 2 22:07:56 2004 @@ -427,6 +427,10 @@ snd_minor_t *reg; snd_info_entry_t *proc_root; snd_info_entry_t *proc_info_entry; +#ifdef CONFIG_SND_DEBUG + unsigned int xrun_debug: 1; + snd_info_entry_t *proc_xrun_debug_entry; +#endif }; struct _snd_pcm { @@ -460,8 +464,6 @@ extern snd_pcm_t *snd_pcm_devices[]; extern snd_minor_t snd_pcm_reg[2]; - -void snd_pcm_lock(int unlock); int snd_pcm_new(snd_card_t * card, char *id, int device, int playback_count, int capture_count, diff -Nru a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h --- a/include/sound/pcm_oss.h Mon Feb 2 22:07:57 2004 +++ b/include/sound/pcm_oss.h Mon Feb 2 22:07:57 2004 @@ -31,7 +31,7 @@ direct:1, block:1, nonblock:1, - wholefrag:1, + partialfrag:1, nosilence:1; unsigned int periods; unsigned int period_size; diff -Nru a/include/sound/sb.h b/include/sound/sb.h --- a/include/sound/sb.h Mon Feb 2 22:07:56 2004 +++ b/include/sound/sb.h Mon Feb 2 22:07:56 2004 @@ -63,8 +63,6 @@ struct _snd_sb { unsigned long port; /* base port of DSP chip */ struct resource *res_port; - unsigned long alt_port; /* alternate port (ALS4000) */ - struct resource *res_alt_port; unsigned long mpu_port; /* MPU port for SB DSP 4.0+ */ int irq; /* IRQ number of DSP chip */ int dma8; /* 8-bit DMA */ @@ -72,6 +70,7 @@ unsigned short version; /* version of DSP chip */ enum sb_hw_type hardware; /* see to SB_HW_XXXX */ + unsigned long alt_port; /* alternate port (ALS4000) */ struct pci_dev *pci; /* ALS4000 */ unsigned int open; /* see to SB_OPEN_XXXX for sb8 */ diff -Nru a/include/sound/seq_kernel.h b/include/sound/seq_kernel.h --- a/include/sound/seq_kernel.h Mon Feb 2 22:07:58 2004 +++ b/include/sound/seq_kernel.h Mon Feb 2 22:07:58 2004 @@ -3,7 +3,7 @@ /* * Main kernel header file for the ALSA sequencer - * Copyright (c) 1998 by Frank van de Pol + * Copyright (c) 1998 by Frank van de Pol * * * This program is free software; you can redistribute it and/or modify diff -Nru a/include/sound/sfnt_info.h b/include/sound/sfnt_info.h --- a/include/sound/sfnt_info.h Mon Feb 2 22:07:57 2004 +++ b/include/sound/sfnt_info.h Mon Feb 2 22:07:57 2004 @@ -22,16 +22,22 @@ * */ -#include "seq_oss_legacy.h" +#include /* * patch information record */ +#ifdef SNDRV_BIG_ENDIAN +#define SNDRV_OSS_PATCHKEY(id) (0xfd00|id) +#else +#define SNDRV_OSS_PATCHKEY(id) ((id<<8)|0xfd) +#endif + /* patch interface header: 16 bytes */ typedef struct soundfont_patch_info_t { unsigned short key; /* use the key below */ -#define SNDRV_OSS_SOUNDFONT_PATCH _PATCHKEY(0x07) +#define SNDRV_OSS_SOUNDFONT_PATCH SNDRV_OSS_PATCHKEY(0x07) short device_no; /* synthesizer number */ unsigned short sf_id; /* file id (should be zero) */ @@ -180,5 +186,29 @@ int src_bank, src_instr, src_key; } soundfont_voice_map_t; + +/* + * ioctls for hwdep + */ + +#define SNDRV_EMUX_HWDEP_NAME "Emux WaveTable" + +#define SNDRV_EMUX_VERSION ((1 << 16) | (0 << 8) | 0) /* 1.0.0 */ + +struct sndrv_emux_misc_mode { + int port; /* -1 = all */ + int mode; + int value; + int value2; /* reserved */ +}; + +enum { + SNDRV_EMUX_IOCTL_VERSION = _IOR('H', 0x80, unsigned int), + SNDRV_EMUX_IOCTL_LOAD_PATCH = _IOWR('H', 0x81, soundfont_patch_info_t), + SNDRV_EMUX_IOCTL_RESET_SAMPLES = _IO('H', 0x82), + SNDRV_EMUX_IOCTL_REMOVE_LAST_SAMPLES = _IO('H', 0x83), + SNDRV_EMUX_IOCTL_MEM_AVAIL = _IOW('H', 0x84, int), + SNDRV_EMUX_IOCTL_MISC_MODE = _IOWR('H', 0x84, struct sndrv_emux_misc_mode), +}; #endif /* __SOUND_SFNT_INFO_H */ diff -Nru a/include/sound/sndmagic.h b/include/sound/sndmagic.h --- a/include/sound/sndmagic.h Mon Feb 2 22:07:56 2004 +++ b/include/sound/sndmagic.h Mon Feb 2 22:07:56 2004 @@ -133,6 +133,7 @@ #define mpu401_t_magic 0xa15a1701 #define fm801_t_magic 0xa15a1801 #define ac97_t_magic 0xa15a1901 +#define ac97_bus_t_magic 0xa15a1902 #define ak4531_t_magic 0xa15a1a01 #define snd_uart16550_t_magic 0xa15a1b01 #define emu10k1_t_magic 0xa15a1c01 @@ -197,7 +198,6 @@ #define vx_core_t_magic 0xa15a4110 #define vx_pipe_t_magic 0xa15a4112 #define azf3328_t_magic 0xa15a4200 - #define snd_card_harmony_t_magic 0xa15a4300 #else diff -Nru a/include/sound/soundfont.h b/include/sound/soundfont.h --- a/include/sound/soundfont.h Mon Feb 2 22:07:58 2004 +++ b/include/sound/soundfont.h Mon Feb 2 22:07:58 2004 @@ -68,7 +68,7 @@ * Type of the sample access callback */ typedef int (*snd_sf_sample_new_t)(void *private_data, snd_sf_sample_t *sp, - snd_util_memhdr_t *hdr, const void *buf, long count); + snd_util_memhdr_t *hdr, const void __user *buf, long count); typedef int (*snd_sf_sample_free_t)(void *private_data, snd_sf_sample_t *sp, snd_util_memhdr_t *hdr); typedef void (*snd_sf_sample_reset_t)(void *private); @@ -101,8 +101,8 @@ } snd_sf_list_t; /* Prototypes for soundfont.c */ -int snd_soundfont_load(snd_sf_list_t *sflist, const void *data, long count, int client); -int snd_soundfont_load_guspatch(snd_sf_list_t *sflist, const char *data, +int snd_soundfont_load(snd_sf_list_t *sflist, const void __user *data, long count, int client); +int snd_soundfont_load_guspatch(snd_sf_list_t *sflist, const char __user *data, long count, int client); int snd_soundfont_close_check(snd_sf_list_t *sflist, int client); diff -Nru a/include/sound/sscape_ioctl.h b/include/sound/sscape_ioctl.h --- a/include/sound/sscape_ioctl.h Mon Feb 2 22:07:55 2004 +++ b/include/sound/sscape_ioctl.h Mon Feb 2 22:07:55 2004 @@ -8,9 +8,11 @@ unsigned version; }; +#define SSCAPE_MICROCODE_SIZE 65536 + struct sscape_microcode { - unsigned char *code; /* 65536 chars */ + unsigned char *code; }; #define SND_SSCAPE_LOAD_BOOTB _IOWR('P', 100, struct sscape_bootblock) diff -Nru a/include/sound/trident.h b/include/sound/trident.h --- a/include/sound/trident.h Mon Feb 2 22:07:57 2004 +++ b/include/sound/trident.h Mon Feb 2 22:07:57 2004 @@ -443,6 +443,7 @@ snd_rawmidi_t *rmidi; snd_seq_device_t *seq_dev; + ac97_bus_t *ac97_bus; ac97_t *ac97; ac97_t *ac97_sec; diff -Nru a/include/sound/version.h b/include/sound/version.h --- a/include/sound/version.h Mon Feb 2 22:07:56 2004 +++ b/include/sound/version.h Mon Feb 2 22:07:56 2004 @@ -1,3 +1,3 @@ -/* include/version.h. Generated automatically by configure. */ -#define CONFIG_SND_VERSION "0.9.7" -#define CONFIG_SND_DATE " (Thu Sep 25 19:16:36 2003 UTC)" +/* include/version.h. Generated by configure. */ +#define CONFIG_SND_VERSION "1.0.2" +#define CONFIG_SND_DATE " (Tue Jan 27 10:28:52 2004 UTC)" diff -Nru a/include/sound/ymfpci.h b/include/sound/ymfpci.h --- a/include/sound/ymfpci.h Mon Feb 2 22:07:56 2004 +++ b/include/sound/ymfpci.h Mon Feb 2 22:07:56 2004 @@ -25,6 +25,7 @@ #include "pcm.h" #include "rawmidi.h" #include "ac97_codec.h" +#include "timer.h" #include #ifndef PCI_VENDOR_ID_YAMAHA @@ -311,8 +312,6 @@ unsigned short old_legacy_ctrl; #if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE) - unsigned int joystick_port; - struct semaphore joystick_mutex; struct resource *joystick_res; struct gameport gameport; #endif @@ -347,8 +346,10 @@ u32 active_bank; ymfpci_voice_t voices[64]; + ac97_bus_t *ac97_bus; ac97_t *ac97; snd_rawmidi_t *rawmidi; + snd_timer_t *timer; struct pci_dev *pci; snd_card_t *card; @@ -389,9 +390,7 @@ int snd_ymfpci_pcm_spdif(ymfpci_t *chip, int device, snd_pcm_t **rpcm); int snd_ymfpci_pcm_4ch(ymfpci_t *chip, int device, snd_pcm_t **rpcm); int snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch); -#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE) -int snd_ymfpci_joystick(ymfpci_t *chip); -#endif +int snd_ymfpci_timer(ymfpci_t *chip, int device); int snd_ymfpci_voice_alloc(ymfpci_t *chip, ymfpci_voice_type_t type, int pair, ymfpci_voice_t **rvoice); int snd_ymfpci_voice_free(ymfpci_t *chip, ymfpci_voice_t *pvoice); @@ -399,6 +398,10 @@ #ifdef CONFIG_PM void snd_ymfpci_suspend(ymfpci_t *chip); void snd_ymfpci_resume(ymfpci_t *chip); +#endif + +#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#define SUPPORT_JOYSTICK #endif #endif /* __SOUND_YMFPCI_H */ diff -Nru a/sound/core/Makefile b/sound/core/Makefile --- a/sound/core/Makefile Mon Feb 2 22:07:57 2004 +++ b/sound/core/Makefile Mon Feb 2 22:07:57 2004 @@ -99,10 +99,6 @@ obj-$(CONFIG_SND_POWERMAC) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o obj-$(CONFIG_SND_PC98_CS4232) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -ifeq ($(CONFIG_SND_SB16_CSP),y) - obj-$(CONFIG_SND_SB16) += snd-hwdep.o - obj-$(CONFIG_SND_SBAWE) += snd-hwdep.o -endif obj-$(CONFIG_SND_USB_AUDIO) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o obj-$(CONFIG_SND_SUN_AMD7930) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o obj-$(CONFIG_SND_SUN_CS4231) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o diff -Nru a/sound/core/control.c b/sound/core/control.c --- a/sound/core/control.c Mon Feb 2 22:07:55 2004 +++ b/sound/core/control.c Mon Feb 2 22:07:55 2004 @@ -253,15 +253,51 @@ } } +static unsigned int snd_ctl_hole_check(snd_card_t * card, + unsigned int count) +{ + struct list_head *list; + snd_kcontrol_t *kctl; + + list_for_each(list, &card->controls) { + kctl = snd_kcontrol(list); + if ((kctl->id.numid <= card->last_numid && + kctl->id.numid + kctl->count > card->last_numid) || + (kctl->id.numid <= card->last_numid + count - 1 && + kctl->id.numid + kctl->count > card->last_numid + count - 1)) + return card->last_numid = kctl->id.numid + kctl->count - 1; + } + return card->last_numid; +} + +static int snd_ctl_find_hole(snd_card_t * card, unsigned int count) +{ + unsigned int last_numid, iter = 100000; + + last_numid = card->last_numid; + while (last_numid != snd_ctl_hole_check(card, count)) { + if (--iter == 0) { + /* this situation is very unlikely */ + snd_printk(KERN_ERR "unable to allocate new control numid\n"); + return -ENOMEM; + } + last_numid = card->last_numid; + } + return 0; +} + /** * snd_ctl_add - add the control instance to the card * @card: the card instance * @kcontrol: the control instance to add * * Adds the control instance created via snd_ctl_new() or - * snd_ctl_new1() to the given card. + * snd_ctl_new1() to the given card. Assigns also an unique + * numid used for fast search. * * Returns zero if successful, or a negative error code on failure. + * + * It frees automatically the control which cannot be added. */ int snd_ctl_add(snd_card_t * card, snd_kcontrol_t * kcontrol) { @@ -270,13 +306,29 @@ snd_runtime_check(card != NULL && kcontrol != NULL, return -EINVAL); snd_assert(kcontrol->info != NULL, return -EINVAL); + id = kcontrol->id; down_write(&card->controls_rwsem); + if (snd_ctl_find_id(card, &id)) { + up_write(&card->controls_rwsem); + snd_ctl_free_one(kcontrol); + snd_printd(KERN_ERR "control %i:%i:%i:%s:%i is already present\n", + id.iface, + id.device, + id.subdevice, + id.name, + id.index); + return -EBUSY; + } + if (snd_ctl_find_hole(card, kcontrol->count) < 0) { + up_write(&card->controls_rwsem); + snd_ctl_free_one(kcontrol); + return -ENOMEM; + } list_add_tail(&kcontrol->list, &card->controls); card->controls_count += kcontrol->count; kcontrol->id.numid = card->last_numid + 1; card->last_numid += kcontrol->count; up_write(&card->controls_rwsem); - id = kcontrol->id; for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); return 0; @@ -288,7 +340,8 @@ * @kcontrol: the control instance to remove * * Removes the control from the card and then releases the instance. - * You don't need to call snd_ctl_free_one(). + * You don't need to call snd_ctl_free_one(). You must be in + * the write lock - down_write(&card->controls_rwsem). * * Returns 0 if successful, or a negative error code on failure. */ @@ -298,10 +351,8 @@ unsigned int idx; snd_runtime_check(card != NULL && kcontrol != NULL, return -EINVAL); - down_write(&card->controls_rwsem); list_del(&kcontrol->list); card->controls_count -= kcontrol->count; - up_write(&card->controls_rwsem); id = kcontrol->id; for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_REMOVE, &id); @@ -322,15 +373,50 @@ int snd_ctl_remove_id(snd_card_t * card, snd_ctl_elem_id_t *id) { snd_kcontrol_t *kctl; + int ret; + down_write(&card->controls_rwsem); kctl = snd_ctl_find_id(card, id); - if (kctl == NULL) + if (kctl == NULL) { + up_write(&card->controls_rwsem); return -ENOENT; - return snd_ctl_remove(card, kctl); + } + ret = snd_ctl_remove(card, kctl); + up_write(&card->controls_rwsem); + return ret; } -static snd_kcontrol_t *_ctl_find_id -(snd_card_t * card, snd_ctl_elem_id_t *id); /* w/o lock */ +/** + * snd_ctl_remove_unlocked_id - remove the unlocked control of the given id and release it + * @file: active control handle + * @id: the control id to remove + * + * Finds the control instance with the given id, removes it from the + * card list and releases it. + * + * Returns 0 if successful, or a negative error code on failure. + */ +static int snd_ctl_remove_unlocked_id(snd_ctl_file_t * file, snd_ctl_elem_id_t *id) +{ + snd_card_t *card = file->card; + snd_kcontrol_t *kctl; + int idx, ret; + + down_write(&card->controls_rwsem); + kctl = snd_ctl_find_id(card, id); + if (kctl == NULL) { + up_write(&card->controls_rwsem); + return -ENOENT; + } + for (idx = 0; idx < kctl->count; idx++) + if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file) { + up_write(&card->controls_rwsem); + return -EBUSY; + } + ret = snd_ctl_remove(card, kctl); + up_write(&card->controls_rwsem); + return ret; +} /** * snd_ctl_rename_id - replace the id of a control on the card @@ -348,7 +434,7 @@ snd_kcontrol_t *kctl; down_write(&card->controls_rwsem); - kctl = _ctl_find_id(card, src_id); + kctl = snd_ctl_find_id(card, src_id); if (kctl == NULL) { up_write(&card->controls_rwsem); return -ENOENT; @@ -360,7 +446,19 @@ return 0; } -static snd_kcontrol_t *_ctl_find_numid(snd_card_t * card, unsigned int numid) +/** + * snd_ctl_find_numid - find the control instance with the given number-id + * @card: the card instance + * @numid: the number-id to search + * + * Finds the control instance with the given number-id from the card. + * + * Returns the pointer of the instance if found, or NULL if not. + * + * The caller must down card->controls_rwsem before calling this function + * (if the race condition can happen). + */ +snd_kcontrol_t *snd_ctl_find_numid(snd_card_t * card, unsigned int numid) { struct list_head *list; snd_kcontrol_t *kctl; @@ -374,14 +472,26 @@ return NULL; } -static snd_kcontrol_t *_ctl_find_id(snd_card_t * card, snd_ctl_elem_id_t *id) +/** + * snd_ctl_find_id - find the control instance with the given id + * @card: the card instance + * @id: the id to search + * + * Finds the control instance with the given id from the card. + * + * Returns the pointer of the instance if found, or NULL if not. + * + * The caller must down card->controls_rwsem before calling this function + * (if the race condition can happen). + */ +snd_kcontrol_t *snd_ctl_find_id(snd_card_t * card, snd_ctl_elem_id_t *id) { struct list_head *list; snd_kcontrol_t *kctl; snd_runtime_check(card != NULL && id != NULL, return NULL); if (id->numid != 0) - return _ctl_find_numid(card, id->numid); + return snd_ctl_find_numid(card, id->numid); list_for_each(list, &card->controls) { kctl = snd_kcontrol(list); if (kctl->id.iface != id->iface) @@ -401,42 +511,6 @@ return NULL; } -/** - * snd_ctl_find_id - find the control instance with the given id - * @card: the card instance - * @id: the id to search - * - * Finds the control instance with the given id from the card. - * - * Returns the pointer of the instance if found, or NULL if not. - */ -snd_kcontrol_t *snd_ctl_find_id(snd_card_t * card, snd_ctl_elem_id_t *id) -{ - snd_kcontrol_t *kctl; - down_read(&card->controls_rwsem); - kctl = _ctl_find_id(card, id); - up_read(&card->controls_rwsem); - return kctl; -} - -/** - * snd_ctl_find_numid - find the control instance with the given number-id - * @card: the card instance - * @numid: the number-id to search - * - * Finds the control instance with the given number-id from the card. - * - * Returns the pointer of the instance if found, or NULL if not. - */ -snd_kcontrol_t *snd_ctl_find_numid(snd_card_t * card, unsigned int numid) -{ - snd_kcontrol_t *kctl; - down_read(&card->controls_rwsem); - kctl = _ctl_find_numid(card, numid); - up_read(&card->controls_rwsem); - return kctl; -} - static int snd_ctl_card_info(snd_card_t * card, snd_ctl_file_t * ctl, unsigned int cmd, unsigned long arg) { @@ -531,7 +605,7 @@ if (copy_from_user(&info, _info, sizeof(info))) return -EFAULT; down_read(&card->controls_rwsem); - kctl = _ctl_find_id(card, &info.id); + kctl = snd_ctl_find_id(card, &info.id); if (kctl == NULL) { up_read(&card->controls_rwsem); return -ENOENT; @@ -564,7 +638,6 @@ static int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t *_control) { - snd_ctl_elem_value_t *control; snd_kcontrol_t *kctl; snd_kcontrol_volatile_t *vd; @@ -577,7 +650,7 @@ if (copy_from_user(control, _control, sizeof(*control))) return -EFAULT; down_read(&card->controls_rwsem); - kctl = _ctl_find_id(card, &control->id); + kctl = snd_ctl_find_id(card, &control->id); if (kctl == NULL) { result = -ENOENT; } else { @@ -618,7 +691,7 @@ if (copy_from_user(control, _control, sizeof(*control))) return -EFAULT; down_read(&card->controls_rwsem); - kctl = _ctl_find_id(card, &control->id); + kctl = snd_ctl_find_id(card, &control->id); if (kctl == NULL) { result = -ENOENT; } else { @@ -664,7 +737,7 @@ if (copy_from_user(&id, _id, sizeof(id))) return -EFAULT; down_write(&card->controls_rwsem); - kctl = _ctl_find_id(card, &id); + kctl = snd_ctl_find_id(card, &id); if (kctl == NULL) { result = -ENOENT; } else { @@ -692,7 +765,7 @@ if (copy_from_user(&id, _id, sizeof(id))) return -EFAULT; down_write(&card->controls_rwsem); - kctl = _ctl_find_id(card, &id); + kctl = snd_ctl_find_id(card, &id); if (kctl == NULL) { result = -ENOENT; } else { @@ -711,6 +784,196 @@ return result; } +struct user_element { + enum sndrv_ctl_elem_type type; /* element type */ + unsigned int elem_count; /* count of elements */ + union { + struct { + unsigned int items; + } enumerated; + } u; + void *elem_data; /* element data */ + unsigned long elem_data_size; /* size of element data in bytes */ + void *priv_data; /* private data (like strings for enumerated type) */ + unsigned long priv_data_size; /* size of private data in bytes */ + unsigned short dimen_count; /* count of dimensions */ + unsigned short dimen[0]; /* array of dimensions */ +}; + +static int snd_ctl_elem_user_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + struct user_element *ue = kcontrol->private_data; + + uinfo->type = ue->type; + uinfo->count = ue->elem_count; + if (ue->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) { + uinfo->value.enumerated.items = ue->u.enumerated.items; + if (uinfo->value.enumerated.item >= ue->u.enumerated.items) + uinfo->value.enumerated.item = 0; + strlcpy(uinfo->value.enumerated.name, + (char *)ue->priv_data + uinfo->value.enumerated.item * 64, + 64); + } + return 0; +} + +static int snd_ctl_elem_user_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + struct user_element *ue = kcontrol->private_data; + + memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size); + return 0; +} + +static int snd_ctl_elem_user_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + int change; + struct user_element *ue = kcontrol->private_data; + + change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size); + memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size); + return !!change; +} + +static void snd_ctl_elem_user_free(snd_kcontrol_t * kcontrol) +{ + kfree(kcontrol->private_data); +} + +static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t *_info, int replace) +{ + snd_card_t *card = file->card; + snd_ctl_elem_info_t info; + snd_kcontrol_t kctl, *_kctl; + unsigned int access; + long private_size, dimen_size, extra_size; + struct user_element *ue; + int idx, err; + + if (copy_from_user(&info, _info, sizeof(info))) + return -EFAULT; + if (info.count > 1024) + return -EINVAL; + access = info.access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : + (info.access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|SNDRV_CTL_ELEM_ACCESS_INACTIVE| + SNDRV_CTL_ELEM_ACCESS_DINDIRECT|SNDRV_CTL_ELEM_ACCESS_INDIRECT)); + if (access & (SNDRV_CTL_ELEM_ACCESS_DINDIRECT | SNDRV_CTL_ELEM_ACCESS_INDIRECT)) + return -EINVAL; + info.id.numid = 0; + memset(&kctl, 0, sizeof(kctl)); + down_write(&card->controls_rwsem); + if (!!((_kctl = snd_ctl_find_id(card, &info.id)) != NULL) ^ replace) { + up_write(&card->controls_rwsem); + return !replace ? -EBUSY : -ENOENT; + } + if (replace) { + err = snd_ctl_remove(card, _kctl); + if (err < 0) { + up_write(&card->controls_rwsem); + return err; + } + } + up_write(&card->controls_rwsem); + memcpy(&kctl.id, &info.id, sizeof(info.id)); + kctl.count = info.owner ? info.owner : 1; + access |= SNDRV_CTL_ELEM_ACCESS_USER; + kctl.info = snd_ctl_elem_user_info; + if (access & SNDRV_CTL_ELEM_ACCESS_READ) + kctl.get = snd_ctl_elem_user_get; + if (access & SNDRV_CTL_ELEM_ACCESS_WRITE) + kctl.put = snd_ctl_elem_user_put; + extra_size = 0; + switch (info.type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + private_size = sizeof(char); + if (info.count > 128) + return -EINVAL; + break; + case SNDRV_CTL_ELEM_TYPE_INTEGER: + private_size = sizeof(long); + if (info.count > 128) + return -EINVAL; + break; + case SNDRV_CTL_ELEM_TYPE_INTEGER64: + private_size = sizeof(long long); + if (info.count > 64) + return -EINVAL; + break; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + private_size = sizeof(unsigned int); + if (info.count > 128) + return -EINVAL; + if (info.value.enumerated.items > 1024) + return -EINVAL; + extra_size = info.value.enumerated.items * 64; + break; + case SNDRV_CTL_ELEM_TYPE_BYTES: + private_size = sizeof(unsigned char); + if (info.count > 512) + return -EINVAL; + break; + case SNDRV_CTL_ELEM_TYPE_IEC958: + private_size = sizeof(struct sndrv_aes_iec958); + if (info.count != 1) + return -EINVAL; + break; + default: + return -EINVAL; + } + private_size *= info.count; + if (private_size > 1024 * 1024) + return -EINVAL; + dimen_size = 0; + if (!(info.access & SNDRV_CTL_ELEM_ACCESS_DINDIRECT)) + for (idx = 0; idx < 4 && info.dimen.d[idx]; idx++) + dimen_size += sizeof(unsigned short); + ue = snd_kcalloc(sizeof(struct user_element) + dimen_size + private_size + extra_size, GFP_KERNEL); + if (ue == NULL) + return -ENOMEM; + ue->type = info.type; + ue->elem_count = info.count; + if (!(info.access & SNDRV_CTL_ELEM_ACCESS_DINDIRECT)) { + for (idx = 0; idx < 4 && info.dimen.d[idx]; idx++) + ue->dimen[idx] = info.dimen.d[idx]; + ue->dimen_count = dimen_size / sizeof(unsigned short); + } + ue->elem_data = (char *)ue + sizeof(ue) + dimen_size; + ue->elem_data_size = private_size; + if (extra_size) { + ue->priv_data = (char *)ue + sizeof(ue) + dimen_size + private_size; + ue->priv_data_size = extra_size; + if (ue->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) { + if (copy_from_user(ue->priv_data, *(char **)info.value.enumerated.name, extra_size)) + return -EFAULT; + ue->u.enumerated.items = info.value.enumerated.items; + } + } + kctl.private_free = snd_ctl_elem_user_free; + _kctl = snd_ctl_new(&kctl, access); + if (_kctl == NULL) { + kfree(_kctl->private_data); + return -ENOMEM; + } + _kctl->private_data = ue; + for (idx = 0; idx < _kctl->count; idx++) + _kctl->vd[idx].owner = file; + err = snd_ctl_add(card, _kctl); + if (err < 0) { + snd_ctl_free_one(_kctl); + return err; + } + return 0; +} + +static int snd_ctl_elem_remove(snd_ctl_file_t *file, snd_ctl_elem_id_t *_id) +{ + snd_ctl_elem_id_t id; + + if (copy_from_user(&id, _id, sizeof(id))) + return -EFAULT; + return snd_ctl_remove_unlocked_id(file, &id); +} + static int snd_ctl_subscribe_events(snd_ctl_file_t *file, int *ptr) { int subscribe; @@ -761,6 +1024,12 @@ return snd_ctl_elem_lock(ctl, (snd_ctl_elem_id_t *) arg); case SNDRV_CTL_IOCTL_ELEM_UNLOCK: return snd_ctl_elem_unlock(ctl, (snd_ctl_elem_id_t *) arg); + case SNDRV_CTL_IOCTL_ELEM_ADD: + return snd_ctl_elem_add(ctl, (snd_ctl_elem_info_t *) arg, 0); + case SNDRV_CTL_IOCTL_ELEM_REPLACE: + return snd_ctl_elem_add(ctl, (snd_ctl_elem_info_t *) arg, 1); + case SNDRV_CTL_IOCTL_ELEM_REMOVE: + return snd_ctl_elem_remove(ctl, (snd_ctl_elem_id_t *) arg); case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: return snd_ctl_subscribe_events(ctl, (int *) arg); case SNDRV_CTL_IOCTL_POWER: @@ -995,9 +1264,11 @@ snd_assert(cardnum >= 0 && cardnum < SNDRV_CARDS, return -ENXIO); if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL, card, 0)) < 0) return err; + down_write(&card->controls_rwsem); while (!list_empty(&card->controls)) { control = snd_kcontrol(card->controls.next); snd_ctl_remove(card, control); } + up_write(&card->controls_rwsem); return 0; } diff -Nru a/sound/core/hwdep.c b/sound/core/hwdep.c --- a/sound/core/hwdep.c Mon Feb 2 22:07:55 2004 +++ b/sound/core/hwdep.c Mon Feb 2 22:07:55 2004 @@ -214,7 +214,7 @@ snd_hwdep_dsp_image_t info; int err; - if (! hw->ops.dsp_load || ! hw->ops.dsp_status) + if (! hw->ops.dsp_load) return -ENXIO; memset(&info, 0, sizeof(info)); if (copy_from_user(&info, _info, sizeof(info))) @@ -487,7 +487,6 @@ memset(snd_hwdep_devices, 0, sizeof(snd_hwdep_devices)); if ((entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = 512; entry->c.text.read = snd_hwdep_proc_read; if (snd_info_register(entry) < 0) { diff -Nru a/sound/core/info_oss.c b/sound/core/info_oss.c --- a/sound/core/info_oss.c Mon Feb 2 22:07:55 2004 +++ b/sound/core/info_oss.c Mon Feb 2 22:07:55 2004 @@ -114,7 +114,6 @@ memset(snd_sndstat_strings, 0, sizeof(snd_sndstat_strings)); if ((entry = snd_info_create_module_entry(THIS_MODULE, "sndstat", snd_oss_root)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = 2048; entry->c.text.read = snd_sndstat_proc_read; if (snd_info_register(entry) < 0) { diff -Nru a/sound/core/init.c b/sound/core/init.c --- a/sound/core/init.c Mon Feb 2 22:07:55 2004 +++ b/sound/core/init.c Mon Feb 2 22:07:55 2004 @@ -442,7 +442,6 @@ snd_printd("unable to create card entry\n"); goto __skip_info; } - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = PAGE_SIZE; entry->c.text.read = snd_card_id_read; if (snd_info_register(entry) < 0) { @@ -527,7 +526,6 @@ entry = snd_info_create_module_entry(THIS_MODULE, "cards", NULL); snd_runtime_check(entry != NULL, return -ENOMEM); - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = PAGE_SIZE; entry->c.text.read = snd_card_info_read; if (snd_info_register(entry) < 0) { @@ -539,7 +537,6 @@ #ifdef MODULE entry = snd_info_create_module_entry(THIS_MODULE, "modules", NULL); if (entry) { - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = PAGE_SIZE; entry->c.text.read = snd_card_module_info_read; if (snd_info_register(entry) < 0) @@ -682,6 +679,7 @@ int snd_power_wait(snd_card_t *card, unsigned int power_state, struct file *file) { wait_queue_t wait; + int result = 0; /* fastpath */ if (snd_power_get_state(card) == power_state) @@ -689,18 +687,24 @@ init_waitqueue_entry(&wait, current); add_wait_queue(&card->power_sleep, &wait); while (1) { - if (card->shutdown) - return -ENODEV; - if (snd_power_get_state(card) == power_state) { - remove_wait_queue(&card->power_sleep, &wait); - return 0; + if (card->shutdown) { + result = -ENODEV; + break; } - if (file && (file->f_flags & O_NONBLOCK)) - return -EAGAIN; + if (snd_power_get_state(card) == power_state) + break; +#if 0 /* block all devices */ + if (file && (file->f_flags & O_NONBLOCK)) { + result = -EAGAIN; + break; + } +#endif set_current_state(TASK_UNINTERRUPTIBLE); snd_power_unlock(card); schedule_timeout(30 * HZ); snd_power_lock(card); } + remove_wait_queue(&card->power_sleep, &wait); + return result; } #endif /* CONFIG_PM */ diff -Nru a/sound/core/ioctl32/ioctl32.c b/sound/core/ioctl32/ioctl32.c --- a/sound/core/ioctl32/ioctl32.c Mon Feb 2 22:07:55 2004 +++ b/sound/core/ioctl32/ioctl32.c Mon Feb 2 22:07:55 2004 @@ -259,12 +259,15 @@ ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO); + down_read(&ctl->card->controls_rwsem); kctl = snd_ctl_find_id(ctl->card, id); if (! kctl) { + up_read(&ctl->card->controls_rwsem); return -ENXIO; } info.id = *id; err = kctl->info(kctl, &info); + up_read(&ctl->card->controls_rwsem); if (err >= 0) err = info.type; return err; diff -Nru a/sound/core/memalloc.c b/sound/core/memalloc.c --- a/sound/core/memalloc.c Mon Feb 2 22:07:58 2004 +++ b/sound/core/memalloc.c Mon Feb 2 22:07:58 2004 @@ -39,7 +39,7 @@ #ifndef SNDRV_CARDS #define SNDRV_CARDS 8 #endif -static int enable[8] = {[0 ... (SNDRV_CARDS-1)] = 1}; +static int enable[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1}; MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(enable, "Enable cards to allocate buffers."); @@ -94,26 +94,29 @@ dma_addr_t *dma_handle) { void *ret; - u64 dma_mask; - unsigned long rmask; + u64 dma_mask, cdma_mask; + unsigned long mask; if (hwdev == NULL) return pci_alloc_consistent(hwdev, size, dma_handle); dma_mask = hwdev->dma_mask; - rmask = ~((unsigned long)dma_mask); + cdma_mask = hwdev->consistent_dma_mask; + mask = (unsigned long)dma_mask && (unsigned long)cdma_mask; hwdev->dma_mask = 0xffffffff; /* do without masking */ + hwdev->consistent_dma_mask = 0xffffffff; /* do without masking */ ret = pci_alloc_consistent(hwdev, size, dma_handle); hwdev->dma_mask = dma_mask; /* restore */ + hwdev->consistent_dma_mask = cdma_mask; /* restore */ if (ret) { /* obtained address is out of range? */ - if (((unsigned long)*dma_handle + size - 1) & rmask) { + if (((unsigned long)*dma_handle + size - 1) & ~mask) { /* reallocate with the proper mask */ pci_free_consistent(hwdev, size, ret, *dma_handle); ret = pci_alloc_consistent(hwdev, size, dma_handle); } } else { /* wish to success now with the proper mask... */ - if (dma_mask != 0xffffffff) + if (mask != 0xffffffffUL) ret = pci_alloc_consistent(hwdev, size, dma_handle); } return ret; @@ -207,8 +210,9 @@ dmab->addr = 0; return -ENXIO; } - if (dmab->area) - dmab->bytes = size; + if (! dmab->area) + return -ENOMEM; + dmab->bytes = size; return 0; } @@ -342,6 +346,8 @@ down(&list_mutex); mem = mem_list_find(dev, 0); if (mem) { + if (mem->used) + printk(KERN_WARNING "snd-page-alloc: releasing the used block (type=%d, id=0x%x\n", mem->dev.type, mem->dev.id); snd_dma_free_pages(dev, &mem->buffer); if (! dmab || ! dmab->bytes) { /* remove the entry */ @@ -361,7 +367,7 @@ return -ENOMEM; } mem->dev = *dev; - list_add(&mem->list, &mem_list_head); + list_add_tail(&mem->list, &mem_list_head); } /* store the entry */ mem->used = 1; @@ -640,13 +646,13 @@ { void *ptr; dma_addr_t addr; - unsigned long rmask; + unsigned long mask; - rmask = ~(unsigned long)(pci ? pci->dma_mask : 0x00ffffff); + mask = pci ? (unsigned long)pci->consistent_dma_mask : 0x00ffffffUL; ptr = (void *)__get_free_page(GFP_KERNEL); if (ptr) { addr = virt_to_phys(ptr); - if (((unsigned long)addr + PAGE_SIZE - 1) & rmask) { + if (((unsigned long)addr + PAGE_SIZE - 1) & ~mask) { /* try to reallocate with the GFP_DMA */ free_page((unsigned long)ptr); /* use GFP_ATOMIC for the DMA zone to avoid stall */ @@ -783,6 +789,7 @@ * allocation of buffers for pre-defined devices */ +#ifdef CONFIG_PCI /* FIXME: for pci only - other bus? */ struct prealloc_dev { unsigned short vendor; @@ -823,37 +830,48 @@ while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) { struct prealloc_dev *dev; + unsigned int i; if (card >= SNDRV_CARDS) break; for (dev = prealloc_devices; dev->vendor; dev++) { - unsigned int i; - if (dev->vendor != pci->vendor || dev->device != pci->device) - continue; - if (! enable[card++]) - continue; + if (dev->vendor == pci->vendor && dev->device == pci->device) + break; + } + if (! dev->vendor) + continue; + if (! enable[card++]) { + printk(KERN_DEBUG "snd-page-alloc: skipping card %d, device %04x:%04x\n", card, pci->vendor, pci->device); + continue; + } - if (pci_set_dma_mask(pci, dev->dma_mask) < 0) { - printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", dev->dma_mask, dev->vendor, dev->device); - continue; + if (pci_set_dma_mask(pci, dev->dma_mask) < 0 || + pci_set_consistent_dma_mask(pci, dev->dma_mask) < 0) { + printk(KERN_ERR "snd-page-alloc: cannot set DMA mask %lx for pci %04x:%04x\n", dev->dma_mask, dev->vendor, dev->device); + continue; + } + for (i = 0; i < dev->buffers; i++) { + struct snd_mem_list *mem; + mem = kmalloc(sizeof(*mem), GFP_KERNEL); + if (! mem) { + printk(KERN_WARNING "snd-page-alloc: can't malloc memlist\n"); + break; } - - for (i = 0; i < dev->buffers; i++) { - struct snd_dma_device dma; - struct snd_dma_buffer buf; - snd_dma_device_pci(&dma, pci, SNDRV_DMA_DEVICE_UNUSED); - memset(&buf, 0, sizeof(buf)); - snd_dma_alloc_pages(&dma, dev->size, &buf); - if (buf.bytes) { - if (snd_dma_set_reserved(&dma, &buf) < 0) { - printk(KERN_WARNING "snd-page-alloc: cannot reserve buffer\n"); - snd_dma_free_pages(&dma, &buf); - } - } else - printk(KERN_WARNING "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", dev->size); + memset(mem, 0, sizeof(*mem)); + snd_dma_device_pci(&mem->dev, pci, SNDRV_DMA_DEVICE_UNUSED); + if (snd_dma_alloc_pages(&mem->dev, dev->size, &mem->buffer) < 0) { + printk(KERN_WARNING "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", dev->size); + kfree(mem); + } else { + down(&list_mutex); + list_add_tail(&mem->list, &mem_list_head); + up(&list_mutex); } } } } +#else +#define preallocate_cards() /* NOP */ +#endif #ifdef CONFIG_PROC_FS @@ -890,7 +908,8 @@ case SNDRV_DMA_TYPE_PCI: case SNDRV_DMA_TYPE_PCI_SG: if (mem->dev.dev.pci) { - len += sprintf(page + len, "PCI [%04x:%04x]", + len += sprintf(page + len, "%s [%04x:%04x]", + mem->dev.type == SNDRV_DMA_TYPE_PCI ? "PCI" : "PCI-SG", mem->dev.dev.pci->vendor, mem->dev.dev.pci->device); } diff -Nru a/sound/core/memory.c b/sound/core/memory.c --- a/sound/core/memory.c Mon Feb 2 22:07:55 2004 +++ b/sound/core/memory.c Mon Feb 2 22:07:55 2004 @@ -231,7 +231,6 @@ entry = snd_info_create_module_entry(THIS_MODULE, "meminfo", NULL); if (entry) { - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = 256; entry->c.text.read = snd_memory_info_read; if (snd_info_register(entry) < 0) { diff -Nru a/sound/core/misc.c b/sound/core/misc.c --- a/sound/core/misc.c Mon Feb 2 22:07:56 2004 +++ b/sound/core/misc.c Mon Feb 2 22:07:56 2004 @@ -51,9 +51,8 @@ printk("ALSA %s:%d: ", file, line); } va_start(args, format); - vsnprintf(tmpbuf, sizeof(tmpbuf)-1, format, args); + vsnprintf(tmpbuf, sizeof(tmpbuf), format, args); va_end(args); - tmpbuf[sizeof(tmpbuf)-1] = '\0'; printk(tmpbuf); } #endif @@ -73,9 +72,8 @@ printk(KERN_DEBUG "ALSA %s:%d: ", file, line); } va_start(args, format); - vsnprintf(tmpbuf, sizeof(tmpbuf)-1, format, args); + vsnprintf(tmpbuf, sizeof(tmpbuf), format, args); va_end(args); - tmpbuf[sizeof(tmpbuf)-1] = '\0'; printk(tmpbuf); } diff -Nru a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c --- a/sound/core/oss/mixer_oss.c Mon Feb 2 22:07:57 2004 +++ b/sound/core/oss/mixer_oss.c Mon Feb 2 22:07:57 2004 @@ -30,9 +30,12 @@ #include #include +#define OSS_ALSAEMULVER _SIOR ('M', 249, int) + MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Mixer OSS emulation for ALSA."); MODULE_LICENSE("GPL"); +MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MIXER); static int snd_mixer_oss_open(struct inode *inode, struct file *file) { @@ -305,34 +308,36 @@ tmp = snd_mixer_oss_set_recsrc(fmixer, tmp); if (tmp < 0) return tmp; - return put_user(tmp, (int *)arg) ? -EFAULT : 0; + return put_user(tmp, (int *)arg); case OSS_GETVERSION: return put_user(SNDRV_OSS_VERSION, (int *) arg); + case OSS_ALSAEMULVER: + return put_user(1, (int *) arg); case SOUND_MIXER_READ_DEVMASK: tmp = snd_mixer_oss_devmask(fmixer); if (tmp < 0) return tmp; - return put_user(tmp, (int *)arg) ? -EFAULT : 0; + return put_user(tmp, (int *)arg); case SOUND_MIXER_READ_STEREODEVS: tmp = snd_mixer_oss_stereodevs(fmixer); if (tmp < 0) return tmp; - return put_user(tmp, (int *)arg) ? -EFAULT : 0; + return put_user(tmp, (int *)arg); case SOUND_MIXER_READ_RECMASK: tmp = snd_mixer_oss_recmask(fmixer); if (tmp < 0) return tmp; - return put_user(tmp, (int *)arg) ? -EFAULT : 0; + return put_user(tmp, (int *)arg); case SOUND_MIXER_READ_CAPS: tmp = snd_mixer_oss_caps(fmixer); if (tmp < 0) return tmp; - return put_user(tmp, (int *)arg) ? -EFAULT : 0; + return put_user(tmp, (int *)arg); case SOUND_MIXER_READ_RECSRC: tmp = snd_mixer_oss_get_recsrc(fmixer); if (tmp < 0) return tmp; - return put_user(tmp, (int *)arg) ? -EFAULT : 0; + return put_user(tmp, (int *)arg); } } if (cmd & SIOC_IN) { @@ -341,12 +346,12 @@ tmp = snd_mixer_oss_set_volume(fmixer, cmd & 0xff, tmp); if (tmp < 0) return tmp; - return put_user(tmp, (int *)arg) ? -EFAULT : 0; + return put_user(tmp, (int *)arg); } else if (cmd & SIOC_OUT) { tmp = snd_mixer_oss_get_volume(fmixer, cmd & 0xff); if (tmp < 0) return tmp; - return put_user(tmp, (int *)arg) ? -EFAULT : 0; + return put_user(tmp, (int *)arg); } return -ENXIO; } @@ -464,12 +469,14 @@ unsigned int signature; unsigned int present; unsigned int channels; - snd_kcontrol_t *kcontrol[SNDRV_MIXER_OSS_ITEM_COUNT]; + unsigned int numid[SNDRV_MIXER_OSS_ITEM_COUNT]; unsigned int capture_item; struct snd_mixer_oss_assign_table *assigned; unsigned int allocated: 1; }; +#define ID_UNKNOWN ((unsigned int)-1) + static snd_kcontrol_t *snd_mixer_oss_test_id(snd_mixer_oss_t *mixer, const char *name, int index) { snd_card_t * card = mixer->card; @@ -484,15 +491,23 @@ static void snd_mixer_oss_get_volume1_vol(snd_mixer_oss_file_t *fmixer, snd_mixer_oss_slot_t *pslot, - snd_kcontrol_t *kctl, + unsigned int numid, int *left, int *right) { snd_ctl_elem_info_t *uinfo; snd_ctl_elem_value_t *uctl; + snd_kcontrol_t *kctl; + snd_card_t *card = fmixer->card; - snd_runtime_check(kctl != NULL, return); - uinfo = snd_kcalloc(sizeof(*uinfo), GFP_ATOMIC); - uctl = snd_kcalloc(sizeof(*uctl), GFP_ATOMIC); + if (numid == ID_UNKNOWN) + return; + down_read(&card->controls_rwsem); + if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { + up_read(&card->controls_rwsem); + return; + } + uinfo = snd_kcalloc(sizeof(*uinfo), GFP_KERNEL); + uctl = snd_kcalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) goto __unalloc; snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); @@ -502,6 +517,7 @@ if (uinfo->count > 1) *right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]); __unalloc: + up_read(&card->controls_rwsem); if (uctl) kfree(uctl); if (uinfo) @@ -510,16 +526,24 @@ static void snd_mixer_oss_get_volume1_sw(snd_mixer_oss_file_t *fmixer, snd_mixer_oss_slot_t *pslot, - snd_kcontrol_t *kctl, + unsigned int numid, int *left, int *right, int route) { snd_ctl_elem_info_t *uinfo; snd_ctl_elem_value_t *uctl; + snd_kcontrol_t *kctl; + snd_card_t *card = fmixer->card; - snd_runtime_check(kctl != NULL, return); - uinfo = snd_kcalloc(sizeof(*uinfo), GFP_ATOMIC); - uctl = snd_kcalloc(sizeof(*uctl), GFP_ATOMIC); + if (numid == ID_UNKNOWN) + return; + down_read(&card->controls_rwsem); + if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { + up_read(&card->controls_rwsem); + return; + } + uinfo = snd_kcalloc(sizeof(*uinfo), GFP_KERNEL); + uctl = snd_kcalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) goto __unalloc; snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); @@ -532,6 +556,7 @@ if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1]) *right = 0; __unalloc: + up_read(&card->controls_rwsem); if (uctl) kfree(uctl); if (uinfo) @@ -542,43 +567,46 @@ snd_mixer_oss_slot_t *pslot, int *left, int *right) { - snd_card_t *card = fmixer->card; struct slot *slot = (struct slot *)pslot->private_data; *left = *right = 100; - down_read(&card->controls_rwsem); if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { - snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); + snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) { - snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right); + snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right); } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) { - snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right); + snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right); } if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) { - snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); + snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) { - snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); + snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) { - snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); + snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) { - snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); + snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); } - up_read(&card->controls_rwsem); return 0; } static void snd_mixer_oss_put_volume1_vol(snd_mixer_oss_file_t *fmixer, snd_mixer_oss_slot_t *pslot, - snd_kcontrol_t *kctl, + unsigned int numid, int left, int right) { snd_ctl_elem_info_t *uinfo; snd_ctl_elem_value_t *uctl; + snd_kcontrol_t *kctl; + snd_card_t *card = fmixer->card; int res; - snd_runtime_check(kctl != NULL, return); - uinfo = snd_kcalloc(sizeof(*uinfo), GFP_ATOMIC); - uctl = snd_kcalloc(sizeof(*uctl), GFP_ATOMIC); + if (numid == ID_UNKNOWN) + return; + down_read(&card->controls_rwsem); + if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) + return; + uinfo = snd_kcalloc(sizeof(*uinfo), GFP_KERNEL); + uctl = snd_kcalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) goto __unalloc; snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); @@ -588,8 +616,9 @@ uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max); snd_runtime_check((res = kctl->put(kctl, uctl)) >= 0, goto __unalloc); if (res > 0) - snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); __unalloc: + up_read(&card->controls_rwsem); if (uctl) kfree(uctl); if (uinfo) @@ -598,17 +627,25 @@ static void snd_mixer_oss_put_volume1_sw(snd_mixer_oss_file_t *fmixer, snd_mixer_oss_slot_t *pslot, - snd_kcontrol_t *kctl, + unsigned int numid, int left, int right, int route) { snd_ctl_elem_info_t *uinfo; snd_ctl_elem_value_t *uctl; + snd_kcontrol_t *kctl; + snd_card_t *card = fmixer->card; int res; - snd_runtime_check(kctl != NULL, return); - uinfo = snd_kcalloc(sizeof(*uinfo), GFP_ATOMIC); - uctl = snd_kcalloc(sizeof(*uctl), GFP_ATOMIC); + if (numid == ID_UNKNOWN) + return; + down_read(&card->controls_rwsem); + if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) { + up_read(&fmixer->card->controls_rwsem); + return; + } + uinfo = snd_kcalloc(sizeof(*uinfo), GFP_KERNEL); + uctl = snd_kcalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) goto __unalloc; snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); @@ -624,8 +661,9 @@ } snd_runtime_check((res = kctl->put(kctl, uctl)) >= 0, goto __unalloc); if (res > 0) - snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); __unalloc: + up_read(&card->controls_rwsem); if (uctl) kfree(uctl); if (uinfo) @@ -636,40 +674,37 @@ snd_mixer_oss_slot_t *pslot, int left, int right) { - snd_card_t *card = fmixer->card; struct slot *slot = (struct slot *)pslot->private_data; - down_read(&card->controls_rwsem); if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) { - snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); + snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right); if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME) - snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right); + snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right); } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) { - snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right); + snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right); } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) { - snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right); + snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right); } if (left || right) { if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) - snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); + snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) - snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); + snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) - snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); + snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) - snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); + snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); } else { if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) { - snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); + snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0); } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) { - snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); + snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0); } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) { - snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); + snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1); } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) { - snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); + snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1); } } - up_read(&card->controls_rwsem); return 0; } @@ -677,14 +712,11 @@ snd_mixer_oss_slot_t *pslot, int *active) { - snd_card_t *card = fmixer->card; struct slot *slot = (struct slot *)pslot->private_data; int left, right; left = right = 1; - down_read(&card->controls_rwsem); - snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_CSWITCH], &left, &right, 0); - up_read(&card->controls_rwsem); + snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], &left, &right, 0); *active = (left || right) ? 1 : 0; return 0; } @@ -693,14 +725,11 @@ snd_mixer_oss_slot_t *pslot, int *active) { - snd_card_t *card = fmixer->card; struct slot *slot = (struct slot *)pslot->private_data; int left, right; left = right = 1; - down_read(&card->controls_rwsem); - snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_CROUTE], &left, &right, 1); - up_read(&card->controls_rwsem); + snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], &left, &right, 1); *active = (left || right) ? 1 : 0; return 0; } @@ -709,12 +738,9 @@ snd_mixer_oss_slot_t *pslot, int active) { - snd_card_t *card = fmixer->card; struct slot *slot = (struct slot *)pslot->private_data; - down_read(&card->controls_rwsem); - snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0); - up_read(&card->controls_rwsem); + snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0); return 0; } @@ -722,12 +748,9 @@ snd_mixer_oss_slot_t *pslot, int active) { - snd_card_t *card = fmixer->card; struct slot *slot = (struct slot *)pslot->private_data; - down_read(&card->controls_rwsem); - snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->kcontrol[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1); - up_read(&card->controls_rwsem); + snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1); return 0; } @@ -838,13 +861,21 @@ { snd_ctl_elem_info_t info; snd_kcontrol_t *kcontrol; + snd_card_t *card = mixer->card; int err; + down_read(&card->controls_rwsem); kcontrol = snd_mixer_oss_test_id(mixer, name, index); - if (kcontrol == NULL) + if (kcontrol == NULL) { + up_read(&card->controls_rwsem); return 0; - snd_runtime_check((err = kcontrol->info(kcontrol, &info)) >= 0, return err); - slot->kcontrol[item] = kcontrol; + } + if ((err = kcontrol->info(kcontrol, &info)) < 0) { + up_read(&card->controls_rwsem); + return err; + } + slot->numid[item] = kcontrol->id.numid; + up_read(&card->controls_rwsem); if (info.count > slot->channels) slot->channels = info.count; slot->present |= 1 << item; @@ -872,7 +903,12 @@ rslot->number = idx; } -static int snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_oss_assign_table *ptr, int ptr_allocated) +/* + * build an OSS mixer element. + * ptr_allocated means the entry is dynamically allocated (change via proc file). + * when replace_old = 1, the old entry is replaced with the new one. + */ +static int snd_mixer_oss_build_input(snd_mixer_oss_t *mixer, struct snd_mixer_oss_assign_table *ptr, int ptr_allocated, int replace_old) { struct slot slot; struct slot *pslot; @@ -880,7 +916,12 @@ snd_mixer_oss_slot_t *rslot; char str[64]; + /* check if already assigned */ + if (mixer->slots[ptr->oss_id].get_volume && ! replace_old) + return 0; + memset(&slot, 0, sizeof(slot)); + memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */ if (snd_mixer_oss_build_test(mixer, &slot, ptr->name, ptr->index, SNDRV_MIXER_OSS_ITEM_GLOBAL)) return 0; @@ -920,6 +961,7 @@ if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index, SNDRV_MIXER_OSS_ITEM_CVOLUME)) return 0; + down_read(&mixer->card->controls_rwsem); if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) { snd_ctl_elem_info_t uinfo; @@ -937,8 +979,10 @@ } else { for (slot.capture_item = 1; slot.capture_item < uinfo.value.enumerated.items; slot.capture_item++) { uinfo.value.enumerated.item = slot.capture_item; - if (kctl->info(kctl, &uinfo)) + if (kctl->info(kctl, &uinfo)) { + up_read(&mixer->card->controls_rwsem); return 0; + } if (!strcmp(uinfo.value.enumerated.name, str)) { slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE; break; @@ -946,6 +990,7 @@ } } } + up_read(&mixer->card->controls_rwsem); if (slot.present != 0) { pslot = (struct slot *)kmalloc(sizeof(slot), GFP_KERNEL); snd_runtime_check(pslot != NULL, return -ENOMEM); @@ -1084,7 +1129,7 @@ goto __unlock; } tbl->index = idx; - if (snd_mixer_oss_build_input(mixer, tbl, 1) <= 0) { + if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) { kfree(tbl->name); kfree(tbl); } @@ -1127,9 +1172,11 @@ { static struct snd_mixer_oss_assign_table table[] = { { SOUND_MIXER_VOLUME, "Master", 0 }, + { SOUND_MIXER_VOLUME, "Front", 0 }, /* fallback */ { SOUND_MIXER_BASS, "Tone Control - Bass", 0 }, { SOUND_MIXER_TREBLE, "Tone Control - Treble", 0 }, { SOUND_MIXER_SYNTH, "Synth", 0 }, + { SOUND_MIXER_SYNTH, "FM", 0 }, /* fallback */ { SOUND_MIXER_PCM, "PCM", 0 }, { SOUND_MIXER_SPEAKER, "PC Speaker", 0 }, { SOUND_MIXER_LINE, "Line", 0 }, @@ -1137,6 +1184,7 @@ { SOUND_MIXER_CD, "CD", 0 }, { SOUND_MIXER_IMIX, "Monitor Mix", 0 }, { SOUND_MIXER_ALTPCM, "PCM", 1 }, + { SOUND_MIXER_ALTPCM, "Wave", 0 }, /* fallback */ { SOUND_MIXER_RECLEV, "-- nothing --", 0 }, { SOUND_MIXER_IGAIN, "Capture", 0 }, { SOUND_MIXER_OGAIN, "Playback", 0 }, @@ -1152,15 +1200,10 @@ { SOUND_MIXER_RADIO, "Radio", 0 }, { SOUND_MIXER_MONITOR, "Monitor", 0 } }; - static struct snd_mixer_oss_assign_table fm_table = { - SOUND_MIXER_SYNTH, "FM", 0 - }; unsigned int idx; for (idx = 0; idx < sizeof(table) / sizeof(struct snd_mixer_oss_assign_table); idx++) - snd_mixer_oss_build_input(mixer, &table[idx], 0); - if (mixer->slots[SOUND_MIXER_SYNTH].get_volume == NULL) - snd_mixer_oss_build_input(mixer, &fm_table, 0); + snd_mixer_oss_build_input(mixer, &table[idx], 0, 0); if (mixer->mask_recsrc) { mixer->get_recsrc = snd_mixer_oss_get_recsrc2; mixer->put_recsrc = snd_mixer_oss_put_recsrc2; diff -Nru a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c --- a/sound/core/oss/pcm_oss.c Mon Feb 2 22:07:58 2004 +++ b/sound/core/oss/pcm_oss.c Mon Feb 2 22:07:58 2004 @@ -40,6 +40,8 @@ #include #include +#define OSS_ALSAEMULVER _SIOR ('M', 249, int) + static int dsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0}; static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1}; static int nonblock_open; @@ -56,6 +58,8 @@ MODULE_PARM(nonblock_open, "i"); MODULE_PARM_DESC(nonblock_open, "Don't block opening busy PCM devices."); MODULE_PARM_SYNTAX(nonblock_open, "default:0,skill:advanced"); +MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM); +MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_PCM1); extern int snd_mixer_oss_ioctl_card(snd_card_t *card, unsigned int cmd, unsigned long arg); static int snd_pcm_oss_get_rate(snd_pcm_oss_file_t *pcm_oss_file); @@ -122,11 +126,11 @@ static long snd_pcm_oss_bytes(snd_pcm_substream_t *substream, long frames) { snd_pcm_runtime_t *runtime = substream->runtime; - if (runtime->period_size == runtime->oss.period_bytes) + snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream); + frames = frames_to_bytes(runtime, frames); + if (buffer_size == runtime->oss.buffer_bytes) return frames; - if (runtime->period_size < runtime->oss.period_bytes) - return frames * (runtime->oss.period_bytes / runtime->period_size); - return frames / (runtime->period_size / runtime->oss.period_bytes); + return (runtime->oss.buffer_bytes * frames) / buffer_size; } static int snd_pcm_oss_format_from(int format) @@ -451,7 +455,7 @@ sw_params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; sw_params->period_step = 1; sw_params->sleep_min = 0; - sw_params->avail_min = runtime->period_size; + sw_params->avail_min = 1; sw_params->xfer_align = 1; if (atomic_read(&runtime->mmap_count) || (substream->oss.setup && substream->oss.setup->nosilence)) { @@ -470,7 +474,6 @@ snd_printd("SW_PARAMS failed: %i\n", err); goto failure; } - runtime->control->avail_min = runtime->period_size; runtime->oss.periods = params_periods(sparams); oss_period_size = snd_pcm_plug_client_size(substream, params_period_size(sparams)); @@ -555,6 +558,7 @@ runtime->oss.prepare = 0; runtime->oss.prev_hw_ptr_interrupt = 0; runtime->oss.period_ptr = 0; + runtime->oss.buffer_used = 0; return 0; } @@ -812,7 +816,7 @@ buf += tmp; bytes -= tmp; xfer += tmp; - if (substream->oss.setup == NULL || !substream->oss.setup->wholefrag || + if ((substream->oss.setup != NULL && substream->oss.setup->partialfrag) || runtime->oss.buffer_used == runtime->oss.period_bytes) { tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer, runtime->oss.buffer_used, 1); if (tmp <= 0) @@ -883,12 +887,13 @@ if (tmp <= 0) return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; runtime->oss.bytes += tmp; - runtime->oss.buffer_used = runtime->oss.period_bytes; + runtime->oss.period_ptr = tmp; + runtime->oss.buffer_used = tmp; } tmp = bytes; if ((size_t) tmp > runtime->oss.buffer_used) tmp = runtime->oss.buffer_used; - if (copy_to_user(buf, runtime->oss.buffer + (runtime->oss.period_bytes - runtime->oss.buffer_used), tmp)) + if (copy_to_user(buf, runtime->oss.buffer + (runtime->oss.period_ptr - runtime->oss.buffer_used), tmp)) return xfer > 0 ? (snd_pcm_sframes_t)xfer : -EFAULT; buf += tmp; bytes -= tmp; @@ -950,6 +955,9 @@ runtime = substream->runtime; init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); +#ifdef OSS_DEBUG + printk("sync1: size = %li\n", size); +#endif while (1) { result = snd_pcm_oss_write2(substream, runtime->oss.buffer, size, 1); if (result > 0) { @@ -991,16 +999,21 @@ snd_pcm_runtime_t *runtime; snd_pcm_format_t format; unsigned long width; - size_t size, size1; + size_t size; substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream != NULL) { + runtime = substream->runtime; + if (atomic_read(&runtime->mmap_count)) + goto __direct; if ((err = snd_pcm_oss_make_ready(substream)) < 0) return err; - runtime = substream->runtime; format = snd_pcm_oss_format_from(runtime->oss.format); width = snd_pcm_format_physical_width(format); if (runtime->oss.buffer_used > 0) { +#ifdef OSS_DEBUG + printk("sync: buffer_used\n"); +#endif size = (8 * (runtime->oss.period_bytes - runtime->oss.buffer_used) + 7) / width; snd_pcm_format_set_silence(format, runtime->oss.buffer + runtime->oss.buffer_used, @@ -1009,6 +1022,9 @@ if (err < 0) return err; } else if (runtime->oss.period_ptr > 0) { +#ifdef OSS_DEBUG + printk("sync: period_ptr\n"); +#endif size = runtime->oss.period_bytes - runtime->oss.period_ptr; snd_pcm_format_set_silence(format, runtime->oss.buffer, @@ -1017,17 +1033,35 @@ if (err < 0) return err; } - size = runtime->oss.period_bytes; - size1 = frames_to_bytes(runtime, runtime->period_size); - while (size < size1) { - snd_pcm_format_set_silence(format, - runtime->oss.buffer, - (8 * runtime->oss.period_bytes + 7) / width); - err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes); - if (err < 0) - return err; - size += runtime->oss.period_bytes; + /* + * The ALSA's period might be a bit large than OSS one. + * Fill the remain portion of ALSA period with zeros. + */ + size = runtime->control->appl_ptr % runtime->period_size; + if (size > 0) { + size = runtime->period_size - size; + if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { + size = (runtime->frame_bits * size) / 8; + while (size > 0) { + size_t size1 = size < runtime->oss.period_bytes ? size : runtime->oss.period_bytes; + size -= size1; + size1 *= 8; + size1 /= runtime->sample_bits; + snd_pcm_format_set_silence(runtime->format, + runtime->oss.buffer, + size1); + snd_pcm_lib_write(substream, runtime->oss.buffer, size1); + } + } else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) { + void *buffers[runtime->channels]; + memset(buffers, 0, runtime->channels * sizeof(void *)); + snd_pcm_lib_writev(substream, (void **)buffers, size); + } } + /* + * finish sync: drain the buffer + */ + __direct: saved_f_flags = substream->ffile->f_flags; substream->ffile->f_flags &= ~O_NONBLOCK; err = snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, 0); @@ -1306,11 +1340,11 @@ return result; } -static void snd_pcm_oss_simulate_fill(snd_pcm_substream_t *substream) +static void snd_pcm_oss_simulate_fill(snd_pcm_substream_t *substream, snd_pcm_uframes_t hw_ptr) { snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_uframes_t appl_ptr; - appl_ptr = runtime->hw_ptr_interrupt + runtime->buffer_size; + appl_ptr = hw_ptr + runtime->buffer_size; appl_ptr %= runtime->boundary; runtime->control->appl_ptr = appl_ptr; } @@ -1331,8 +1365,6 @@ if (psubstream) { if ((err = snd_pcm_oss_make_ready(psubstream)) < 0) return err; - if (atomic_read(&psubstream->runtime->mmap_count)) - snd_pcm_oss_simulate_fill(psubstream); } if (csubstream) { if ((err = snd_pcm_oss_make_ready(csubstream)) < 0) @@ -1343,6 +1375,8 @@ if (trigger & PCM_ENABLE_OUTPUT) { if (runtime->oss.trigger) goto _skip1; + if (atomic_read(&psubstream->runtime->mmap_count)) + snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt); runtime->oss.trigger = 1; runtime->start_threshold = 1; cmd = SNDRV_PCM_IOCTL_START; @@ -1425,6 +1459,7 @@ snd_pcm_substream_t *substream; snd_pcm_runtime_t *runtime; snd_pcm_sframes_t delay; + int fixup; struct count_info info; int err; @@ -1444,32 +1479,37 @@ } if (stream == SNDRV_PCM_STREAM_PLAYBACK) { err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay); - if (err == -EPIPE || err == -ESTRPIPE) { + if (err == -EPIPE || err == -ESTRPIPE || (! err && delay < 0)) { err = 0; delay = 0; + fixup = 0; + } else { + fixup = runtime->oss.buffer_used; } } else { err = snd_pcm_oss_capture_position_fixup(substream, &delay); + fixup = -runtime->oss.buffer_used; } if (err < 0) return err; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - info.bytes = runtime->oss.bytes - snd_pcm_oss_bytes(substream, delay); - } else { - info.bytes = runtime->oss.bytes + snd_pcm_oss_bytes(substream, delay); - } info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size); if (atomic_read(&runtime->mmap_count)) { snd_pcm_sframes_t n; - n = runtime->hw_ptr_interrupt - runtime->oss.prev_hw_ptr_interrupt; + n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt; if (n < 0) n += runtime->boundary; info.blocks = n / runtime->period_size; - runtime->oss.prev_hw_ptr_interrupt = runtime->hw_ptr_interrupt; + runtime->oss.prev_hw_ptr_interrupt = delay; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_pcm_oss_simulate_fill(substream); + snd_pcm_oss_simulate_fill(substream, delay); + info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr); } else { - info.blocks = delay / runtime->period_size; + delay = snd_pcm_oss_bytes(substream, delay) + fixup; + info.blocks = delay / runtime->oss.period_bytes; + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + info.bytes = runtime->oss.bytes - delay; + else + info.bytes = runtime->oss.bytes + delay; } if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; @@ -1481,6 +1521,7 @@ snd_pcm_substream_t *substream; snd_pcm_runtime_t *runtime; snd_pcm_sframes_t avail; + int fixup; struct audio_buf_info info; int err; @@ -1499,8 +1540,8 @@ info.fragstotal = runtime->periods; if (runtime->oss.prepare) { if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - info.bytes = runtime->oss.period_bytes * runtime->periods; - info.fragments = runtime->periods; + info.bytes = runtime->oss.period_bytes * runtime->oss.periods; + info.fragments = runtime->oss.periods; } else { info.bytes = 0; info.fragments = 0; @@ -1508,19 +1549,22 @@ } else { if (stream == SNDRV_PCM_STREAM_PLAYBACK) { err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &avail); - if (err == -EPIPE || err == -ESTRPIPE) { + if (err == -EPIPE || err == -ESTRPIPE || (! err && avail < 0)) { avail = runtime->buffer_size; err = 0; + fixup = 0; } else { avail = runtime->buffer_size - avail; + fixup = -runtime->oss.buffer_used; } } else { err = snd_pcm_oss_capture_position_fixup(substream, &avail); + fixup = runtime->oss.buffer_used; } if (err < 0) return err; - info.bytes = snd_pcm_oss_bytes(substream, avail); - info.fragments = avail / runtime->period_size; + info.bytes = snd_pcm_oss_bytes(substream, avail) + fixup; + info.fragments = info.bytes / runtime->oss.period_bytes; } #ifdef OSS_DEBUG @@ -1858,7 +1902,9 @@ pcm_oss_file = snd_magic_cast(snd_pcm_oss_file_t, file->private_data, return -ENXIO); if (cmd == OSS_GETVERSION) - return put_user(SNDRV_OSS_VERSION, (int *)arg) ? -EFAULT : 0; + return put_user(SNDRV_OSS_VERSION, (int *)arg); + if (cmd == OSS_ALSAEMULVER) + return put_user(1, (int *)arg); #if defined(CONFIG_SND_MIXER_OSS) || (defined(MODULE) && defined(CONFIG_SND_MIXER_OSS_MODULE)) if (((cmd >> 8) & 0xff) == 'M') { /* mixer ioctl - for OSS compatibility */ snd_pcm_substream_t *substream; @@ -1887,48 +1933,48 @@ return -EFAULT; if ((res = snd_pcm_oss_set_rate(pcm_oss_file, res))<0) return res; - return put_user(res, (int *)arg) ? -EFAULT : 0; + return put_user(res, (int *)arg); case SOUND_PCM_READ_RATE: res = snd_pcm_oss_get_rate(pcm_oss_file); if (res < 0) return res; - return put_user(res, (int *)arg) ? -EFAULT : 0; + return put_user(res, (int *)arg); case SNDCTL_DSP_STEREO: if (get_user(res, (int *)arg)) return -EFAULT; res = res > 0 ? 2 : 1; if ((res = snd_pcm_oss_set_channels(pcm_oss_file, res)) < 0) return res; - return put_user(--res, (int *)arg) ? -EFAULT : 0; + return put_user(--res, (int *)arg); case SNDCTL_DSP_GETBLKSIZE: res = snd_pcm_oss_get_block_size(pcm_oss_file); if (res < 0) return res; - return put_user(res, (int *)arg) ? -EFAULT : 0; + return put_user(res, (int *)arg); case SNDCTL_DSP_SETFMT: if (get_user(res, (int *)arg)) return -EFAULT; res = snd_pcm_oss_set_format(pcm_oss_file, res); if (res < 0) return res; - return put_user(res, (int *)arg) ? -EFAULT : 0; + return put_user(res, (int *)arg); case SOUND_PCM_READ_BITS: res = snd_pcm_oss_get_format(pcm_oss_file); if (res < 0) return res; - return put_user(res, (int *)arg) ? -EFAULT : 0; + return put_user(res, (int *)arg); case SNDCTL_DSP_CHANNELS: if (get_user(res, (int *)arg)) return -EFAULT; res = snd_pcm_oss_set_channels(pcm_oss_file, res); if (res < 0) return res; - return put_user(res, (int *)arg) ? -EFAULT : 0; + return put_user(res, (int *)arg); case SOUND_PCM_READ_CHANNELS: res = snd_pcm_oss_get_channels(pcm_oss_file); if (res < 0) return res; - return put_user(res, (int *)arg) ? -EFAULT : 0; + return put_user(res, (int *)arg); case SOUND_PCM_WRITE_FILTER: case SOUND_PCM_READ_FILTER: return -EIO; @@ -1940,7 +1986,7 @@ res = snd_pcm_oss_set_subdivide(pcm_oss_file, res); if (res < 0) return res; - return put_user(res, (int *)arg) ? -EFAULT : 0; + return put_user(res, (int *)arg); case SNDCTL_DSP_SETFRAGMENT: if (get_user(res, (int *)arg)) return -EFAULT; @@ -1949,7 +1995,7 @@ res = snd_pcm_oss_get_formats(pcm_oss_file); if (res < 0) return res; - return put_user(res, (int *)arg) ? -EFAULT : 0; + return put_user(res, (int *)arg); case SNDCTL_DSP_GETOSPACE: case SNDCTL_DSP_GETISPACE: return snd_pcm_oss_get_space(pcm_oss_file, @@ -1962,12 +2008,12 @@ res = snd_pcm_oss_get_caps(pcm_oss_file); if (res < 0) return res; - return put_user(res, (int *)arg) ? -EFAULT : 0; + return put_user(res, (int *)arg); case SNDCTL_DSP_GETTRIGGER: res = snd_pcm_oss_get_trigger(pcm_oss_file); if (res < 0) return res; - return put_user(res, (int *)arg) ? -EFAULT : 0; + return put_user(res, (int *)arg); case SNDCTL_DSP_SETTRIGGER: if (get_user(res, (int *)arg)) return -EFAULT; @@ -1998,7 +2044,7 @@ put_user(0, (int *)arg); return res; } - return put_user(res, (int *)arg) ? -EFAULT : 0; + return put_user(res, (int *)arg); case SNDCTL_DSP_PROFILE: return 0; /* silently ignore */ default: @@ -2160,6 +2206,8 @@ if (err < 0) return err; runtime->oss.mmap_bytes = area->vm_end - area->vm_start; + runtime->silence_threshold = 0; + runtime->silence_size = 0; #ifdef OSS_DEBUG printk("pcm_oss: mmap ok, bytes = 0x%x\n", runtime->oss.mmap_bytes); #endif @@ -2188,7 +2236,7 @@ setup->direct ? " direct" : "", setup->block ? " block" : "", setup->nonblock ? " non-block" : "", - setup->wholefrag ? " whole-frag" : "", + setup->partialfrag ? " partial-frag" : "", setup->nosilence ? " no-silence" : ""); setup = setup->next; } @@ -2255,8 +2303,8 @@ template.block = 1; } else if (!strcmp(str, "non-block")) { template.nonblock = 1; - } else if (!strcmp(str, "whole-frag")) { - template.wholefrag = 1; + } else if (!strcmp(str, "partial-frag")) { + template.partialfrag = 1; } else if (!strcmp(str, "no-silence")) { template.nosilence = 1; } diff -Nru a/sound/core/pcm.c b/sound/core/pcm.c --- a/sound/core/pcm.c Mon Feb 2 22:07:58 2004 +++ b/sound/core/pcm.c Mon Feb 2 22:07:58 2004 @@ -43,15 +43,6 @@ static int snd_pcm_dev_disconnect(snd_device_t *device); static int snd_pcm_dev_unregister(snd_device_t *device); -void snd_pcm_lock(int xup) -{ - if (!xup) { - down(®ister_mutex); - } else { - up(®ister_mutex); - } -} - static int snd_pcm_control_ioctl(snd_card_t * card, snd_ctl_file_t * control, unsigned int cmd, unsigned long arg) @@ -380,6 +371,7 @@ snd_iprintf(buffer, "closed\n"); return; } + memset(&status, 0, sizeof(status)); err = snd_pcm_status(substream, &status); if (err < 0) { snd_iprintf(buffer, "error %d\n", err); @@ -398,6 +390,22 @@ snd_iprintf(buffer, "appl_ptr : %ld\n", runtime->control->appl_ptr); } +#ifdef CONFIG_SND_DEBUG +static void snd_pcm_xrun_debug_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) +{ + snd_pcm_str_t *pstr = (snd_pcm_str_t *)entry->private_data; + snd_iprintf(buffer, "%d\n", pstr->xrun_debug); +} + +static void snd_pcm_xrun_debug_write(snd_info_entry_t *entry, snd_info_buffer_t *buffer) +{ + snd_pcm_str_t *pstr = (snd_pcm_str_t *)entry->private_data; + char line[64]; + if (!snd_info_get_line(buffer, line, sizeof(line))) + pstr->xrun_debug = !!simple_strtoul(line, NULL, 10); +} +#endif + static int snd_pcm_stream_proc_init(snd_pcm_str_t *pstr) { snd_pcm_t *pcm = pstr->pcm; @@ -416,11 +424,7 @@ pstr->proc_root = entry; if ((entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->mode = S_IFREG | S_IRUGO; - entry->c.text.read_size = 256; - entry->c.text.read = snd_pcm_stream_proc_info_read; - entry->private_data = pstr; + snd_info_set_text_ops(entry, pstr, 256, snd_pcm_stream_proc_info_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -428,11 +432,31 @@ } pstr->proc_info_entry = entry; +#ifdef CONFIG_SND_DEBUG + if ((entry = snd_info_create_card_entry(pcm->card, "xrun_debug", pstr->proc_root)) != NULL) { + entry->c.text.read_size = 64; + entry->c.text.read = snd_pcm_xrun_debug_read; + entry->c.text.write_size = 64; + entry->c.text.write = snd_pcm_xrun_debug_write; + entry->private_data = pstr; + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + entry = NULL; + } + } + pstr->proc_xrun_debug_entry = entry; +#endif return 0; } static int snd_pcm_stream_proc_done(snd_pcm_str_t *pstr) { +#ifdef CONFIG_SND_DEBUG + if (pstr->proc_xrun_debug_entry) { + snd_info_unregister(pstr->proc_xrun_debug_entry); + pstr->proc_xrun_debug_entry = NULL; + } +#endif if (pstr->proc_info_entry) { snd_info_unregister(pstr->proc_info_entry); pstr->proc_info_entry = NULL; @@ -463,11 +487,7 @@ substream->proc_root = entry; if ((entry = snd_info_create_card_entry(card, "info", substream->proc_root)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->mode = S_IFREG | S_IRUGO; - entry->c.text.read_size = 256; - entry->c.text.read = snd_pcm_substream_proc_info_read; - entry->private_data = substream; + snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_info_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -476,11 +496,7 @@ substream->proc_info_entry = entry; if ((entry = snd_info_create_card_entry(card, "hw_params", substream->proc_root)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->mode = S_IFREG | S_IRUGO; - entry->c.text.read_size = 256; - entry->c.text.read = snd_pcm_substream_proc_hw_params_read; - entry->private_data = substream; + snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_hw_params_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -489,11 +505,7 @@ substream->proc_hw_params_entry = entry; if ((entry = snd_info_create_card_entry(card, "sw_params", substream->proc_root)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->mode = S_IFREG | S_IRUGO; - entry->c.text.read_size = 256; - entry->c.text.read = snd_pcm_substream_proc_sw_params_read; - entry->private_data = substream; + snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_sw_params_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -502,11 +514,7 @@ substream->proc_sw_params_entry = entry; if ((entry = snd_info_create_card_entry(card, "status", substream->proc_root)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->mode = S_IFREG | S_IRUGO; - entry->c.text.read_size = 256; - entry->c.text.read = snd_pcm_substream_proc_status_read; - entry->private_data = substream; + snd_info_set_text_ops(entry, substream, 256, snd_pcm_substream_proc_status_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -521,23 +529,23 @@ { if (substream->proc_info_entry) { snd_info_unregister(substream->proc_info_entry); - substream->proc_info_entry = 0; + substream->proc_info_entry = NULL; } if (substream->proc_hw_params_entry) { snd_info_unregister(substream->proc_hw_params_entry); - substream->proc_hw_params_entry = 0; + substream->proc_hw_params_entry = NULL; } if (substream->proc_sw_params_entry) { snd_info_unregister(substream->proc_sw_params_entry); - substream->proc_sw_params_entry = 0; + substream->proc_sw_params_entry = NULL; } if (substream->proc_status_entry) { snd_info_unregister(substream->proc_status_entry); - substream->proc_status_entry = 0; + substream->proc_status_entry = NULL; } if (substream->proc_root) { snd_info_unregister(substream->proc_root); - substream->proc_root = 0; + substream->proc_root = NULL; } return 0; } @@ -819,7 +827,8 @@ runtime->private_free(runtime); snd_free_pages((void*)runtime->status, PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t))); snd_free_pages((void*)runtime->control, PAGE_ALIGN(sizeof(snd_pcm_mmap_control_t))); - kfree(runtime->hw_constraints.rules); + if (runtime->hw_constraints.rules) + kfree(runtime->hw_constraints.rules); kfree(runtime); substream->runtime = NULL; substream->pstr->substream_opened--; @@ -835,10 +844,10 @@ snd_pcm_t *pcm = snd_magic_cast(snd_pcm_t, device->device_data, return -ENXIO); snd_assert(pcm != NULL && device != NULL, return -ENXIO); - snd_pcm_lock(0); + down(®ister_mutex); idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device; if (snd_pcm_devices[idx]) { - snd_pcm_lock(1); + up(®ister_mutex); return -EBUSY; } snd_pcm_devices[idx] = pcm; @@ -860,7 +869,7 @@ } if ((err = snd_register_device(devtype, pcm->card, pcm->device, pcm->streams[cidx].reg, str)) < 0) { snd_pcm_devices[idx] = NULL; - snd_pcm_lock(1); + up(®ister_mutex); return err; } for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) @@ -871,7 +880,7 @@ notify = list_entry(list, snd_pcm_notify_t, list); notify->n_register(pcm); } - snd_pcm_lock(1); + up(®ister_mutex); return 0; } @@ -879,17 +888,22 @@ { snd_pcm_t *pcm = snd_magic_cast(snd_pcm_t, device->device_data, return -ENXIO); struct list_head *list; - int idx; + snd_pcm_substream_t *substream; + int idx, cidx; - snd_pcm_lock(0); + down(®ister_mutex); idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device; snd_pcm_devices[idx] = NULL; + for (cidx = 0; cidx < 2; cidx++) + for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) + if (substream->runtime) + substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED; list_for_each(list, &snd_pcm_notify_list) { snd_pcm_notify_t *notify; notify = list_entry(list, snd_pcm_notify_t, list); notify->n_disconnect(pcm); } - snd_pcm_lock(1); + up(®ister_mutex); return 0; } @@ -901,7 +915,7 @@ snd_pcm_t *pcm = snd_magic_cast(snd_pcm_t, device->device_data, return -ENXIO); snd_assert(pcm != NULL, return -ENXIO); - snd_pcm_lock(0); + down(®ister_mutex); idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device; snd_pcm_devices[idx] = NULL; for (cidx = 0; cidx < 2; cidx++) { @@ -923,7 +937,7 @@ notify = list_entry(list, snd_pcm_notify_t, list); notify->n_unregister(pcm); } - snd_pcm_lock(1); + up(®ister_mutex); return snd_pcm_free(pcm); } @@ -932,7 +946,7 @@ int idx; snd_assert(notify != NULL && notify->n_register != NULL && notify->n_unregister != NULL, return -EINVAL); - snd_pcm_lock(0); + down(®ister_mutex); if (nfree) { list_del(¬ify->list); for (idx = 0; idx < SNDRV_CARDS * SNDRV_PCM_DEVICES; idx++) { @@ -948,7 +962,7 @@ notify->n_register(snd_pcm_devices[idx]); } } - snd_pcm_lock(1); + up(®ister_mutex); return 0; } @@ -989,9 +1003,7 @@ snd_ctl_register_ioctl(snd_pcm_control_ioctl); if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; - entry->c.text.read_size = SNDRV_CARDS * SNDRV_PCM_DEVICES * 128; - entry->c.text.read = snd_pcm_proc_read; + snd_info_set_text_ops(entry, NULL, SNDRV_CARDS * SNDRV_PCM_DEVICES * 128, snd_pcm_proc_read); if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); entry = NULL; @@ -1013,7 +1025,6 @@ module_init(alsa_pcm_init) module_exit(alsa_pcm_exit) -EXPORT_SYMBOL(snd_pcm_lock); EXPORT_SYMBOL(snd_pcm_devices); EXPORT_SYMBOL(snd_pcm_new); EXPORT_SYMBOL(snd_pcm_new_stream); diff -Nru a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c --- a/sound/core/pcm_lib.c Mon Feb 2 22:07:56 2004 +++ b/sound/core/pcm_lib.c Mon Feb 2 22:07:56 2004 @@ -125,15 +125,11 @@ } } -static inline int snd_pcm_update_hw_ptr_interrupt(snd_pcm_substream_t *substream) +static inline snd_pcm_uframes_t snd_pcm_update_hw_ptr_pos(snd_pcm_substream_t *substream, + snd_pcm_runtime_t *runtime) { - snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_uframes_t pos; - snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_ptr_interrupt; - snd_pcm_uframes_t avail; - snd_pcm_sframes_t delta; - old_hw_ptr = runtime->status->hw_ptr; pos = substream->ops->pointer(substream); if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP) snd_timestamp_now((snd_timestamp_t*)&runtime->status->tstamp, runtime->tstamp_timespec); @@ -143,18 +139,64 @@ } else #endif snd_runtime_check(pos < runtime->buffer_size, return 0); - pos -= pos % runtime->min_align; - new_hw_ptr = runtime->hw_ptr_base + pos; + return pos; +} + +static inline int snd_pcm_update_hw_ptr_post(snd_pcm_substream_t *substream, + snd_pcm_runtime_t *runtime) +{ + snd_pcm_uframes_t avail; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + avail = snd_pcm_playback_avail(runtime); + else + avail = snd_pcm_capture_avail(runtime); + if (avail > runtime->avail_max) + runtime->avail_max = avail; + if (avail >= runtime->stop_threshold) { + snd_pcm_stop(substream, + runtime->status->state == SNDRV_PCM_STATE_DRAINING ? + SNDRV_PCM_STATE_SETUP : SNDRV_PCM_STATE_XRUN); +#ifdef CONFIG_SND_DEBUG + if (substream->pstr->xrun_debug) { + snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n", + substream->pcm->card->number, + substream->pcm->device, + substream->stream ? 'c' : 'p'); + dump_stack(); + } +#endif + return -EPIPE; + } + if (avail >= runtime->control->avail_min) + wake_up(&runtime->sleep); + return 0; +} +static inline int snd_pcm_update_hw_ptr_interrupt(snd_pcm_substream_t *substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + snd_pcm_uframes_t pos; + snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt; + snd_pcm_sframes_t delta; + + pos = snd_pcm_update_hw_ptr_pos(substream, runtime); + if (runtime->period_size == runtime->buffer_size) + goto __next_buf; + new_hw_ptr = runtime->hw_ptr_base + pos; hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size; delta = hw_ptr_interrupt - new_hw_ptr; if (delta > 0) { if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) { - snd_printd("Unexpected hw_pointer value (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2); +#ifdef CONFIG_SND_DEBUG + if (runtime->periods > 1) + snd_printd(KERN_ERR "Unexpected hw_pointer value [1] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2); +#endif return 0; } + __next_buf: runtime->hw_ptr_base += runtime->buffer_size; if (runtime->hw_ptr_base == runtime->boundary) runtime->hw_ptr_base = 0; @@ -168,21 +210,7 @@ runtime->status->hw_ptr = new_hw_ptr; runtime->hw_ptr_interrupt = new_hw_ptr - new_hw_ptr % runtime->period_size; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - avail = snd_pcm_playback_avail(runtime); - else - avail = snd_pcm_capture_avail(runtime); - if (avail > runtime->avail_max) - runtime->avail_max = avail; - if (avail >= runtime->stop_threshold) { - snd_pcm_stop(substream, - runtime->status->state == SNDRV_PCM_STATE_DRAINING ? - SNDRV_PCM_STATE_SETUP : SNDRV_PCM_STATE_XRUN); - return -EPIPE; - } - if (avail >= runtime->control->avail_min) - wake_up(&runtime->sleep); - return 0; + return snd_pcm_update_hw_ptr_post(substream, runtime); } /* CAUTION: call it with irq disabled */ @@ -191,27 +219,19 @@ snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_uframes_t pos; snd_pcm_uframes_t old_hw_ptr, new_hw_ptr; - snd_pcm_uframes_t avail; snd_pcm_sframes_t delta; old_hw_ptr = runtime->status->hw_ptr; - pos = substream->ops->pointer(substream); - if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP) - snd_timestamp_now((snd_timestamp_t*)&runtime->status->tstamp, runtime->tstamp_timespec); -#ifdef CONFIG_SND_DEBUG - if (pos >= runtime->buffer_size) { - snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size); - } else -#endif - snd_runtime_check(pos < runtime->buffer_size, return 0); - - pos -= pos % runtime->min_align; + pos = snd_pcm_update_hw_ptr_pos(substream, runtime); new_hw_ptr = runtime->hw_ptr_base + pos; delta = old_hw_ptr - new_hw_ptr; if (delta > 0) { if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) { - snd_printd("Unexpected hw_pointer value (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2); +#ifdef CONFIG_SND_DEBUG + if (runtime->periods > 2) + snd_printd(KERN_ERR "Unexpected hw_pointer value [2] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2); +#endif return 0; } runtime->hw_ptr_base += runtime->buffer_size; @@ -222,23 +242,10 @@ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && runtime->silence_size > 0) snd_pcm_playback_silence(substream, new_hw_ptr); + runtime->status->hw_ptr = new_hw_ptr; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - avail = snd_pcm_playback_avail(runtime); - else - avail = snd_pcm_capture_avail(runtime); - if (avail > runtime->avail_max) - runtime->avail_max = avail; - if (avail >= runtime->stop_threshold) { - snd_pcm_stop(substream, - runtime->status->state == SNDRV_PCM_STATE_DRAINING ? - SNDRV_PCM_STATE_SETUP : SNDRV_PCM_STATE_XRUN); - return -EPIPE; - } - if (avail >= runtime->control->avail_min) - wake_up(&runtime->sleep); - return 0; + return snd_pcm_update_hw_ptr_post(substream, runtime); } /** diff -Nru a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c --- a/sound/core/pcm_memory.c Mon Feb 2 22:07:57 2004 +++ b/sound/core/pcm_memory.c Mon Feb 2 22:07:57 2004 @@ -59,14 +59,18 @@ if (dmab->bytes >= size) return 0; /* yes */ /* no, reset the reserved block */ + /* if we can find bigger pages below, this block will be + * automatically removed in snd_dma_set_reserved(). + */ snd_dma_free_reserved(&substream->dma_device); dmab->bytes = 0; } do { - if ((err = snd_dma_alloc_pages(&substream->dma_device, size, dmab)) < 0) - return err; - if (dmab->area) { + if ((err = snd_dma_alloc_pages(&substream->dma_device, size, dmab)) < 0) { + if (err != -ENOMEM) + return err; /* fatal error */ + } else { /* remember this one */ snd_dma_set_reserved(&substream->dma_device, dmab); return 0; @@ -167,12 +171,12 @@ memset(&new_dmab, 0, sizeof(new_dmab)); if (size > 0) { - if (snd_dma_alloc_pages(&substream->dma_device, size, &new_dmab) < 0 || - new_dmab.area == NULL) { + if (snd_dma_alloc_pages(&substream->dma_device, size, &new_dmab) < 0) { buffer->error = -ENOMEM; return; } substream->buffer_bytes_max = size; + snd_dma_free_reserved(&substream->dma_device); } else { substream->buffer_bytes_max = UINT_MAX; } @@ -219,8 +223,9 @@ */ static inline void setup_pcm_id(snd_pcm_substream_t *subs) { - subs->dma_device.id = subs->pcm->device << 16 | - subs->stream << 8 | subs->number; + if (! subs->dma_device.id) + subs->dma_device.id = subs->pcm->device << 16 | + subs->stream << 8 | (subs->number + 1); } /** @@ -346,13 +351,12 @@ snd_pcm_lib_free_pages(substream); } if (substream->dma_buffer.area != NULL && substream->dma_buffer.bytes >= size) { - dmab = substream->dma_buffer; + dmab = substream->dma_buffer; /* use the pre-allocated buffer */ } else { - memset(&dmab, 0, sizeof(dmab)); - snd_dma_alloc_pages(&substream->dma_device, size, &dmab); + memset(&dmab, 0, sizeof(dmab)); /* allocate a new buffer */ + if (snd_dma_alloc_pages(&substream->dma_device, size, &dmab) < 0) + return -ENOMEM; } - if (! dmab.area) - return -ENOMEM; runtime->dma_area = dmab.area; runtime->dma_addr = dmab.addr; runtime->dma_private = dmab.private_data; @@ -378,6 +382,7 @@ if (runtime->dma_area == NULL) return 0; if (runtime->dma_area != substream->dma_buffer.area) { + /* it's a newly allocated buffer. release it now. */ struct snd_dma_buffer dmab; memset(&dmab, 0, sizeof(dmab)); dmab.area = runtime->dma_area; diff -Nru a/sound/core/pcm_native.c b/sound/core/pcm_native.c --- a/sound/core/pcm_native.c Mon Feb 2 22:07:56 2004 +++ b/sound/core/pcm_native.c Mon Feb 2 22:07:56 2004 @@ -620,7 +620,7 @@ */ static int snd_pcm_action_group(struct action_ops *ops, snd_pcm_substream_t *substream, - int state) + int state, int atomic_only) { struct list_head *pos; snd_pcm_substream_t *s = NULL; @@ -628,6 +628,8 @@ snd_pcm_group_for_each(pos, substream) { s = snd_pcm_group_substream_entry(pos); + if (atomic_only && (s->pcm->info_flags & SNDRV_PCM_INFO_NONATOMIC_OPS)) + continue; if (s != substream) spin_lock(&s->self_group.lock); res = ops->pre_action(s, state); @@ -637,6 +639,8 @@ if (res >= 0) { snd_pcm_group_for_each(pos, substream) { s = snd_pcm_group_substream_entry(pos); + if (atomic_only && (s->pcm->info_flags & SNDRV_PCM_INFO_NONATOMIC_OPS)) + continue; err = ops->do_action(s, state); if (err < 0) { if (res == 0) @@ -652,7 +656,9 @@ /* unlock all streams */ snd_pcm_group_for_each(pos, substream) { s1 = snd_pcm_group_substream_entry(pos); - if (s1 != substream) + if (atomic_only && (s1->pcm->info_flags & SNDRV_PCM_INFO_NONATOMIC_OPS)) + ; + else if (s1 != substream) spin_unlock(&s1->self_group.lock); if (s1 == s) /* end */ break; @@ -682,6 +688,8 @@ /* * Note: call with stream lock + * + * NB2: this won't handle the non-atomic callbacks */ static int snd_pcm_action(struct action_ops *ops, snd_pcm_substream_t *substream, @@ -695,7 +703,7 @@ spin_lock(&substream->group->lock); spin_lock(&substream->self_group.lock); } - res = snd_pcm_action_group(ops, substream, state); + res = snd_pcm_action_group(ops, substream, state, 0); spin_unlock(&substream->group->lock); } else { res = snd_pcm_action_single(ops, substream, state); @@ -705,10 +713,14 @@ /* * Note: don't use any locks before + * + * NB2: this can handle the non-atomic callbacks if allow_nonatomic = 1 + * when the pcm->info_flags has NONATOMIC_OPS bit, it's handled + * ouside the lock to allow sleep in the callback. */ static int snd_pcm_action_lock_irq(struct action_ops *ops, snd_pcm_substream_t *substream, - int state) + int state, int allow_nonatomic) { int res; @@ -716,10 +728,43 @@ if (snd_pcm_stream_linked(substream)) { spin_lock(&substream->group->lock); spin_lock(&substream->self_group.lock); - res = snd_pcm_action_group(ops, substream, state); + res = snd_pcm_action_group(ops, substream, state, allow_nonatomic); spin_unlock(&substream->self_group.lock); spin_unlock(&substream->group->lock); + if (res >= 0 && allow_nonatomic) { + /* now process the non-atomic substreams separately + * outside the lock + */ +#define MAX_LINKED_STREAMS 16 /* FIXME: should be variable */ + + struct list_head *pos; + int i, num_s = 0; + snd_pcm_substream_t *s; + snd_pcm_substream_t *subs[MAX_LINKED_STREAMS]; + snd_pcm_group_for_each(pos, substream) { + if (num_s >= MAX_LINKED_STREAMS) { + res = -ENOMEM; + num_s = 0; /* don't proceed */ + break; + } + s = snd_pcm_group_substream_entry(pos); + if (s->pcm->info_flags & SNDRV_PCM_INFO_NONATOMIC_OPS) + subs[num_s++] = s; + } + if (num_s > 0) { + read_unlock_irq(&snd_pcm_link_rwlock); + for (i = 0; i < num_s && res >= 0; i++) + res = snd_pcm_action_single(ops, subs[i], state); + return res; + } + } } else { + if (allow_nonatomic && + (substream->pcm->info_flags & SNDRV_PCM_INFO_NONATOMIC_OPS)) { + read_unlock_irq(&snd_pcm_link_rwlock); + /* process outside the lock */ + return snd_pcm_action_single(ops, substream, state); + } spin_lock(&substream->self_group.lock); res = snd_pcm_action_single(ops, substream, state); spin_unlock(&substream->self_group.lock); @@ -888,7 +933,8 @@ snd_pcm_runtime_t *runtime = substream->runtime; if (runtime->trigger_master != substream) return 0; - if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING) + if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING && + runtime->status->suspended_state != SNDRV_PCM_STATE_DRAINING) return 0; return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND); } @@ -962,7 +1008,8 @@ snd_pcm_runtime_t *runtime = substream->runtime; if (runtime->trigger_master != substream) return 0; - if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING) + if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING && + runtime->status->suspended_state != SNDRV_PCM_STATE_DRAINING) return 0; return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_RESUME); } @@ -991,7 +1038,7 @@ snd_power_lock(card); if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0) - return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0); + return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0, 0); snd_power_unlock(card); return res; } @@ -1081,7 +1128,7 @@ static int snd_pcm_reset(snd_pcm_substream_t *substream) { - return snd_pcm_action_lock_irq(&snd_pcm_action_reset, substream, 0); + return snd_pcm_action_lock_irq(&snd_pcm_action_reset, substream, 0, 0); } static int snd_pcm_pre_prepare(snd_pcm_substream_t * substream, int state) @@ -1129,7 +1176,7 @@ snd_power_lock(card); if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0) - res = snd_pcm_action_lock_irq(&snd_pcm_action_prepare, substream, 0); + res = snd_pcm_action_lock_irq(&snd_pcm_action_prepare, substream, 0, 1); /* allow sleep if specified */ snd_power_unlock(card); return res; } @@ -1243,7 +1290,9 @@ } set_current_state(TASK_INTERRUPTIBLE); snd_pcm_stream_unlock_irq(substream); + snd_power_unlock(card); tout = schedule_timeout(10 * HZ); + snd_power_lock(card); snd_pcm_stream_lock_irq(substream); if (tout == 0) { state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED; @@ -1497,7 +1546,7 @@ write_lock_irq(&snd_pcm_link_rwlock); if (!snd_pcm_stream_linked(substream)) { - res = -EINVAL; + res = -EALREADY; goto _end; } list_del(&substream->link_list); @@ -2326,7 +2375,7 @@ case SNDRV_PCM_IOCTL_RESET: return snd_pcm_reset(substream); case SNDRV_PCM_IOCTL_START: - return snd_pcm_action(&snd_pcm_action_start, substream, 0); + return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, 0, 0); case SNDRV_PCM_IOCTL_LINK: return snd_pcm_link(substream, (long) arg); case SNDRV_PCM_IOCTL_UNLINK: diff -Nru a/sound/core/rawmidi.c b/sound/core/rawmidi.c --- a/sound/core/rawmidi.c Mon Feb 2 22:07:55 2004 +++ b/sound/core/rawmidi.c Mon Feb 2 22:07:55 2004 @@ -1507,7 +1507,6 @@ sprintf(name, "midi%d", rmidi->device); entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root); if (entry) { - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = rmidi; entry->c.text.read_size = 1024; entry->c.text.read = snd_rawmidi_proc_info_read; diff -Nru a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c --- a/sound/core/seq/oss/seq_oss.c Mon Feb 2 22:07:58 2004 +++ b/sound/core/seq/oss/seq_oss.c Mon Feb 2 22:07:58 2004 @@ -35,6 +35,9 @@ MODULE_DESCRIPTION("OSS-compatible sequencer module"); MODULE_LICENSE("GPL"); MODULE_CLASSES("{sound}"); +/* Takashi says this is really only for sound-service-0-, but this is OK. */ +MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_SEQUENCER); +MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MUSIC); #ifdef SNDRV_SEQ_OSS_DEBUG MODULE_PARM(seq_oss_debug, "i"); diff -Nru a/sound/core/seq/seq.c b/sound/core/seq/seq.c --- a/sound/core/seq/seq.c Mon Feb 2 22:07:57 2004 +++ b/sound/core/seq/seq.c Mon Feb 2 22:07:57 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer main module - * Copyright (c) 1998-1999 by Frank van de Pol + * Copyright (c) 1998-1999 by Frank van de Pol * * * This program is free software; you can redistribute it and/or modify @@ -42,7 +42,7 @@ int seq_default_timer_subdevice = 0; int seq_default_timer_resolution = 0; /* Hz */ -MODULE_AUTHOR("Frank van de Pol , Jaroslav Kysela "); +MODULE_AUTHOR("Frank van de Pol , Jaroslav Kysela "); MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer."); MODULE_LICENSE("GPL"); MODULE_CLASSES("{sound}"); diff -Nru a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c --- a/sound/core/seq/seq_clientmgr.c Mon Feb 2 22:07:55 2004 +++ b/sound/core/seq/seq_clientmgr.c Mon Feb 2 22:07:55 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer Client Manager - * Copyright (c) 1998-2001 by Frank van de Pol + * Copyright (c) 1998-2001 by Frank van de Pol * Jaroslav Kysela * Takashi Iwai * @@ -137,7 +137,7 @@ if (clientid < 64) { int idx; - if (! client_requested[clientid]) { + if (! client_requested[clientid] && current->fs->root) { client_requested[clientid] = 1; for (idx = 0; idx < 64; idx++) { if (seq_client_load[idx] < 0) diff -Nru a/sound/core/seq/seq_clientmgr.h b/sound/core/seq/seq_clientmgr.h --- a/sound/core/seq/seq_clientmgr.h Mon Feb 2 22:07:58 2004 +++ b/sound/core/seq/seq_clientmgr.h Mon Feb 2 22:07:58 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer Client Manager - * Copyright (c) 1998-1999 by Frank van de Pol + * Copyright (c) 1998-1999 by Frank van de Pol * * * This program is free software; you can redistribute it and/or modify diff -Nru a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c --- a/sound/core/seq/seq_device.c Mon Feb 2 22:07:56 2004 +++ b/sound/core/seq/seq_device.c Mon Feb 2 22:07:56 2004 @@ -132,6 +132,9 @@ #ifdef CONFIG_KMOD struct list_head *head; + if (! current->fs->root) + return; + down(&ops_mutex); list_for_each(head, &opslist) { ops_list_t *ops = list_entry(head, ops_list_t, list); diff -Nru a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c --- a/sound/core/seq/seq_dummy.c Mon Feb 2 22:07:56 2004 +++ b/sound/core/seq/seq_dummy.c Mon Feb 2 22:07:56 2004 @@ -45,7 +45,7 @@ snd-seq-client-62 as "off". This will help modprobe. The number of ports to be created can be specified via the module - paramter "ports". For example, to create four ports, add the + parameter "ports". For example, to create four ports, add the following option in /etc/modules.conf: option snd-seq-dummy ports=4 diff -Nru a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c --- a/sound/core/seq/seq_fifo.c Mon Feb 2 22:07:56 2004 +++ b/sound/core/seq/seq_fifo.c Mon Feb 2 22:07:56 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer FIFO - * Copyright (c) 1998 by Frank van de Pol + * Copyright (c) 1998 by Frank van de Pol * * * This program is free software; you can redistribute it and/or modify diff -Nru a/sound/core/seq/seq_fifo.h b/sound/core/seq/seq_fifo.h --- a/sound/core/seq/seq_fifo.h Mon Feb 2 22:07:56 2004 +++ b/sound/core/seq/seq_fifo.h Mon Feb 2 22:07:56 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer FIFO - * Copyright (c) 1998 by Frank van de Pol + * Copyright (c) 1998 by Frank van de Pol * * * This program is free software; you can redistribute it and/or modify diff -Nru a/sound/core/seq/seq_info.c b/sound/core/seq/seq_info.c --- a/sound/core/seq/seq_info.c Mon Feb 2 22:07:56 2004 +++ b/sound/core/seq/seq_info.c Mon Feb 2 22:07:56 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer /proc interface - * Copyright (c) 1998 by Frank van de Pol + * Copyright (c) 1998 by Frank van de Pol * * * This program is free software; you can redistribute it and/or modify diff -Nru a/sound/core/seq/seq_info.h b/sound/core/seq/seq_info.h --- a/sound/core/seq/seq_info.h Mon Feb 2 22:07:57 2004 +++ b/sound/core/seq/seq_info.h Mon Feb 2 22:07:57 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer /proc info - * Copyright (c) 1998 by Frank van de Pol + * Copyright (c) 1998 by Frank van de Pol * * * This program is free software; you can redistribute it and/or modify diff -Nru a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c --- a/sound/core/seq/seq_memory.c Mon Feb 2 22:07:55 2004 +++ b/sound/core/seq/seq_memory.c Mon Feb 2 22:07:55 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer Memory Manager - * Copyright (c) 1998 by Frank van de Pol + * Copyright (c) 1998 by Frank van de Pol * Jaroslav Kysela * 2000 by Takashi Iwai * diff -Nru a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h --- a/sound/core/seq/seq_memory.h Mon Feb 2 22:07:57 2004 +++ b/sound/core/seq/seq_memory.h Mon Feb 2 22:07:57 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer Memory Manager - * Copyright (c) 1998 by Frank van de Pol + * Copyright (c) 1998 by Frank van de Pol * * * This program is free software; you can redistribute it and/or modify diff -Nru a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c --- a/sound/core/seq/seq_midi.c Mon Feb 2 22:07:58 2004 +++ b/sound/core/seq/seq_midi.c Mon Feb 2 22:07:58 2004 @@ -1,6 +1,6 @@ /* * Generic MIDI synth driver for ALSA sequencer - * Copyright (c) 1998 by Frank van de Pol + * Copyright (c) 1998 by Frank van de Pol * Jaroslav Kysela * * This program is free software; you can redistribute it and/or modify @@ -39,7 +39,7 @@ #include #include -MODULE_AUTHOR("Frank van de Pol , Jaroslav Kysela "); +MODULE_AUTHOR("Frank van de Pol , Jaroslav Kysela "); MODULE_DESCRIPTION("Advanced Linux Sound Architecture sequencer MIDI synth."); MODULE_LICENSE("GPL"); MODULE_CLASSES("{sound}"); diff -Nru a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c --- a/sound/core/seq/seq_ports.c Mon Feb 2 22:07:57 2004 +++ b/sound/core/seq/seq_ports.c Mon Feb 2 22:07:57 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer Ports - * Copyright (c) 1998 by Frank van de Pol + * Copyright (c) 1998 by Frank van de Pol * Jaroslav Kysela * * diff -Nru a/sound/core/seq/seq_ports.h b/sound/core/seq/seq_ports.h --- a/sound/core/seq/seq_ports.h Mon Feb 2 22:07:57 2004 +++ b/sound/core/seq/seq_ports.h Mon Feb 2 22:07:57 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer Ports - * Copyright (c) 1998 by Frank van de Pol + * Copyright (c) 1998 by Frank van de Pol * * * This program is free software; you can redistribute it and/or modify diff -Nru a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c --- a/sound/core/seq/seq_prioq.c Mon Feb 2 22:07:55 2004 +++ b/sound/core/seq/seq_prioq.c Mon Feb 2 22:07:55 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer Priority Queue - * Copyright (c) 1998-1999 by Frank van de Pol + * Copyright (c) 1998-1999 by Frank van de Pol * * * This program is free software; you can redistribute it and/or modify diff -Nru a/sound/core/seq/seq_prioq.h b/sound/core/seq/seq_prioq.h --- a/sound/core/seq/seq_prioq.h Mon Feb 2 22:07:58 2004 +++ b/sound/core/seq/seq_prioq.h Mon Feb 2 22:07:58 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer Priority Queue - * Copyright (c) 1998 by Frank van de Pol + * Copyright (c) 1998 by Frank van de Pol * * * This program is free software; you can redistribute it and/or modify diff -Nru a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c --- a/sound/core/seq/seq_queue.c Mon Feb 2 22:07:58 2004 +++ b/sound/core/seq/seq_queue.c Mon Feb 2 22:07:58 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer Timing queue handling - * Copyright (c) 1998-1999 by Frank van de Pol + * Copyright (c) 1998-1999 by Frank van de Pol * * 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 diff -Nru a/sound/core/seq/seq_queue.h b/sound/core/seq/seq_queue.h --- a/sound/core/seq/seq_queue.h Mon Feb 2 22:07:56 2004 +++ b/sound/core/seq/seq_queue.h Mon Feb 2 22:07:56 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer Queue handling - * Copyright (c) 1998-1999 by Frank van de Pol + * Copyright (c) 1998-1999 by Frank van de Pol * * 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 diff -Nru a/sound/core/seq/seq_system.c b/sound/core/seq/seq_system.c --- a/sound/core/seq/seq_system.c Mon Feb 2 22:07:57 2004 +++ b/sound/core/seq/seq_system.c Mon Feb 2 22:07:57 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer System services Client - * Copyright (c) 1998-1999 by Frank van de Pol + * Copyright (c) 1998-1999 by Frank van de Pol * * * This program is free software; you can redistribute it and/or modify diff -Nru a/sound/core/seq/seq_system.h b/sound/core/seq/seq_system.h --- a/sound/core/seq/seq_system.h Mon Feb 2 22:07:57 2004 +++ b/sound/core/seq/seq_system.h Mon Feb 2 22:07:57 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer System Client - * Copyright (c) 1998 by Frank van de Pol + * Copyright (c) 1998 by Frank van de Pol * * * This program is free software; you can redistribute it and/or modify diff -Nru a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c --- a/sound/core/seq/seq_timer.c Mon Feb 2 22:07:58 2004 +++ b/sound/core/seq/seq_timer.c Mon Feb 2 22:07:58 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer Timer - * Copyright (c) 1998-1999 by Frank van de Pol + * Copyright (c) 1998-1999 by Frank van de Pol * Jaroslav Kysela * * @@ -335,7 +335,7 @@ if (! r && t->hw.c_resolution) r = t->hw.c_resolution(t); if (r) { - tmr->ticks = (unsigned int)(tmr->preferred_resolution / r); + tmr->ticks = (unsigned int)(1000000000uL / (r * tmr->preferred_resolution)); if (! tmr->ticks) tmr->ticks = 1; } diff -Nru a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h --- a/sound/core/seq/seq_timer.h Mon Feb 2 22:07:57 2004 +++ b/sound/core/seq/seq_timer.h Mon Feb 2 22:07:57 2004 @@ -1,6 +1,6 @@ /* * ALSA sequencer Timer - * Copyright (c) 1998-1999 by Frank van de Pol + * Copyright (c) 1998-1999 by Frank van de Pol * * * This program is free software; you can redistribute it and/or modify @@ -47,7 +47,7 @@ snd_timer_id_t alsa_id; /* ALSA's timer ID */ snd_timer_instance_t *timeri; /* timer instance */ unsigned int ticks; - unsigned long preferred_resolution; /* timer resolution */ + unsigned long preferred_resolution; /* timer resolution, ticks/sec */ unsigned int skew; unsigned int skew_base; diff -Nru a/sound/core/sound.c b/sound/core/sound.c --- a/sound/core/sound.c Mon Feb 2 22:07:57 2004 +++ b/sound/core/sound.c Mon Feb 2 22:07:57 2004 @@ -37,7 +37,7 @@ static int major = CONFIG_SND_MAJOR; int snd_major; -static int cards_limit = SNDRV_CARDS; +static int cards_limit = 1; static int device_mode = S_IFCHR | S_IRUGO | S_IWUGO; MODULE_AUTHOR("Jaroslav Kysela "); @@ -49,7 +49,7 @@ MODULE_PARM_DESC(major, "Major # for sound driver."); MODULE_PARM_SYNTAX(major, "default:116,skill:devel"); MODULE_PARM(cards_limit, "i"); -MODULE_PARM_DESC(cards_limit, "Count of soundcards installed in the system."); +MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards."); MODULE_PARM_SYNTAX(cards_limit, "default:8,skill:advanced"); MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR); #ifdef CONFIG_DEVFS_FS @@ -57,7 +57,12 @@ MODULE_PARM_DESC(device_mode, "Device file permission mask for devfs."); MODULE_PARM_SYNTAX(device_mode, "default:0666,base:8"); #endif +MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR); +/* this one holds the actual max. card number currently available. + * as default, it's identical with cards_limit option. when more + * modules are loaded manually, this limit number increases, too. + */ int snd_ecards_limit; static struct list_head snd_minors_hash[SNDRV_CARDS]; @@ -78,6 +83,8 @@ { int locked; + if (! current->fs->root) + return; read_lock(&snd_card_rwlock); locked = snd_cards_lock & (1 << card); read_unlock(&snd_card_rwlock); @@ -92,6 +99,8 @@ { char *str; + if (! current->fs->root) + return; switch (minor) { case SNDRV_MINOR_SEQUENCER: str = "snd-seq"; break; case SNDRV_MINOR_TIMER: str = "snd-timer"; break; @@ -221,8 +230,7 @@ return -EBUSY; } list_add_tail(&preg->list, &snd_minors_hash[SNDRV_MINOR_CARD(minor)]); - - if (strncmp(name, "controlC", 8)) { /* created in sound.c */ + if (strncmp(name, "controlC", 8) || card->number >= cards_limit) { devfs_mk_cdev(MKDEV(major, minor), S_IFCHR | device_mode, "snd/%s", name); if (card) device = card->dev; @@ -257,7 +265,7 @@ return -EINVAL; } - if (strncmp(mptr->name, "controlC", 8)) { /* created in sound.c */ + if (strncmp(mptr->name, "controlC", 8) || card->number >= cards_limit) { /* created in sound.c */ devfs_remove("snd/%s", mptr->name); class_simple_device_remove(MKDEV(major, minor)); } @@ -303,7 +311,6 @@ entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL); if (entry) { - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = PAGE_SIZE; entry->c.text.read = snd_minor_info_read; if (snd_info_register(entry) < 0) { diff -Nru a/sound/core/sound_oss.c b/sound/core/sound_oss.c --- a/sound/core/sound_oss.c Mon Feb 2 22:07:58 2004 +++ b/sound/core/sound_oss.c Mon Feb 2 22:07:58 2004 @@ -217,7 +217,6 @@ entry = snd_info_create_module_entry(THIS_MODULE, "devices", snd_oss_root); if (entry) { - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = PAGE_SIZE; entry->c.text.read = snd_minor_info_oss_read; if (snd_info_register(entry) < 0) { diff -Nru a/sound/core/timer.c b/sound/core/timer.c --- a/sound/core/timer.c Mon Feb 2 22:07:57 2004 +++ b/sound/core/timer.c Mon Feb 2 22:07:57 2004 @@ -148,6 +148,8 @@ static void snd_timer_request(snd_timer_id_t *tid) { + if (! current->fs->root) + return; switch (tid->dev_class) { case SNDRV_TIMER_CLASS_GLOBAL: if (tid->device < timer_limit) @@ -304,14 +306,31 @@ snd_assert(timeri != NULL, return -ENXIO); - snd_timer_stop(timeri); /* force to stop the timer */ + /* force to stop the timer */ + snd_timer_stop(timeri); if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { + /* wait, until the active callback is finished */ + spin_lock_irq(&slave_active_lock); + while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { + spin_unlock_irq(&slave_active_lock); + udelay(10); + spin_lock_irq(&slave_active_lock); + } + spin_unlock_irq(&slave_active_lock); down(®ister_mutex); list_del(&timeri->open_list); up(®ister_mutex); } else { timer = timeri->timer; + /* wait, until the active callback is finished */ + spin_lock_irq(&timer->lock); + while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { + spin_unlock_irq(&timer->lock); + udelay(10); + spin_lock_irq(&timer->lock); + } + spin_unlock_irq(&timer->lock); down(®ister_mutex); list_del(&timeri->open_list); if (timer && list_empty(&timer->open_list_head) && timer->hw.close) @@ -389,12 +408,15 @@ list_del(&timeri->active_list); list_add_tail(&timeri->active_list, &timer->active_list_head); if (timer->running) { + if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) + goto __start_now; timer->flags |= SNDRV_TIMER_FLG_RESCHED; timeri->flags |= SNDRV_TIMER_IFLG_START; return 1; /* delayed start */ } else { timer->sticks = sticks; timer->hw.start(timer); + __start_now: timer->running++; timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; return 0; @@ -448,22 +470,21 @@ snd_assert(timeri != NULL, return -ENXIO); + if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { + if (!keep_flag) { + spin_lock_irqsave(&slave_active_lock, flags); + timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; + spin_unlock_irqrestore(&slave_active_lock, flags); + } + goto __end; + } timer = timeri->timer; - if (! timer) + if (!timer) return -EINVAL; spin_lock_irqsave(&timer->lock, flags); list_del_init(&timeri->ack_list); -#if 0 /* FIXME: this causes dead lock with the sequencer timer */ - /* wait until the callback is finished */ - while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { - spin_unlock_irqrestore(&timer->lock, flags); - udelay(10); - spin_lock_irqsave(&timer->lock, flags); - } -#endif list_del_init(&timeri->active_list); if ((timeri->flags & SNDRV_TIMER_IFLG_RUNNING) && - !(timeri->flags & SNDRV_TIMER_IFLG_SLAVE) && !(--timer->running)) { timer->hw.stop(timer); if (timer->flags & SNDRV_TIMER_FLG_RESCHED) { @@ -478,6 +499,7 @@ if (!keep_flag) timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING|SNDRV_TIMER_IFLG_START); spin_unlock_irqrestore(&timer->lock, flags); + __end: if (event != SNDRV_TIMER_EVENT_RESOLUTION) snd_timer_notify1(timeri, event); return 0; @@ -913,6 +935,14 @@ * System timer */ +struct snd_timer_system_private { + struct timer_list tlist; + struct timer * timer; + unsigned long last_expires; + unsigned long last_jiffies; + unsigned long correction; +}; + unsigned int snd_timer_system_resolution(void) { return 1000000000L / HZ; @@ -921,26 +951,44 @@ static void snd_timer_s_function(unsigned long data) { snd_timer_t *timer = (snd_timer_t *)data; - snd_timer_interrupt(timer, timer->sticks); + struct snd_timer_system_private *priv = timer->private_data; + unsigned long jiff = jiffies; + if (time_after(jiff, priv->last_expires)) + priv->correction = (long)jiff - (long)priv->last_expires; + snd_timer_interrupt(timer, (long)jiff - (long)priv->last_jiffies); } static int snd_timer_s_start(snd_timer_t * timer) { - struct timer_list *tlist; + struct snd_timer_system_private *priv; + unsigned long njiff; - tlist = (struct timer_list *) timer->private_data; - tlist->expires = jiffies + timer->sticks; - add_timer(tlist); + priv = (struct snd_timer_system_private *) timer->private_data; + njiff = (priv->last_jiffies = jiffies); + if (priv->correction > timer->sticks - 1) { + priv->correction -= timer->sticks - 1; + njiff++; + } else { + njiff += timer->sticks - priv->correction; + priv->correction -= timer->sticks; + } + priv->last_expires = priv->tlist.expires = njiff; + add_timer(&priv->tlist); return 0; } static int snd_timer_s_stop(snd_timer_t * timer) { - struct timer_list *tlist; + struct snd_timer_system_private *priv; + unsigned long jiff; - tlist = (struct timer_list *) timer->private_data; - del_timer(tlist); - timer->sticks = tlist->expires - jiffies; + priv = (struct snd_timer_system_private *) timer->private_data; + del_timer(&priv->tlist); + jiff = jiffies; + if (time_before(jiff, priv->last_expires)) + timer->sticks = priv->last_expires - jiff; + else + timer->sticks = 1; return 0; } @@ -962,22 +1010,22 @@ static int snd_timer_register_system(void) { snd_timer_t *timer; - struct timer_list *tlist; + struct snd_timer_system_private *priv; int err; if ((err = snd_timer_global_new("system", SNDRV_TIMER_GLOBAL_SYSTEM, &timer)) < 0) return err; strcpy(timer->name, "system timer"); timer->hw = snd_timer_system; - tlist = (struct timer_list *) snd_kcalloc(sizeof(struct timer_list), GFP_KERNEL); - if (tlist == NULL) { + priv = (struct snd_timer_system_private *) snd_kcalloc(sizeof(struct snd_timer_system_private), GFP_KERNEL); + if (priv == NULL) { snd_timer_free(timer); return -ENOMEM; } - init_timer(tlist); - tlist->function = snd_timer_s_function; - tlist->data = (unsigned long) timer; - timer->private_data = tlist; + init_timer(&priv->tlist); + priv->tlist.function = snd_timer_s_function; + priv->tlist.data = (unsigned long) timer; + timer->private_data = priv; timer->private_free = snd_timer_free_system; return snd_timer_global_register(timer); } @@ -1381,8 +1429,8 @@ if (t->hw.precise_resolution) { t->hw.precise_resolution(t, &gstatus.resolution_num, &gstatus.resolution_den); } else { - gstatus.resolution_num = 1; - gstatus.resolution_den = gstatus.resolution; + gstatus.resolution_num = gstatus.resolution; + gstatus.resolution_den = 1000000000uL; } } else { err = -ENODEV; @@ -1684,20 +1732,20 @@ break; } } - if (err < 0) - break; spin_unlock_irq(&tu->qlock); + if (err < 0) + goto _error; if (tu->tread) { if (copy_to_user(buffer, &tu->tqueue[tu->qhead++], sizeof(snd_timer_tread_t))) { err = -EFAULT; - break; + goto _error; } } else { if (copy_to_user(buffer, &tu->queue[tu->qhead++], sizeof(snd_timer_read_t))) { err = -EFAULT; - break; + goto _error; } } @@ -1710,6 +1758,7 @@ tu->qused--; } spin_unlock_irq(&tu->qlock); + _error: return result > 0 ? result : err; } @@ -1761,7 +1810,6 @@ snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1, "system timer"); #endif if ((entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL)) != NULL) { - entry->content = SNDRV_INFO_CONTENT_TEXT; entry->c.text.read_size = SNDRV_TIMER_DEVICES * 128; entry->c.text.read = snd_timer_proc_read; if (snd_info_register(entry) < 0) { diff -Nru a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c --- a/sound/drivers/mpu401/mpu401.c Mon Feb 2 22:07:57 2004 +++ b/sound/drivers/mpu401/mpu401.c Mon Feb 2 22:07:57 2004 @@ -157,7 +157,7 @@ #ifdef CONFIG_X86_PC9800 get_option(&str,&pc98ii[nr_dev]) == 2 && #endif - get_option(&str,(int *)&port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2); nr_dev++; return 1; diff -Nru a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c --- a/sound/drivers/mpu401/mpu401_uart.c Mon Feb 2 22:07:56 2004 +++ b/sound/drivers/mpu401/mpu401_uart.c Mon Feb 2 22:07:56 2004 @@ -498,6 +498,7 @@ if (!integrated) { int res_size = hardware == MPU401_HW_PC98II ? 4 : 2; if ((mpu->res = request_region(port, res_size, "MPU401 UART")) == NULL) { + snd_printk(KERN_ERR "mpu401_uart: unable to grab port 0x%lx size %d\n", port, res_size); snd_device_free(card, rmidi); return -EBUSY; } @@ -519,7 +520,7 @@ mpu->cport = port + 1; if (irq >= 0 && irq_flags) { if (request_irq(irq, snd_mpu401_uart_interrupt, irq_flags, "MPU401 UART", (void *) mpu)) { - snd_printk("unable to grab IRQ %d\n", irq); + snd_printk(KERN_ERR "mpu401_uart: unable to grab IRQ %d\n", irq); snd_device_free(card, rmidi); return -EBUSY; } diff -Nru a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c --- a/sound/drivers/mtpav.c Mon Feb 2 22:07:58 2004 +++ b/sound/drivers/mtpav.c Mon Feb 2 22:07:58 2004 @@ -813,7 +813,7 @@ (void)(get_option(&str,&enable) == 2 && get_option(&str,&index) == 2 && get_id(&str,&id) == 2 && - get_option(&str,(int *)&port) == 2 && + get_option_long(&str,&port) == 2 && get_option(&str,&irq) == 2 && get_option(&str,&hwports) == 2); return 1; diff -Nru a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c --- a/sound/drivers/opl3/opl3_lib.c Mon Feb 2 22:07:55 2004 +++ b/sound/drivers/opl3/opl3_lib.c Mon Feb 2 22:07:55 2004 @@ -387,11 +387,13 @@ goto __step1; /* ports are already reserved */ if ((opl3->res_l_port = request_region(l_port, 2, "OPL2/3 (left)")) == NULL) { + snd_printk(KERN_ERR "opl3: can't grab left port 0x%lx\n", l_port); snd_opl3_free(opl3); return -EBUSY; } if (r_port != 0 && (opl3->res_r_port = request_region(r_port, 2, "OPL2/3 (right)")) == NULL) { + snd_printk(KERN_ERR "opl3: can't grab right port 0x%lx\n", r_port); snd_opl3_free(opl3); return -EBUSY; } diff -Nru a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c --- a/sound/drivers/opl3/opl3_synth.c Mon Feb 2 22:07:55 2004 +++ b/sound/drivers/opl3/opl3_synth.c Mon Feb 2 22:07:55 2004 @@ -20,7 +20,6 @@ */ #include -#define __SND_OSS_COMPAT__ #include /* diff -Nru a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c --- a/sound/drivers/opl4/opl4_lib.c Mon Feb 2 22:07:58 2004 +++ b/sound/drivers/opl4/opl4_lib.c Mon Feb 2 22:07:58 2004 @@ -206,6 +206,7 @@ opl4->res_fm_port = request_region(fm_port, 8, "OPL4 FM"); opl4->res_pcm_port = request_region(pcm_port, 8, "OPL4 PCM/MIX"); if (!opl4->res_fm_port || !opl4->res_pcm_port) { + snd_printk(KERN_ERR "opl4: can't grab ports 0x%lx, 0x%lx\n", fm_port, pcm_port); snd_opl4_free(opl4); return -EBUSY; } diff -Nru a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c --- a/sound/drivers/opl4/opl4_proc.c Mon Feb 2 22:07:58 2004 +++ b/sound/drivers/opl4/opl4_proc.c Mon Feb 2 22:07:58 2004 @@ -18,6 +18,7 @@ */ #include "opl4_local.h" +#include #include #ifdef CONFIG_PROC_FS @@ -59,15 +60,15 @@ if (file->f_pos + size > entry->size) size = entry->size - file->f_pos; if (size > 0) { - buf = kmalloc(size, GFP_KERNEL); + buf = vmalloc(size); if (!buf) return -ENOMEM; snd_opl4_read_memory(opl4, buf, file->f_pos, size); if (copy_to_user(_buf, buf, size)) { - kfree(buf); + vfree(buf); return -EFAULT; } - kfree(buf); + vfree(buf); file->f_pos += size; return size; } @@ -85,15 +86,15 @@ if (file->f_pos + size > entry->size) size = entry->size - file->f_pos; if (size > 0) { - buf = kmalloc(size, GFP_KERNEL); + buf = vmalloc(size); if (!buf) return -ENOMEM; if (copy_from_user(buf, _buf, size)) { - kfree(buf); + vfree(buf); return -EFAULT; } snd_opl4_write_memory(opl4, buf, file->f_pos, size); - kfree(buf); + vfree(buf); file->f_pos += size; return size; } diff -Nru a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c --- a/sound/drivers/serial-u16550.c Mon Feb 2 22:07:55 2004 +++ b/sound/drivers/serial-u16550.c Mon Feb 2 22:07:55 2004 @@ -63,6 +63,9 @@ "Generic" }; +#define SNDRV_SERIAL_NORMALBUFF 0 /* Normal blocking buffer operation */ +#define SNDRV_SERIAL_DROPBUFF 1 /* Non-blocking discard operation */ + 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 */ @@ -73,6 +76,7 @@ static int outs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; /* 1 to 16 */ static int ins[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; /* 1 to 16 */ static int adaptor[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = SNDRV_SERIAL_SOUNDCANVAS}; +static int droponfull[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS -1)] = SNDRV_SERIAL_NORMALBUFF }; MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(index, "Index value for Serial MIDI."); @@ -99,6 +103,9 @@ MODULE_PARM_DESC(outs, "Number of MIDI outputs."); MODULE_PARM(ins, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(ins, "Number of MIDI inputs."); +MODULE_PARM(droponfull, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(droponfull, "Flag to enable drop-on-full buffer mode"); +MODULE_PARM_SYNTAX(droponfull, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); MODULE_PARM_SYNTAX(outs, SNDRV_ENABLED ",allows:{{1,16}},dialog:list"); MODULE_PARM_SYNTAX(ins, SNDRV_ENABLED ",allows:{{1,16}},dialog:list"); @@ -163,6 +170,7 @@ int buff_in_count; int buff_in; int buff_out; + int drop_on_full; // wait timer unsigned int timer_running:1; @@ -194,12 +202,14 @@ inline static void snd_uart16550_buffer_output(snd_uart16550_t *uart) { unsigned short buff_out = uart->buff_out; - outb(uart->tx_buff[buff_out], uart->base + UART_TX); - uart->fifo_count++; - buff_out++; - buff_out &= TX_BUFF_MASK; - uart->buff_out = buff_out; - uart->buff_in_count--; + if( uart->buff_in_count > 0 ) { + outb(uart->tx_buff[buff_out], uart->base + UART_TX); + uart->fifo_count++; + buff_out++; + buff_out &= TX_BUFF_MASK; + uart->buff_out = buff_out; + uart->buff_in_count--; + } } /* This loop should be called with interrupts disabled @@ -257,9 +267,11 @@ || uart->adaptor == SNDRV_SERIAL_GENERIC) { /* Can't use FIFO, must send only when CTS is true */ status = inb(uart->base + UART_MSR); - if (uart->fifo_count == 0 && (status & UART_MSR_CTS) - && uart->buff_in_count > 0) - snd_uart16550_buffer_output(uart); + while( (uart->fifo_count == 0) && (status & UART_MSR_CTS) && + (uart->buff_in_count > 0) ) { + snd_uart16550_buffer_output(uart); + status = inb( uart->base + UART_MSR ); + } } else { /* Write loop */ while (uart->fifo_count < uart->fifo_limit /* Can we write ? */ @@ -335,8 +347,10 @@ } uart->res_base = request_region(io_base, 8, "Serial MIDI"); - if (uart->res_base == NULL) + if (uart->res_base == NULL) { + snd_printk(KERN_ERR "u16550: can't grab port 0x%lx\n", io_base); return -EBUSY; + } ok = 1; /* uart detected unless one of the following tests should fail */ /* 8 data-bits, 1 stop-bit, parity off, DLAB = 0 */ @@ -576,19 +590,31 @@ return 0; }; -inline static void snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte) +inline static int snd_uart16550_buffer_can_write( snd_uart16550_t *uart, int Num ) +{ + if( uart->buff_in_count + Num < TX_BUFF_SIZE ) + return 1; + else + return 0; +} + +inline static int snd_uart16550_write_buffer(snd_uart16550_t *uart, unsigned char byte) { unsigned short buff_in = uart->buff_in; - uart->tx_buff[buff_in] = byte; - buff_in++; - buff_in &= TX_BUFF_MASK; - uart->buff_in = buff_in; - uart->buff_in_count++; - if (uart->irq < 0) /* polling mode */ - snd_uart16550_add_timer(uart); + if( uart->buff_in_count < TX_BUFF_SIZE ) { + uart->tx_buff[buff_in] = byte; + buff_in++; + buff_in &= TX_BUFF_MASK; + uart->buff_in = buff_in; + uart->buff_in_count++; + if (uart->irq < 0) /* polling mode */ + snd_uart16550_add_timer(uart); + return 1; + } else + return 0; } -static void snd_uart16550_output_byte(snd_uart16550_t *uart, snd_rawmidi_substream_t * substream, unsigned char midi_byte) +static int snd_uart16550_output_byte(snd_uart16550_t *uart, snd_rawmidi_substream_t * substream, unsigned char midi_byte) { if (uart->buff_in_count == 0 /* Buffer empty? */ && ((uart->adaptor != SNDRV_SERIAL_MS124W_SA && @@ -611,13 +637,14 @@ } } } else { - if (uart->buff_in_count >= TX_BUFF_SIZE) { + if( !snd_uart16550_write_buffer(uart, midi_byte) ) { snd_printk("%s: Buffer overrun on device at 0x%lx\n", uart->rmidi->name, uart->base); - return; + return 0; } - snd_uart16550_write_buffer(uart, midi_byte); } + + return 1; } static void snd_uart16550_output_write(snd_rawmidi_substream_t * substream) @@ -661,40 +688,38 @@ } } else { first = 0; - while (1) { - if (snd_rawmidi_transmit(substream, &midi_byte, 1) != 1) - break; + while( 1 == snd_rawmidi_transmit_peek(substream, &midi_byte, 1) ) { /* Also send F5 after 3 seconds with no data to handle device disconnect */ if (first == 0 && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS || uart->adaptor == SNDRV_SERIAL_GENERIC) && (uart->prev_out != substream->number || jiffies-lasttime > 3*HZ)) { - /* We will need three bytes of data here (worst case). */ - if (uart->buff_in_count >= TX_BUFF_SIZE - 3) + if( snd_uart16550_buffer_can_write( uart, 3 ) ) { + /* Roland Soundcanvas part selection */ + /* If this substream of the data is different previous + substream in this uart, send the change part event */ + uart->prev_out = substream->number; + /* change part */ + snd_uart16550_output_byte(uart, substream, 0xf5); + /* data */ + snd_uart16550_output_byte(uart, substream, uart->prev_out + 1); + /* If midi_byte is a data byte, send the previous status byte */ + if ((midi_byte < 0x80) && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS)) + snd_uart16550_output_byte(uart, substream, uart->prev_status[uart->prev_out]); + } else if( !uart->drop_on_full ) break; - /* Roland Soundcanvas part selection */ - /* If this substream of the data is different previous - substream in this uart, send the change part event */ - uart->prev_out = substream->number; - /* change part */ - snd_uart16550_output_byte(uart, substream, 0xf5); - /* data */ - snd_uart16550_output_byte(uart, substream, uart->prev_out + 1); - /* If midi_byte is a data byte, send the previous status byte */ - if ((midi_byte < 0x80) && (uart->adaptor == SNDRV_SERIAL_SOUNDCANVAS)) - snd_uart16550_output_byte(uart, substream, uart->prev_status[uart->prev_out]); } - /* buffer full? */ - if (uart->buff_in_count >= TX_BUFF_SIZE) + /* send midi byte */ + if( !snd_uart16550_output_byte(uart, substream, midi_byte) && !uart->drop_on_full ) break; - /* send midi byte */ - snd_uart16550_output_byte(uart, substream, midi_byte); if (midi_byte >= 0x80 && midi_byte < 0xf0) uart->prev_status[uart->prev_out] = midi_byte; first = 1; + + snd_rawmidi_transmit_ack( substream, 1 ); } lasttime = jiffies; } @@ -755,6 +780,7 @@ unsigned int speed, unsigned int base, int adaptor, + int droponfull, snd_uart16550_t **ruart) { static snd_device_ops_t ops = { @@ -771,6 +797,7 @@ spin_lock_init(&uart->open_lock); uart->irq = -1; uart->base = iobase; + uart->drop_on_full = droponfull; if ((err = snd_uart16550_detect(uart)) <= 0) { printk(KERN_ERR "no UART detected at 0x%lx\n", iobase); @@ -900,6 +927,7 @@ speed[dev], base[dev], adaptor[dev], + droponfull[dev], &uart)) < 0) { snd_card_free(card); return err; @@ -910,7 +938,7 @@ return err; } - sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d ins %d adaptor %s", + sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d ins %d adaptor %s droponfull %d", card->shortname, uart->base, uart->irq, @@ -918,7 +946,8 @@ (int)uart->divisor, outs[dev], ins[dev], - adaptor_names[uart->adaptor]); + adaptor_names[uart->adaptor], + uart->drop_on_full); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); @@ -964,7 +993,7 @@ /* format is: snd-serial=enable,index,id, port,irq,speed,base,outs, - ins,adaptor */ + ins,adaptor,droponfull */ static int __init alsa_card_serial_setup(char *str) { @@ -975,13 +1004,14 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&speed[nr_dev]) == 2 && get_option(&str,&base[nr_dev]) == 2 && get_option(&str,&outs[nr_dev]) == 2 && get_option(&str,&ins[nr_dev]) == 2 && - get_option(&str,&adaptor[nr_dev]) == 2); + get_option(&str,&adaptor[nr_dev]) == 2 && + get_option(&str,&droponfull[nr_dev]) == 2 ); nr_dev++; return 1; } diff -Nru a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c --- a/sound/drivers/vx/vx_core.c Mon Feb 2 22:07:58 2004 +++ b/sound/drivers/vx/vx_core.c Mon Feb 2 22:07:58 2004 @@ -641,7 +641,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(chip->card, "vx-status", &entry)) - snd_info_set_text_ops(entry, chip, vx_proc_read); + snd_info_set_text_ops(entry, chip, 1024, vx_proc_read); } diff -Nru a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c --- a/sound/drivers/vx/vx_pcm.c Mon Feb 2 22:07:55 2004 +++ b/sound/drivers/vx/vx_pcm.c Mon Feb 2 22:07:55 2004 @@ -611,6 +611,10 @@ runtime->hw.period_bytes_min = chip->ibl.size; runtime->private_data = pipe; + /* align to 4 bytes (otherwise will be problematic when 24bit is used) */ + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4); + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4); + return 0; } @@ -1014,6 +1018,10 @@ runtime->hw = vx_pcm_capture_hw; runtime->hw.period_bytes_min = chip->ibl.size; runtime->private_data = pipe; + + /* align to 4 bytes (otherwise will be problematic when 24bit is used) */ + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4); + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4); return 0; } diff -Nru a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c --- a/sound/i2c/cs8427.c Mon Feb 2 22:07:55 2004 +++ b/sound/i2c/cs8427.c Mon Feb 2 22:07:55 2004 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -557,6 +558,18 @@ snd_cs8427_reset(cs8427); return err < 0 ? err : 0; } + +static int __init alsa_cs8427_module_init(void) +{ + return 0; +} + +static void __exit alsa_cs8427_module_exit(void) +{ +} + +module_init(alsa_cs8427_module_init) +module_exit(alsa_cs8427_module_exit) EXPORT_SYMBOL(snd_cs8427_detect); EXPORT_SYMBOL(snd_cs8427_create); diff -Nru a/sound/i2c/i2c.c b/sound/i2c/i2c.c --- a/sound/i2c/i2c.c Mon Feb 2 22:07:56 2004 +++ b/sound/i2c/i2c.c Mon Feb 2 22:07:56 2004 @@ -84,7 +84,7 @@ bus = (snd_i2c_bus_t *)snd_magic_kcalloc(snd_i2c_bus_t, 0, GFP_KERNEL); if (bus == NULL) return -ENOMEM; - spin_lock_init(&bus->lock); + init_MUTEX(&bus->lock_mutex); INIT_LIST_HEAD(&bus->devices); INIT_LIST_HEAD(&bus->buses); bus->card = card; diff -Nru a/sound/i2c/l3/uda1341.c b/sound/i2c/l3/uda1341.c --- a/sound/i2c/l3/uda1341.c Mon Feb 2 22:07:56 2004 +++ b/sound/i2c/l3/uda1341.c Mon Feb 2 22:07:56 2004 @@ -17,7 +17,7 @@ * 2002-05-12 Tomas Kasparek another code cleanup */ -/* $Id: uda1341.c,v 1.9 2003/04/19 13:34:33 perex Exp $ */ +/* $Id: uda1341.c,v 1.10 2003/10/23 14:34:52 perex Exp $ */ #include #include @@ -421,9 +421,9 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(card, "uda1341", &entry)) - snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_read); + snd_info_set_text_ops(entry, clnt, 1024, snd_uda1341_proc_read); if (! snd_card_proc_new(card, "uda1341-regs", &entry)) - snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_regs_read); + snd_info_set_text_ops(entry, clnt, 1024, snd_uda1341_proc_regs_read); } /* }}} */ diff -Nru a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c --- a/sound/i2c/other/ak4xxx-adda.c Mon Feb 2 22:07:58 2004 +++ b/sound/i2c/other/ak4xxx-adda.c Mon Feb 2 22:07:58 2004 @@ -445,6 +445,18 @@ return 0; } +static int __init alsa_akm4xxx_module_init(void) +{ + return 0; +} + +static void __exit alsa_akm4xxx_module_exit(void) +{ +} + +module_init(alsa_akm4xxx_module_init) +module_exit(alsa_akm4xxx_module_exit) + EXPORT_SYMBOL(snd_akm4xxx_write); EXPORT_SYMBOL(snd_akm4xxx_reset); EXPORT_SYMBOL(snd_akm4xxx_init); diff -Nru a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c --- a/sound/isa/ad1816a/ad1816a.c Mon Feb 2 22:07:56 2004 +++ b/sound/isa/ad1816a/ad1816a.c Mon Feb 2 22:07:56 2004 @@ -210,6 +210,7 @@ snd_card_free(card); return error; } + snd_card_set_dev(card, &pcard->card->dev); if ((error = snd_ad1816a_create(card, port[dev], irq[dev], @@ -220,6 +221,11 @@ return error; } + strcpy(card->driver, "AD1816A"); + strcpy(card->shortname, "ADI SoundPort AD1816A"); + sprintf(card->longname, "%s, SS at 0x%lx, irq %d, dma %d&%d", + card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]); + if ((error = snd_ad1816a_pcm(chip, 0, NULL)) < 0) { snd_card_free(card); return error; @@ -254,11 +260,6 @@ } } - strcpy(card->driver, "AD1816A"); - strcpy(card->shortname, "ADI SoundPort AD1816A"); - sprintf(card->longname, "%s soundcard, SS at 0x%lx, irq %d, dma %d&%d", - card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]); - if ((error = snd_card_register(card)) < 0) { snd_card_free(card); return error; @@ -338,9 +339,9 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && diff -Nru a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c --- a/sound/isa/ad1816a/ad1816a_lib.c Mon Feb 2 22:07:57 2004 +++ b/sound/isa/ad1816a/ad1816a_lib.c Mon Feb 2 22:07:57 2004 @@ -593,20 +593,24 @@ chip->dma2 = -1; if ((chip->res_port = request_region(port, 16, "AD1816A")) == NULL) { + snd_printk(KERN_ERR "ad1816a: can't grab port 0x%lx\n", port); snd_ad1816a_free(chip); return -EBUSY; } if (request_irq(irq, snd_ad1816a_interrupt, SA_INTERRUPT, "AD1816A", (void *) chip)) { + snd_printk(KERN_ERR "ad1816a: can't grab IRQ %d\n", irq); snd_ad1816a_free(chip); return -EBUSY; } chip->irq = irq; if (request_dma(dma1, "AD1816A - 1")) { + snd_printk(KERN_ERR "ad1816a: can't grab DMA1 %d\n", dma1); snd_ad1816a_free(chip); return -EBUSY; } chip->dma1 = dma1; if (request_dma(dma2, "AD1816A - 2")) { + snd_printk(KERN_ERR "ad1816a: can't grab DMA2 %d\n", dma2); snd_ad1816a_free(chip); return -EBUSY; } diff -Nru a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c --- a/sound/isa/ad1848/ad1848.c Mon Feb 2 22:07:57 2004 +++ b/sound/isa/ad1848/ad1848.c Mon Feb 2 22:07:57 2004 @@ -174,7 +174,7 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && get_option(&str,&thinkpad[nr_dev]) == 2); diff -Nru a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c --- a/sound/isa/ad1848/ad1848_lib.c Mon Feb 2 22:07:58 2004 +++ b/sound/isa/ad1848/ad1848_lib.c Mon Feb 2 22:07:58 2004 @@ -736,11 +736,13 @@ snd_ad1848_out(chip, AD1848_RIGHT_INPUT, 0x45); rev = snd_ad1848_in(chip, AD1848_RIGHT_INPUT); if (rev == 0x65) { + spin_unlock_irqrestore(&chip->reg_lock, flags); id = 1; ad1847 = 1; break; } if (snd_ad1848_in(chip, AD1848_LEFT_INPUT) == 0xaa && rev == 0x45) { + spin_unlock_irqrestore(&chip->reg_lock, flags); id = 1; break; } @@ -950,15 +952,18 @@ memcpy(&chip->image, &snd_ad1848_original_image, sizeof(snd_ad1848_original_image)); if ((chip->res_port = request_region(port, 4, "AD1848")) == NULL) { + snd_printk(KERN_ERR "ad1848: can't grab port 0x%lx\n", port); snd_ad1848_free(chip); return -EBUSY; } if (request_irq(irq, snd_ad1848_interrupt, SA_INTERRUPT, "AD1848", (void *) chip)) { + snd_printk(KERN_ERR "ad1848: can't grab IRQ %d\n", irq); snd_ad1848_free(chip); return -EBUSY; } chip->irq = irq; if (request_dma(dma, "AD1848")) { + snd_printk(KERN_ERR "ad1848: can't grab DMA %d\n", dma); snd_ad1848_free(chip); return -EBUSY; } diff -Nru a/sound/isa/als100.c b/sound/isa/als100.c --- a/sound/isa/als100.c Mon Feb 2 22:07:55 2004 +++ b/sound/isa/als100.c Mon Feb 2 22:07:55 2004 @@ -228,6 +228,7 @@ snd_card_free(card); return error; } + snd_card_set_dev(card, &pcard->card->dev); if ((error = snd_sbdsp_create(card, port[dev], irq[dev], @@ -239,6 +240,12 @@ return error; } + 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); return error; @@ -249,7 +256,7 @@ return error; } - if (mpu_port[dev] > 0) { + if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { if (snd_mpu401_uart_new(card, 0, MPU401_HW_ALS100, mpu_port[dev], 0, mpu_irq[dev], SA_INTERRUPT, @@ -257,7 +264,7 @@ snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]); } - if (fm_port[dev] > 0) { + 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) { @@ -275,11 +282,6 @@ } } - strcpy(card->driver, "ALS100"); - strcpy(card->shortname, "Avance Logic ALS100"); - sprintf(card->longname, "%s soundcard, %s at 0x%lx, irq %d, dma %d&%d", - card->shortname, chip->name, chip->port, - irq[dev], dma8[dev], dma16[dev]); if ((error = snd_card_register(card)) < 0) { snd_card_free(card); return error; @@ -359,9 +361,9 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && get_option(&str,&dma8[nr_dev]) == 2 && diff -Nru a/sound/isa/azt2320.c b/sound/isa/azt2320.c --- a/sound/isa/azt2320.c Mon Feb 2 22:07:58 2004 +++ b/sound/isa/azt2320.c Mon Feb 2 22:07:58 2004 @@ -255,6 +255,7 @@ snd_card_free(card); return error; } + snd_card_set_dev(card, &pcard->card->dev); if ((error = snd_card_azt2320_enable_wss(port[dev]))) { snd_card_free(card); @@ -270,6 +271,11 @@ return error; } + strcpy(card->driver, "AZT2320"); + strcpy(card->shortname, "Aztech AZT2320"); + sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i", + card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]); + if ((error = snd_cs4231_pcm(chip, 0, NULL)) < 0) { snd_card_free(card); return error; @@ -283,7 +289,7 @@ return error; } - if (mpu_port[dev] > 0) { + if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320, mpu_port[dev], 0, mpu_irq[dev], SA_INTERRUPT, @@ -291,7 +297,7 @@ snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]); } - if (fm_port[dev] > 0) { + 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) { @@ -309,11 +315,6 @@ } } - strcpy(card->driver, "AZT2320"); - strcpy(card->shortname, "Aztech AZT2320"); - sprintf(card->longname, "%s soundcard, WSS at 0x%lx, irq %i, dma %i&%i", - card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]); - if ((error = snd_card_register(card)) < 0) { snd_card_free(card); return error; @@ -393,9 +394,9 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&wss_port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&wss_port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && diff -Nru a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c --- a/sound/isa/cmi8330.c Mon Feb 2 22:07:55 2004 +++ b/sound/isa/cmi8330.c Mon Feb 2 22:07:55 2004 @@ -481,10 +481,13 @@ acard->card = card; #ifdef CONFIG_PNP - if (isapnp[dev] && (err = snd_cmi8330_pnp(dev, acard, pcard, pid)) < 0) { - snd_printk("PnP detection failed\n"); - snd_card_free(card); - return err; + if (isapnp[dev]) { + if ((err = snd_cmi8330_pnp(dev, acard, pcard, pid)) < 0) { + snd_printk("PnP detection failed\n"); + snd_card_free(card); + return err; + } + snd_card_set_dev(card, &pcard->card->dev); } #endif @@ -658,11 +661,11 @@ get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && get_option(&str,&pnp) == 2 && - get_option(&str,(int *)&sbport[nr_dev]) == 2 && + get_option_long(&str,&sbport[nr_dev]) == 2 && get_option(&str,&sbirq[nr_dev]) == 2 && get_option(&str,&sbdma8[nr_dev]) == 2 && get_option(&str,&sbdma16[nr_dev]) == 2 && - get_option(&str,(int *)&wssport[nr_dev]) == 2 && + get_option_long(&str,&wssport[nr_dev]) == 2 && get_option(&str,&wssirq[nr_dev]) == 2 && get_option(&str,&wssdma[nr_dev]) == 2); #ifdef CONFIG_PNP diff -Nru a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c --- a/sound/isa/cs423x/cs4231.c Mon Feb 2 22:07:55 2004 +++ b/sound/isa/cs423x/cs4231.c Mon Feb 2 22:07:55 2004 @@ -103,8 +103,6 @@ if (card == NULL) return -ENOMEM; acard = (struct snd_card_cs4231 *)card->private_data; - if (mpu_port[dev] < 0) - mpu_port[dev] = SNDRV_AUTO_PORT; if ((err = snd_cs4231_create(card, port[dev], -1, irq[dev], dma1[dev], @@ -119,6 +117,14 @@ snd_card_free(card); return err; } + + strcpy(card->driver, "CS4231"); + strcpy(card->shortname, pcm->name); + sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", + pcm->name, chip->port, irq[dev], dma1[dev]); + if (dma2[dev] >= 0) + sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]); + if ((err = snd_cs4231_mixer(chip)) < 0) { snd_card_free(card); return err; @@ -128,19 +134,16 @@ return err; } - if (mpu_irq[dev] >= 0 && mpu_irq[dev] != SNDRV_AUTO_IRQ) { + 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_CS4232, mpu_port[dev], 0, - mpu_irq[dev], SA_INTERRUPT, + mpu_irq[dev], + mpu_irq[dev] >= 0 ? SA_INTERRUPT : 0, NULL) < 0) printk(KERN_ERR "cs4231: MPU401 not detected\n"); } - strcpy(card->driver, "CS4231"); - strcpy(card->shortname, pcm->name); - sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", - pcm->name, chip->port, irq[dev], dma1[dev]); - if (dma2[dev] >= 0) - sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; @@ -194,8 +197,8 @@ get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && get_option(&str,&pnp) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && diff -Nru a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c --- a/sound/isa/cs423x/cs4231_lib.c Mon Feb 2 22:07:55 2004 +++ b/sound/isa/cs423x/cs4231_lib.c Mon Feb 2 22:07:56 2004 @@ -1531,26 +1531,31 @@ chip->dma2 = -1; if ((chip->res_port = request_region(port, 4, "CS4231")) == NULL) { + snd_printk(KERN_ERR "cs4231: can't grab port 0x%lx\n", port); snd_cs4231_free(chip); return -EBUSY; } chip->port = port; if ((long)cport >= 0 && (chip->res_cport = request_region(cport, 8, "CS4232 Control")) == NULL) { + snd_printk(KERN_ERR "cs4231: can't grab control port 0x%lx\n", cport); snd_cs4231_free(chip); return -ENODEV; } chip->cport = cport; if (!(hwshare & CS4231_HWSHARE_IRQ) && request_irq(irq, snd_cs4231_interrupt, SA_INTERRUPT, "CS4231", (void *) chip)) { + snd_printk(KERN_ERR "cs4231: can't grab IRQ %d\n", irq); snd_cs4231_free(chip); return -EBUSY; } chip->irq = irq; if (!(hwshare & CS4231_HWSHARE_DMA1) && request_dma(dma1, "CS4231 - 1")) { + snd_printk(KERN_ERR "cs4231: can't grab DMA1 %d\n", dma1); snd_cs4231_free(chip); return -EBUSY; } chip->dma1 = dma1; if (!(hwshare & CS4231_HWSHARE_DMA2) && dma1 != dma2 && dma2 >= 0 && request_dma(dma2, "CS4231 - 2")) { + snd_printk(KERN_ERR "cs4231: can't grab DMA2 %d\n", dma2); snd_cs4231_free(chip); return -EBUSY; } diff -Nru a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c --- a/sound/isa/cs423x/cs4236.c Mon Feb 2 22:07:55 2004 +++ b/sound/isa/cs423x/cs4236.c Mon Feb 2 22:07:55 2004 @@ -307,7 +307,7 @@ pnp_init_resource_table(cfg); if (port[dev] != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[0], port[dev], 4); - if (fm_port[dev] != SNDRV_AUTO_PORT && fm_port[dev] >= 0) + if (fm_port[dev] != SNDRV_AUTO_PORT && fm_port[dev] > 0) pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4); if (sb_port[dev] != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[2], sb_port[dev], 16); @@ -327,7 +327,7 @@ return -EBUSY; } port[dev] = pnp_port_start(pdev, 0); - if (fm_port[dev] >= 0) + if (fm_port[dev] > 0) fm_port[dev] = pnp_port_start(pdev, 1); sb_port[dev] = pnp_port_start(pdev, 2); irq[dev] = pnp_irq(pdev, 0); @@ -338,7 +338,7 @@ snd_printdd("isapnp WSS: irq=%i, dma1=%i, dma2=%i\n", irq[dev], dma1[dev], dma2[dev]); /* CTRL initialization */ - if (acard->ctrl && cport[dev] >= 0) { + if (acard->ctrl && cport[dev] > 0) { pdev = acard->ctrl; pnp_init_resource_table(cfg); if (cport[dev] != SNDRV_AUTO_PORT) @@ -356,12 +356,13 @@ snd_printdd("isapnp CTRL: control port=0x%lx\n", cport[dev]); } /* MPU initialization */ - if (acard->mpu && mpu_port[dev] >= 0) { + if (acard->mpu && mpu_port[dev] > 0) { pdev = acard->mpu; pnp_init_resource_table(cfg); if (mpu_port[dev] != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2); - if (mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] >= 0) + if (mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] >= 0 && + pnp_irq_valid(pdev, 0)) pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1); err = pnp_manual_config_dev(pdev, cfg, 0); if (err < 0) @@ -373,7 +374,8 @@ mpu_irq[dev] = SNDRV_AUTO_IRQ; } else { mpu_port[dev] = pnp_port_start(pdev, 0); - if (pnp_irq_valid(pdev, 0) && pnp_irq(pdev, 0) >= 0) { + if (mpu_irq[dev] >= 0 && + pnp_irq_valid(pdev, 0) && pnp_irq(pdev, 0) >= 0) { mpu_irq[dev] = pnp_irq(pdev, 0); } else { mpu_irq[dev] = -1; /* disable interrupt */ @@ -429,19 +431,16 @@ acard = (struct snd_card_cs4236 *)card->private_data; card->private_free = snd_card_cs4236_free; #ifdef CONFIG_PNP - if (isapnp[dev] && (err = snd_card_cs4236_pnp(dev, acard, pcard, pid))<0) { - printk(KERN_ERR "isapnp detection failed and probing for " IDENT " is not supported\n"); - snd_card_free(card); - return -ENXIO; + if (isapnp[dev]) { + if ((err = snd_card_cs4236_pnp(dev, acard, pcard, pid))<0) { + printk(KERN_ERR "isapnp detection failed and probing for " IDENT " is not supported\n"); + snd_card_free(card); + return -ENXIO; + } + snd_card_set_dev(card, &pcard->card->dev); } #endif - if (mpu_port[dev] < 0) - mpu_port[dev] = SNDRV_AUTO_PORT; - if (fm_port[dev] < 0) - fm_port[dev] = SNDRV_AUTO_PORT; - if (sb_port[dev] < 0) - sb_port[dev] = SNDRV_AUTO_PORT; - if (sb_port[dev] != SNDRV_AUTO_PORT) + if (sb_port[dev] > 0 && sb_port[dev] != SNDRV_AUTO_PORT) if ((acard->res_sb_port = request_region(sb_port[dev], 16, IDENT " SB")) == NULL) { printk(KERN_ERR IDENT ": unable to register SB port at 0x%lx\n", sb_port[dev]); snd_card_free(card); @@ -492,13 +491,22 @@ return err; } #endif + strcpy(card->driver, pcm->name); + strcpy(card->shortname, pcm->name); + sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i", + pcm->name, + chip->port, + irq[dev], + dma1[dev]); + if (dma2[dev] >= 0) + sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]); if ((err = snd_cs4231_timer(chip, 0, NULL)) < 0) { snd_card_free(card); return err; } - if (fm_port[dev] != SNDRV_AUTO_PORT) { + 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_OPL3_CS, 0, &opl3) < 0) { @@ -511,22 +519,15 @@ } } - if (mpu_port[dev] != SNDRV_AUTO_PORT) { + 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_CS4232, mpu_port[dev], 0, mpu_irq[dev], mpu_irq[dev] >= 0 ? SA_INTERRUPT : 0, NULL) < 0) printk(KERN_ERR IDENT ": MPU401 not detected\n"); } - strcpy(card->driver, pcm->name); - strcpy(card->shortname, pcm->name); - sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i", - pcm->name, - chip->port, - irq[dev], - dma1[dev]); - if (dma2[dev] >= 0) - sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; @@ -546,7 +547,7 @@ int res; for ( ; dev < SNDRV_CARDS; dev++) { - if (!enable[dev]) + if (!enable[dev] || !isapnp[dev]) continue; res = snd_card_cs423x_probe(dev, card, id); if (res < 0) @@ -638,11 +639,11 @@ get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && get_option(&str,&pnp) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&cport[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && - get_option(&str,(int *)&sb_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&cport[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && + get_option_long(&str,&sb_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && diff -Nru a/sound/isa/cs423x/pc98.c b/sound/isa/cs423x/pc98.c --- a/sound/isa/cs423x/pc98.c Mon Feb 2 22:07:56 2004 +++ b/sound/isa/cs423x/pc98.c Mon Feb 2 22:07:56 2004 @@ -327,10 +327,6 @@ card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); if (card == NULL) return -ENOMEM; - if (mpu_port[dev] < 0 || mpu_irq[dev] < 0) - mpu_port[dev] = SNDRV_AUTO_PORT; - if (fm_port[dev] < 0) - fm_port[dev] = SNDRV_AUTO_PORT; if ((err = pc98_cs4231_chip_init(dev)) < 0) { snd_card_free(card); @@ -363,7 +359,7 @@ return err; } - if (fm_port[dev] != SNDRV_AUTO_PORT) { + if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { /* ??? */ outb(0x00, fm_port[dev] + 6); inb(fm_port[dev] + 7); @@ -381,7 +377,7 @@ } } - if (mpu_port[dev] != SNDRV_AUTO_PORT) { + if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { err = pc98_mpu401_init(mpu_irq[dev]); if (! err) { err = snd_mpu401_uart_new(card, 0, @@ -455,9 +451,9 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && diff -Nru a/sound/isa/dt019x.c b/sound/isa/dt019x.c --- a/sound/isa/dt019x.c Mon Feb 2 22:07:56 2004 +++ b/sound/isa/dt019x.c Mon Feb 2 22:07:56 2004 @@ -210,6 +210,7 @@ return -ENOMEM; acard = (struct snd_card_dt019x *)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; @@ -226,6 +227,12 @@ return error; } + 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; @@ -235,18 +242,20 @@ return error; } - if (mpu_port[dev] > 0) { + 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], - SA_INTERRUPT, + mpu_irq[dev] >= 0 ? SA_INTERRUPT : 0, NULL) < 0) snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx ?\n", mpu_port[dev]); } - if (fm_port[dev] > 0) { + if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2, @@ -265,11 +274,6 @@ } } - strcpy(card->driver, "DT-019X"); - strcpy(card->shortname, "Diamond Tech. DT-019X"); - sprintf(card->longname, "%s soundcard, %s at 0x%lx, irq %d, dma %d", - card->shortname, chip->name, chip->port, - irq[dev], dma8[dev]); if ((error = snd_card_register(card)) < 0) { snd_card_free(card); return error; @@ -347,9 +351,9 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && get_option(&str,&dma8[nr_dev]) == 2); diff -Nru a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c --- a/sound/isa/es1688/es1688.c Mon Feb 2 22:07:56 2004 +++ b/sound/isa/es1688/es1688.c Mon Feb 2 22:07:56 2004 @@ -130,6 +130,10 @@ return err; } + strcpy(card->driver, "ES1688"); + strcpy(card->shortname, pcm->name); + sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i", pcm->name, chip->port, xirq, xdma); + if ((snd_opl3_create(card, chip->port, chip->port + 2, OPL3_HW_OPL3, 0, &opl3)) < 0) { printk(KERN_ERR "es1688: opl3 not detected at 0x%lx\n", chip->port); } else { @@ -149,9 +153,6 @@ return err; } } - strcpy(card->driver, "ES1688"); - strcpy(card->shortname, pcm->name); - sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i", pcm->name, chip->port, xirq, xdma); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; @@ -226,8 +227,8 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && get_option(&str,&dma8[nr_dev]) == 2); diff -Nru a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c --- a/sound/isa/es1688/es1688_lib.c Mon Feb 2 22:07:57 2004 +++ b/sound/isa/es1688/es1688_lib.c Mon Feb 2 22:07:57 2004 @@ -659,15 +659,18 @@ chip->dma8 = -1; if ((chip->res_port = request_region(port + 4, 12, "ES1688")) == NULL) { + snd_printk(KERN_ERR "es1688: can't grab port 0x%lx\n", port + 4); snd_es1688_free(chip); return -EBUSY; } if (request_irq(irq, snd_es1688_interrupt, SA_INTERRUPT, "ES1688", (void *) chip)) { + snd_printk(KERN_ERR "es1688: can't grab IRQ %d\n", irq); snd_es1688_free(chip); return -EBUSY; } chip->irq = irq; if (request_dma(dma8, "ES1688")) { + snd_printk(KERN_ERR "es1688: can't grab DMA8 %d\n", dma8); snd_es1688_free(chip); return -EBUSY; } diff -Nru a/sound/isa/es18xx.c b/sound/isa/es18xx.c --- a/sound/isa/es18xx.c Mon Feb 2 22:07:56 2004 +++ b/sound/isa/es18xx.c Mon Feb 2 22:07:56 2004 @@ -1471,8 +1471,10 @@ chip->ctrl_port = inb(chip->port + 0x05) << 8; chip->ctrl_port += inb(chip->port + 0x05); - if ((chip->res_ctrl_port = request_region(chip->ctrl_port, 8, "ES18xx - CTRL")) == NULL) + if ((chip->res_ctrl_port = request_region(chip->ctrl_port, 8, "ES18xx - CTRL")) == NULL) { + snd_printk(KERN_ERR PFX "unable go grab port 0x%lx\n", chip->ctrl_port); return -EBUSY; + } return 0; } @@ -2056,9 +2058,12 @@ return -ENOMEM; acard = (struct snd_audiodrive *)card->private_data; #ifdef CONFIG_PNP - if (isapnp[dev] && (err = snd_audiodrive_pnp(dev, acard, pcard, pid)) < 0) { - snd_card_free(card); - return err; + if (isapnp[dev]) { + if ((err = snd_audiodrive_pnp(dev, acard, pcard, pid)) < 0) { + snd_card_free(card); + return err; + } + snd_card_set_dev(card, &pcard->card->dev); } #endif @@ -2096,6 +2101,20 @@ snd_card_free(card); return err; } + + sprintf(card->driver, "ES%x", chip->version); + sprintf(card->shortname, "ESS AudioDrive ES%x", chip->version); + if (xdma1 != xdma2) + sprintf(card->longname, "%s at 0x%lx, irq %d, dma1 %d, dma2 %d", + card->shortname, + chip->port, + xirq, xdma1, xdma2); + else + sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", + card->shortname, + chip->port, + xirq, xdma1); + if ((err = snd_es18xx_pcm(chip, 0, NULL)) < 0) { snd_card_free(card); return err; @@ -2137,18 +2156,6 @@ card->power_state_private_data = chip; } #endif - sprintf(card->driver, "ES%x", chip->version); - sprintf(card->shortname, "ESS AudioDrive ES%x", chip->version); - if (xdma1 != xdma2) - sprintf(card->longname, "%s at 0x%lx, irq %d, dma1 %d, dma2 %d", - card->shortname, - chip->port, - xirq, xdma1, xdma2); - else - sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", - card->shortname, - chip->port, - xirq, xdma1); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; @@ -2286,9 +2293,9 @@ get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && get_option(&str,&pnp) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && get_option(&str,&dma2[nr_dev]) == 2); diff -Nru a/sound/isa/gus/gus_irq.c b/sound/isa/gus/gus_irq.c --- a/sound/isa/gus/gus_irq.c Mon Feb 2 22:07:58 2004 +++ b/sound/isa/gus/gus_irq.c Mon Feb 2 22:07:58 2004 @@ -136,7 +136,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(gus->card, "gusirq", &entry)) - snd_info_set_text_ops(entry, gus, snd_gus_irq_info_read); + snd_info_set_text_ops(entry, gus, 1024, snd_gus_irq_info_read); } #endif diff -Nru a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c --- a/sound/isa/gus/gus_main.c Mon Feb 2 22:07:55 2004 +++ b/sound/isa/gus/gus_main.c Mon Feb 2 22:07:55 2004 @@ -178,25 +178,30 @@ gus->gf1.reg_timerdata = GUSP(gus, TIMERDATA); /* allocate resources */ if ((gus->gf1.res_port1 = request_region(port, 16, "GUS GF1 (Adlib/SB)")) == NULL) { + snd_printk(KERN_ERR "gus: can't grab SB port 0x%lx\n", port); snd_gus_free(gus); return -EBUSY; } if ((gus->gf1.res_port2 = request_region(port + 0x100, 12, "GUS GF1 (Synth)")) == NULL) { + snd_printk(KERN_ERR "gus: can't grab synth port 0x%lx\n", port + 0x100); snd_gus_free(gus); return -EBUSY; } if (irq >= 0 && request_irq(irq, snd_gus_interrupt, SA_INTERRUPT, "GUS GF1", (void *) gus)) { + snd_printk(KERN_ERR "gus: can't grab irq %d\n", irq); snd_gus_free(gus); return -EBUSY; } gus->gf1.irq = irq; if (request_dma(dma1, "GUS - 1")) { + snd_printk(KERN_ERR "gus: can't grab DMA1 %d\n", dma1); snd_gus_free(gus); return -EBUSY; } gus->gf1.dma1 = dma1; if (dma2 >= 0 && dma1 != dma2) { if (request_dma(dma2, "GUS - 2")) { + snd_printk(KERN_ERR "gus: can't grab DMA2 %d\n", dma2); snd_gus_free(gus); return -EBUSY; } diff -Nru a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c --- a/sound/isa/gus/gus_mem.c Mon Feb 2 22:07:56 2004 +++ b/sound/isa/gus/gus_mem.c Mon Feb 2 22:07:56 2004 @@ -265,7 +265,7 @@ return -ENOMEM; #ifdef CONFIG_SND_DEBUG if (! snd_card_proc_new(gus->card, "gusmem", &entry)) { - snd_info_set_text_ops(entry, gus, snd_gf1_mem_info_read); + snd_info_set_text_ops(entry, gus, 1024, snd_gf1_mem_info_read); entry->c.text.read_size = 256 * 1024; } #endif diff -Nru a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c --- a/sound/isa/gus/gus_pcm.c Mon Feb 2 22:07:56 2004 +++ b/sound/isa/gus/gus_pcm.c Mon Feb 2 22:07:56 2004 @@ -334,9 +334,11 @@ snd_gf1_poke(gus, pos++, *buf++ ^ invert); } } - schedule_timeout(1); - if (signal_pending(current)) - return -EAGAIN; + if (count > 0 && !in_interrupt()) { + schedule_timeout(1); + if (signal_pending(current)) + return -EAGAIN; + } } return 0; } @@ -813,6 +815,15 @@ .put = snd_gf1_pcm_volume_put }; +static snd_kcontrol_new_t snd_gf1_pcm_volume_control1 = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "GPCM Playback Volume", + .info = snd_gf1_pcm_volume_info, + .get = snd_gf1_pcm_volume_get, + .put = snd_gf1_pcm_volume_put +}; + static snd_pcm_ops_t snd_gf1_pcm_playback_ops = { .open = snd_gf1_pcm_playback_open, .close = snd_gf1_pcm_playback_close, @@ -880,7 +891,11 @@ strcat(pcm->name, " (synth)"); gus->pcm = pcm; - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control, gus))) < 0) + if (gus->codec_flag) + kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control1, gus); + else + kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control, gus); + if ((err = snd_ctl_add(card, kctl)) < 0) return err; kctl->id.index = control_index; diff -Nru a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c --- a/sound/isa/gus/gusclassic.c Mon Feb 2 22:07:58 2004 +++ b/sound/isa/gus/gusclassic.c Mon Feb 2 22:07:58 2004 @@ -284,7 +284,7 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && get_option(&str,&dma2[nr_dev]) == 2 && diff -Nru a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c --- a/sound/isa/gus/gusextreme.c Mon Feb 2 22:07:57 2004 +++ b/sound/isa/gus/gusextreme.c Mon Feb 2 22:07:57 2004 @@ -417,9 +417,9 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&gf1_port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&gf1_port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&gf1_irq[nr_dev]) == 2 && get_option(&str,&mpu_irq[nr_dev]) == 2 && diff -Nru a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c --- a/sound/isa/gus/gusmax.c Mon Feb 2 22:07:57 2004 +++ b/sound/isa/gus/gusmax.c Mon Feb 2 22:07:57 2004 @@ -424,7 +424,7 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && get_option(&str,&dma2[nr_dev]) == 2 && diff -Nru a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c --- a/sound/isa/gus/interwave.c Mon Feb 2 22:07:57 2004 +++ b/sound/isa/gus/interwave.c Mon Feb 2 22:07:57 2004 @@ -229,12 +229,14 @@ break; port += 0x10; } - if (port > 0x380) - return -ENODEV; } else { - if ((iwcard->i2c_res = request_region(port, 1, "InterWave (I2C bus)")) != NULL) - return -ENODEV; + iwcard->i2c_res = request_region(port, 1, "InterWave (I2C bus)"); } + if (iwcard->i2c_res == NULL) { + snd_printk(KERN_ERR "interwave: can't grab i2c bus port\n"); + return -ENODEV; + } + sprintf(name, "InterWave-%i", card->number); if ((err = snd_i2c_bus_create(card, name, NULL, &bus)) < 0) return err; @@ -626,7 +628,7 @@ return -ENOENT; } port[dev] = pnp_port_start(pdev, 0); - dma1[dev] = pnp_dma(pdev, 1); + dma1[dev] = pnp_dma(pdev, 0); if (dma2[dev] >= 0) dma2[dev] = pnp_dma(pdev, 1); irq[dev] = pnp_irq(pdev, 0); @@ -699,9 +701,12 @@ iwcard->irq = -1; card->private_free = snd_interwave_free; #ifdef CONFIG_PNP - if (isapnp[dev] && snd_interwave_pnp(dev, iwcard, pcard, pid)) { - snd_card_free(card); - return -ENODEV; + if (isapnp[dev]) { + if (snd_interwave_pnp(dev, iwcard, pcard, pid)) { + snd_card_free(card); + return -ENODEV; + } + snd_card_set_dev(card, &pcard->card->dev); } #endif xirq = irq[dev]; @@ -994,9 +999,9 @@ get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && get_option(&str,&pnp) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && #ifdef SNDRV_STB - get_option(&str,(int *)&port_tc[nr_dev]) == 2 && + get_option_long(&str,&port_tc[nr_dev]) == 2 && #endif get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && diff -Nru a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c --- a/sound/isa/opl3sa2.c Mon Feb 2 22:07:58 2004 +++ b/sound/isa/opl3sa2.c Mon Feb 2 22:07:58 2004 @@ -236,8 +236,10 @@ card = chip->card; port = chip->port; - if ((chip->res_port = request_region(port, 2, "OPL3-SA control")) == NULL) + if ((chip->res_port = request_region(port, 2, "OPL3-SA control")) == NULL) { + snd_printk(KERN_ERR "opl3sa2: can't grab port 0x%lx\n", port); return -EBUSY; + } // snd_printk("REG 0A = 0x%x\n", snd_opl3sa2_read(chip, 0x0a)); chip->version = 0; tmp = snd_opl3sa2_read(chip, OPL3SA2_MISC); @@ -757,8 +759,11 @@ if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) goto __error; #ifdef CONFIG_PNP - if (isapnp[dev] && (err = snd_opl3sa2_pnp(dev, chip, pcard, pid)) < 0) - goto __error; + if (isapnp[dev]) { + if ((err = snd_opl3sa2_pnp(dev, chip, pcard, pid)) < 0) + goto __error; + snd_card_set_dev(card, &pcard->card->dev); + } #endif chip->ymode = opl3sa3_ymode[dev] & 0x03 ; /* initialise this card from supplied (or default) parameter*/ chip->card = card; @@ -771,6 +776,7 @@ if ((err = snd_opl3sa2_detect(chip)) < 0) goto __error; if (request_irq(xirq, snd_opl3sa2_interrupt, SA_INTERRUPT, "OPL3-SA2/3", (void *)chip)) { + snd_printk(KERN_ERR "opl3sa2: can't grab IRQ %d\n", xirq); err = -ENODEV; goto __error; } @@ -945,11 +951,11 @@ get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && get_option(&str,&pnp) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&sb_port[nr_dev]) == 2 && - get_option(&str,(int *)&wss_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && - get_option(&str,(int *)&midi_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&sb_port[nr_dev]) == 2 && + get_option_long(&str,&wss_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && + get_option_long(&str,&midi_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && get_option(&str,&dma2[nr_dev]) == 2 && diff -Nru a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c --- a/sound/isa/opti9xx/opti92x-ad1848.c Mon Feb 2 22:07:55 2004 +++ b/sound/isa/opti9xx/opti92x-ad1848.c Mon Feb 2 22:07:55 2004 @@ -543,11 +543,11 @@ __skip_base: switch (chip->irq) { -#ifdef OPTi93X +//#ifdef OPTi93X case 5: irq_bits = 0x05; break; -#endif /* OPTi93X */ +//#endif /* OPTi93X */ case 7: irq_bits = 0x01; break; @@ -604,6 +604,7 @@ __skip_resources: if (chip->hardware > OPTi9XX_HW_82C928) { switch (chip->mpu_port) { + case 0: case -1: break; case 0x300: @@ -644,7 +645,7 @@ } snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), - (chip->mpu_port == -1) ? 0x00 : + (chip->mpu_port <= 0) ? 0x00 : 0x80 | mpu_port_bits << 5 | mpu_irq_bits << 3, 0xf8); } @@ -1304,23 +1305,27 @@ codec->dma2 = -1; if ((codec->res_port = request_region(chip->wss_base + 4, 4, "OPTI93x CODEC")) == NULL) { + snd_printk(KERN_ERR "opti9xx: can't grab port 0x%lx\n", chip->wss_base + 4); snd_opti93x_free(codec); return -EBUSY; } if (request_dma(dma1, "OPTI93x - 1")) { + snd_printk(KERN_ERR "opti9xx: can't grab DMA1 %d\n", dma1); snd_opti93x_free(codec); return -EBUSY; } codec->dma1 = chip->dma1; if (request_dma(dma2, "OPTI93x - 2")) { + snd_printk(KERN_ERR "opti9xx: can't grab DMA2 %d\n", dma2); snd_opti93x_free(codec); return -EBUSY; } codec->dma2 = chip->dma2; if (request_irq(chip->irq, snd_opti93x_interrupt, SA_INTERRUPT, DRIVER_NAME" - WSS", codec)) { - snd_opti93x_free(codec); - return -EBUSY; + snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq); + snd_opti93x_free(codec); + return -EBUSY; } codec->card = card; @@ -1734,15 +1739,23 @@ #if defined(CS4231) || defined(OPTi93X) if (dma2 != SNDRV_AUTO_DMA) pnp_resource_change(&cfg->dma_resource[1], dma2, 1); +#else +#ifdef snd_opti9xx_fixup_dma2 + snd_opti9xx_fixup_dma2(pdev); +#endif #endif /* CS4231 || OPTi93X */ - if (fm_port != SNDRV_AUTO_PORT) +#ifdef OPTi93X + if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[1], fm_port, 4); - +#else + if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) + pnp_resource_change(&cfg->port_resource[2], fm_port, 4); +#endif if (pnp_manual_config_dev(pdev, cfg, 0) < 0) snd_printk(KERN_ERR "AUDIO the requested resources are invalid, using auto config\n"); err = pnp_activate_dev(pdev); if (err < 0) { - snd_printk(KERN_ERR "AUDIO pnp configure failure\n"); + snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err); kfree(cfg); return err; } @@ -1762,7 +1775,7 @@ #endif /* CS4231 || OPTi93X */ pdev = chip->devmpu; - if (pdev) { + if (pdev && mpu_port > 0) { pnp_init_resource_table(cfg); if (mpu_port != SNDRV_AUTO_PORT) @@ -1960,6 +1973,7 @@ } if (hw <= OPTi9XX_HW_82C930) chip->mc_base -= 0x80; + snd_card_set_dev(card, &pcard->card->dev); } else { #endif /* CONFIG_PNP */ if ((error = snd_card_opti9xx_detect(card, chip)) < 0) { @@ -1985,9 +1999,6 @@ chip->dma2 = dma2; #endif -#ifdef CONFIG_PNP - if (!isapnp) { -#endif if (chip->wss_base == SNDRV_AUTO_PORT) { if ((chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4)) < 0) { snd_card_free(card); @@ -1995,6 +2006,9 @@ return -EBUSY; } } +#ifdef CONFIG_PNP + if (!isapnp) { +#endif if (chip->mpu_port == SNDRV_AUTO_PORT) { if ((chip->mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2)) < 0) { snd_card_free(card); @@ -2092,8 +2106,19 @@ return error; } #endif + strcpy(card->driver, chip->name); + sprintf(card->shortname, "OPTi %s", card->driver); +#if defined(CS4231) || defined(OPTi93X) + sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d", + card->shortname, pcm->name, chip->wss_base + 4, + chip->irq, chip->dma1, chip->dma2); +#else + sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d", + card->shortname, pcm->name, chip->wss_base + 4, + chip->irq, chip->dma1); +#endif /* CS4231 || OPTi93X */ - if (chip->mpu_port <= 0) + if (chip->mpu_port <= 0 || chip->mpu_port == SNDRV_AUTO_PORT) rmidi = NULL; else if ((error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, @@ -2101,7 +2126,7 @@ &rmidi))) snd_printk("no MPU-401 device at 0x%lx?\n", chip->mpu_port); - if (chip->fm_port > 0) { + if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) { opl3_t *opl3 = NULL; #ifndef OPTi93X if (chip->hardware == OPTi9XX_HW_82C928 || @@ -2145,17 +2170,6 @@ } } - strcpy(card->driver, chip->name); - sprintf(card->shortname, "OPTi %s", card->driver); -#if defined(CS4231) || defined(OPTi93X) - sprintf(card->longname, "%s soundcard, %s at 0x%lx, irq %d, dma %d&%d", - card->shortname, pcm->name, chip->wss_base + 4, - chip->irq, chip->dma1, chip->dma2); -#else - sprintf(card->longname, "%s soundcard, %s at 0x%lx, irq %d, dma %d", - card->shortname, pcm->name, chip->wss_base + 4, - chip->irq, chip->dma1); -#endif /* CS4231 || OPTi93X */ if ((error = snd_card_register(card))) { snd_card_free(card); return error; @@ -2240,9 +2254,9 @@ get_option(&str,&index) == 2 && get_id(&str,&id) == 2 && get_option(&str,&pnp) == 2 && - get_option(&str,(int *)&port) == 2 && - get_option(&str,(int *)&mpu_port) == 2 && - get_option(&str,(int *)&fm_port) == 2 && + get_option_long(&str,&port) == 2 && + get_option_long(&str,&mpu_port) == 2 && + get_option_long(&str,&fm_port) == 2 && get_option(&str,&irq) == 2 && get_option(&str,&mpu_irq) == 2 && get_option(&str,&dma1) == 2 diff -Nru a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c --- a/sound/isa/sb/emu8000.c Mon Feb 2 22:07:56 2004 +++ b/sound/isa/sb/emu8000.c Mon Feb 2 22:07:56 2004 @@ -655,7 +655,7 @@ }; /*exported*/ int -snd_emu8000_load_chorus_fx(emu8000_t *emu, int mode, const void *buf, long len) +snd_emu8000_load_chorus_fx(emu8000_t *emu, int mode, const void __user *buf, long len) { soundfont_chorus_fx_t rec; if (mode < SNDRV_EMU8000_CHORUS_PREDEFINED || mode >= SNDRV_EMU8000_CHORUS_NUMBERS) { @@ -782,7 +782,7 @@ }; /*exported*/ int -snd_emu8000_load_reverb_fx(emu8000_t *emu, int mode, const void *buf, long len) +snd_emu8000_load_reverb_fx(emu8000_t *emu, int mode, const void __user *buf, long len) { soundfont_reverb_fx_t rec; @@ -1044,8 +1044,10 @@ __error: for (i = 0; i < EMU8000_NUM_CONTROLS; i++) { + down_write(&card->controls_rwsem); if (emu->controls[i]) snd_ctl_remove(card, emu->controls[i]); + up_write(&card->controls_rwsem); } return err; } @@ -1110,6 +1112,7 @@ if (!(hw->res_port1 = request_region(hw->port1, 4, "Emu8000-1")) || !(hw->res_port2 = request_region(hw->port2, 4, "Emu8000-2")) || !(hw->res_port3 = request_region(hw->port3, 4, "Emu8000-3"))) { + snd_printk(KERN_ERR "sbawe: can't grab ports 0x%lx, 0x%lx, 0x%lx\n", hw->port1, hw->port2, hw->port3); snd_emu8000_free(hw); return -EBUSY; } diff -Nru a/sound/isa/sb/emu8000_callback.c b/sound/isa/sb/emu8000_callback.c --- a/sound/isa/sb/emu8000_callback.c Mon Feb 2 22:07:56 2004 +++ b/sound/isa/sb/emu8000_callback.c Mon Feb 2 22:07:56 2004 @@ -36,7 +36,7 @@ #ifdef CONFIG_SND_SEQUENCER_OSS static int oss_ioctl(snd_emux_t *emu, int cmd, int p1, int p2); #endif -static int load_fx(snd_emux_t *emu, int type, int mode, const void *buf, long len); +static int load_fx(snd_emux_t *emu, int type, int mode, const void __user *buf, long len); static void set_pitch(emu8000_t *hw, snd_emux_voice_t *vp); static void set_volume(emu8000_t *hw, snd_emux_voice_t *vp); @@ -523,7 +523,7 @@ */ static int -load_fx(snd_emux_t *emu, int type, int mode, const void *buf, long len) +load_fx(snd_emux_t *emu, int type, int mode, const void __user *buf, long len) { emu8000_t *hw; hw = snd_magic_cast(emu8000_t, emu->hw, return -EINVAL); diff -Nru a/sound/isa/sb/emu8000_local.h b/sound/isa/sb/emu8000_local.h --- a/sound/isa/sb/emu8000_local.h Mon Feb 2 22:07:57 2004 +++ b/sound/isa/sb/emu8000_local.h Mon Feb 2 22:07:57 2004 @@ -32,7 +32,7 @@ #define NELEM(arr) (sizeof(arr)/sizeof((arr)[0])) /* emu8000_patch.c */ -int snd_emu8000_sample_new(snd_emux_t *rec, snd_sf_sample_t *sp, snd_util_memhdr_t *hdr, const void *data, long count); +int snd_emu8000_sample_new(snd_emux_t *rec, snd_sf_sample_t *sp, snd_util_memhdr_t *hdr, const void __user *data, long count); int snd_emu8000_sample_free(snd_emux_t *rec, snd_sf_sample_t *sp, snd_util_memhdr_t *hdr); void snd_emu8000_sample_reset(snd_emux_t *rec); diff -Nru a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c --- a/sound/isa/sb/emu8000_patch.c Mon Feb 2 22:07:55 2004 +++ b/sound/isa/sb/emu8000_patch.c Mon Feb 2 22:07:55 2004 @@ -82,7 +82,7 @@ * 8bit samples etc. */ static unsigned short -read_word(const void *buf, int offset, int mode) +read_word(const void __user *buf, int offset, int mode) { unsigned short c; if (mode & SNDRV_SFNT_SAMPLE_8BITS) { @@ -146,7 +146,7 @@ */ int snd_emu8000_sample_new(snd_emux_t *rec, snd_sf_sample_t *sp, - snd_util_memhdr_t *hdr, const void *data, long count) + snd_util_memhdr_t *hdr, const void __user *data, long count) { int i; int rc; diff -Nru a/sound/isa/sb/emu8000_synth.c b/sound/isa/sb/emu8000_synth.c --- a/sound/isa/sb/emu8000_synth.c Mon Feb 2 22:07:57 2004 +++ b/sound/isa/sb/emu8000_synth.c Mon Feb 2 22:07:57 2004 @@ -71,6 +71,7 @@ emu->midi_ports = hw->seq_ports < 2 ? hw->seq_ports : 2; /* number of virmidi ports */ emu->midi_devidx = 1; emu->linear_panning = 1; + emu->hwdep_idx = 2; /* FIXED */ if (snd_emux_register(emu, dev->card, hw->index, "Emu8000") < 0) { snd_emux_free(emu); diff -Nru a/sound/isa/sb/es968.c b/sound/isa/sb/es968.c --- a/sound/isa/sb/es968.c Mon Feb 2 22:07:56 2004 +++ b/sound/isa/sb/es968.c Mon Feb 2 22:07:56 2004 @@ -149,6 +149,7 @@ snd_card_free(card); return error; } + snd_card_set_dev(card, &pcard->card->dev); if ((error = snd_sbdsp_create(card, port[dev], irq[dev], @@ -257,7 +258,7 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma8[nr_dev]) == 2); nr_dev++; diff -Nru a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c --- a/sound/isa/sb/sb16.c Mon Feb 2 22:07:58 2004 +++ b/sound/isa/sb/sb16.c Mon Feb 2 22:07:58 2004 @@ -77,7 +77,7 @@ static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; #endif static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260,0x280 */ -static long mpu_port[SNDRV_CARDS] = {0x330, 0x300,[2 ... (SNDRV_CARDS - 1)] = -1}; +static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x330,0x300 */ static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; #ifdef SNDRV_SBAWE_EMU8000 static long awe_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; @@ -157,6 +157,8 @@ static snd_card_t *snd_sb16_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; +#ifdef CONFIG_PNP + static struct pnp_card_device_id snd_sb16_pnpids[] = { #ifndef SNDRV_SBAWE /* Sound Blaster 16 PnP */ @@ -250,6 +252,8 @@ MODULE_DEVICE_TABLE(pnp_card, snd_sb16_pnpids); +#endif /* CONFIG_PNP */ + #ifdef SNDRV_SBAWE_EMU8000 #define DRIVER_NAME "snd-card-sbawe" #else @@ -393,6 +397,7 @@ snd_card_free(card); return err; } + snd_card_set_dev(card, &pcard->card->dev); } #endif @@ -465,7 +470,23 @@ return -ENXIO; } - if (chip->mpu_port) { + strcpy(card->driver, +#ifdef SNDRV_SBAWE_EMU8000 + awe_port[dev] > 0 ? "SB AWE" : +#endif + "SB16"); + strcpy(card->shortname, chip->name); + sprintf(card->longname, "%s at 0x%lx, irq %i, dma ", + chip->name, + chip->port, + xirq); + if (xdma8 >= 0) + sprintf(card->longname + strlen(card->longname), "%d", xdma8); + if (xdma16 >= 0) + sprintf(card->longname + strlen(card->longname), "%s%d", + xdma8 >= 0 ? "&" : "", xdma16); + + if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SB, chip->mpu_port, 0, xirq, 0, &chip->rmidi)) < 0) { @@ -475,10 +496,15 @@ chip->rmidi_callback = snd_mpu401_uart_interrupt; } - if (fm_port[dev] > 0) { +#ifdef SNDRV_SBAWE_EMU8000 + if (awe_port[dev] == SNDRV_AUTO_PORT) + awe_port[dev] = 0; /* disable */ +#endif + + 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_OPL3, - fm_port[dev] == port[dev] || fm_port[dev] == 0x388, + acard->fm_res != NULL || fm_port[dev] == port[dev], &opl3) < 0) { snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n", fm_port[dev], fm_port[dev] + 2); @@ -530,21 +556,6 @@ (mic_agc[dev] ? 0x00 : 0x01)); spin_unlock_irqrestore(&chip->mixer_lock, flags); - strcpy(card->driver, -#ifdef SNDRV_SBAWE_EMU8000 - awe_port[dev] > 0 ? "SB AWE" : -#endif - "SB16"); - strcpy(card->shortname, chip->name); - sprintf(card->longname, "%s at 0x%lx, irq %i, dma ", - chip->name, - chip->port, - xirq); - if (xdma8 >= 0) - sprintf(card->longname + strlen(card->longname), "%d", xdma8); - if (xdma16 >= 0) - sprintf(card->longname + strlen(card->longname), "%s%d", - xdma8 >= 0 ? "&" : "", xdma16); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; @@ -696,9 +707,9 @@ get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && get_option(&str,&pnp) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma8[nr_dev]) == 2 && get_option(&str,&dma16[nr_dev]) == 2 && @@ -709,7 +720,7 @@ #endif #ifdef SNDRV_SBAWE_EMU8000 && - get_option(&str,(int *)&awe_port[nr_dev]) == 2 && + get_option_long(&str,&awe_port[nr_dev]) == 2 && get_option(&str,&seq_ports[nr_dev]) == 2 #endif ); diff -Nru a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c --- a/sound/isa/sb/sb16_csp.c Mon Feb 2 22:07:58 2004 +++ b/sound/isa/sb/sb16_csp.c Mon Feb 2 22:07:58 2004 @@ -1059,10 +1059,12 @@ card = p->chip->card; + down_write(&card->controls_rwsem); if (p->qsound_switch) snd_ctl_remove(card, p->qsound_switch); if (p->qsound_space) snd_ctl_remove(card, p->qsound_space); + up_write(&card->controls_rwsem); /* cancel pending transfer of QSound parameters */ spin_lock_irqsave (&p->q_lock, flags); @@ -1105,7 +1107,7 @@ snd_info_entry_t *entry; sprintf(name, "cspD%d", device); if (! snd_card_proc_new(p->chip->card, name, &entry)) - snd_info_set_text_ops(entry, p, info_read); + snd_info_set_text_ops(entry, p, 1024, info_read); return 0; } diff -Nru a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c --- a/sound/isa/sb/sb8.c Mon Feb 2 22:07:57 2004 +++ b/sound/isa/sb/sb8.c Mon Feb 2 22:07:57 2004 @@ -242,7 +242,7 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&port[nr_dev]) == 2 && + get_option_long(&str,&port[nr_dev]) == 2 && get_option(&str,&irq[nr_dev]) == 2 && get_option(&str,&dma8[nr_dev]) == 2); nr_dev++; diff -Nru a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c --- a/sound/isa/sb/sb_common.c Mon Feb 2 22:07:58 2004 +++ b/sound/isa/sb/sb_common.c Mon Feb 2 22:07:58 2004 @@ -185,10 +185,6 @@ release_resource(chip->res_port); kfree_nocheck(chip->res_port); } - if (chip->res_alt_port) { - release_resource(chip->res_alt_port); - kfree_nocheck(chip->res_alt_port); - } if (chip->irq >= 0) free_irq(chip->irq, (void *) chip); #ifdef CONFIG_ISA @@ -243,6 +239,7 @@ if (request_irq(irq, irq_handler, hardware == SB_HW_ALS4000 ? SA_INTERRUPT | SA_SHIRQ : SA_INTERRUPT, "SoundBlaster", (void *) chip)) { + snd_printk(KERN_ERR "sb: can't grab irq %d\n", irq); snd_sbdsp_free(chip); return -EBUSY; } @@ -252,12 +249,14 @@ goto __skip_allocation; if ((chip->res_port = request_region(port, 16, "SoundBlaster")) == NULL) { + snd_printk(KERN_ERR "sb: can't grab port 0x%lx\n", port); snd_sbdsp_free(chip); return -EBUSY; } #ifdef CONFIG_ISA if (dma8 >= 0 && request_dma(dma8, "SoundBlaster - 8bit")) { + snd_printk(KERN_ERR "sb: can't grab DMA8 %d\n", dma8); snd_sbdsp_free(chip); return -EBUSY; } @@ -267,6 +266,7 @@ /* no duplex */ dma16 = -1; } else if (request_dma(dma16, "SoundBlaster - 16bit")) { + snd_printk(KERN_ERR "sb: can't grab DMA16 %d\n", dma16); snd_sbdsp_free(chip); return -EBUSY; } diff -Nru a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c --- a/sound/isa/sgalaxy.c Mon Feb 2 22:07:58 2004 +++ b/sound/isa/sgalaxy.c Mon Feb 2 22:07:58 2004 @@ -150,8 +150,10 @@ if (tmp < 0) return -EINVAL; - if (request_irq(irq, snd_sgalaxy_dummy_interrupt, SA_INTERRUPT, "sgalaxy", NULL)) + if (request_irq(irq, snd_sgalaxy_dummy_interrupt, SA_INTERRUPT, "sgalaxy", NULL)) { + snd_printk(KERN_ERR "sgalaxy: can't grab irq %d\n", irq); return -EIO; + } outb(tmp | 0x40, port); tmp1 = dma_bits[dma % 4]; @@ -341,10 +343,10 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&sbport[nr_dev]) == 2 && - get_option(&str,(int *)&wssport[nr_dev]) == 2 && - get_option(&str,(int *)&irq[nr_dev]) == 2 && - get_option(&str,(int *)&dma1[nr_dev]) == 2); + get_option_long(&str,&sbport[nr_dev]) == 2 && + get_option_long(&str,&wssport[nr_dev]) == 2 && + get_option(&str,&irq[nr_dev]) == 2 && + get_option(&str,&dma1[nr_dev]) == 2); nr_dev++; return 1; } diff -Nru a/sound/isa/sscape.c b/sound/isa/sscape.c --- a/sound/isa/sscape.c Mon Feb 2 22:07:55 2004 +++ b/sound/isa/sscape.c Mon Feb 2 22:07:55 2004 @@ -31,6 +31,7 @@ #include #include #include +#define SNDRV_GET_ID #include #include @@ -616,10 +617,10 @@ */ if (get_user(code, &mc->code)) return -EFAULT; - if ((err = verify_area(VERIFY_READ, code, 65536)) != 0) + if ((err = verify_area(VERIFY_READ, code, SSCAPE_MICROCODE_SIZE)) != 0) return err; - if ((ret = upload_dma_data(sscape, code, 65536)) == 0) { + if ((ret = upload_dma_data(sscape, code, SSCAPE_MICROCODE_SIZE)) == 0) { snd_printk(KERN_INFO "sscape: MIDI firmware loaded\n"); } @@ -1173,6 +1174,7 @@ * can detect and control this hardware ... */ if ((io_res = request_region(params->port, 8, "SoundScape")) == NULL) { + snd_printk(KERN_ERR "sscape: can't grab port 0x%x\n", params->port); return -EBUSY; } @@ -1180,6 +1182,7 @@ * Grab both DMA channels (OK, only one for now) ... */ if ((err = request_dma(params->dma1, "SoundScape")) < 0) { + snd_printk(KERN_ERR "sscape: can't grab DMA %d\n", params->dma1); goto _release_region; } @@ -1406,6 +1409,7 @@ ret = create_sscape(this, &card); if (ret < 0) return ret; + snd_card_set_dev(card, &pcard->card->dev); pnp_set_card_drvdata(pcard, card); ++sscape_cards; ++idx; @@ -1538,8 +1542,8 @@ return 0; (void)((get_option(&str, &index[nr_dev]) == 2) && - (get_option(&str, (int*)&id[nr_dev]) == 2) && - (get_option(&str, (int*)&port[nr_dev]) == 2) && + (get_id(&str, &id[nr_dev]) == 2) && + (get_option_long(&str, &port[nr_dev]) == 2) && (get_option(&str, &irq[nr_dev]) == 2) && (get_option(&str, &mpu_irq[nr_dev]) == 2) && (get_option(&str, &dma[nr_dev]) == 2)); diff -Nru a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c --- a/sound/isa/wavefront/wavefront.c Mon Feb 2 22:07:57 2004 +++ b/sound/isa/wavefront/wavefront.c Mon Feb 2 22:07:58 2004 @@ -418,13 +418,6 @@ snd_hwdep_t *fx_processor; int hw_dev = 0, midi_dev = 0, err; - if (cs4232_mpu_port[dev] < 0) - cs4232_mpu_port[dev] = SNDRV_AUTO_PORT; - if (fm_port[dev] < 0) - fm_port[dev] = SNDRV_AUTO_PORT; - if (ics2115_port[dev] < 0) - ics2115_port[dev] = SNDRV_AUTO_PORT; - #ifdef CONFIG_PNP if (!isapnp[dev]) { #endif @@ -456,12 +449,15 @@ card->private_free = snd_wavefront_free; #ifdef CONFIG_PNP - if (isapnp[dev] && snd_wavefront_pnp (dev, acard, pcard, pid) < 0) { - if (cs4232_pcm_port[dev] == SNDRV_AUTO_PORT) { - snd_printk ("isapnp detection failed\n"); - snd_card_free (card); - return -ENODEV; + if (isapnp[dev]) { + if (snd_wavefront_pnp (dev, acard, pcard, pid) < 0) { + if (cs4232_pcm_port[dev] == SNDRV_AUTO_PORT) { + snd_printk ("isapnp detection failed\n"); + snd_card_free (card); + return -ENODEV; + } } + snd_card_set_dev(card, &pcard->card->dev); } #endif /* CONFIG_PNP */ @@ -490,7 +486,7 @@ /* ---------- OPL3 synth --------- */ - if (fm_port[dev] != SNDRV_AUTO_PORT) { + if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { opl3_t *opl3; if ((err = snd_opl3_create(card, @@ -561,7 +557,7 @@ /* ------ ICS2115 internal MIDI ------------ */ - if (ics2115_port[dev] >= 0 && ics2115_port[dev] != SNDRV_AUTO_PORT) { + if (ics2115_port[dev] > 0 && ics2115_port[dev] != SNDRV_AUTO_PORT) { ics2115_internal_rmidi = snd_wavefront_new_midi (card, midi_dev, @@ -578,7 +574,7 @@ /* ------ ICS2115 external MIDI ------------ */ - if (ics2115_port[dev] >= 0 && ics2115_port[dev] != SNDRV_AUTO_PORT) { + if (ics2115_port[dev] > 0 && ics2115_port[dev] != SNDRV_AUTO_PORT) { ics2115_external_rmidi = snd_wavefront_new_midi (card, midi_dev, @@ -631,7 +627,7 @@ if (dma2[dev] >= 0 && dma2[dev] < 8) sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]); - if (cs4232_mpu_port[dev] != SNDRV_AUTO_PORT) { + if (cs4232_mpu_port[dev] > 0 && cs4232_mpu_port[dev] != SNDRV_AUTO_PORT) { sprintf (card->longname + strlen (card->longname), " MPU-401 0x%lx irq %d", cs4232_mpu_port[dev], @@ -756,13 +752,13 @@ get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && get_option(&str,&isapnp[nr_dev]) == 2 && - get_option(&str,(int *)&cs4232_pcm_port[nr_dev]) == 2 && + get_option_long(&str,&cs4232_pcm_port[nr_dev]) == 2 && get_option(&str,&cs4232_pcm_irq[nr_dev]) == 2 && - get_option(&str,(int *)&cs4232_mpu_port[nr_dev]) == 2 && + get_option_long(&str,&cs4232_mpu_port[nr_dev]) == 2 && get_option(&str,&cs4232_mpu_irq[nr_dev]) == 2 && - get_option(&str,(int *)&ics2115_port[nr_dev]) == 2 && + get_option_long(&str,&ics2115_port[nr_dev]) == 2 && get_option(&str,&ics2115_irq[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 && get_option(&str,&dma1[nr_dev]) == 2 && get_option(&str,&dma2[nr_dev]) == 2 && get_option(&str,&use_cs4232_midi[nr_dev]) == 2); diff -Nru a/sound/pci/ac97/Makefile b/sound/pci/ac97/Makefile --- a/sound/pci/ac97/Makefile Mon Feb 2 22:07:57 2004 +++ b/sound/pci/ac97/Makefile Mon Feb 2 22:07:57 2004 @@ -3,7 +3,7 @@ # Copyright (c) 2001 by Jaroslav Kysela # -snd-ac97-codec-objs := ac97_codec.o ac97_proc.o ac97_patch.o +snd-ac97-codec-objs := ac97_codec.o ac97_pcm.o ac97_proc.o ac97_patch.o snd-ak4531-codec-objs := ak4531_codec.o # Toplevel Module Dependency diff -Nru a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c --- a/sound/pci/ac97/ac97_codec.c Mon Feb 2 22:07:56 2004 +++ b/sound/pci/ac97/ac97_codec.c Mon Feb 2 22:07:56 2004 @@ -101,8 +101,8 @@ { 0x41445362, 0xffffffff, "AD1887", patch_ad1881, NULL }, { 0x41445363, 0xffffffff, "AD1886A", patch_ad1881, NULL }, { 0x41445370, 0xffffffff, "AD1980", patch_ad1980, NULL }, -{ 0x41445372, 0xffffffff, "AD1981A", patch_ad1881, NULL }, -{ 0x41445374, 0xffffffff, "AD1981B", patch_ad1881, NULL }, +{ 0x41445372, 0xffffffff, "AD1981A", patch_ad1981a, NULL }, +{ 0x41445374, 0xffffffff, "AD1981B", patch_ad1981b, NULL }, { 0x41445375, 0xffffffff, "AD1985", patch_ad1985, NULL }, { 0x414c4300, 0xfffffff0, "RL5306", NULL, NULL }, { 0x414c4310, 0xfffffff0, "RL5382", NULL, NULL }, @@ -112,6 +112,8 @@ { 0x414c4721, 0xfffffff0, "ALC650D", patch_alc650, NULL }, { 0x414c4722, 0xfffffff0, "ALC650E", patch_alc650, NULL }, { 0x414c4723, 0xfffffff0, "ALC650F", patch_alc650, NULL }, +{ 0x414c4760, 0xfffffff0, "ALC655", patch_alc655, NULL }, +{ 0x414c4780, 0xfffffff0, "ALC658", patch_alc655, NULL }, { 0x414c4730, 0xffffffff, "ALC101", NULL, NULL }, { 0x414c4740, 0xfffffff0, "ALC202", NULL, NULL }, { 0x414c4750, 0xfffffff0, "ALC250", NULL, NULL }, @@ -139,11 +141,12 @@ { 0x49434551, 0xffffffff, "VT1616", patch_vt1616, NULL }, { 0x49434552, 0xffffffff, "VT1616i", patch_vt1616, NULL }, // VT1616 compatible (chipset integrated) { 0x49544520, 0xffffffff, "IT2226E", NULL, NULL }, +{ 0x49544561, 0xffffffff, "IT2646E", patch_it2646, NULL }, { 0x4e534300, 0xffffffff, "LM4540/43/45/46/48", NULL, NULL }, // only guess --jk { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, { 0x4e534350, 0xffffffff, "LM4550", NULL, NULL }, { 0x50534304, 0xffffffff, "UCB1400", NULL, NULL }, -{ 0x53494c20, 0xffffffe0, "Si3036/8", NULL, NULL }, +{ 0x53494c20, 0xffffffe0, "Si3036/8", NULL, mpatch_si3036 }, { 0x54524102, 0xffffffff, "TR28022", NULL, NULL }, { 0x54524106, 0xffffffff, "TR28026", NULL, NULL }, { 0x54524108, 0xffffffff, "TR28028", patch_tritech_tr28028, NULL }, // added by xin jin [07/09/99] @@ -202,7 +205,7 @@ /* 24 */ "Wolfson Microelectronics 3D Enhancement", /* 25 */ "Delta Integration 3D Enhancement", /* 26 */ "SigmaTel 3D Enhancement", - /* 27 */ "Reserved 27", + /* 27 */ "IC Ensemble/KS Waves", /* 28 */ "Rockwell 3D Stereo Enhancement", /* 29 */ "Reserved 29", /* 30 */ "Reserved 30", @@ -270,7 +273,7 @@ { if (!snd_ac97_valid_reg(ac97, reg)) return; - ac97->write(ac97, reg, value); + ac97->bus->write(ac97, reg, value); } /** @@ -288,7 +291,7 @@ { if (!snd_ac97_valid_reg(ac97, reg)) return 0; - return ac97->read(ac97, reg); + return ac97->bus->read(ac97, reg); } /** @@ -308,7 +311,7 @@ spin_lock(&ac97->reg_lock); ac97->regs[reg] = value; spin_unlock(&ac97->reg_lock); - ac97->write(ac97, reg, value); + ac97->bus->write(ac97, reg, value); set_bit(reg, ac97->reg_accessed); } @@ -335,7 +338,7 @@ if (change) { ac97->regs[reg] = value; spin_unlock(&ac97->reg_lock); - ac97->write(ac97, reg, value); + ac97->bus->write(ac97, reg, value); } else spin_unlock(&ac97->reg_lock); return change; @@ -368,7 +371,7 @@ if (change) { ac97->regs[reg] = new; spin_unlock(&ac97->reg_lock); - ac97->write(ac97, reg, new); + ac97->bus->write(ac97, reg, new); } else spin_unlock(&ac97->reg_lock); return change; @@ -388,11 +391,11 @@ ac97->spec.ad18xx.pcmreg[codec] = new; spin_unlock(&ac97->reg_lock); /* select single codec */ - ac97->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]); + ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]); /* update PCM bits */ - ac97->write(ac97, AC97_PCM, new); + ac97->bus->write(ac97, AC97_PCM, new); /* select all codecs */ - ac97->write(ac97, AC97_AD_SERIAL_CFG, 0x7000); + ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, 0x7000); } else spin_unlock(&ac97->reg_lock); up(&ac97->spec.ad18xx.mutex); @@ -976,9 +979,31 @@ * */ +static int snd_ac97_bus_free(ac97_bus_t *bus) +{ + if (bus) { + snd_ac97_bus_proc_done(bus); + if (bus->pcms) + kfree(bus->pcms); + if (bus->private_free) + bus->private_free(bus); + snd_magic_kfree(bus); + } + return 0; +} + +static int snd_ac97_bus_dev_free(snd_device_t *device) +{ + ac97_bus_t *bus = snd_magic_cast(ac97_bus_t, device->device_data, return -ENXIO); + return snd_ac97_bus_free(bus); +} + static int snd_ac97_free(ac97_t *ac97) { if (ac97) { + snd_ac97_proc_done(ac97); + if (ac97->bus) + ac97->bus->codec[ac97->num] = NULL; if (ac97->private_free) ac97->private_free(ac97); snd_magic_kfree(ac97); @@ -1014,17 +1039,17 @@ } return 0; case AC97_CENTER_LFE_MASTER: /* center */ - if ((ac97->ext_id & 0x40) == 0) + if ((ac97->ext_id & AC97_EI_CDAC) == 0) return 0; break; case AC97_CENTER_LFE_MASTER+1: /* lfe */ - if ((ac97->ext_id & 0x100) == 0) + if ((ac97->ext_id & AC97_EI_LDAC) == 0) return 0; reg = AC97_CENTER_LFE_MASTER; mask = 0x0080; break; case AC97_SURROUND_MASTER: - if ((ac97->ext_id & 0x80) == 0) + if ((ac97->ext_id & AC97_EI_SDAC) == 0) return 0; break; } @@ -1193,7 +1218,7 @@ static int snd_ac97_mixer_build(ac97_t * ac97) { - snd_card_t *card = ac97->card; + snd_card_t *card = ac97->bus->card; snd_kcontrol_t *kctl; int err; unsigned int idx; @@ -1492,6 +1517,12 @@ static int snd_ac97_modem_build(snd_card_t * card, ac97_t * ac97) { /* TODO */ + //printk("AC97_GPIO_CFG = %x\n",snd_ac97_read(ac97,AC97_GPIO_CFG)); + snd_ac97_write(ac97, AC97_GPIO_CFG, 0xffff & ~(AC97_GPIO_LINE1_OH)); + snd_ac97_write(ac97, AC97_GPIO_POLARITY, 0xffff & ~(AC97_GPIO_LINE1_OH)); + snd_ac97_write(ac97, AC97_GPIO_STICKY, 0xffff); + snd_ac97_write(ac97, AC97_GPIO_WAKEUP, 0x0); + snd_ac97_write(ac97, AC97_MISC_AFE, 0x0); return 0; } @@ -1500,7 +1531,7 @@ unsigned short val; unsigned int tmp; - tmp = ((unsigned int)rate * ac97->clock) / 48000; + tmp = ((unsigned int)rate * ac97->bus->clock) / 48000; snd_ac97_write_cache(ac97, reg, tmp & 0xffff); val = snd_ac97_read(ac97, reg); return val == (tmp & 0xffff); @@ -1605,13 +1636,62 @@ } /** - * snd_ac97_mixer - create an AC97 codec component + * snd_ac97_bus - create an AC97 bus component * @card: the card instance + * @_bus: the template of AC97 bus, callbacks and + * the private data. + * @rbus: the pointer to store the new AC97 bus instance. + * + * Creates an AC97 bus component. An ac97_bus_t instance is newly + * allocated and initialized from the template (_bus). + * + * The template must include the valid callbacks (at least read and + * write), the bus number (num), and the private data (private_data). + * The other callbacks, wait and reset, are not mandatory. + * + * The clock is set to 48000. If another clock is needed, set + * bus->clock manually. + * + * The AC97 bus instance is registered as a low-level device, so you don't + * have to release it manually. + * + * Returns zero if successful, or a negative error code on failure. + */ +int snd_ac97_bus(snd_card_t * card, ac97_bus_t * _bus, ac97_bus_t ** rbus) +{ + int err; + ac97_bus_t *bus; + static snd_device_ops_t ops = { + .dev_free = snd_ac97_bus_dev_free, + }; + + snd_assert(card != NULL, return -EINVAL); + snd_assert(_bus != NULL && rbus != NULL, return -EINVAL); + bus = snd_magic_kmalloc(ac97_bus_t, 0, GFP_KERNEL); + if (bus == NULL) + return -ENOMEM; + *bus = *_bus; + bus->card = card; + if (bus->clock == 0) + bus->clock = 48000; + spin_lock_init(&bus->bus_lock); + snd_ac97_bus_proc_init(bus); + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, bus, &ops)) < 0) { + snd_ac97_bus_free(bus); + return err; + } + *rbus = bus; + return 0; +} + +/** + * snd_ac97_mixer - create an Codec97 component + * @bus: the AC97 bus which codec is attached to * @_ac97: the template of ac97, including index, callbacks and * the private data. * @rac97: the pointer to store the new ac97 instance. * - * Creates an AC97 codec component. An ac97_t instance is newly + * Creates an Codec97 component. An ac97_t instance is newly * allocated and initialized from the template (_ac97). The codec * is then initialized by the standard procedure. * @@ -1620,21 +1700,16 @@ * data (private_data). The other callbacks, wait and reset, are not * mandatory. * - * The clock is set to 48000. If another clock is needed, reset - * ac97->clock manually afterwards. - * * The ac97 instance is registered as a low-level device, so you don't * have to release it manually. * - * The MCs (Modem Codecs only) are only detected but valid. The PCM driver - * have to check for MCs using the !ac97_is_audio() function. - * * Returns zero if successful, or a negative error code on failure. */ -int snd_ac97_mixer(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97) +int snd_ac97_mixer(ac97_bus_t * bus, ac97_t * _ac97, ac97_t ** rac97) { int err; ac97_t *ac97; + snd_card_t *card; char name[64]; unsigned long end_time; unsigned int reg; @@ -1644,40 +1719,42 @@ snd_assert(rac97 != NULL, return -EINVAL); *rac97 = NULL; - snd_assert(card != NULL && _ac97 != NULL, return -EINVAL); + snd_assert(bus != NULL && _ac97 != NULL, return -EINVAL); + snd_assert(_ac97->num < 4 && bus->codec[_ac97->num] == NULL, return -EINVAL); + card = bus->card; ac97 = snd_magic_kmalloc(ac97_t, 0, GFP_KERNEL); if (ac97 == NULL) return -ENOMEM; *ac97 = *_ac97; - ac97->card = card; + ac97->bus = bus; + bus->codec[ac97->num] = ac97; spin_lock_init(&ac97->reg_lock); if (ac97->pci) { pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_VENDOR_ID, &ac97->subsystem_vendor); pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_ID, &ac97->subsystem_device); } - if (ac97->reset) { - ac97->reset(ac97); + if (bus->reset) { + bus->reset(ac97); goto __access_ok; } snd_ac97_write(ac97, AC97_RESET, 0); /* reset to defaults */ - if (ac97->wait) - ac97->wait(ac97); + if (bus->wait) + bus->wait(ac97); else { udelay(50); if (ac97_reset_wait(ac97, HZ/2, 0) < 0 && ac97_reset_wait(ac97, HZ/2, 1) < 0) { - snd_printk("AC'97 %d:%d does not respond - RESET\n", ac97->num, ac97->addr); - snd_ac97_free(ac97); - return -ENXIO; + snd_printk(KERN_WARNING "AC'97 %d does not respond - RESET\n", ac97->num); + /* proceed anyway - it's often non-critical */ } } __access_ok: ac97->id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16; ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2); if (ac97->id == 0x00000000 || ac97->id == 0xffffffff) { - snd_printk("AC'97 %d:%d access is not valid [0x%x], removing mixer.\n", ac97->num, ac97->addr, ac97->id); + snd_printk(KERN_ERR "AC'97 %d access is not valid [0x%x], removing mixer.\n", ac97->num, ac97->id); snd_ac97_free(ac97); return -EIO; } @@ -1697,7 +1774,7 @@ } /* test for AC'97 */ - if (! (ac97->scaps & AC97_SCAP_AUDIO)) { + if (!(ac97->scaps & AC97_SCAP_SKIP_AUDIO) && !(ac97->scaps & AC97_SCAP_AUDIO)) { /* test if we can write to the record gain volume register */ snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a06); if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a06) @@ -1711,13 +1788,22 @@ } /* test for MC'97 */ - ac97->ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID); - if (ac97->ext_mid == 0xffff) /* invalid combination */ - ac97->ext_mid = 0; - if (ac97->ext_mid & 1) - ac97->scaps |= AC97_SCAP_MODEM; + if (!(ac97->scaps & AC97_SCAP_SKIP_MODEM) && !(ac97->scaps & AC97_SCAP_MODEM)) { + ac97->ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID); + if (ac97->ext_mid == 0xffff) /* invalid combination */ + ac97->ext_mid = 0; + if (ac97->ext_mid & 1) + ac97->scaps |= AC97_SCAP_MODEM; + } + + if (!ac97_is_audio(ac97) && !ac97_is_modem(ac97)) { + if (!(ac97->scaps & (AC97_SCAP_SKIP_AUDIO|AC97_SCAP_SKIP_MODEM))) + snd_printk(KERN_ERR "AC'97 %d access error (not audio or modem codec)\n", ac97->num); + snd_ac97_free(ac97); + return -EACCES; + } - if (ac97->reset) // FIXME: always skipping? + if (bus->reset) // FIXME: always skipping? goto __ready_ok; /* FIXME: add powerdown control */ @@ -1736,12 +1822,43 @@ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); } while (time_after_eq(end_time, jiffies)); - snd_printk("AC'97 %d:%d analog subsections not ready\n", ac97->num, ac97->addr); + snd_printk(KERN_ERR "AC'97 %d analog subsections not ready\n", ac97->num); } + /* FIXME: add powerdown control */ + if (ac97_is_modem(ac97)) { + unsigned char tmp; + + /* nothing should be in powerdown mode */ + /* note: it's important to set the rate at first */ + tmp = AC97_MEA_GPIO; + if (ac97->ext_mid & AC97_MEI_LINE1) { + snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 12000); + tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1; + } + if (ac97->ext_mid & AC97_MEI_LINE2) { + snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 12000); + tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2; + } + if (ac97->ext_mid & AC97_MEI_HANDSET) { + snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 12000); + tmp |= AC97_MEA_HADC | AC97_MEA_HDAC; + } + snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); + udelay(100); + /* nothing should be in powerdown mode */ + snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); + end_time = jiffies + (HZ / 10); + do { + if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp) + goto __ready_ok; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/10); + } while (time_after_eq(end_time, jiffies)); + snd_printk(KERN_ERR "MC'97 %d converters and GPIO not ready (0x%x)\n", ac97->num, snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS)); + } + __ready_ok: - if (ac97->clock == 0) - ac97->clock = 48000; /* standard value */ if (ac97_is_audio(ac97)) ac97->addr = (ac97->ext_id & AC97_EI_ADDR_MASK) >> AC97_EI_ADDR_SHIFT; else @@ -1780,8 +1897,8 @@ ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC; } /* additional initializations */ - if (ac97->init) - ac97->init(ac97); + if (bus->init) + bus->init(ac97); snd_ac97_get_name(ac97, ac97->id, name, 0); snd_ac97_get_name(NULL, ac97->id, name, 0); // ac97->id might be changed in the special setup code if (ac97_is_audio(ac97)) { @@ -1802,183 +1919,6 @@ return -ENOMEM; } } - snd_ac97_proc_init(card, ac97, "ac97"); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ac97, &ops)) < 0) { - snd_ac97_free(ac97); - return err; - } - *rac97 = ac97; - return 0; -} - -/* wait for a while until registers are accessible after RESET - * return 0 if ok, negative not ready - */ -static int ac97_modem_reset_wait(ac97_t *ac97, int timeout) -{ - unsigned long end_time; - end_time = jiffies + timeout; - do { - unsigned short ext_mid; - - /* use preliminary reads to settle the communication */ - snd_ac97_read(ac97, AC97_EXTENDED_MID); - snd_ac97_read(ac97, AC97_VENDOR_ID1); - snd_ac97_read(ac97, AC97_VENDOR_ID2); - ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID); - if (ext_mid != 0xffff && (ext_mid & 1) != 0) - return 0; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/100); - } while (time_after_eq(end_time, jiffies)); - return -ENODEV; -} - -/** - * snd_ac97_modem - create an MC97 codec component - * @card: the card instance - * @_ac97: the template of ac97, including index, callbacks and - * the private data. - * @rac97: the pointer to store the new ac97 instance. - * - * Creates an MC97 codec component. An ac97_t instance is newly - * allocated and initialized from the template (_ac97). The codec - * is then initialized by the standard procedure. - * - * The template must include the valid callbacks (at least read and - * write), the codec number (num) and address (addr), and the private - * data (private_data). The other callbacks, wait and reset, are not - * mandatory. - * - * The clock is set to 48000. If another clock is needed, reset - * ac97->clock manually afterwards. - * - * The ac97 instance is registered as a low-level device, so you don't - * have to release it manually. - * - * The ACs (Audio Codecs only) are only detected but valid. The PCM driver - * have to check for ACs using the !ac97_is_modem() function. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_ac97_modem(snd_card_t * card, ac97_t * _ac97, ac97_t ** rac97) -{ - int err; - ac97_t *ac97; - char name[64]; - unsigned long end_time; - unsigned short tmp; - static snd_device_ops_t ops = { - .dev_free = snd_ac97_dev_free, - }; - - snd_assert(rac97 != NULL, return -EINVAL); - *rac97 = NULL; - snd_assert(card != NULL && _ac97 != NULL, return -EINVAL); - ac97 = snd_magic_kcalloc(ac97_t, 0, GFP_KERNEL); - if (ac97 == NULL) - return -ENOMEM; - *ac97 = *_ac97; - ac97->card = card; - spin_lock_init(&ac97->reg_lock); - - ac97->pci = _ac97->pci; - if (ac97->pci) { - pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_VENDOR_ID, &ac97->subsystem_vendor); - pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_ID, &ac97->subsystem_device); - } - - if (ac97->reset) { - ac97->reset(ac97); - goto __access_ok; - } - - snd_ac97_write(ac97, AC97_EXTENDED_MID, 0); /* reset to defaults */ - if (ac97->wait) - ac97->wait(ac97); - else { - udelay(50); - if (ac97_modem_reset_wait(ac97, HZ/2) < 0) { - snd_printk("MC'97 %d:%d does not respond - MODEM RESET\n", ac97->num, ac97->addr); - snd_ac97_free(ac97); - return -ENXIO; - } - } - __access_ok: - ac97->id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16; - ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2); - if (ac97->id == 0x00000000 || ac97->id == 0xffffffff) { - snd_printk("MC'97 %d:%d access is not valid [0x%x], removing modem controls.\n", ac97->num, ac97->addr, ac97->id); - snd_ac97_free(ac97); - return -EIO; - } - - /* test for MC'97 */ - ac97->ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID); - if (ac97->ext_mid == 0xffff) /* invalid combination */ - ac97->ext_mid = 0; - if (ac97->ext_mid & 1) - ac97->scaps |= AC97_SCAP_MODEM; - - /* non-destructive test for AC'97 */ - tmp = snd_ac97_read(ac97, AC97_RESET); - if (tmp == 0 || tmp == 0xffff) { - tmp = snd_ac97_read(ac97, AC97_EXTENDED_ID); - if (tmp == 0 || tmp == 0xffff) { - tmp = snd_ac97_read(ac97, AC97_REC_GAIN); - if (tmp == 0 || tmp == 0xffff) - tmp = snd_ac97_read(ac97, AC97_POWERDOWN); - } - } - if ((tmp != 0 && tmp != 0xffff) || !(ac97->scaps & AC97_SCAP_MODEM)) - ac97->scaps |= AC97_SCAP_AUDIO; - - if (ac97->reset) // FIXME: always skipping? - goto __ready_ok; - - /* FIXME: add powerdown control */ - if (ac97->scaps & AC97_SCAP_MODEM) { - /* nothing should be in powerdown mode */ - /* note: it's important to set the rate at first */ - tmp = AC97_MEA_GPIO; - if (ac97->ext_mid & AC97_MEI_LINE1) { - snd_ac97_write_cache(ac97, AC97_LINE1_RATE, 12000); - tmp |= AC97_MEA_ADC1 | AC97_MEA_DAC1; - } - if (ac97->ext_mid & AC97_MEI_LINE2) { - snd_ac97_write_cache(ac97, AC97_LINE2_RATE, 12000); - tmp |= AC97_MEA_ADC2 | AC97_MEA_DAC2; - } - if (ac97->ext_mid & AC97_MEI_HANDSET) { - snd_ac97_write_cache(ac97, AC97_HANDSET_RATE, 12000); - tmp |= AC97_MEA_HADC | AC97_MEA_HDAC; - } - snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); - udelay(100); - /* nothing should be in powerdown mode */ - snd_ac97_write_cache(ac97, AC97_EXTENDED_MSTATUS, 0xff00 & ~(tmp << 8)); - end_time = jiffies + (HZ / 10); - do { - if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp) - goto __ready_ok; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/10); - } while (time_after_eq(end_time, jiffies)); - snd_printk("MC'97 %d:%d converters and GPIO not ready (0x%x)\n", ac97->num, ac97->addr, snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS)); - } - - __ready_ok: - /* additional initializations */ - /* FIXME: ADD MODEM INITALIZATION */ - if (ac97_is_modem(ac97)) - ac97->addr = (ac97->ext_mid & AC97_MEI_ADDR_MASK) >> AC97_MEI_ADDR_SHIFT; - else - ac97->addr = (ac97->ext_id & AC97_EI_ADDR_MASK) >> AC97_EI_ADDR_SHIFT; - - if (ac97->init) - ac97->init(ac97); - snd_ac97_get_name(ac97, ac97->id, name, 1); - snd_ac97_get_name(NULL, ac97->id, name, 1); // ac97->id might be changed in the special setup code if (ac97_is_modem(ac97)) { if (card->mixername[0] == '\0') { strcpy(card->mixername, name); @@ -1992,12 +1932,12 @@ snd_ac97_free(ac97); return err; } + if (snd_ac97_modem_build(card, ac97) < 0) { + snd_ac97_free(ac97); + return -ENOMEM; + } } - if (ac97_is_modem(ac97) && snd_ac97_modem_build(card, ac97) < 0) { - snd_ac97_free(ac97); - return -ENOMEM; - } - snd_ac97_proc_init(card, ac97, "mc97"); + snd_ac97_proc_init(ac97); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ac97, &ops)) < 0) { snd_ac97_free(ac97); return err; @@ -2006,110 +1946,6 @@ return 0; } -/* - * PCM support - */ - -static int set_spdif_rate(ac97_t *ac97, unsigned short rate) -{ - unsigned short old, bits, reg, mask; - - if (! (ac97->ext_id & AC97_EI_SPDIF)) - return -ENODEV; - - if (ac97->flags & AC97_CS_SPDIF) { - switch (rate) { - case 48000: bits = 0; break; - case 44100: bits = 1 << AC97_SC_SPSR_SHIFT; break; - default: /* invalid - disable output */ - snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); - return -EINVAL; - } - reg = AC97_CSR_SPDIF; - mask = 1 << AC97_SC_SPSR_SHIFT; - } else { - if (ac97->id == AC97_ID_CM9739 && rate != 48000) { - snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); - return -EINVAL; - } - switch (rate) { - case 44100: bits = AC97_SC_SPSR_44K; break; - case 48000: bits = AC97_SC_SPSR_48K; break; - case 32000: bits = AC97_SC_SPSR_32K; break; - default: /* invalid - disable output */ - snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); - return -EINVAL; - } - reg = AC97_SPDIF; - mask = AC97_SC_SPSR_MASK; - } - - spin_lock(&ac97->reg_lock); - old = ac97->regs[reg] & mask; - spin_unlock(&ac97->reg_lock); - if (old != bits) { - snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); - snd_ac97_update_bits(ac97, reg, mask, bits); - } - snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); - return 0; -} - -/** - * snd_ac97_set_rate - change the rate of the given input/output. - * @ac97: the ac97 instance - * @reg: the register to change - * @rate: the sample rate to set - * - * Changes the rate of the given input/output on the codec. - * If the codec doesn't support VAR, the rate must be 48000 (except - * for SPDIF). - * - * The valid registers are AC97_PMC_MIC_ADC_RATE, - * AC97_PCM_FRONT_DAC_RATE, AC97_PCM_LR_ADC_RATE and AC97_SPDIF. - * The SPDIF register is a pseudo-register to change the rate of SPDIF - * (only if supported). - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_ac97_set_rate(ac97_t *ac97, int reg, unsigned short rate) -{ - unsigned short mask; - unsigned int tmp; - - switch (reg) { - case AC97_PCM_MIC_ADC_RATE: - mask = 0x0000; - if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRM) == 0) /* MIC VRA */ - if (rate != 48000) - return -EINVAL; - break; - case AC97_PCM_FRONT_DAC_RATE: - mask = 0x0200; - if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRA) == 0) /* VRA */ - if (rate != 48000) - return -EINVAL; - break; - case AC97_PCM_LR_ADC_RATE: - mask = 0x0100; - if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRA) == 0) /* VRA */ - if (rate != 48000) - return -EINVAL; - break; - case AC97_SPDIF: - return set_spdif_rate(ac97, rate); - default: - return -EINVAL; - } - tmp = ((unsigned int)rate * ac97->clock) / 48000; - if (tmp > 65535) - return -EINVAL; - snd_ac97_update(ac97, reg, tmp & 0xffff); - snd_ac97_read(ac97, reg); - return 0; -} - - #ifdef CONFIG_PM /** * snd_ac97_suspend - General suspend function for AC97 codec @@ -2143,8 +1979,8 @@ { int i, is_ad18xx, codec; - if (ac97->reset) { - ac97->reset(ac97); + if (ac97->bus->reset) { + ac97->bus->reset(ac97); goto __reset_ready; } @@ -2155,29 +1991,29 @@ snd_ac97_write(ac97, AC97_GENERAL_PURPOSE, 0); snd_ac97_write(ac97, AC97_POWERDOWN, ac97->regs[AC97_POWERDOWN]); - snd_ac97_write(ac97, AC97_MASTER, 0x8000); + snd_ac97_write(ac97, AC97_MASTER, 0x8101); for (i = 0; i < 10; i++) { - if (snd_ac97_read(ac97, AC97_MASTER) == 0x8000) + if (snd_ac97_read(ac97, AC97_MASTER) == 0x8101) break; mdelay(1); } __reset_ready: - if (ac97->init) - ac97->init(ac97); + if (ac97->bus->init) + ac97->bus->init(ac97); - is_ad18xx = (ac97->id & 0xffffff40) == AC97_ID_AD1881; + is_ad18xx = (ac97->flags & AC97_AD_MULTI); if (is_ad18xx) { /* restore the AD18xx codec configurations */ for (codec = 0; codec < 3; codec++) { if (! ac97->spec.ad18xx.id[codec]) continue; /* select single codec */ - ac97->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]); - ac97->write(ac97, AC97_AD_CODEC_CFG, ac97->spec.ad18xx.codec_cfg[codec]); + ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]); + ac97->bus->write(ac97, AC97_AD_CODEC_CFG, ac97->spec.ad18xx.codec_cfg[codec]); } /* select all codecs */ - ac97->write(ac97, AC97_AD_SERIAL_CFG, 0x7000); + ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, 0x7000); } /* restore ac97 status */ @@ -2196,12 +2032,12 @@ if (! ac97->spec.ad18xx.id[codec]) continue; /* select single codec */ - ac97->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]); + ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]); /* update PCM bits */ - ac97->write(ac97, AC97_PCM, ac97->spec.ad18xx.pcmreg[codec]); + ac97->bus->write(ac97, AC97_PCM, ac97->spec.ad18xx.pcmreg[codec]); } /* select all codecs */ - ac97->write(ac97, AC97_AD_SERIAL_CFG, 0x7000); + ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, 0x7000); continue; } else if (i == AC97_AD_TEST || i == AC97_AD_CODEC_CFG || @@ -2231,13 +2067,13 @@ /* */ -static int remove_ctl(ac97_t *ac97, const char *name) +int snd_ac97_remove_ctl(ac97_t *ac97, const char *name) { snd_ctl_elem_id_t id; memset(&id, 0, sizeof(id)); strcpy(id.name, name); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - return snd_ctl_remove_id(ac97->card, &id); + return snd_ctl_remove_id(ac97->bus->card, &id); } static snd_kcontrol_t *ctl_find(ac97_t *ac97, const char *name) @@ -2246,10 +2082,10 @@ memset(&sid, 0, sizeof(sid)); strcpy(sid.name, name); sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - return snd_ctl_find_id(ac97->card, &sid); + return snd_ctl_find_id(ac97->bus->card, &sid); } -static int rename_ctl(ac97_t *ac97, const char *src, const char *dst) +int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst) { snd_kcontrol_t *kctl = ctl_find(ac97, src); if (kctl) { @@ -2259,7 +2095,7 @@ return -ENOENT; } -static int swap_ctl(ac97_t *ac97, const char *s1, const char *s2) +int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2) { snd_kcontrol_t *kctl1, *kctl2; kctl1 = ctl_find(ac97, s1); @@ -2276,22 +2112,22 @@ { /* FIXME: error checks.. */ if (remove_master) { - remove_ctl(ac97, "Master Playback Switch"); - remove_ctl(ac97, "Master Playback Volume"); + snd_ac97_remove_ctl(ac97, "Master Playback Switch"); + snd_ac97_remove_ctl(ac97, "Master Playback Volume"); } else { - rename_ctl(ac97, "Master Playback Switch", "Line-Out Playback Switch"); - rename_ctl(ac97, "Master Playback Volume", "Line-Out Playback Volume"); + snd_ac97_rename_ctl(ac97, "Master Playback Switch", "Line-Out Playback Switch"); + snd_ac97_rename_ctl(ac97, "Master Playback Volume", "Line-Out Playback Volume"); } - rename_ctl(ac97, "Headphone Playback Switch", "Master Playback Switch"); - rename_ctl(ac97, "Headphone Playback Volume", "Master Playback Volume"); + snd_ac97_rename_ctl(ac97, "Headphone Playback Switch", "Master Playback Switch"); + snd_ac97_rename_ctl(ac97, "Headphone Playback Volume", "Master Playback Volume"); return 0; } static int swap_surround(ac97_t *ac97) { /* FIXME: error checks.. */ - swap_ctl(ac97, "Master Playback Switch", "Surround Playback Switch"); - swap_ctl(ac97, "Master Playback Volume", "Surround Playback Volume"); + snd_ac97_swap_ctl(ac97, "Master Playback Switch", "Surround Playback Switch"); + snd_ac97_swap_ctl(ac97, "Master Playback Volume", "Surround Playback Volume"); return 0; } @@ -2301,7 +2137,7 @@ /* Turn on OMS bit to route microphone to back panel */ scfg = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG); snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, scfg | 0x0200); - return swap_headphone(ac97, 1); + return 0; } /** @@ -2353,10 +2189,13 @@ EXPORT_SYMBOL(snd_ac97_write_cache); EXPORT_SYMBOL(snd_ac97_update); EXPORT_SYMBOL(snd_ac97_update_bits); +EXPORT_SYMBOL(snd_ac97_bus); EXPORT_SYMBOL(snd_ac97_mixer); -EXPORT_SYMBOL(snd_ac97_modem); -EXPORT_SYMBOL(snd_ac97_set_rate); +EXPORT_SYMBOL(snd_ac97_pcm_assign); +EXPORT_SYMBOL(snd_ac97_pcm_open); +EXPORT_SYMBOL(snd_ac97_pcm_close); EXPORT_SYMBOL(snd_ac97_tune_hardware); +EXPORT_SYMBOL(snd_ac97_set_rate); #ifdef CONFIG_PM EXPORT_SYMBOL(snd_ac97_resume); #endif diff -Nru a/sound/pci/ac97/ac97_local.h b/sound/pci/ac97/ac97_local.h --- a/sound/pci/ac97/ac97_local.h Mon Feb 2 22:07:56 2004 +++ b/sound/pci/ac97/ac97_local.h Mon Feb 2 22:07:56 2004 @@ -37,6 +37,12 @@ int snd_ac97_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol); int snd_ac97_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol); int snd_ac97_try_bit(ac97_t * ac97, int reg, int bit); +int snd_ac97_remove_ctl(ac97_t *ac97, const char *name); +int snd_ac97_rename_ctl(ac97_t *ac97, const char *src, const char *dst); +int snd_ac97_swap_ctl(ac97_t *ac97, const char *s1, const char *s2); /* ac97_proc.c */ -void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97, const char *prefix); +void snd_ac97_bus_proc_init(ac97_bus_t * ac97); +void snd_ac97_bus_proc_done(ac97_bus_t * ac97); +void snd_ac97_proc_init(ac97_t * ac97); +void snd_ac97_proc_done(ac97_t * ac97); diff -Nru a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c --- a/sound/pci/ac97/ac97_patch.c Mon Feb 2 22:07:58 2004 +++ b/sound/pci/ac97/ac97_patch.c Mon Feb 2 22:07:58 2004 @@ -46,7 +46,7 @@ int idx, err; for (idx = 0; idx < count; idx++) - if ((err = snd_ctl_add(ac97->card, snd_ac97_cnew(&controls[idx], ac97))) < 0) + if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&controls[idx], ac97))) < 0) return err; return 0; } @@ -201,12 +201,12 @@ snd_kcontrol_t *kctl; int err; - if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) + if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) return err; strcpy(kctl->id.name, "3D Control - Wide"); kctl->private_value = AC97_3D_CONTROL | (9 << 8) | (7 << 16); snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); - if ((err = snd_ctl_add(ac97->card, snd_ac97_cnew(&snd_ac97_ymf753_controls_speaker, ac97))) < 0) + if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&snd_ac97_ymf753_controls_speaker, ac97))) < 0) return err; snd_ac97_write_cache(ac97, AC97_YMF753_3D_MODE_SEL, 0x0c00); return 0; @@ -306,7 +306,7 @@ snd_kcontrol_t *kctl; int err; - if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) + if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) return err; strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); kctl->private_value = AC97_3D_CONTROL | (3 << 16); @@ -319,11 +319,11 @@ snd_kcontrol_t *kctl; int err; - if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) + if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) return err; strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); kctl->private_value = AC97_3D_CONTROL | (3 << 16); - if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) + if ((err = snd_ctl_add(ac97->bus->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) return err; strcpy(kctl->id.name, "3D Control Sigmatel - Rear Depth"); kctl->private_value = AC97_3D_CONTROL | (2 << 8) | (3 << 16); @@ -708,7 +708,7 @@ #define AC97_AD198X_2MIC 0x0040 /* 2-channel mic select */ #define AC97_AD198X_SPRD 0x0080 /* SPREAD enable */ #define AC97_AD198X_DMIX0 0x0100 /* downmix mode: 0 = 6-to-4, 1 = 6-to-2 downmix */ -#define AC97_AD198X_DMIX1 0x0300 /* downmix mode: 1 = enabled */ +#define AC97_AD198X_DMIX1 0x0200 /* downmix mode: 1 = enabled */ #define AC97_AD198X_HPSEL 0x0400 /* headphone amplifier input select */ #define AC97_AD198X_CLDIS 0x0800 /* center/lfe disable */ #define AC97_AD198X_LODIS 0x1000 /* LINE_OUT disable */ @@ -717,7 +717,7 @@ #define AC97_AD198X_DACZ 0x8000 /* DAC zero-fill mode */ -static int snd_ac97_ad1980_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +static int snd_ac97_ad198x_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { static char *texts[2] = { "AC-Link", "A/D Converter" }; @@ -730,7 +730,7 @@ return 0; } -static int snd_ac97_ad1980_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int snd_ac97_ad198x_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; @@ -740,7 +740,7 @@ return 0; } -static int snd_ac97_ad1980_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int snd_ac97_ad198x_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; @@ -751,21 +751,163 @@ return snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x0004, val); } -static const snd_kcontrol_new_t snd_ac97_ad1980_spdif_source = { +static const snd_kcontrol_new_t snd_ac97_ad198x_spdif_source = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - .info = snd_ac97_ad1980_spdif_source_info, - .get = snd_ac97_ad1980_spdif_source_get, - .put = snd_ac97_ad1980_spdif_source_put, + .info = snd_ac97_ad198x_spdif_source_info, + .get = snd_ac97_ad198x_spdif_source_get, + .put = snd_ac97_ad198x_spdif_source_put, }; -static int patch_ad1980_post_spdif(ac97_t * ac97) +static int patch_ad198x_post_spdif(ac97_t * ac97) { - return patch_build_controls(ac97, &snd_ac97_ad1980_spdif_source, 1); + return patch_build_controls(ac97, &snd_ac97_ad198x_spdif_source, 1); +} + +static struct snd_ac97_build_ops patch_ad1981a_build_ops = { + .build_post_spdif = patch_ad198x_post_spdif +}; + +int patch_ad1981a(ac97_t *ac97) +{ + patch_ad1881(ac97); + ac97->build_ops = &patch_ad1981a_build_ops; + snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD198X_MSPLT, AC97_AD198X_MSPLT); + ac97->flags |= AC97_STEREO_MUTES; + return 0; +} + +static const snd_kcontrol_new_t snd_ac97_ad198x_2cmic = +AC97_SINGLE("Stereo Mic", AC97_AD_MISC, 6, 1, 0); + +static int patch_ad1981b_specific(ac97_t *ac97) +{ + return patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1); +} + +static struct snd_ac97_build_ops patch_ad1981b_build_ops = { + .build_post_spdif = patch_ad198x_post_spdif, + .build_specific = patch_ad1981b_specific +}; + +int patch_ad1981b(ac97_t *ac97) +{ + patch_ad1881(ac97); + ac97->build_ops = &patch_ad1981b_build_ops; + snd_ac97_update_bits(ac97, AC97_AD_MISC, AC97_AD198X_MSPLT, AC97_AD198X_MSPLT); + ac97->flags |= AC97_STEREO_MUTES; + return 0; +} + +static int snd_ac97_ad1980_lohpsel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_ac97_ad1980_lohpsel_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + val = ac97->regs[AC97_AD_MISC]; + ucontrol->value.integer.value[0] = !(val & AC97_AD198X_LOSEL); + return 0; +} + +static int snd_ac97_ad1980_lohpsel_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + val = !ucontrol->value.integer.value[0] + ? (AC97_AD198X_LOSEL | AC97_AD198X_HPSEL) : 0; + return snd_ac97_update_bits(ac97, AC97_AD_MISC, + AC97_AD198X_LOSEL | AC97_AD198X_HPSEL, val); +} + +static int snd_ac97_ad1980_downmix_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[3] = {"Off", "6 -> 4", "6 -> 2"}; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item > 2) + uinfo->value.enumerated.item = 2; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_ac97_ad1980_downmix_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + val = ac97->regs[AC97_AD_MISC]; + if (!(val & AC97_AD198X_DMIX1)) + ucontrol->value.enumerated.item[0] = 0; + else + ucontrol->value.enumerated.item[0] = 1 + ((val >> 8) & 1); + return 0; +} + +static int snd_ac97_ad1980_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + if (ucontrol->value.enumerated.item[0] > 2) + return -EINVAL; + if (ucontrol->value.enumerated.item[0] == 0) + val = 0; + else + val = AC97_AD198X_DMIX1 | + ((ucontrol->value.enumerated.item[0] - 1) << 8); + return snd_ac97_update_bits(ac97, AC97_AD_MISC, + AC97_AD198X_DMIX0 | AC97_AD198X_DMIX1, val); +} + +static const snd_kcontrol_new_t snd_ac97_ad1980_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Exchange Front/Surround", + .info = snd_ac97_ad1980_lohpsel_info, + .get = snd_ac97_ad1980_lohpsel_get, + .put = snd_ac97_ad1980_lohpsel_put + }, + AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Downmix", + .info = snd_ac97_ad1980_downmix_info, + .get = snd_ac97_ad1980_downmix_get, + .put = snd_ac97_ad1980_downmix_put + }, + AC97_SINGLE("Surround Jack as Input", AC97_AD_MISC, 12, 1, 0), + AC97_SINGLE("Center/LFE Jack as Input", AC97_AD_MISC, 11, 1, 0), +}; + +static int patch_ad1980_specific(ac97_t *ac97) +{ + int err; + + /* rename 0x04 as "Master" and 0x02 as "Master Surround" */ + snd_ac97_rename_ctl(ac97, "Master Playback Switch", "Master Surround Playback Switch"); + snd_ac97_rename_ctl(ac97, "Master Playback Volume", "Master Surround Playback Volume"); + snd_ac97_rename_ctl(ac97, "Headphone Playback Switch", "Master Playback Switch"); + snd_ac97_rename_ctl(ac97, "Headphone Playback Volume", "Master Playback Volume"); + if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0) + return err; + return patch_build_controls(ac97, snd_ac97_ad1980_controls, ARRAY_SIZE(snd_ac97_ad1980_controls)); } static struct snd_ac97_build_ops patch_ad1980_build_ops = { - .build_post_spdif = &patch_ad1980_post_spdif + .build_post_spdif = patch_ad198x_post_spdif, + .build_specific = patch_ad1980_specific }; int patch_ad1980(ac97_t * ac97) @@ -776,29 +918,50 @@ ac97->build_ops = &patch_ad1980_build_ops; /* Switch FRONT/SURROUND LINE-OUT/HP-OUT default connection */ /* it seems that most vendors connect line-out connector to headphone out of AC'97 */ + /* AD-compatible mode */ /* Stereo mutes enabled */ misc = snd_ac97_read(ac97, AC97_AD_MISC); snd_ac97_write_cache(ac97, AC97_AD_MISC, misc | AC97_AD198X_LOSEL | AC97_AD198X_HPSEL | - AC97_AD198X_MSPLT); + AC97_AD198X_MSPLT | + AC97_AD198X_AC97NC); ac97->flags |= AC97_STEREO_MUTES; return 0; } +static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = { + AC97_SINGLE("Center/LFE Jack as Mic", AC97_AD_SERIAL_CFG, 9, 1, 0), + AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0) +}; + +static int patch_ad1985_specific(ac97_t *ac97) +{ + int err; + + if ((err = patch_ad1980_specific(ac97)) < 0) + return err; + return patch_build_controls(ac97, snd_ac97_ad1985_controls, ARRAY_SIZE(snd_ac97_ad1985_controls)); +} + +static struct snd_ac97_build_ops patch_ad1985_build_ops = { + .build_post_spdif = patch_ad198x_post_spdif, + .build_specific = patch_ad1985_specific +}; + int patch_ad1985(ac97_t * ac97) { unsigned short misc; - patch_ad1881(ac97); - ac97->build_ops = &patch_ad1980_build_ops; + ac97->build_ops = &patch_ad1985_build_ops; misc = snd_ac97_read(ac97, AC97_AD_MISC); /* switch front/surround line-out/hp-out */ - /* center/LFE, surround in High-Z mode */ + /* center/LFE, mic in 3.75V mode */ /* AD-compatible mode */ /* Stereo mutes enabled */ + /* in accordance with ADI driver: misc | 0x5c28 */ snd_ac97_write_cache(ac97, AC97_AD_MISC, misc | - AC97_AD198X_VREFD | + AC97_AD198X_VREFH | AC97_AD198X_LOSEL | AC97_AD198X_HPSEL | AC97_AD198X_CLDIS | @@ -820,6 +983,8 @@ /* 7: Independent Master Volume Left */ /* 8: reserved */ AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), + /* 10: mic, see below */ + /* 11-13: in IEC958 controls */ AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0), #if 0 /* always set in patch_alc650 */ AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0), @@ -898,7 +1063,6 @@ int patch_alc650(ac97_t * ac97) { unsigned short val; - int spdif = 0; ac97->build_ops = &patch_alc650_ops; @@ -907,22 +1071,16 @@ ac97->spec.dev_flags = (ac97->id == 0x414c4722 || ac97->id == 0x414c4723); - /* check spdif (should be only on rev.E) */ - if (ac97->spec.dev_flags) { - val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS); - if (val & AC97_EA_SPCV) - spdif = 1; - } + /* enable AC97_ALC650_GPIO_SETUP, AC97_ALC650_CLOCK for R/W */ + snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_STATUS, + snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS) | 0x8000); - if (spdif) { - /* enable AC97_ALC650_GPIO_SETUP, AC97_ALC650_CLOCK for R/W */ - snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_STATUS, - snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS) | 0x8000); + /* Enable SPDIF-IN only on Rev.E and above */ + if (ac97->spec.dev_flags) { /* enable spdif in */ snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK, snd_ac97_read(ac97, AC97_ALC650_CLOCK) | 0x03); - } else - ac97->ext_id &= ~AC97_EI_SPDIF; /* disable extended-id */ + } val = snd_ac97_read(ac97, AC97_ALC650_MULTICH); val &= ~0xc000; /* slot: 3,4,7,8,6,9 */ @@ -953,6 +1111,98 @@ return 0; } +static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = { + AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0), + AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), + AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0), +}; + +static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static char *texts_655[3] = { "PCM", "Analog In", "IEC958 In" }; + static char *texts_658[4] = { "PCM", "Analog1 In", "Analog2 In", "IEC958 In" }; + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = ac97->spec.dev_flags ? 4 : 3; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + ac97->spec.dev_flags ? + texts_658[uinfo->value.enumerated.item] : + texts_655[uinfo->value.enumerated.item]); + return 0; + +} + +static int alc655_iec958_route_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + unsigned short val; + + val = ac97->regs[AC97_ALC650_MULTICH]; + val = (val >> 12) & 3; + if (ac97->spec.dev_flags && val == 3) + val = 0; + ucontrol->value.enumerated.item[0] = val; + return 0; +} + +static int alc655_iec958_route_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + return snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 3 << 12, + (unsigned short)ucontrol->value.enumerated.item[0]); +} + +static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc655[] = { + AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0), + AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 14, 1, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC958 Playback Route", + .info = alc655_iec958_route_info, + .get = alc655_iec958_route_get, + .put = alc655_iec958_route_put, + }, +}; + +static int patch_alc655_specific(ac97_t * ac97) +{ + int err; + + if ((err = patch_build_controls(ac97, snd_ac97_controls_alc655, ARRAY_SIZE(snd_ac97_controls_alc655))) < 0) + return err; + if (ac97->ext_id & AC97_EI_SPDIF) { + if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc655, ARRAY_SIZE(snd_ac97_spdif_controls_alc655))) < 0) + return err; + } + return 0; +} + +static struct snd_ac97_build_ops patch_alc655_ops = { + .build_specific = patch_alc655_specific +}; + +int patch_alc655(ac97_t * ac97) +{ + ac97->spec.dev_flags = (ac97->id == 0x414c4780); /* ALC658 */ + + ac97->build_ops = &patch_alc655_ops; + + /* enable spdif in */ + snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK, + snd_ac97_read(ac97, AC97_ALC650_MULTICH) | 0x8000); + snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK, + snd_ac97_read(ac97, AC97_ALC650_CLOCK) | 0x02); + + /* full DAC volume */ + snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808); + snd_ac97_write_cache(ac97, AC97_ALC650_LFE_DAC_VOL, 0x0808); + return 0; +} + static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = { AC97_SINGLE("Line-In As Surround", AC97_CM9738_VENDOR_CTRL, 10, 1, 0), AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0), @@ -1097,5 +1347,50 @@ int patch_vt1616(ac97_t * ac97) { ac97->build_ops = &patch_vt1616_ops; + return 0; +} + +static const snd_kcontrol_new_t snd_ac97_controls_it2646[] = { + AC97_SINGLE("Line-In As Surround", 0x76, 9, 1, 0), + AC97_SINGLE("Mic As Center/LFE", 0x76, 10, 1, 0), +}; + +static const snd_kcontrol_new_t snd_ac97_spdif_controls_it2646[] = { + AC97_SINGLE("IEC958 Capture Switch", 0x76, 11, 1, 0), + AC97_SINGLE("Analog to IEC958 Output", 0x76, 12, 1, 0), + AC97_SINGLE("IEC958 Input Monitor", 0x76, 13, 1, 0), +}; + +static int patch_it2646_specific(ac97_t * ac97) +{ + int err; + if ((err = patch_build_controls(ac97, snd_ac97_controls_it2646, ARRAY_SIZE(snd_ac97_controls_it2646))) < 0) + return err; + if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_it2646, ARRAY_SIZE(snd_ac97_spdif_controls_it2646))) < 0) + return err; + return 0; +} + +static struct snd_ac97_build_ops patch_it2646_ops = { + .build_specific = patch_it2646_specific +}; + +int patch_it2646(ac97_t * ac97) +{ + ac97->build_ops = &patch_it2646_ops; + /* full DAC volume */ + snd_ac97_write_cache(ac97, 0x5E, 0x0808); + snd_ac97_write_cache(ac97, 0x7A, 0x0808); + return 0; +} + +/* Si3036/8 specific registers */ +#define AC97_SI3036_CHIP_ID 0x5a + +int mpatch_si3036(ac97_t * ac97) +{ + //printk("mpatch_si3036: chip id = %x\n", snd_ac97_read(ac97, 0x5a)); + snd_ac97_write_cache(ac97, 0x5c, 0xf210 ); + snd_ac97_write_cache(ac97, 0x68, 0); return 0; } diff -Nru a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h --- a/sound/pci/ac97/ac97_patch.h Mon Feb 2 22:07:55 2004 +++ b/sound/pci/ac97/ac97_patch.h Mon Feb 2 22:07:55 2004 @@ -42,8 +42,13 @@ int patch_ad1885(ac97_t * ac97); int patch_ad1886(ac97_t * ac97); int patch_ad1980(ac97_t * ac97); +int patch_ad1981a(ac97_t * ac97); +int patch_ad1981b(ac97_t * ac97); int patch_ad1985(ac97_t * ac97); int patch_alc650(ac97_t * ac97); +int patch_alc655(ac97_t * ac97); int patch_cm9738(ac97_t * ac97); int patch_cm9739(ac97_t * ac97); int patch_vt1616(ac97_t * ac97); +int patch_it2646(ac97_t * ac97); +int mpatch_si3036(ac97_t * ac97); diff -Nru a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/ac97/ac97_pcm.c Mon Feb 2 22:07:58 2004 @@ -0,0 +1,593 @@ +/* + * Copyright (c) by Jaroslav Kysela + * Universal interface for Audio Codec '97 + * + * For more details look to AC '97 component specification revision 2.2 + * by Intel Corporation (http://developer.intel.com) and to datasheets + * for specific codecs. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ac97_patch.h" +#include "ac97_id.h" +#include "ac97_local.h" + +#define chip_t ac97_t + +/* + * PCM support + */ + +static unsigned char rate_reg_tables[2][4][9] = { +{ + /* standard rates */ + { + /* 3&4 front, 7&8 rear, 6&9 center/lfe */ + AC97_PCM_FRONT_DAC_RATE, /* slot 3 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 4 */ + 0xff, /* slot 5 */ + AC97_PCM_LFE_DAC_RATE, /* slot 6 */ + AC97_PCM_SURR_DAC_RATE, /* slot 7 */ + AC97_PCM_SURR_DAC_RATE, /* slot 8 */ + AC97_PCM_LFE_DAC_RATE, /* slot 9 */ + 0xff, /* slot 10 */ + 0xff, /* slot 11 */ + }, + { + /* 7&8 front, 6&9 rear, 10&11 center/lfe */ + 0xff, /* slot 3 */ + 0xff, /* slot 4 */ + 0xff, /* slot 5 */ + AC97_PCM_SURR_DAC_RATE, /* slot 6 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 7 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 8 */ + AC97_PCM_SURR_DAC_RATE, /* slot 9 */ + AC97_PCM_LFE_DAC_RATE, /* slot 10 */ + AC97_PCM_LFE_DAC_RATE, /* slot 11 */ + }, + { + /* 6&9 front, 10&11 rear, 3&4 center/lfe */ + AC97_PCM_LFE_DAC_RATE, /* slot 3 */ + AC97_PCM_LFE_DAC_RATE, /* slot 4 */ + 0xff, /* slot 5 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 6 */ + 0xff, /* slot 7 */ + 0xff, /* slot 8 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 9 */ + AC97_PCM_SURR_DAC_RATE, /* slot 10 */ + AC97_PCM_SURR_DAC_RATE, /* slot 11 */ + }, + { + /* 10&11 front, 3&4 rear, 7&8 center/lfe */ + AC97_PCM_SURR_DAC_RATE, /* slot 3 */ + AC97_PCM_SURR_DAC_RATE, /* slot 4 */ + 0xff, /* slot 5 */ + 0xff, /* slot 6 */ + AC97_PCM_LFE_DAC_RATE, /* slot 7 */ + AC97_PCM_LFE_DAC_RATE, /* slot 8 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 9 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 10 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 11 */ + }, +}, +{ + /* FIXME: double rates */ + { + /* 3&4 front, 7&8 rear, 6&9 center/lfe */ + AC97_PCM_FRONT_DAC_RATE, /* slot 3 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 4 */ + 0xff, /* slot 5 */ + AC97_PCM_LFE_DAC_RATE, /* slot 6 */ + AC97_PCM_SURR_DAC_RATE, /* slot 7 */ + AC97_PCM_SURR_DAC_RATE, /* slot 8 */ + AC97_PCM_LFE_DAC_RATE, /* slot 9 */ + 0xff, /* slot 10 */ + 0xff, /* slot 11 */ + }, + { + /* 7&8 front, 6&9 rear, 10&11 center/lfe */ + 0xff, /* slot 3 */ + 0xff, /* slot 4 */ + 0xff, /* slot 5 */ + AC97_PCM_SURR_DAC_RATE, /* slot 6 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 7 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 8 */ + AC97_PCM_SURR_DAC_RATE, /* slot 9 */ + AC97_PCM_LFE_DAC_RATE, /* slot 10 */ + AC97_PCM_LFE_DAC_RATE, /* slot 11 */ + }, + { + /* 6&9 front, 10&11 rear, 3&4 center/lfe */ + AC97_PCM_LFE_DAC_RATE, /* slot 3 */ + AC97_PCM_LFE_DAC_RATE, /* slot 4 */ + 0xff, /* slot 5 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 6 */ + 0xff, /* slot 7 */ + 0xff, /* slot 8 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 9 */ + AC97_PCM_SURR_DAC_RATE, /* slot 10 */ + AC97_PCM_SURR_DAC_RATE, /* slot 11 */ + }, + { + /* 10&11 front, 3&4 rear, 7&8 center/lfe */ + AC97_PCM_SURR_DAC_RATE, /* slot 3 */ + AC97_PCM_SURR_DAC_RATE, /* slot 4 */ + 0xff, /* slot 5 */ + 0xff, /* slot 6 */ + AC97_PCM_LFE_DAC_RATE, /* slot 7 */ + AC97_PCM_LFE_DAC_RATE, /* slot 8 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 9 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 10 */ + AC97_PCM_FRONT_DAC_RATE, /* slot 11 */ + } +}}; + +/* FIXME: more various mappings for ADC? */ +static unsigned char rate_cregs[9] = { + AC97_PCM_LR_ADC_RATE, /* 3 */ + AC97_PCM_LR_ADC_RATE, /* 4 */ + 0xff, /* 5 */ + AC97_PCM_MIC_ADC_RATE, /* 6 */ + 0xff, /* 7 */ + 0xff, /* 8 */ + 0xff, /* 9 */ + 0xff, /* 10 */ + 0xff, /* 11 */ +}; + +static unsigned char get_slot_reg(struct ac97_pcm *pcm, unsigned short cidx, + unsigned short slot, int dbl) +{ + if (slot < 3) + return 0xff; + if (slot > 11) + return 0xff; + if (pcm->spdif) + return AC97_SPDIF; /* pseudo register */ + if (pcm->stream == SNDRV_PCM_STREAM_PLAYBACK) + return rate_reg_tables[dbl][pcm->r[dbl].rate_table[cidx]][slot - 3]; + else + return rate_cregs[slot - 3]; +} + +static int set_spdif_rate(ac97_t *ac97, unsigned short rate) +{ + unsigned short old, bits, reg, mask; + + if (! (ac97->ext_id & AC97_EI_SPDIF)) + return -ENODEV; + + if (ac97->flags & AC97_CS_SPDIF) { + switch (rate) { + case 48000: bits = 0; break; + case 44100: bits = 1 << AC97_SC_SPSR_SHIFT; break; + default: /* invalid - disable output */ + snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); + return -EINVAL; + } + reg = AC97_CSR_SPDIF; + mask = 1 << AC97_SC_SPSR_SHIFT; + } else { + if (ac97->id == AC97_ID_CM9739 && rate != 48000) { + snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); + return -EINVAL; + } + switch (rate) { + case 44100: bits = AC97_SC_SPSR_44K; break; + case 48000: bits = AC97_SC_SPSR_48K; break; + case 32000: bits = AC97_SC_SPSR_32K; break; + default: /* invalid - disable output */ + snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); + return -EINVAL; + } + reg = AC97_SPDIF; + mask = AC97_SC_SPSR_MASK; + } + + spin_lock(&ac97->reg_lock); + old = ac97->regs[reg] & mask; + spin_unlock(&ac97->reg_lock); + if (old != bits) { + snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); + snd_ac97_update_bits(ac97, reg, mask, bits); + } + snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); + return 0; +} + +/** + * snd_ac97_set_rate - change the rate of the given input/output. + * @ac97: the ac97 instance + * @reg: the register to change + * @rate: the sample rate to set + * + * Changes the rate of the given input/output on the codec. + * If the codec doesn't support VAR, the rate must be 48000 (except + * for SPDIF). + * + * The valid registers are AC97_PMC_MIC_ADC_RATE, + * AC97_PCM_FRONT_DAC_RATE, AC97_PCM_LR_ADC_RATE. + * AC97_PCM_SURR_DAC_RATE and AC97_PCM_LFE_DAC_RATE are accepted + * if the codec supports them. + * AC97_SPDIF is accepted as a pseudo register to modify the SPDIF + * status bits. + * + * Returns zero if successful, or a negative error code on failure. + */ +int snd_ac97_set_rate(ac97_t *ac97, int reg, unsigned short rate) +{ + unsigned int tmp; + + switch (reg) { + case AC97_PCM_MIC_ADC_RATE: + if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRM) == 0) /* MIC VRA */ + if (rate != 48000) + return -EINVAL; + break; + case AC97_PCM_FRONT_DAC_RATE: + case AC97_PCM_LR_ADC_RATE: + if ((ac97->regs[AC97_EXTENDED_STATUS] & AC97_EA_VRA) == 0) /* VRA */ + if (rate != 48000) + return -EINVAL; + break; + case AC97_PCM_SURR_DAC_RATE: + if (! (ac97->scaps & AC97_SCAP_SURROUND_DAC)) + return -EINVAL; + break; + case AC97_PCM_LFE_DAC_RATE: + if (! (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC)) + return -EINVAL; + break; + case AC97_SPDIF: + /* special case */ + return set_spdif_rate(ac97, rate); + default: + return -EINVAL; + } + tmp = ((unsigned int)rate * ac97->bus->clock) / 48000; + if (tmp > 65535) + return -EINVAL; + snd_ac97_update(ac97, reg, tmp & 0xffff); + snd_ac97_read(ac97, reg); + return 0; +} + +static unsigned short get_pslots(ac97_t *ac97, unsigned char *rate_table, unsigned short *spdif_slots) +{ + if (!ac97_is_audio(ac97)) + return 0; + if (ac97_is_rev22(ac97) || ac97_can_amap(ac97)) { + unsigned short slots = 0; + if (ac97_is_rev22(ac97)) { + /* Note: it's simply emulation of AMAP behaviour */ + u16 es; + es = ac97->regs[AC97_EXTENDED_STATUS] &= ~AC97_EI_DACS_SLOT_MASK; + switch (ac97->addr) { + case 1: + case 2: es |= (1<addr) { + case 0: + slots |= (1<scaps & AC97_SCAP_SURROUND_DAC) + slots |= (1<scaps & AC97_SCAP_CENTER_LFE_DAC) + slots |= (1<ext_id & AC97_EI_SPDIF) { + if (!(ac97->scaps & AC97_SCAP_SURROUND_DAC)) + *spdif_slots = (1<scaps & AC97_SCAP_CENTER_LFE_DAC)) + *spdif_slots = (1<scaps & AC97_SCAP_SURROUND_DAC) + slots |= (1<ext_id & AC97_EI_SPDIF) { + if (!(ac97->scaps & AC97_SCAP_SURROUND_DAC)) + *spdif_slots = (1<ext_id & AC97_EI_SPDIF) + *spdif_slots = (1<scaps & AC97_SCAP_SURROUND_DAC) + slots |= (1<scaps & AC97_SCAP_CENTER_LFE_DAC) + slots |= (1<ext_id & AC97_EI_SPDIF) { + if (!(ac97->scaps & AC97_SCAP_SURROUND_DAC)) + *spdif_slots = (1<scaps & AC97_SCAP_CENTER_LFE_DAC)) + *spdif_slots = (1<r[dbl].codec[cidx]->rates[idx]; + } + return rates; +} + +/** + * snd_ac97_pcm_assign - assign AC97 slots to given PCM streams + * @bus: the ac97 bus instance + * @pcms_count: count of PCMs to be assigned + * @pcms: PCMs to be assigned + * + * It assigns available AC97 slots for given PCMs. If none or only + * some slots are available, pcm->xxx.slots and pcm->xxx.rslots[] members + * are reduced and might be zero. + */ +int snd_ac97_pcm_assign(ac97_bus_t *bus, + unsigned short pcms_count, + const struct ac97_pcm *pcms) +{ + int i, j, k; + const struct ac97_pcm *pcm; + struct ac97_pcm *rpcms, *rpcm; + unsigned short avail_slots[2][4]; + unsigned char rate_table[2][4]; + unsigned short tmp, slots; + unsigned short spdif_slots[4]; + unsigned int rates; + ac97_t *codec; + + rpcms = snd_kcalloc(sizeof(struct ac97_pcm) * pcms_count, GFP_KERNEL); + if (rpcms == NULL) + return -ENOMEM; + memset(avail_slots, 0, sizeof(avail_slots)); + memset(rate_table, 0, sizeof(rate_table)); + memset(spdif_slots, 0, sizeof(spdif_slots)); + for (i = 0; i < 4; i++) { + codec = bus->codec[i]; + if (!codec) + continue; + avail_slots[0][i] = get_pslots(codec, &rate_table[0][i], &spdif_slots[i]); + avail_slots[1][i] = get_cslots(codec); + if (!(codec->scaps & AC97_SCAP_INDEP_SDIN)) { + for (j = 0; j < i; j++) { + if (bus->codec[j]) + avail_slots[1][i] &= ~avail_slots[1][j]; + } + } + } + /* FIXME: add double rate allocation */ + /* first step - exclusive devices */ + for (i = 0; i < pcms_count; i++) { + pcm = &pcms[i]; + rpcm = &rpcms[i]; + /* low-level driver thinks that it's more clever */ + if (pcm->copy_flag) { + *rpcm = *pcm; + continue; + } + rpcm->stream = pcm->stream; + rpcm->exclusive = pcm->exclusive; + rpcm->spdif = pcm->spdif; + rpcm->private_value = pcm->private_value; + rpcm->bus = bus; + rpcm->rates = ~0; + slots = pcm->r[0].slots; + for (j = 0; j < 4 && slots; j++) { + if (!bus->codec[j]) + continue; + rates = ~0; + if (pcm->spdif && pcm->stream == 0) + tmp = spdif_slots[j]; + else + tmp = avail_slots[pcm->stream][j]; + if (pcm->exclusive) { + /* exclusive access */ + tmp &= slots; + for (k = 0; k < i; k++) { + if (rpcm->stream == rpcms[k].stream) + tmp &= ~rpcms[k].r[0].rslots[j]; + } + } else { + /* non-exclusive access */ + tmp &= pcm->r[0].slots; + } + if (tmp) { + rpcm->r[0].rslots[j] = tmp; + rpcm->r[0].codec[j] = bus->codec[j]; + rpcm->r[0].rate_table[j] = rate_table[pcm->stream][j]; + rates = get_rates(rpcm, j, tmp, 0); + if (pcm->exclusive) + avail_slots[pcm->stream][j] &= ~tmp; + } + slots &= ~tmp; + rpcm->r[0].slots |= tmp; + rpcm->rates &= rates; + } + if (rpcm->rates == ~0) + rpcm->rates = 0; /* not used */ + } + bus->pcms_count = pcms_count; + bus->pcms = rpcms; + return 0; +} + +/** + * snd_ac97_pcm_open - opens the given AC97 pcm + * @pcm: the ac97 pcm instance + * @rate: rate in Hz, if codec does not support VRA, this value must be 48000Hz + * @cfg: output stream characteristics + * @slots: a subset of allocated slots (snd_ac97_pcm_assign) for this pcm + * + * It locks the specified slots and sets the given rate to AC97 registers. + */ +int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate, + enum ac97_pcm_cfg cfg, unsigned short slots) +{ + ac97_bus_t *bus; + int i, cidx, r = 0, ok_flag; + unsigned int reg_ok = 0; + unsigned char reg; + int err = 0; + + if (rate > 48000) /* FIXME: add support for double rate */ + return -EINVAL; + bus = pcm->bus; + if (cfg == AC97_PCM_CFG_SPDIF) { + int err; + for (cidx = 0; cidx < 4; cidx++) + if (bus->codec[cidx] && (bus->codec[cidx]->ext_id & AC97_EI_SPDIF)) { + err = set_spdif_rate(bus->codec[cidx], rate); + if (err < 0) + return err; + } + } + spin_lock_irq(&pcm->bus->bus_lock); + for (i = 3; i < 12; i++) { + if (!(slots & (1 << i))) + continue; + ok_flag = 0; + for (cidx = 0; cidx < 4; cidx++) { + if (bus->used_slots[pcm->stream][cidx] & (1 << i)) { + spin_unlock_irq(&pcm->bus->bus_lock); + err = -EBUSY; + goto error; + } + if (pcm->r[r].rslots[cidx] & (1 << i)) { + bus->used_slots[pcm->stream][cidx] |= (1 << i); + ok_flag++; + } + } + if (!ok_flag) { + spin_unlock_irq(&pcm->bus->bus_lock); + snd_printk(KERN_ERR "cannot find configuration for AC97 slot %i\n", i); + err = -EAGAIN; + goto error; + } + } + spin_unlock_irq(&pcm->bus->bus_lock); + for (i = 3; i < 12; i++) { + if (!(slots & (1 << i))) + continue; + for (cidx = 0; cidx < 4; cidx++) { + if (pcm->r[r].rslots[cidx] & (1 << i)) { + reg = get_slot_reg(pcm, cidx, i, r); + if (reg == 0xff) { + snd_printk(KERN_ERR "invalid AC97 slot %i?\n", i); + continue; + } + if (reg_ok & (1 << (reg - AC97_PCM_FRONT_DAC_RATE))) + continue; + //printk(KERN_DEBUG "setting ac97 reg 0x%x to rate %d\n", reg, rate); + err = snd_ac97_set_rate(pcm->r[r].codec[cidx], reg, rate); + if (err < 0) + snd_printk(KERN_ERR "error in snd_ac97_set_rate: cidx=%d, reg=0x%x, rate=%d, err=%d\n", cidx, reg, rate, err); + else + reg_ok |= (1 << (reg - AC97_PCM_FRONT_DAC_RATE)); + } + } + } + pcm->aslots = slots; + return 0; + + error: + pcm->aslots = slots; + snd_ac97_pcm_close(pcm); + return err; +} + +/** + * snd_ac97_pcm_close - closes the given AC97 pcm + * @pcm: the ac97 pcm instance + * + * It frees the locked AC97 slots. + */ +int snd_ac97_pcm_close(struct ac97_pcm *pcm) +{ + ac97_bus_t *bus; + unsigned short slots = pcm->aslots; + int i, cidx; + + bus = pcm->bus; + spin_lock_irq(&pcm->bus->bus_lock); + for (i = 3; i < 12; i++) { + if (!(slots & (1 << i))) + continue; + for (cidx = 0; cidx < 4; cidx++) + bus->used_slots[pcm->stream][cidx] &= ~(1 << i); + } + pcm->aslots = 0; + spin_unlock_irq(&pcm->bus->bus_lock); + return 0; +} diff -Nru a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c --- a/sound/pci/ac97/ac97_proc.c Mon Feb 2 22:07:58 2004 +++ b/sound/pci/ac97/ac97_proc.c Mon Feb 2 22:07:58 2004 @@ -37,15 +37,12 @@ static void snd_ac97_proc_read_main(ac97_t *ac97, snd_info_buffer_t * buffer, int subidx) { char name[64]; - unsigned int id; unsigned short val, tmp, ext, mext; static const char *spdif_slots[4] = { " SPDIF=3/4", " SPDIF=7/8", " SPDIF=6/9", " SPDIF=res" }; static const char *spdif_rates[4] = { " Rate=44.1kHz", " Rate=res", " Rate=48kHz", " Rate=32kHz" }; static const char *spdif_rates_cs4205[4] = { " Rate=48kHz", " Rate=44.1kHz", " Rate=res", " Rate=res" }; - id = snd_ac97_read(ac97, AC97_VENDOR_ID1) << 16; - id |= snd_ac97_read(ac97, AC97_VENDOR_ID2); - snd_ac97_get_name(NULL, id, name, 0); + snd_ac97_get_name(NULL, ac97->id, name, 0); snd_iprintf(buffer, "%d-%d/%d: %s\n\n", ac97->addr, ac97->num, subidx, name); if ((ac97->scaps & AC97_SCAP_AUDIO) == 0) goto __modem; @@ -299,21 +296,67 @@ } } -void snd_ac97_proc_init(snd_card_t * card, ac97_t * ac97, const char *prefix) +void snd_ac97_proc_init(ac97_t * ac97) { snd_info_entry_t *entry; char name[32]; + const char *prefix; - if (ac97->num) - sprintf(name, "%s#%d-%d", prefix, ac97->addr, ac97->num); - else - sprintf(name, "%s#%d", prefix, ac97->addr); - if (! snd_card_proc_new(card, name, &entry)) - snd_info_set_text_ops(entry, ac97, snd_ac97_proc_read); - if (ac97->num) - sprintf(name, "%s#%d-%dregs", prefix, ac97->addr, ac97->num); - else - sprintf(name, "%s#%dregs", prefix, ac97->addr); - if (! snd_card_proc_new(card, name, &entry)) - snd_info_set_text_ops(entry, ac97, snd_ac97_proc_regs_read); + if (ac97->bus->proc == NULL) + return; + prefix = ac97_is_audio(ac97) ? "ac97" : "mc97"; + sprintf(name, "%s#%d-%d", prefix, ac97->addr, ac97->num); + if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) { + snd_info_set_text_ops(entry, ac97, 1024, snd_ac97_proc_read); + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + entry = NULL; + } + } + ac97->proc = entry; + sprintf(name, "%s#%d-%d+regs", prefix, ac97->addr, ac97->num); + if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) { + snd_info_set_text_ops(entry, ac97, 1024, snd_ac97_proc_regs_read); + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + entry = NULL; + } + } + ac97->proc_regs = entry; +} + +void snd_ac97_proc_done(ac97_t * ac97) +{ + if (ac97->proc_regs) { + snd_info_unregister(ac97->proc_regs); + ac97->proc_regs = NULL; + } + if (ac97->proc) { + snd_info_unregister(ac97->proc); + ac97->proc = NULL; + } +} + +void snd_ac97_bus_proc_init(ac97_bus_t * bus) +{ + snd_info_entry_t *entry; + char name[32]; + + sprintf(name, "codec97#%d", bus->num); + if ((entry = snd_info_create_card_entry(bus->card, name, bus->card->proc_root)) != NULL) { + entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + entry = NULL; + } + } + bus->proc = entry; +} + +void snd_ac97_bus_proc_done(ac97_bus_t * bus) +{ + if (bus->proc) { + snd_info_unregister(bus->proc); + bus->proc = NULL; + } } diff -Nru a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c --- a/sound/pci/ac97/ak4531_codec.c Mon Feb 2 22:07:55 2004 +++ b/sound/pci/ac97/ak4531_codec.c Mon Feb 2 22:07:55 2004 @@ -425,7 +425,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(card, "ak4531", &entry)) - snd_info_set_text_ops(entry, ak4531, snd_ak4531_proc_read); + snd_info_set_text_ops(entry, ak4531, 1024, snd_ak4531_proc_read); } EXPORT_SYMBOL(snd_ak4531_mixer); diff -Nru a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c --- a/sound/pci/ali5451/ali5451.c Mon Feb 2 22:07:58 2004 +++ b/sound/pci/ali5451/ali5451.c Mon Feb 2 22:07:58 2004 @@ -265,6 +265,7 @@ unsigned int spurious_irq_count; unsigned int spurious_irq_max_delta; + ac97_bus_t *ac97_bus; ac97_t *ac97; unsigned short ac97_ext_id; unsigned short ac97_ext_status; @@ -1860,6 +1861,12 @@ ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, 2) }; +static void snd_ali_mixer_free_ac97_bus(ac97_bus_t *bus) +{ + ali_t *codec = snd_magic_cast(ali_t, bus->private_data, return); + codec->ac97_bus = NULL; +} + static void snd_ali_mixer_free_ac97(ac97_t *ac97) { ali_t *codec = snd_magic_cast(ali_t, ac97->private_data, return); @@ -1868,16 +1875,23 @@ static int __devinit snd_ali_mixer(ali_t * codec) { + ac97_bus_t bus; ac97_t ac97; unsigned int idx; int err; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_ali_codec_write; + bus.read = snd_ali_codec_read; + bus.private_data = codec; + bus.private_free = snd_ali_mixer_free_ac97_bus; + if ((err = snd_ac97_bus(codec->card, &bus, &codec->ac97_bus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_ali_codec_write; - ac97.read = snd_ali_codec_read; ac97.private_data = codec; ac97.private_free = snd_ali_mixer_free_ac97; - if ((err = snd_ac97_mixer(codec->card, &ac97, &codec->ac97)) < 0) { + if ((err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97)) < 0) { snd_printk("ali mixer creating error.\n"); return err; } @@ -2092,11 +2106,11 @@ if ((err = pci_enable_device(pci)) < 0) return err; /* check, if we can restrict PCI DMA transfers to 31 bits */ - if (!pci_dma_supported(pci, 0x7fffffff)) { + if (pci_set_dma_mask(pci, 0x7fffffff) < 0 || + pci_set_consistent_dma_mask(pci, 0x7fffffff) < 0) { snd_printk("architecture does not support 31bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x7fffffff); if ((codec = snd_magic_kcalloc(ali_t, 0, GFP_KERNEL)) == NULL) return -ENOMEM; diff -Nru a/sound/pci/als4000.c b/sound/pci/als4000.c --- a/sound/pci/als4000.c Mon Feb 2 22:07:58 2004 +++ b/sound/pci/als4000.c Mon Feb 2 22:07:58 2004 @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -78,14 +79,15 @@ MODULE_CLASSES("{sound}"); MODULE_DEVICES("{{Avance Logic,ALS4000}}"); +#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#define SUPPORT_JOYSTICK 1 +#endif + 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_PNP; /* Enable this card */ -static int joystick_port[SNDRV_CARDS] = -#ifdef CONFIG_ISA - {0x200}; /* enable as default */ -#else - {0}; /* disabled */ +#ifdef SUPPORT_JOYSTICK +static int joystick_port[SNDRV_CARDS]; #endif MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); @@ -105,6 +107,11 @@ typedef struct { unsigned long gcr; + struct resource *res_gcr; +#ifdef SUPPORT_JOYSTICK + struct gameport gameport; + struct resource *res_joystick; +#endif } snd_card_als4000_t; static struct pci_device_id snd_als4000_ids[] = { @@ -523,7 +530,7 @@ /******************************************************************/ -static void __devinit snd_als4000_set_addr(unsigned long gcr, +static void snd_als4000_set_addr(unsigned long gcr, unsigned int sb, unsigned int mpu, unsigned int opl, @@ -574,6 +581,18 @@ snd_card_als4000_t * acard = (snd_card_als4000_t *)card->private_data; /* make sure that interrupts are disabled */ snd_als4000_gcr_write_addr( acard->gcr, 0x8c, 0); + /* free resources */ +#ifdef SUPPORT_JOYSTICK + if (acard->res_joystick) { + if (acard->gameport.io) + gameport_unregister_port(&acard->gameport); + snd_als4000_set_addr(acard->gcr, 0, 0, 0, 0); /* disable joystick */ + release_resource(acard->res_joystick); + kfree_nocheck(acard->res_joystick); + } +#endif + release_resource(acard->res_gcr); + kfree_nocheck(acard->res_gcr); } static int __devinit snd_card_als4000_probe(struct pci_dev *pci, @@ -588,6 +607,7 @@ opl3_t *opl3; unsigned short word; int err; + int joystick = 0; if (dev >= SNDRV_CARDS) return -ENODEV; @@ -601,11 +621,11 @@ return err; } /* check, if we can restrict PCI DMA transfers to 24 bits */ - if (!pci_dma_supported(pci, 0x00ffffff)) { + if (pci_set_dma_mask(pci, 0x00ffffff) < 0 || + pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) { snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x00ffffff); gcr = pci_resource_start(pci, 0); if ((res_gcr_port = request_region(gcr, 0x40, "ALS4000")) == NULL) { @@ -617,9 +637,6 @@ pci_write_config_word(pci, PCI_COMMAND, word | PCI_COMMAND_IO); pci_set_master(pci); - /* disable all legacy ISA stuff except for joystick */ - snd_als4000_set_addr(gcr, 0, 0, 0, joystick_port[dev]); - card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof( snd_card_als4000_t ) ); if (card == NULL) { @@ -630,8 +647,29 @@ acard = (snd_card_als4000_t *)card->private_data; acard->gcr = gcr; + acard->res_gcr = res_gcr_port; card->private_free = snd_card_als4000_free; + /* disable all legacy ISA stuff except for joystick */ +#ifdef SUPPORT_JOYSTICK + if (joystick_port[dev] == 1) { + /* auto-detect */ + long p; + for (p = 0x200; p <= 0x218; p += 8) { + if ((acard->res_joystick = request_region(p, 8, "ALS4000 gameport")) != NULL) { + joystick_port[dev] = p; + break; + } + } + } else if (joystick_port[dev] > 0) + acard->res_joystick = request_region(joystick_port[dev], 8, "ALS4000 gameport"); + if (acard->res_joystick) + joystick = joystick_port[dev]; + else + joystick = 0; +#endif + snd_als4000_set_addr(gcr, 0, 0, 0, joystick); + if ((err = snd_sbdsp_create(card, gcr + 0x10, pci->irq, @@ -640,18 +678,21 @@ -1, SB_HW_ALS4000, &chip)) < 0) { - release_resource(res_gcr_port); - kfree_nocheck(res_gcr_port); snd_card_free(card); return err; } chip->pci = pci; chip->alt_port = gcr; - chip->res_alt_port = res_gcr_port; + snd_card_set_dev(card, &pci->dev); snd_als4000_configure(chip); - + + strcpy(card->driver, "ALS4000"); + strcpy(card->shortname, "Avance Logic ALS4000"); + sprintf(card->longname, "%s at 0x%lx, irq %i", + card->shortname, chip->alt_port, chip->irq); + if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_ALS4000, gcr+0x30, 1, pci->irq, 0, &chip->rmidi)) < 0) { @@ -680,10 +721,12 @@ } } - strcpy(card->driver, "ALS4000"); - strcpy(card->shortname, "Avance Logic ALS4000"); - sprintf(card->longname, "%s at 0x%lx, irq %i", - card->shortname, chip->alt_port, chip->irq); +#ifdef SUPPORT_JOYSTICK + if (acard->res_joystick) { + acard->gameport.io = joystick; + gameport_register_port(&acard->gameport); + } +#endif if ((err = snd_card_register(card)) < 0) { snd_card_free(card); @@ -730,7 +773,7 @@ #ifndef MODULE -/* format is: snd-als4000=enable,index,id */ +/* format is: snd-als4000=enable,index,id,joystick_port */ static int __init alsa_card_als4000_setup(char *str) { @@ -740,7 +783,11 @@ return 0; (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && - get_id(&str,&id[nr_dev]) == 2); + get_id(&str,&id[nr_dev]) == 2 +#ifdef SUPPORT_JOYSTICK + && get_option(&str,&joystick_port[nr_dev]) == 2 +#endif + ); nr_dev++; return 1; } diff -Nru a/sound/pci/azt3328.c b/sound/pci/azt3328.c --- a/sound/pci/azt3328.c Mon Feb 2 22:07:57 2004 +++ b/sound/pci/azt3328.c Mon Feb 2 22:07:57 2004 @@ -97,6 +97,7 @@ #include #include #include +#include #include #include #include @@ -113,6 +114,10 @@ MODULE_CLASSES("{sound}"); MODULE_DEVICES("{{Aztech,AZF3328}}"); +#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#define SUPPORT_JOYSTICK 1 +#endif + #define DEBUG_MISC 0 #define DEBUG_CALLS 0 #define DEBUG_MIXER 0 @@ -158,8 +163,9 @@ 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_PNP; /* Enable this card */ -static int joystick[SNDRV_CARDS] = - {-1}; /* "unset" as default */ +#ifdef SUPPORT_JOYSTICK +static int joystick[SNDRV_CARDS]; +#endif MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard."); @@ -170,9 +176,11 @@ MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(enable, "Enable AZF3328 soundcard."); MODULE_PARM_SYNTAX(enable, SNDRV_INDEX_DESC); +#ifdef SUPPORT_JOYSTICK MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); -MODULE_PARM_DESC(joystick, "Forced joystick port enable for AZF3328 soundcard. (0 = force disable)"); -MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLED); +MODULE_PARM_DESC(joystick, "Enable joystick for AZF3328 soundcard."); +MODULE_PARM_SYNTAX(joystick, SNDRV_BOOLEAN_FALSE_DESC); +#endif typedef struct _snd_azf3328 azf3328_t; #define chip_t azf3328_t @@ -190,7 +198,11 @@ struct resource *res_synth_port; unsigned long mixer_port; struct resource *res_mixer_port; - unsigned long game_port; + +#ifdef SUPPORT_JOYSTICK + struct gameport gameport; + struct resource *res_joystick; +#endif struct pci_dev *pci; snd_card_t *card; @@ -1259,6 +1271,16 @@ synchronize_irq(chip->irq); __end_hw: +#ifdef SUPPORT_JOYSTICK + if (chip->res_joystick) { + gameport_unregister_port(&chip->gameport); + /* disable gameport */ + snd_azf3328_io2_write(chip, IDX_IO2_LEGACY_ADDR, + snd_azf3328_io2_read(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY); + release_resource(chip->res_joystick); + kfree_nocheck(chip->res_joystick); + } +#endif if (chip->res_codec_port) { release_resource(chip->res_codec_port); kfree_nocheck(chip->res_codec_port); @@ -1339,11 +1361,11 @@ chip->irq = -1; /* check if we can restrict PCI DMA transfers to 24 bits */ - if (!pci_dma_supported(pci, 0x00ffffff)) { + if (pci_set_dma_mask(pci, 0x00ffffff) < 0 || + pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) { snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x00ffffff); chip->codec_port = pci_resource_start(pci, 0); if ((chip->res_codec_port = request_region(chip->codec_port, 0x80, "Aztech AZF3328 I/O")) == NULL) { @@ -1415,57 +1437,33 @@ spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_card_set_dev(card, &pci->dev); + *rchip = chip; return 0; } +#ifdef SUPPORT_JOYSTICK static void __devinit snd_azf3328_config_joystick(azf3328_t *chip, int joystick) { - int i, detected = 0, activate = 0; - char *msg = NULL; unsigned char val; - if (joystick == -1) /* auto detection/activation */ - { - for (i=0x200; i <= 0x207; i++) - if (inb(i) != 0xff) - detected = 1; /* other joy found, don't activate */ + if (joystick == 1) { + if ((chip->res_joystick = request_region(0x200, 8, "AZF3328 gameport")) != NULL) + chip->gameport.io = 0x200; } - if ((joystick == -1) && (detected == 1)) - { - activate = 0; - msg = "DISABLED (address occupied by another joystick port)"; - } - else - if ((joystick == -1) && (detected == 0)) - { - activate = 1; - msg = "ENABLED (via autodetect)"; - } - else - if (joystick == 0) - { - activate = 0; - msg = "DISABLED (forced)"; - } - else - if (joystick == 1) - { - activate = 1; - msg = "ENABLED (Warning: forced!)"; - } val = inb(chip->io2_port + IDX_IO2_LEGACY_ADDR); - if (activate) - val |= LEGACY_JOY; + if (chip->res_joystick) + val |= LEGACY_JOY; else - val &= ~LEGACY_JOY; + val &= ~LEGACY_JOY; outb(val, chip->io2_port + IDX_IO2_LEGACY_ADDR); -#ifdef MODULE - printk("azt3328: Joystick port: %s.\n", msg); -#endif + if (chip->res_joystick) + gameport_register_port(&chip->gameport); } +#endif static int __devinit snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) @@ -1537,7 +1535,9 @@ "azt3328: Feel free to contact hw7oshyuv3001@sneakemail.com for bug reports etc.!\n"); #endif +#ifdef SUPPORT_JOYSTICK snd_azf3328_config_joystick(chip, joystick[dev]); +#endif pci_set_drvdata(pci, chip); dev++; @@ -1598,7 +1598,7 @@ #ifndef MODULE -/* format is: snd-azf3328=enable,index,id */ +/* format is: snd-azf3328=enable,index,id,joystick */ static int __init alsa_card_azf3328_setup(char *str) { @@ -1610,12 +1610,16 @@ return 0; (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && - get_id(&str,&id[nr_dev]) == 2); + get_id(&str,&id[nr_dev]) == 2 +#ifdef SUPPORT_JOYSTICK + && get_option(&str,&joystick[nr_dev]) == 2 +#endif + ); nr_dev++; snd_azf3328_dbgcallleave(); return 1; } -__setup("snd-azf3328=", alsa_card_azf3328_setup); +__setup("snd-azt3328=", alsa_card_azf3328_setup); #endif /* ifndef MODULE */ diff -Nru a/sound/pci/cmipci.c b/sound/pci/cmipci.c --- a/sound/pci/cmipci.c Mon Feb 2 22:07:57 2004 +++ b/sound/pci/cmipci.c Mon Feb 2 22:07:57 2004 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -52,14 +53,21 @@ "{C-Media,CMI8338A}," "{C-Media,CMI8338B}}"); +#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#define SUPPORT_JOYSTICK 1 +#endif + 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_PNP; /* Enable switches */ -static long mpu_port[SNDRV_CARDS] = {0x330, [1 ... (SNDRV_CARDS-1)]=-1}; -static long fm_port[SNDRV_CARDS] = {0x388, [1 ... (SNDRV_CARDS-1)]=-1}; +static long mpu_port[SNDRV_CARDS]; +static long fm_port[SNDRV_CARDS]; #ifdef DO_SOFT_AC3 static int soft_ac3[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)]=1}; #endif +#ifdef SUPPORT_JOYSTICK +static int joystick_port[SNDRV_CARDS]; +#endif MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(index, "Index value for C-Media PCI soundcard."); @@ -72,15 +80,20 @@ MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); MODULE_PARM_DESC(mpu_port, "MPU-401 port."); -MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED ",allows:{{-1},{0x330},{0x320},{0x310},{0x300}},dialog:list"); +MODULE_PARM_SYNTAX(mpu_port, SNDRV_ENABLED ",allows:{{0},{0x330},{0x320},{0x310},{0x300}},dialog:list"); MODULE_PARM(fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); MODULE_PARM_DESC(fm_port, "FM port."); -MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED ",allows:{{-1},{0x388},{0x3c8},{0x3e0},{0x3e8}},dialog:list"); +MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED ",allows:{{0},{0x388},{0x3c8},{0x3e0},{0x3e8}},dialog:list"); #ifdef DO_SOFT_AC3 MODULE_PARM(soft_ac3, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); MODULE_PARM_DESC(soft_ac3, "Sofware-conversion of raw SPDIF packets (model 033 only)."); MODULE_PARM_SYNTAX(soft_ac3, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC); #endif +#ifdef SUPPORT_JOYSTICK +MODULE_PARM(joystick_port, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(joystick_port, "Joystick port address."); +MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED ",allows:{{0},{1},{0x200},{0x201}},dialog:list"); +#endif #ifndef PCI_DEVICE_ID_CMEDIA_CM8738 #define PCI_DEVICE_ID_CMEDIA_CM8738 0x0111 @@ -339,6 +352,7 @@ #define CM_EXTENT_MIDI 0x2 #define CM_EXTENT_SYNTH 0x4 + /* * pci ids */ @@ -480,6 +494,11 @@ /* external MIDI */ snd_rawmidi_t *rmidi; +#ifdef SUPPORT_JOYSTICK + struct gameport gameport; + struct resource *res_joystick; +#endif + spinlock_t reg_lock; }; @@ -703,6 +722,7 @@ spin_lock_irqsave(&cm->reg_lock, flags); snd_cmipci_set_bit(cm, CM_REG_LEGACY_CTRL, CM_NXCHG); + snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC); if (channels > 4) { snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D); snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_CHB3D5C); @@ -727,6 +747,7 @@ snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_CHB3D5C); snd_cmipci_clear_bit(cm, CM_REG_LEGACY_CTRL, CM_CHB3D6C); snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_ENCENTER); + snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_XCHGDAC); spin_unlock_irqrestore(&cm->reg_lock, flags); } } @@ -1851,6 +1872,7 @@ return err; runtime->hw = snd_cmipci_playback; snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x10000); + cm->dig_pcm_status = cm->dig_status; return 0; } @@ -2599,7 +2621,7 @@ DEFINE_BIT_SWITCH_ARG(fourch, CM_REG_MISC_CTRL, CM_N4SPK3D, 0, 0); DEFINE_BIT_SWITCH_ARG(line_rear, CM_REG_MIXER1, CM_SPK4, 1, 0); DEFINE_BIT_SWITCH_ARG(line_bass, CM_REG_LEGACY_CTRL, CM_LINE_AS_BASS, 0, 0); -DEFINE_BIT_SWITCH_ARG(joystick, CM_REG_FUNCTRL1, CM_JYSTK_EN, 0, 0); +// DEFINE_BIT_SWITCH_ARG(joystick, CM_REG_FUNCTRL1, CM_JYSTK_EN, 0, 0); /* now module option */ DEFINE_SWITCH_ARG(modem, CM_REG_MISC_CTRL, CM_FLINKON|CM_FLINKOFF, CM_FLINKON, 0, 0); #define DEFINE_SWITCH(sname, stype, sarg) \ @@ -2649,11 +2671,14 @@ /* both for CM8338/8738 */ static snd_kcontrol_new_t snd_cmipci_mixer_switches[] __devinitdata = { - DEFINE_MIXER_SWITCH("Exchange DAC", exchange_dac), DEFINE_MIXER_SWITCH("Four Channel Mode", fourch), DEFINE_MIXER_SWITCH("Line-In As Rear", line_rear), }; +/* for non-multichannel chips */ +static snd_kcontrol_new_t snd_cmipci_nomulti_switch __devinitdata = +DEFINE_MIXER_SWITCH("Exchange DAC", exchange_dac); + /* only for CM8738 */ static snd_kcontrol_new_t snd_cmipci_8738_mixer_switches[] __devinitdata = { #if 0 /* controlled in pcm device */ @@ -2693,7 +2718,7 @@ /* card control switches */ static snd_kcontrol_new_t snd_cmipci_control_switches[] __devinitdata = { - DEFINE_CARD_SWITCH("Joystick", joystick), + // DEFINE_CARD_SWITCH("Joystick", joystick), /* now module option */ DEFINE_CARD_SWITCH("Modem", modem), }; @@ -2729,6 +2754,11 @@ if (err < 0) return err; } + if (! cm->can_multi_ch) { + err = snd_ctl_add(cm->card, snd_ctl_new1(&snd_cmipci_nomulti_switch, cm)); + if (err < 0) + return err; + } if (cm->device == PCI_DEVICE_ID_CMEDIA_CM8738 || cm->device == PCI_DEVICE_ID_CMEDIA_CM8738B) { sw = snd_cmipci_8738_mixer_switches; @@ -2816,7 +2846,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(cm->card, "cmipci", &entry)) - snd_info_set_text_ops(entry, cm, snd_cmipci_proc_read); + snd_info_set_text_ops(entry, cm, 1024, snd_cmipci_proc_read); } #else /* !CONFIG_PROC_FS */ static inline void snd_cmipci_proc_init(cmipci_t *cm) {} @@ -2905,6 +2935,14 @@ free_irq(cm->irq, (void *)cm); } +#ifdef SUPPORT_JOYSTICK + if (cm->res_joystick) { + gameport_unregister_port(&cm->gameport); + snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN); + release_resource(cm->res_joystick); + kfree_nocheck(cm->res_joystick); + } +#endif if (cm->res_iobase) { release_resource(cm->res_iobase); kfree_nocheck(cm->res_iobase); @@ -2928,8 +2966,8 @@ .dev_free = snd_cmipci_dev_free, }; unsigned int val = 0; - unsigned long iomidi = mpu_port[dev]; - unsigned long iosynth = fm_port[dev]; + long iomidi = mpu_port[dev]; + long iosynth = fm_port[dev]; int pcm_index, pcm_spdif_index; *rcmipci = NULL; @@ -3110,6 +3148,33 @@ snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPDIF48K|CM_SPDF_AC97); #endif /* USE_VAR48KRATE */ +#ifdef SUPPORT_JOYSTICK + if (joystick_port[dev] > 0) { + if (joystick_port[dev] == 1) { /* auto-detect */ + static int ports[] = { 0x200, 0x201, 0 }; + int i; + for (i = 0; ports[i]; i++) { + joystick_port[dev] = ports[i]; + cm->res_joystick = request_region(ports[i], 8, "CMIPCI gameport"); + if (cm->res_joystick) + break; + } + } else { + cm->res_joystick = request_region(joystick_port[dev], 8, "CMIPCI gameport"); + } + } + if (cm->res_joystick) { + cm->gameport.io = joystick_port[dev]; + snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN); + gameport_register_port(&cm->gameport); + } else { + if (joystick_port[dev] > 0) + printk(KERN_WARNING "cmipci: cannot reserve joystick ports\n"); + snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN); + } +#endif + snd_card_set_dev(card, &pci->dev); + *rcmipci = cm; return 0; @@ -3218,7 +3283,7 @@ #ifndef MODULE /* format is: snd-cmipci=enable,index,id, - mpu_port,fm_port */ + mpu_port,fm_port,soft_ac3,joystick_port */ static int __init alsa_card_cmipci_setup(char *str) { @@ -3229,8 +3294,15 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2); + get_option_long(&str,&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&fm_port[nr_dev]) == 2 +#ifdef DO_SOFT_AC3 + && get_option(&str,&soft_ac3[nr_dev]) == 2 +#endif +#ifdef SUPPORT_JOYSTICK + && get_option(&str,&joystick_port[nr_dev]) == 2 +#endif + ); nr_dev++; return 1; } diff -Nru a/sound/pci/cs4281.c b/sound/pci/cs4281.c --- a/sound/pci/cs4281.c Mon Feb 2 22:07:58 2004 +++ b/sound/pci/cs4281.c Mon Feb 2 22:07:58 2004 @@ -479,6 +479,7 @@ int dual_codec; + ac97_bus_t *ac97_bus; ac97_t *ac97; ac97_t *ac97_secondary; @@ -564,7 +565,7 @@ } static void snd_cs4281_ac97_write(ac97_t *ac97, - unsigned short reg, unsigned short val) + unsigned short reg, unsigned short val) { /* * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address @@ -609,7 +610,7 @@ } static unsigned short snd_cs4281_ac97_read(ac97_t *ac97, - unsigned short reg) + unsigned short reg) { cs4281_t *chip = snd_magic_cast(cs4281_t, ac97->private_data, return -ENXIO); int count; @@ -1119,6 +1120,12 @@ .private_value = ((BA0_PPLVC << 16) | BA0_PPRVC), }; +static void snd_cs4281_mixer_free_ac97_bus(ac97_bus_t *bus) +{ + cs4281_t *chip = snd_magic_cast(cs4281_t, bus->private_data, return); + chip->ac97_bus = NULL; +} + static void snd_cs4281_mixer_free_ac97(ac97_t *ac97) { cs4281_t *chip = snd_magic_cast(cs4281_t, ac97->private_data, return); @@ -1131,19 +1138,26 @@ static int __devinit snd_cs4281_mixer(cs4281_t * chip) { snd_card_t *card = chip->card; + ac97_bus_t bus; ac97_t ac97; int err; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_cs4281_ac97_write; + bus.read = snd_cs4281_ac97_read; + bus.private_data = chip; + bus.private_free = snd_cs4281_mixer_free_ac97_bus; + if ((err = snd_ac97_bus(card, &bus, &chip->ac97_bus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_cs4281_ac97_write; - ac97.read = snd_cs4281_ac97_read; ac97.private_data = chip; ac97.private_free = snd_cs4281_mixer_free_ac97; - if ((err = snd_ac97_mixer(card, &ac97, &chip->ac97)) < 0) + if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) return err; if (chip->dual_codec) { ac97.num = 1; - if ((err = snd_ac97_mixer(card, &ac97, &chip->ac97_secondary)) < 0) + if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97_secondary)) < 0) return err; } if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4281_fm_vol, chip))) < 0) @@ -1178,23 +1192,11 @@ if (file->f_pos + size > CS4281_BA0_SIZE) size = (long)CS4281_BA0_SIZE - file->f_pos; if (size > 0) { - char *tmp; - long res; - unsigned long virt; - if ((tmp = kmalloc(size, GFP_KERNEL)) == NULL) - return -ENOMEM; - virt = chip->ba0 + file->f_pos; - memcpy_fromio(tmp, virt, size); - if (copy_to_user(buf, tmp, size)) - res = -EFAULT; - else { - res = size; - file->f_pos += size; - } - kfree(tmp); - return res; + if (copy_to_user_fromio(buf, chip->ba0 + file->f_pos, size)) + return -EFAULT; + file->f_pos += size; } - return 0; + return size; } static long snd_cs4281_BA1_read(snd_info_entry_t *entry, void *file_private_data, @@ -1207,23 +1209,11 @@ if (file->f_pos + size > CS4281_BA1_SIZE) size = (long)CS4281_BA1_SIZE - file->f_pos; if (size > 0) { - char *tmp; - long res; - unsigned long virt; - if ((tmp = kmalloc(size, GFP_KERNEL)) == NULL) - return -ENOMEM; - virt = chip->ba1 + file->f_pos; - memcpy_fromio(tmp, virt, size); - if (copy_to_user(buf, tmp, size)) - res = -EFAULT; - else { - res = size; - file->f_pos += size; - } - kfree(tmp); - return res; + if (copy_to_user_fromio(buf, chip->ba1 + file->f_pos, size)) + return -EFAULT; + file->f_pos += size; } - return 0; + return size; } static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = { @@ -1239,7 +1229,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(chip->card, "cs4281", &entry)) - snd_info_set_text_ops(entry, chip, snd_cs4281_proc_read); + snd_info_set_text_ops(entry, chip, 1024, snd_cs4281_proc_read); if (! snd_card_proc_new(chip->card, "cs4281_BA0", &entry)) { entry->content = SNDRV_INFO_CONTENT_DATA; entry->private_data = chip; @@ -1479,6 +1469,8 @@ snd_cs4281_free(chip); return err; } + + snd_card_set_dev(card, &pci->dev); *rchip = chip; return 0; diff -Nru a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c --- a/sound/pci/cs46xx/cs46xx_lib.c Mon Feb 2 22:07:55 2004 +++ b/sound/pci/cs46xx/cs46xx_lib.c Mon Feb 2 22:07:55 2004 @@ -1804,6 +1804,13 @@ /* * Mixer routines */ +static void snd_cs46xx_mixer_free_ac97_bus(ac97_bus_t *bus) +{ + cs46xx_t *chip = snd_magic_cast(cs46xx_t, bus->private_data, return); + + chip->ac97_bus = NULL; +} + static void snd_cs46xx_mixer_free_ac97(ac97_t *ac97) { cs46xx_t *chip = snd_magic_cast(cs46xx_t, ac97->private_data, return); @@ -2445,6 +2452,7 @@ int __devinit snd_cs46xx_mixer(cs46xx_t *chip) { snd_card_t *card = chip->card; + ac97_bus_t bus; ac97_t ac97; snd_ctl_elem_id_t id; int err; @@ -2453,14 +2461,20 @@ /* detect primary codec */ chip->nr_ac97_codecs = 0; snd_printdd("snd_cs46xx: detecting primary codec\n"); + memset(&bus, 0, sizeof(bus)); + bus.write = snd_cs46xx_ac97_write; + bus.read = snd_cs46xx_ac97_read; +#ifdef CONFIG_SND_CS46XX_NEW_DSP + bus.reset = snd_cs46xx_codec_reset; +#endif + bus.private_data = chip; + bus.private_free = snd_cs46xx_mixer_free_ac97_bus; + if ((err = snd_ac97_bus(card, &bus, &chip->ac97_bus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_cs46xx_ac97_write; - ac97.read = snd_cs46xx_ac97_read; ac97.private_data = chip; ac97.private_free = snd_cs46xx_mixer_free_ac97; -#ifdef CONFIG_SND_CS46XX_NEW_DSP - ac97.reset = snd_cs46xx_codec_reset; -#endif chip->ac97[CS46XX_PRIMARY_CODEC_INDEX] = &ac97; snd_cs46xx_ac97_write(&ac97, AC97_MASTER, 0x8000); @@ -2474,7 +2488,7 @@ return -ENXIO; _ok: - if ((err = snd_ac97_mixer(card, &ac97, &chip->ac97[CS46XX_PRIMARY_CODEC_INDEX])) < 0) + if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97[CS46XX_PRIMARY_CODEC_INDEX])) < 0) return err; snd_printdd("snd_cs46xx: primary codec phase one\n"); chip->nr_ac97_codecs = 1; @@ -2483,8 +2497,6 @@ snd_printdd("snd_cs46xx: detecting seconadry codec\n"); /* try detect a secondary codec */ memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_cs46xx_ac97_write; - ac97.read = snd_cs46xx_ac97_read; ac97.private_data = chip; ac97.private_free = snd_cs46xx_mixer_free_ac97; ac97.num = CS46XX_SECONDARY_CODEC_INDEX; @@ -2516,13 +2528,7 @@ /* well, one codec only ... */ goto _end; _ok2: - /* set secondary codec in extended mode */ - - /* use custom reset to set secondary codec in - extended mode */ - ac97.reset = snd_cs46xx_codec_reset; - - if ((err = snd_ac97_mixer(card, &ac97, &chip->ac97[CS46XX_SECONDARY_CODEC_INDEX])) < 0) + if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97[CS46XX_SECONDARY_CODEC_INDEX])) < 0) return err; chip->nr_ac97_codecs = 2; @@ -2546,8 +2552,10 @@ #ifdef CONFIG_SND_CS46XX_NEW_DSP if (chip->nr_ac97_codecs == 1 && - snd_cs46xx_codec_read(chip, AC97_VENDOR_ID2, - CS46XX_PRIMARY_CODEC_INDEX) == 0x592d) { + (snd_cs46xx_codec_read(chip, AC97_VENDOR_ID2, + CS46XX_PRIMARY_CODEC_INDEX) == 0x592b || + snd_cs46xx_codec_read(chip, AC97_VENDOR_ID2, + CS46XX_PRIMARY_CODEC_INDEX) == 0x592d)) { /* set primary cs4294 codec into Extended Audio Mode */ snd_printdd("setting EAM bit on cs4294 CODEC\n"); snd_cs46xx_codec_write(chip, AC97_CSR_ACMODE, 0x200, @@ -2849,23 +2857,11 @@ if (file->f_pos + (size_t)size > region->size) size = region->size - file->f_pos; if (size > 0) { - char *tmp; - long res; - unsigned long virt; - if ((tmp = kmalloc(size, GFP_KERNEL)) == NULL) - return -ENOMEM; - virt = region->remap_addr + file->f_pos; - memcpy_fromio(tmp, virt, size); - if (copy_to_user(buf, tmp, size)) - res = -EFAULT; - else { - res = size; - file->f_pos += size; - } - kfree(tmp); - return res; + if (copy_to_user_fromio(buf, region->remap_addr + file->f_pos, size)) + return -EFAULT; + file->f_pos += size; } - return 0; + return size; } static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = { @@ -4004,6 +4000,8 @@ } chip->active_ctrl(chip, -1); /* disable CLKRUN */ + + snd_card_set_dev(card, &pci->dev); *rchip = chip; return 0; diff -Nru a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c --- a/sound/pci/emu10k1/emu10k1_main.c Mon Feb 2 22:07:58 2004 +++ b/sound/pci/emu10k1/emu10k1_main.c Mon Feb 2 22:07:58 2004 @@ -239,14 +239,9 @@ } } - if (!emu->APS) { /* enable analog output */ - if (!emu->audigy) { - unsigned int reg = inl(emu->port + HCFG); - outl(reg | HCFG_GPOUT0, emu->port + HCFG); - } else { - unsigned int reg = inl(emu->port + A_IOCFG); - outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); - } + if (emu->audigy) { /* enable analog output */ + unsigned int reg = inl(emu->port + A_IOCFG); + outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); } /* @@ -269,6 +264,9 @@ * This has to be done after init ALice3 I2SOut beyond 48KHz. * So, sequence is important. */ outl(inl(emu->port + A_IOCFG) | 0x0040, emu->port + A_IOCFG); + } else { + /* Disable routing from AC97 line out to Front speakers */ + outl(inl(emu->port + A_IOCFG) | 0x0080, emu->port + A_IOCFG); } } @@ -601,7 +599,8 @@ return -ENOMEM; /* set the DMA transfer mask */ emu->dma_mask = is_audigy ? AUDIGY_DMA_MASK : EMU10K1_DMA_MASK; - if (pci_set_dma_mask(pci, emu->dma_mask) < 0) { + if (pci_set_dma_mask(pci, emu->dma_mask) < 0 || + pci_set_consistent_dma_mask(pci, emu->dma_mask) < 0) { snd_printk(KERN_ERR "architecture does not support PCI busmaster DMA with mask 0x%lx\n", emu->dma_mask); snd_magic_kfree(emu); return -ENXIO; @@ -715,6 +714,7 @@ snd_emu10k1_proc_init(emu); + snd_card_set_dev(card, &pci->dev); *remu = emu; return 0; } diff -Nru a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c --- a/sound/pci/emu10k1/emu10k1_patch.c Mon Feb 2 22:07:56 2004 +++ b/sound/pci/emu10k1/emu10k1_patch.c Mon Feb 2 22:07:56 2004 @@ -36,7 +36,7 @@ */ int snd_emu10k1_sample_new(snd_emux_t *rec, snd_sf_sample_t *sp, - snd_util_memhdr_t *hdr, const void *data, long count) + snd_util_memhdr_t *hdr, const void __user *data, long count) { int offset; int truesize, size, loopsize, blocksize; diff -Nru a/sound/pci/emu10k1/emu10k1_synth.c b/sound/pci/emu10k1/emu10k1_synth.c --- a/sound/pci/emu10k1/emu10k1_synth.c Mon Feb 2 22:07:56 2004 +++ b/sound/pci/emu10k1/emu10k1_synth.c Mon Feb 2 22:07:56 2004 @@ -58,6 +58,7 @@ emu->midi_ports = arg->seq_ports < 2 ? arg->seq_ports : 2; /* maximum two ports */ emu->midi_devidx = hw->audigy ? 2 : 1; /* audigy has two external midis */ emu->linear_panning = 0; + emu->hwdep_idx = 2; /* FIXED */ if (snd_emux_register(emu, dev->card, arg->index, "Emu10k1") < 0) { snd_emux_free(emu); diff -Nru a/sound/pci/emu10k1/emu10k1_synth_local.h b/sound/pci/emu10k1/emu10k1_synth_local.h --- a/sound/pci/emu10k1/emu10k1_synth_local.h Mon Feb 2 22:07:56 2004 +++ b/sound/pci/emu10k1/emu10k1_synth_local.h Mon Feb 2 22:07:56 2004 @@ -26,7 +26,7 @@ #include /* emu10k1_patch.c */ -int snd_emu10k1_sample_new(snd_emux_t *private_data, snd_sf_sample_t *sp, snd_util_memhdr_t *hdr, const void *_data, long count); +int snd_emu10k1_sample_new(snd_emux_t *private_data, snd_sf_sample_t *sp, snd_util_memhdr_t *hdr, const void __user *_data, long count); int snd_emu10k1_sample_free(snd_emux_t *private_data, snd_sf_sample_t *sp, snd_util_memhdr_t *hdr); int snd_emu10k1_memhdr_init(snd_emux_t *emu); diff -Nru a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c --- a/sound/pci/emu10k1/emufx.c Mon Feb 2 22:07:56 2004 +++ b/sound/pci/emu10k1/emufx.c Mon Feb 2 22:07:56 2004 @@ -913,8 +913,12 @@ return -EFAULT; if (snd_emu10k1_look_for_ctl(emu, &gctl.id)) continue; - if (snd_ctl_find_id(emu->card, &gctl.id) != NULL) + down_read(&emu->card->controls_rwsem); + if (snd_ctl_find_id(emu->card, &gctl.id) != NULL) { + up_read(&emu->card->controls_rwsem); return -EEXIST; + } + up_read(&emu->card->controls_rwsem); if (gctl.id.iface != SNDRV_CTL_ELEM_IFACE_MIXER && gctl.id.iface != SNDRV_CTL_ELEM_IFACE_PCM) return -EINVAL; @@ -1009,13 +1013,16 @@ unsigned int i; snd_ctl_elem_id_t *_id, id; snd_emu10k1_fx8010_ctl_t *ctl; + snd_card_t *card = emu->card; for (i = 0, _id = icode->gpr_del_controls; i < icode->gpr_del_control_count; i++, _id++) { snd_runtime_check(copy_from_user(&id, _id, sizeof(id)) == 0, continue); + down_write(&card->controls_rwsem); ctl = snd_emu10k1_look_for_ctl(emu, &id); - snd_runtime_check(ctl == NULL, continue); - snd_ctl_remove(emu->card, ctl->kcontrol); + if (ctl) + snd_ctl_remove(card, ctl->kcontrol); + up_write(&card->controls_rwsem); } } @@ -1234,14 +1241,12 @@ * initial DSP configuration for Audigy */ -#define A_GPR_ACCU 0xd6 -#define A_GPR_COND 0xd7 - static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu) { int err, i, z, gpr, nctl; const int playback = 10; const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */ + const int stereo_mix = capture + 2; const int tmp = 0x88; u32 ptr; emu10k1_fx8010_code_t *icode; @@ -1265,45 +1270,52 @@ strcpy(icode->name, "Audigy DSP code for ALSA"); ptr = 0; nctl = 0; - gpr = capture + 10; + gpr = stereo_mix + 10; /* stop FX processor */ snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP); - /* Wave Playback Volume */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100); + /* PCM front Playback Volume (independent from stereo mix) */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100); gpr += 2; - - /* Wave Surround Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Surround Playback Volume", gpr, 0); + + /* PCM Surround Playback (independent from stereo mix) */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100); gpr += 2; - /* Wave Center Playback */ - /* Center = sub = Left/2 + Right/2 */ - A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_FXBUS(FXBUS_PCM_LEFT), 0xcd, A_FXBUS(FXBUS_PCM_RIGHT)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_GPR(tmp)); - snd_emu10k1_init_mono_control(&controls[nctl++], "Wave Center Playback Volume", gpr, 0); + /* PCM Center Playback (independent from stereo mix) */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER)); + snd_emu10k1_init_mono_control(&controls[nctl++], "PCM Center Playback Volume", gpr, 100); gpr++; - /* Wave LFE Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_GPR(tmp)); - snd_emu10k1_init_mono_control(&controls[nctl++], "Wave LFE Playback Volume", gpr, 0); + /* PCM LFE Playback (independent from stereo mix) */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE)); + snd_emu10k1_init_mono_control(&controls[nctl++], "PCM LFE Playback Volume", gpr, 100); gpr++; + + /* + * Stereo Mix + */ + /* Wave (PCM) Playback Volume (will be renamed later) */ + A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); + A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Playback Volume", gpr, 100); + gpr += 2; /* Music Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+0), A_GPR(playback+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT)); + A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+0), A_GPR(stereo_mix+0), A_GPR(gpr), A_FXBUS(FXBUS_MIDI_LEFT)); + A_OP(icode, &ptr, iMAC0, A_GPR(stereo_mix+1), A_GPR(stereo_mix+1), A_GPR(gpr+1), A_FXBUS(FXBUS_MIDI_RIGHT)); snd_emu10k1_init_stereo_control(&controls[nctl++], "Music Playback Volume", gpr, 100); gpr += 2; - /* Wave Capture */ + /* Wave (PCM) Capture */ A_OP(icode, &ptr, iMAC0, A_GPR(capture+0), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT)); A_OP(icode, &ptr, iMAC0, A_GPR(capture+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT)); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Capture Volume", gpr, 0); + snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Capture Volume", gpr, 0); gpr += 2; /* Music Capture */ @@ -1312,42 +1324,29 @@ snd_emu10k1_init_stereo_control(&controls[nctl++], "Music Capture Volume", gpr, 0); gpr += 2; - /* Surround Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR)); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 80); - gpr += 2; - - /* Center Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_FXBUS(FXBUS_PCM_CENTER)); - snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 80); - gpr++; - - /* LFE Playback */ - A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_FXBUS(FXBUS_PCM_LFE)); - snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 80); - gpr++; - /* * inputs */ #define A_ADD_VOLUME_IN(var,vol,input) \ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) - /* AC'97 Playback Volume */ - A_ADD_VOLUME_IN(playback, gpr, A_EXTIN_AC97_L); - A_ADD_VOLUME_IN(playback+1, gpr+1, A_EXTIN_AC97_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], "AC97 Playback Volume", gpr, 0); + /* AC'97 Playback Volume - used only for mic */ + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AC97_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AC97_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], "AMic Playback Volume", gpr, 0); gpr += 2; - /* AC'97 Capture Volume */ + /* AC'97 Capture Volume - used only for mic */ A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_AC97_L); A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AC97_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], "AC97 Capture Volume", gpr, 100); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Mic Capture Volume", gpr, 0); gpr += 2; + /* mic capture buffer */ + A_OP(icode, &ptr, iINTERP, A_EXTOUT(A_EXTOUT_MIC_CAP), A_EXTIN(A_EXTIN_AC97_L), 0xcd, A_EXTIN(A_EXTIN_AC97_R)); + /* Audigy CD Playback Volume */ - A_ADD_VOLUME_IN(playback, gpr, A_EXTIN_SPDIF_CD_L); - A_ADD_VOLUME_IN(playback+1, gpr+1, A_EXTIN_SPDIF_CD_R); + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_SPDIF_CD_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_SPDIF_CD_R); snd_emu10k1_init_stereo_control(&controls[nctl++], "Audigy CD Playback Volume", gpr, 0); gpr += 2; /* Audigy CD Capture Volume */ @@ -1357,19 +1356,19 @@ gpr += 2; /* Optical SPDIF Playback Volume */ - A_ADD_VOLUME_IN(playback, gpr, A_EXTIN_OPT_SPDIF_L); - A_ADD_VOLUME_IN(playback+1, gpr+1, A_EXTIN_OPT_SPDIF_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Optical IEC958 Playback Volume", gpr, 0); + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_OPT_SPDIF_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_OPT_SPDIF_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], "IEC958 Optical Playback Volume", gpr, 0); gpr += 2; /* Optical SPDIF Capture Volume */ A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_OPT_SPDIF_L); A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_OPT_SPDIF_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Optical IEC958 Capture Volume", gpr, 0); + snd_emu10k1_init_stereo_control(&controls[nctl++], "IEC958 Optical Capture Volume", gpr, 0); gpr += 2; /* Line2 Playback Volume */ - A_ADD_VOLUME_IN(playback, gpr, A_EXTIN_LINE2_L); - A_ADD_VOLUME_IN(playback+1, gpr+1, A_EXTIN_LINE2_R); + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_LINE2_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_LINE2_R); snd_emu10k1_init_stereo_control(&controls[nctl++], "Line2 Playback Volume", gpr, 0); gpr += 2; /* Line2 Capture Volume */ @@ -1378,20 +1377,20 @@ snd_emu10k1_init_stereo_control(&controls[nctl++], "Line2 Capture Volume", gpr, 0); gpr += 2; - /* RCA SPDIF Playback Volume */ - A_ADD_VOLUME_IN(playback, gpr, A_EXTIN_RCA_SPDIF_L); - A_ADD_VOLUME_IN(playback+1, gpr+1, A_EXTIN_RCA_SPDIF_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], "RCA SPDIF Playback Volume", gpr, 0); - gpr += 2; - /* RCA SPDIF Capture Volume */ - A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_RCA_SPDIF_L); - A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_RCA_SPDIF_R); - snd_emu10k1_init_stereo_control(&controls[nctl++], "RCA SPDIF Capture Volume", gpr, 0); + /* Philips ADC Playback Volume */ + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_ADC_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_ADC_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Playback Volume", gpr, 0); + gpr += 2; + /* Philips ADC Capture Volume */ + A_ADD_VOLUME_IN(capture, gpr, A_EXTIN_ADC_L); + A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_ADC_R); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Analog Mix Capture Volume", gpr, 0); gpr += 2; /* Aux2 Playback Volume */ - A_ADD_VOLUME_IN(playback, gpr, A_EXTIN_AUX2_L); - A_ADD_VOLUME_IN(playback+1, gpr+1, A_EXTIN_AUX2_R); + A_ADD_VOLUME_IN(stereo_mix, gpr, A_EXTIN_AUX2_L); + A_ADD_VOLUME_IN(stereo_mix+1, gpr+1, A_EXTIN_AUX2_R); snd_emu10k1_init_stereo_control(&controls[nctl++], "Aux2 Playback Volume", gpr, 0); gpr += 2; /* Aux2 Capture Volume */ @@ -1399,6 +1398,30 @@ A_ADD_VOLUME_IN(capture+1, gpr+1, A_EXTIN_AUX2_R); snd_emu10k1_init_stereo_control(&controls[nctl++], "Aux2 Capture Volume", gpr, 0); gpr += 2; + + /* Stereo Mix Front Playback Volume */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_GPR(playback), A_GPR(gpr), A_GPR(stereo_mix)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_GPR(playback+1), A_GPR(gpr+1), A_GPR(stereo_mix+1)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Front Playback Volume", gpr, 100); + gpr += 2; + + /* Stereo Mix Surround Playback */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_GPR(playback+2), A_GPR(gpr), A_GPR(stereo_mix)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_GPR(playback+3), A_GPR(gpr+1), A_GPR(stereo_mix+1)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Surround Playback Volume", gpr, 0); + gpr += 2; + + /* Stereo Mix Center Playback */ + /* Center = sub = Left/2 + Right/2 */ + A_OP(icode, &ptr, iINTERP, A_GPR(tmp), A_GPR(stereo_mix), 0xcd, A_GPR(stereo_mix+1)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+4), A_GPR(playback+4), A_GPR(gpr), A_GPR(tmp)); + snd_emu10k1_init_mono_control(&controls[nctl++], "Center Playback Volume", gpr, 0); + gpr++; + + /* Stereo Mix LFE Playback */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback+5), A_GPR(playback+5), A_GPR(gpr), A_GPR(tmp)); + snd_emu10k1_init_mono_control(&controls[nctl++], "LFE Playback Volume", gpr, 0); + gpr++; /* * outputs @@ -1497,20 +1520,18 @@ snd_emu10k1_init_stereo_onoff_control(controls + nctl++, "Tone Control - Switch", gpr, 0); gpr += 2; - /* Master volume for audigy2 */ - if (emu->revision == 4) { - A_OP(icode, &ptr, iMAC0, A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS)); - A_OP(icode, &ptr, iMAC0, A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS)); - snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0); - gpr += 2; - } + /* Master volume (will be renamed later) */ + A_OP(icode, &ptr, iMAC0, A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr), A_GPR(playback+0+SND_EMU10K1_PLAYBACK_CHANNELS)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+1+SND_EMU10K1_PLAYBACK_CHANNELS)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+2+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+2+SND_EMU10K1_PLAYBACK_CHANNELS)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+3+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+3+SND_EMU10K1_PLAYBACK_CHANNELS)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+4+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+4+SND_EMU10K1_PLAYBACK_CHANNELS)); + A_OP(icode, &ptr, iMAC0, A_GPR(playback+5+SND_EMU10K1_PLAYBACK_CHANNELS), A_C_00000000, A_GPR(gpr+1), A_GPR(playback+5+SND_EMU10K1_PLAYBACK_CHANNELS)); + snd_emu10k1_init_stereo_control(&controls[nctl++], "Wave Master Playback Volume", gpr, 0); + gpr += 2; /* analog speakers */ - if (emu->revision == 4) { /* audigy2 */ - A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); - } else { - A_PUT_STEREO_OUTPUT(A_EXTOUT_AC97_L, A_EXTOUT_AC97_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); - } + A_PUT_STEREO_OUTPUT(A_EXTOUT_AFRONT_L, A_EXTOUT_AFRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); A_PUT_STEREO_OUTPUT(A_EXTOUT_AREAR_L, A_EXTOUT_AREAR_R, playback+2 + SND_EMU10K1_PLAYBACK_CHANNELS); A_PUT_OUTPUT(A_EXTOUT_ACENTER, playback+4 + SND_EMU10K1_PLAYBACK_CHANNELS); A_PUT_OUTPUT(A_EXTOUT_ALFE, playback+5 + SND_EMU10K1_PLAYBACK_CHANNELS); @@ -1519,7 +1540,7 @@ A_PUT_STEREO_OUTPUT(A_EXTOUT_HEADPHONE_L, A_EXTOUT_HEADPHONE_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); /* digital outputs */ -// A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); + /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */ /* IEC958 Optical Raw Playback Switch */ icode->gpr_map[gpr++] = 0x1008; @@ -1804,28 +1825,28 @@ snd_emu10k1_init_stereo_onoff_control(controls + i++, "Music Capture Switch", gpr + 2, 0); gpr += 4; - /* Surround Digital Playback Volume */ + /* Surround Digital Playback Volume (renamed later without Digital) */ for (z = 0; z < 2; z++) VOLUME_ADD(icode, &ptr, playback + 2 + z, 4 + z, gpr + z); snd_emu10k1_init_stereo_control(controls + i++, "Surround Digital Playback Volume", gpr, 100); gpr += 2; - /* Surround Digital Capture Volume + Switch */ + /* Surround Capture Volume + Switch */ for (z = 0; z < 2; z++) { SWITCH(icode, &ptr, tmp + 0, 4 + z, gpr + 2 + z); VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z); } - snd_emu10k1_init_stereo_control(controls + i++, "Surround Digital Capture Volume", gpr, 0); - snd_emu10k1_init_stereo_onoff_control(controls + i++, "Surround Digital Capture Switch", gpr + 2, 0); + snd_emu10k1_init_stereo_control(controls + i++, "Surround Capture Volume", gpr, 0); + snd_emu10k1_init_stereo_onoff_control(controls + i++, "Surround Capture Switch", gpr + 2, 0); gpr += 4; - /* Center Playback Volume */ + /* Center Playback Volume (renamed later without Digital) */ VOLUME_ADD(icode, &ptr, playback + 4, 6, gpr); - snd_emu10k1_init_mono_control(controls + i++, "Center Playback Volume", gpr++, 100); + snd_emu10k1_init_mono_control(controls + i++, "Center Digital Playback Volume", gpr++, 100); - /* LFE Playback Volume + Switch */ + /* LFE Playback Volume + Switch (renamed later without Digital) */ VOLUME_ADD(icode, &ptr, playback + 5, 7, gpr); - snd_emu10k1_init_mono_control(controls + i++, "LFE Playback Volume", gpr++, 100); + snd_emu10k1_init_mono_control(controls + i++, "LFE Digital Playback Volume", gpr++, 100); /* * Process inputs @@ -1880,7 +1901,7 @@ /* IEC958 Optical Playback Volume */ for (z = 0; z < 2; z++) VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_TOSLINK_L + z, gpr + z); - snd_emu10k1_init_stereo_control(controls + i++, "IEC958 Optical Playback Volume", gpr, 0); + snd_emu10k1_init_stereo_control(controls + i++, "IEC958 LiveDrive Playback Volume", gpr, 0); gpr += 2; /* IEC958 Optical Capture Volume */ @@ -1888,8 +1909,8 @@ SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_TOSLINK_L + z, gpr + 2 + z); VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z); } - snd_emu10k1_init_stereo_control(controls + i++, "IEC958 Optical Capture Volume", gpr, 0); - snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 Optical Capture Switch", gpr + 2, 0); + snd_emu10k1_init_stereo_control(controls + i++, "IEC958 LiveDrive Capture Volume", gpr, 0); + snd_emu10k1_init_stereo_onoff_control(controls + i++, "IEC958 LiveDrive Capture Switch", gpr + 2, 0); gpr += 4; } @@ -1931,7 +1952,7 @@ /* Line LiveDrive Playback Volume */ for (z = 0; z < 2; z++) VOLUME_ADDIN(icode, &ptr, playback + z, EXTIN_LINE2_L + z, gpr + z); - snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Playback Volume", gpr, 0); + snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Playback Volume", gpr, 0); controls[i-1].id.index = 1; gpr += 2; @@ -1940,8 +1961,9 @@ SWITCH_IN(icode, &ptr, tmp + 0, EXTIN_LINE2_L + z, gpr + 2 + z); VOLUME_ADD(icode, &ptr, capture + z, tmp + 0, gpr + z); } - snd_emu10k1_init_stereo_control(controls + i++, "Line LiveDrive Capture Volume", gpr, 0); - snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line LiveDrive Capture Switch", gpr + 2, 0); + snd_emu10k1_init_stereo_control(controls + i++, "Line2 LiveDrive Capture Volume", gpr, 0); + controls[i-1].id.index = 1; + snd_emu10k1_init_stereo_onoff_control(controls + i++, "Line2 LiveDrive Capture Switch", gpr + 2, 0); controls[i-1].id.index = 1; gpr += 4; } diff -Nru a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c --- a/sound/pci/emu10k1/emumixer.c Mon Feb 2 22:07:58 2004 +++ b/sound/pci/emu10k1/emumixer.c Mon Feb 2 22:07:58 2004 @@ -455,31 +455,89 @@ int __devinit snd_emu10k1_mixer(emu10k1_t *emu) { - ac97_t ac97; int err, pcm; snd_kcontrol_t *kctl; snd_card_t *card = emu->card; + char **c; + static char *emu10k1_remove_ctls[] = { + /* no AC97 mono, surround, center/lfe */ + "Master Mono Playback Switch", + "Master Mono Playback Volume", + "PCM Out Path & Mute", + "Mono Output Select", + "Surround Playback Switch", + "Surround Playback Volume", + "Center Playback Switch", + "Center Playback Volume", + "LFE Playback Switch", + "LFE Playback Volume", + NULL + }; + static char *emu10k1_rename_ctls[] = { + "Surround Digital Playback Volume", "Surround Playback Volume", + "Center Digital Playback Volume", "Center Playback Volume", + "LFE Digital Playback Volume", "LFE Playback Volume", + NULL + }; + static char *audigy_remove_ctls[] = { + /* Master/PCM controls on ac97 of Audigy has no effect */ + "PCM Playback Switch", + "PCM Playback Volume", + "Master Mono Playback Switch", + "Master Mono Playback Volume", + "Master Playback Switch", + "Master Playback Volume", + "PCM Out Path & Mute", + "Mono Output Select", + /* remove unused AC97 capture controls */ + "Capture Source", + "Capture Switch", + "Capture Volume", + "Mic Select", + "Video Playback Switch", + "Video Playback Volume", + "Mic Playback Switch", + "Mic Playback Volume", + NULL + }; + static char *audigy_rename_ctls[] = { + /* use conventional names */ + "Wave Playback Volume", "PCM Playback Volume", + /* "Wave Capture Volume", "PCM Capture Volume", */ + "Wave Master Playback Volume", "Master Playback Volume", + "AMic Playback Volume", "Mic Playback Volume", + NULL + }; if (!emu->no_ac97) { + ac97_bus_t bus, *pbus; + ac97_t ac97; + + memset(&bus, 0, sizeof(bus)); + bus.write = snd_emu10k1_ac97_write; + bus.read = snd_emu10k1_ac97_read; + if ((err = snd_ac97_bus(emu->card, &bus, &pbus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_emu10k1_ac97_write; - ac97.read = snd_emu10k1_ac97_read; ac97.private_data = emu; ac97.private_free = snd_emu10k1_mixer_free_ac97; - if ((err = snd_ac97_mixer(emu->card, &ac97, &emu->ac97)) < 0) + if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) return err; - if (emu->audigy && emu->revision == 4) { - /* Master/PCM controls on ac97 of Audigy2 has no effect */ - /* FIXME: keep master volume/switch to be sure. - * once after we check that they play really no roles, - * they shall be removed. - */ - rename_ctl(card, "Master Playback Switch", "AC97 Master Playback Switch"); - rename_ctl(card, "Master Playback Volume", "AC97 Master Playback Volume"); - /* pcm controls are removed */ - remove_ctl(card, "PCM Playback Switch"); - remove_ctl(card, "PCM Playback Volume"); + if (emu->audigy) { + /* set master volume to 0 dB */ + snd_ac97_write(emu->ac97, AC97_MASTER, 0x0202); + /* set capture source to mic */ + snd_ac97_write(emu->ac97, AC97_REC_SEL, 0x0000); + c = audigy_remove_ctls; + } else { + /* remove unused AC97 controls */ + snd_ac97_write(emu->ac97, AC97_SURROUND_MASTER, 0x0202); + snd_ac97_write(emu->ac97, AC97_CENTER_LFE_MASTER, 0x0202); + c = emu10k1_remove_ctls; } + for (; *c; c++) + remove_ctl(card, *c); } else { if (emu->APS) strcpy(emu->card->mixername, "EMU APS"); @@ -489,13 +547,12 @@ strcpy(emu->card->mixername, "Emu10k1"); } - if (emu->audigy && emu->revision == 4) { - /* Audigy2 and Audigy2 EX */ - /* use the conventional names */ - rename_ctl(card, "Wave Playback Volume", "PCM Playback Volume"); - rename_ctl(card, "Wave Playback Volume", "PCM Capture Volume"); - rename_ctl(card, "Wave Master Playback Volume", "Master Playback Volume"); - } + if (emu->audigy) + c = audigy_rename_ctls; + else + c = emu10k1_rename_ctls; + for (; *c; c += 2) + rename_ctl(card, c[0], c[1]); if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL) return -ENOMEM; @@ -536,6 +593,11 @@ return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; + if ((kctl = ctl_find(card, SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT))) != NULL) { + /* already defined by ac97, remove it */ + /* FIXME: or do we need both controls? */ + remove_ctl(card, SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT)); + } if ((kctl = snd_ctl_new1(&snd_emu10k1_spdif_control, emu)) == NULL) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) diff -Nru a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c --- a/sound/pci/emu10k1/emupcm.c Mon Feb 2 22:07:55 2004 +++ b/sound/pci/emu10k1/emupcm.c Mon Feb 2 22:07:55 2004 @@ -871,7 +871,7 @@ epcm->capture_inte = INTE_MICBUFENABLE; epcm->capture_ba_reg = MICBA; epcm->capture_bs_reg = MICBS; - epcm->capture_idx_reg = MICIDX; + epcm->capture_idx_reg = emu->audigy ? A_MICIDX : MICIDX; substream->runtime->private_data = epcm; substream->runtime->private_free = snd_emu10k1_pcm_free_substream; runtime->hw = snd_emu10k1_capture; diff -Nru a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c --- a/sound/pci/emu10k1/emuproc.c Mon Feb 2 22:07:56 2004 +++ b/sound/pci/emu10k1/emuproc.c Mon Feb 2 22:07:56 2004 @@ -240,7 +240,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(emu->card, "emu10k1", &entry)) - snd_info_set_text_ops(entry, emu, snd_emu10k1_proc_read); + snd_info_set_text_ops(entry, emu, 1024, snd_emu10k1_proc_read); if (! snd_card_proc_new(emu->card, "fx8010_gpr", &entry)) { entry->content = SNDRV_INFO_CONTENT_DATA; diff -Nru a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c --- a/sound/pci/emu10k1/memory.c Mon Feb 2 22:07:58 2004 +++ b/sound/pci/emu10k1/memory.c Mon Feb 2 22:07:58 2004 @@ -529,7 +529,7 @@ /* * copy_from_user(blk + offset, data, size) */ -int snd_emu10k1_synth_copy_from_user(emu10k1_t *emu, snd_util_memblk_t *blk, int offset, const char *data, int size) +int snd_emu10k1_synth_copy_from_user(emu10k1_t *emu, snd_util_memblk_t *blk, int offset, const char __user *data, int size) { int page, nextofs, end_offset, temp, temp1; void *ptr; diff -Nru a/sound/pci/ens1370.c b/sound/pci/ens1370.c --- a/sound/pci/ens1370.c Mon Feb 2 22:07:58 2004 +++ b/sound/pci/ens1370.c Mon Feb 2 22:07:58 2004 @@ -72,9 +72,20 @@ "{Ectiva,EV1938}}"); #endif +#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#define SUPPORT_JOYSTICK +#endif + 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_PNP; /* Enable switches */ +#ifdef SUPPORT_JOYSTICK +#ifdef CHIP1371 +static int joystick_port[SNDRV_CARDS]; +#else +static int joystick[SNDRV_CARDS]; +#endif +#endif MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(index, "Index value for Ensoniq AudioPCI soundcard."); @@ -85,6 +96,17 @@ MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(enable, "Enable Ensoniq AudioPCI soundcard."); MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); +#ifdef SUPPORT_JOYSTICK +#ifdef CHIP1371 +MODULE_PARM(joystick_port, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(joystick_port, "Joystick port address."); +MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED ",allows:{{0},{1},{0x200},{0x208},{0x210},{0x218}},dialog:list"); +#else +MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(joystick, "Enable joystick."); +MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); +#endif +#endif /* SUPPORT_JOYSTICK */ #ifndef PCI_DEVICE_ID_ENSONIQ_CT5880 #define PCI_DEVICE_ID_ENSONIQ_CT5880 0x5880 @@ -416,9 +438,8 @@ dma_addr_t bugbuf_addr; #endif -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#ifdef SUPPORT_JOYSTICK struct gameport gameport; - struct semaphore joy_sem; // gameport configuration semaphore #endif }; @@ -1371,33 +1392,6 @@ return change; } -static snd_kcontrol_new_t snd_ens1373_spdif_default __devinitdata = -{ - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), - .info = snd_ens1373_spdif_info, - .get = snd_ens1373_spdif_default_get, - .put = snd_ens1373_spdif_default_put, -}; - -static snd_kcontrol_new_t snd_ens1373_spdif_mask __devinitdata = -{ - .access = SNDRV_CTL_ELEM_ACCESS_READ, - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), - .info = snd_ens1373_spdif_info, - .get = snd_ens1373_spdif_mask_get -}; - -static snd_kcontrol_new_t snd_ens1373_spdif_stream __devinitdata = -{ - .iface = SNDRV_CTL_ELEM_IFACE_PCM, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM), - .info = snd_ens1373_spdif_info, - .get = snd_ens1373_spdif_stream_get, - .put = snd_ens1373_spdif_stream_put -}; - #define ES1371_SPDIF(xname) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_es1371_spdif_info, \ .get = snd_es1371_spdif_get, .put = snd_es1371_spdif_put } @@ -1441,8 +1435,33 @@ return change; } -static snd_kcontrol_new_t snd_es1371_mixer_spdif __devinitdata = -ES1371_SPDIF("IEC958 Playback Switch"); + +/* spdif controls */ +static snd_kcontrol_new_t snd_es1371_mixer_spdif[] __devinitdata = { + ES1371_SPDIF("IEC958 Playback Switch"), + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), + .info = snd_ens1373_spdif_info, + .get = snd_ens1373_spdif_default_get, + .put = snd_ens1373_spdif_default_put, + }, + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), + .info = snd_ens1373_spdif_info, + .get = snd_ens1373_spdif_mask_get + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM), + .info = snd_ens1373_spdif_info, + .get = snd_ens1373_spdif_stream_get, + .put = snd_ens1373_spdif_stream_put + }, +}; + static int snd_es1373_rear_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { @@ -1491,6 +1510,56 @@ .put = snd_es1373_rear_put, }; +static int snd_es1373_line_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_es1373_line_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol); + int val = 0; + + spin_lock_irq(&ensoniq->reg_lock); + if ((ensoniq->ctrl & ES_1371_GPIO_OUTM) >= 4) + val = 1; + ucontrol->value.integer.value[0] = val; + spin_unlock_irq(&ensoniq->reg_lock); + return 0; +} + +static int snd_es1373_line_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol); + int changed; + unsigned int ctrl; + + spin_lock_irq(&ensoniq->reg_lock); + ctrl = ensoniq->ctrl; + if (ucontrol->value.integer.value[0]) + ensoniq->ctrl |= ES_1371_GPIO_OUT(4); /* switch line-in -> rear out */ + else + ensoniq->ctrl &= ~ES_1371_GPIO_OUT(4); + changed = (ctrl != ensoniq->ctrl); + if (changed) + outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); + spin_unlock_irq(&ensoniq->reg_lock); + return changed; +} + +static snd_kcontrol_new_t snd_ens1373_line __devinitdata = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Line In->Rear Out Switch", + .info = snd_es1373_line_info, + .get = snd_es1373_line_get, + .put = snd_es1373_line_put, +}; + static void snd_ensoniq_mixer_free_ac97(ac97_t *ac97) { ensoniq_t *ensoniq = snd_magic_cast(ensoniq_t, ac97->private_data, return); @@ -1513,23 +1582,28 @@ static int snd_ensoniq_1371_mixer(ensoniq_t * ensoniq) { snd_card_t *card = ensoniq->card; + ac97_bus_t bus, *pbus; ac97_t ac97; int err, idx; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_es1371_codec_write; + bus.read = snd_es1371_codec_read; + if ((err = snd_ac97_bus(card, &bus, &pbus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_es1371_codec_write; - ac97.read = snd_es1371_codec_read; ac97.private_data = ensoniq; ac97.private_free = snd_ensoniq_mixer_free_ac97; ac97.scaps = AC97_SCAP_AUDIO; - if ((err = snd_ac97_mixer(card, &ac97, &ensoniq->u.es1371.ac97)) < 0) + if ((err = snd_ac97_mixer(pbus, &ac97, &ensoniq->u.es1371.ac97)) < 0) return err; for (idx = 0; es1371_spdif_present[idx].vid != (unsigned short)PCI_ANY_ID; idx++) if (ensoniq->pci->vendor == es1371_spdif_present[idx].vid && ensoniq->pci->device == es1371_spdif_present[idx].did && ensoniq->rev == es1371_spdif_present[idx].rev) { snd_kcontrol_t *kctl; - int index = 0; + int i, index = 0; ensoniq->spdif_default = ensoniq->spdif_stream = SNDRV_PCM_DEFAULT_CON_SPDIF; outl(ensoniq->spdif_default, ES_REG(ensoniq, CHANNEL_STATUS)); @@ -1537,36 +1611,38 @@ if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SPDIF) index++; - kctl = snd_ctl_new1(&snd_es1371_mixer_spdif, ensoniq); - kctl->id.index = index; - snd_ctl_add(card, kctl); - - kctl = snd_ctl_new1(&snd_ens1373_spdif_default, ensoniq); - kctl->id.index = index; - snd_ctl_add(card, kctl); - - kctl = snd_ctl_new1(&snd_ens1373_spdif_mask, ensoniq); - kctl->id.index = index; - snd_ctl_add(card, kctl); - - kctl = snd_ctl_new1(&snd_ens1373_spdif_stream, ensoniq); - kctl->id.index = index; - snd_ctl_add(card, kctl); + for (i = 0; i < (int)ARRAY_SIZE(snd_es1371_mixer_spdif); i++) { + kctl = snd_ctl_new1(&snd_es1371_mixer_spdif[i], ensoniq); + if (! kctl) + return -ENOMEM; + kctl->id.index = index; + if ((err = snd_ctl_add(card, kctl)) < 0) + return err; + } break; } if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SDAC) { /* mirror rear to front speakers */ ensoniq->cssr &= ~(ES_1373_REAR_BIT27|ES_1373_REAR_BIT24); ensoniq->cssr |= ES_1373_REAR_BIT26; - snd_ctl_add(card, snd_ctl_new1(&snd_ens1373_rear, ensoniq)); + err = snd_ctl_add(card, snd_ctl_new1(&snd_ens1373_rear, ensoniq)); + if (err < 0) + return err; + } + if ((ensoniq->subsystem_vendor_id == 0x1274) && + (ensoniq->subsystem_device_id == 0x2000)) { /* GA-7DXR */ + err = snd_ctl_add(card, snd_ctl_new1(&snd_ens1373_line, ensoniq)); + if (err < 0) + return err; } + return 0; } #endif /* CHIP1371 */ -/* generic control callbacks for ens1370 and for joystick */ -#if defined(CHIP1370) || defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +/* generic control callbacks for ens1370 */ +#ifdef CHIP1370 #define ENSONIQ_CONTROL(xname, mask) \ { .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = xname, .info = snd_ensoniq_control_info, \ .get = snd_ensoniq_control_get, .put = snd_ensoniq_control_put, \ @@ -1593,7 +1669,6 @@ return 0; } -#ifdef CHIP1370 static int snd_ensoniq_control_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol); @@ -1611,14 +1686,11 @@ spin_unlock_irqrestore(&ensoniq->reg_lock, flags); return change; } -#endif /* CHIP1370 */ -#endif /* CHIP1370 || GAMEPORT */ /* * ENS1370 mixer */ -#ifdef CHIP1370 static snd_kcontrol_new_t snd_es1370_controls[2] __devinitdata = { ENSONIQ_CONTROL("PCM 0 Output also on Line-In Jack", ES_1370_XCTL0), ENSONIQ_CONTROL("Mic +5V bias", ES_1370_XCTL1) @@ -1653,136 +1725,55 @@ ak4531.private_free = snd_ensoniq_mixer_free_ak4531; if ((err = snd_ak4531_mixer(card, &ak4531, &ensoniq->u.es1370.ak4531)) < 0) return err; - for (idx = 0; idx < ES1370_CONTROLS; idx++) - snd_ctl_add(card, snd_ctl_new1(&snd_es1370_controls[idx], ensoniq)); + for (idx = 0; idx < ES1370_CONTROLS; idx++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_es1370_controls[idx], ensoniq)); + if (err < 0) + return err; + } return 0; } #endif /* CHIP1370 */ -/* - * General Switches... - */ - -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) -/* MQ: gameport driver connectivity */ -#define ENSONIQ_JOY_CONTROL(xname, mask) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = xname, .info = snd_ensoniq_control_info, \ - .get = snd_ensoniq_control_get, .put = snd_ensoniq_joy_control_put, \ - .private_value = mask } - -static int snd_ensoniq_joy_enable(ensoniq_t *ensoniq) +#ifdef SUPPORT_JOYSTICK +static int snd_ensoniq_joystick(ensoniq_t *ensoniq, long port) { - static unsigned long last_jiffies = 0; - unsigned long flags; - - if (!request_region(ensoniq->gameport.io, 8, "ens137x: gameport")) { -#define ES___GAMEPORT_LOG_DELAY (30*HZ) - // avoid log pollution: limit to 2 infos per minute - if (time_after(jiffies, last_jiffies + ES___GAMEPORT_LOG_DELAY)) { - last_jiffies = jiffies; +#ifdef CHIP1371 + if (port == 1) { /* auto-detect */ + for (port = 0x200; port <= 0x218; port += 8) + if (request_region(port, 8, "ens137x: gameport")) + break; + if (port > 0x218) { + snd_printk("no gameport available\n"); + return -EBUSY; + } + } else +#endif + { + if (!request_region(port, 8, "ens137x: gameport")) { snd_printk("gameport io port 0x%03x in use", ensoniq->gameport.io); + return -EBUSY; } - return 0; } - spin_lock_irqsave(&ensoniq->reg_lock, flags); + ensoniq->gameport.io = port; ensoniq->ctrl |= ES_JYSTK_EN; +#ifdef CHIP1371 + ensoniq->ctrl &= ~ES_1371_JOY_ASELM; + ensoniq->ctrl |= ES_1371_JOY_ASEL((ensoniq->gameport.io - 0x200) / 8); +#endif outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); - spin_unlock_irqrestore(&ensoniq->reg_lock, flags); gameport_register_port(&ensoniq->gameport); - return 1; + return 0; } -static int snd_ensoniq_joy_disable(ensoniq_t *ensoniq) +static void snd_ensoniq_joystick_free(ensoniq_t *ensoniq) { - unsigned long flags; - gameport_unregister_port(&ensoniq->gameport); - spin_lock_irqsave(&ensoniq->reg_lock, flags); ensoniq->ctrl &= ~ES_JYSTK_EN; outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); - spin_unlock_irqrestore(&ensoniq->reg_lock, flags); release_region(ensoniq->gameport.io, 8); - return 1; } - -static int snd_ensoniq_joy_control_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol); - unsigned int nval; - int change; - - down(&ensoniq->joy_sem); - nval = ucontrol->value.integer.value[0] ? ES_JYSTK_EN : 0; - change = (ensoniq->ctrl & ES_JYSTK_EN) != nval; // spinlock shouldn't be needed because of joy_sem - if (change) { - if (nval) // enable - change = snd_ensoniq_joy_enable(ensoniq); - else change = snd_ensoniq_joy_disable(ensoniq); - } - up(&ensoniq->joy_sem); - return change; -} - -static snd_kcontrol_new_t snd_ensoniq_control_joystick __devinitdata = -ENSONIQ_JOY_CONTROL("Joystick Enable", ES_JYSTK_EN); - -#ifdef CHIP1371 - -#define ES1371_JOYSTICK_ADDR(xname) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = xname, .info = snd_es1371_joystick_addr_info, \ - .get = snd_es1371_joystick_addr_get, .put = snd_es1371_joystick_addr_put } - -static int snd_es1371_joystick_addr_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item >= 4) - uinfo->value.enumerated.item = 3; - sprintf(uinfo->value.enumerated.name, "port 0x%x", (uinfo->value.enumerated.item * 8) + 0x200); - return 0; -} - -static int snd_es1371_joystick_addr_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol); - unsigned long flags; - - spin_lock_irqsave(&ensoniq->reg_lock, flags); - ucontrol->value.enumerated.item[0] = ES_1371_JOY_ASELI(ensoniq->ctrl); - spin_unlock_irqrestore(&ensoniq->reg_lock, flags); - return 0; -} - -static int snd_es1371_joystick_addr_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol); - unsigned long flags; - unsigned int nval; - int change; - - down(&ensoniq->joy_sem); - nval = ES_1371_JOY_ASEL(ucontrol->value.integer.value[0]); - spin_lock_irqsave(&ensoniq->reg_lock, flags); - if (!(change = !(ensoniq->ctrl & ES_JYSTK_EN))) - goto no_change; // FIXME: now we allow change only when joystick is disabled - change = (ensoniq->ctrl & ES_1371_JOY_ASELM) != nval; - ensoniq->ctrl &= ~ES_1371_JOY_ASELM; - ensoniq->ctrl |= nval; - outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); - ensoniq->gameport.io = 0x200 + ES_1371_JOY_ASELI(nval) * 8; -no_change: - spin_unlock_irqrestore(&ensoniq->reg_lock, flags); - up(&ensoniq->joy_sem); - return change; -} - -static snd_kcontrol_new_t snd_es1371_joystick_addr __devinitdata = -ES1371_JOYSTICK_ADDR("Joystick Address"); - -#endif /* CHIP1371 */ -#endif /* CONFIG_GAMEPORT */ +#endif /* SUPPORT_JOYSTICK */ /* @@ -1812,7 +1803,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(ensoniq->card, "audiopci", &entry)) - snd_info_set_text_ops(entry, ensoniq, snd_ensoniq_proc_read); + snd_info_set_text_ops(entry, ensoniq, 1024, snd_ensoniq_proc_read); } /* @@ -1821,9 +1812,9 @@ static int snd_ensoniq_free(ensoniq_t *ensoniq) { -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#ifdef SUPPORT_JOYSTICK if (ensoniq->ctrl & ES_JYSTK_EN) - snd_ensoniq_joy_disable(ensoniq); + snd_ensoniq_joystick_free(ensoniq); #endif if (ensoniq->irq < 0) goto __hw_end; @@ -2019,14 +2010,6 @@ outb(ensoniq->uartc = 0x00, ES_REG(ensoniq, UART_CONTROL)); outb(0x00, ES_REG(ensoniq, UART_RES)); outl(ensoniq->cssr, ES_REG(ensoniq, STATUS)); -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) - init_MUTEX(&ensoniq->joy_sem); -#ifdef CHIP1371 - snd_ctl_add(card, snd_ctl_new1(&snd_es1371_joystick_addr, ensoniq)); -#endif - snd_ctl_add(card, snd_ctl_new1(&snd_ensoniq_control_joystick, ensoniq)); - ensoniq->gameport.io = 0x200; // FIXME: is ES1371 configured like this above ? -#endif synchronize_irq(ensoniq->irq); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ensoniq, &ops)) < 0) { @@ -2034,6 +2017,8 @@ return err; } + snd_card_set_dev(card, &pci->dev); + *rensoniq = ensoniq; return 0; } @@ -2331,6 +2316,22 @@ snd_card_free(card); return err; } +#ifdef SUPPORT_JOYSTICK +#ifdef CHIP1371 + switch (joystick_port[dev]) { + case 1: /* auto-detect */ + case 0x200: + case 0x208: + case 0x210: + case 0x218: + snd_ensoniq_joystick(ensoniq, joystick_port[dev]); + break; + } +#else + if (joystick[dev]) + snd_ensoniq_joystick(ensoniq, 0x200); +#endif +#endif /* SUPPORT_JOYSTICK */ strcpy(card->driver, DRIVER_NAME); strcpy(card->shortname, "Ensoniq AudioPCI"); @@ -2386,7 +2387,7 @@ #ifndef MODULE -/* format is: snd-ens1370=enable,index,id */ +/* format is: snd-ens1370=enable,index,id,joystick */ static int __init alsa_card_ens137x_setup(char *str) { @@ -2396,7 +2397,15 @@ return 0; (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && - get_id(&str,&id[nr_dev]) == 2); + get_id(&str,&id[nr_dev]) == 2 +#ifdef SUPPORT_JOYSTICK +#ifdef CHIP1371 + && get_option(&str,&joystick_port[nr_dev]) == 2 +#else + && get_option(&str,&joystick[nr_dev]) == 2 +#endif +#endif + ); nr_dev++; return 1; } diff -Nru a/sound/pci/es1938.c b/sound/pci/es1938.c --- a/sound/pci/es1938.c Mon Feb 2 22:07:57 2004 +++ b/sound/pci/es1938.c Mon Feb 2 22:07:57 2004 @@ -1398,11 +1398,11 @@ if ((err = pci_enable_device(pci)) < 0) return err; /* check, if we can restrict PCI DMA transfers to 24 bits */ - if (!pci_dma_supported(pci, 0x00ffffff)) { + if (pci_set_dma_mask(pci, 0x00ffffff) < 0 || + pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) { snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x00ffffff); chip = snd_magic_kcalloc(es1938_t, 0, GFP_KERNEL); if (chip == NULL) @@ -1483,6 +1483,8 @@ return err; } + snd_card_set_dev(card, &pci->dev); + *rchip = chip; return 0; } @@ -1633,6 +1635,14 @@ snd_card_free(card); return err; } + + strcpy(card->driver, "ES1938"); + strcpy(card->shortname, "ESS ES1938 (Solo-1)"); + sprintf(card->longname, "%s rev %i, irq %i", + card->shortname, + chip->revision, + chip->irq); + if ((err = snd_es1938_new_pcm(chip, 0, &pcm)) < 0) { snd_card_free(card); return err; @@ -1667,13 +1677,6 @@ chip->gameport.io = chip->game_port; gameport_register_port(&chip->gameport); #endif - - strcpy(card->driver, "ES1938"); - strcpy(card->shortname, "ESS ES1938 (Solo-1)"); - sprintf(card->longname, "%s rev %i, irq %i", - card->shortname, - chip->revision, - chip->irq); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); diff -Nru a/sound/pci/es1968.c b/sound/pci/es1968.c --- a/sound/pci/es1968.c Mon Feb 2 22:07:57 2004 +++ b/sound/pci/es1968.c Mon Feb 2 22:07:57 2004 @@ -94,7 +94,6 @@ * places. */ -#define __SND_OSS_COMPAT__ #include #include #include @@ -102,6 +101,7 @@ #include #include #include +#include #include #include #include @@ -122,6 +122,10 @@ "{ESS,Maestro 1}," "{TerraTec,DMX}}"); +#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#define SUPPORT_JOYSTICK 1 +#endif + static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 1-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ @@ -131,6 +135,9 @@ static int clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; static int use_pm[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; static int enable_mpu[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; +#ifdef SUPPORT_JOYSTICK +static int joystick[SNDRV_CARDS]; +#endif MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); @@ -159,6 +166,11 @@ MODULE_PARM(enable_mpu, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(enable_mpu, "Enable MPU401. (0 = off, 1 = on, 2 = auto)"); MODULE_PARM_SYNTAX(enable_mpu, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC); +#ifdef SUPPORT_JOYSTICK +MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(joystick, "Enable joystick."); +MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); +#endif /* PCI Dev ID's */ @@ -602,6 +614,11 @@ #ifdef CONFIG_PM u16 apu_map[NR_APUS][NR_APU_REGS]; #endif + +#ifdef SUPPORT_JOYSTICK + struct gameport gameport; + struct resource *res_joystick; +#endif }; static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -2020,15 +2037,20 @@ static int __devinit snd_es1968_mixer(es1968_t *chip) { + ac97_bus_t bus, *pbus; ac97_t ac97; snd_ctl_elem_id_t id; int err; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_es1968_ac97_write; + bus.read = snd_es1968_ac97_read; + if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_es1968_ac97_write; - ac97.read = snd_es1968_ac97_read; ac97.private_data = chip; - if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0) + if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97)) < 0) return err; /* attach master switch / volumes for h/w volume control */ @@ -2478,6 +2500,13 @@ if (chip->res_io_port) snd_es1968_reset(chip); +#ifdef SUPPORT_JOYSTICK + if (chip->res_joystick) { + gameport_unregister_port(&chip->gameport); + release_resource(chip->res_joystick); + kfree_nocheck(chip->res_joystick); + } +#endif snd_es1968_set_acpi(chip, ACPI_D3); chip->master_switch = NULL; chip->master_volume = NULL; @@ -2534,11 +2563,11 @@ if ((err = pci_enable_device(pci)) < 0) return err; /* check, if we can restrict PCI DMA transfers to 28 bits */ - if (!pci_dma_supported(pci, 0x0fffffff)) { + if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || + pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { snd_printk("architecture does not support 28bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x0fffffff); chip = (es1968_t *) snd_magic_kcalloc(es1968_t, 0, GFP_KERNEL); if (! chip) @@ -2617,62 +2646,13 @@ return err; } - *chip_ret = chip; - - return 0; -} - - -/* - * joystick - */ - -static int snd_es1968_joystick_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int snd_es1968_joystick_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - es1968_t *chip = snd_kcontrol_chip(kcontrol); - u16 val; - - pci_read_config_word(chip->pci, ESM_LEGACY_AUDIO_CONTROL, &val); - ucontrol->value.integer.value[0] = (val & 0x04) ? 1 : 0; - return 0; -} + snd_card_set_dev(card, &pci->dev); -static int snd_es1968_joystick_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - es1968_t *chip = snd_kcontrol_chip(kcontrol); - u16 val, oval; + *chip_ret = chip; - pci_read_config_word(chip->pci, ESM_LEGACY_AUDIO_CONTROL, &oval); - val = oval & ~0x04; - if (ucontrol->value.integer.value[0]) - val |= 0x04; - if (val != oval) { - pci_write_config_word(chip->pci, ESM_LEGACY_AUDIO_CONTROL, val); - return 1; - } return 0; } -#define num_controls(ary) (sizeof(ary) / sizeof(snd_kcontrol_new_t)) - -static snd_kcontrol_new_t snd_es1968_control_switches[] __devinitdata = { - { - .name = "Joystick", - .iface = SNDRV_CTL_ELEM_IFACE_CARD, - .info = snd_es1968_joystick_info, - .get = snd_es1968_joystick_get, - .put = snd_es1968_joystick_put, - } -}; /* */ @@ -2756,14 +2736,17 @@ } } - /* card switches */ - for (i = 0; i < num_controls(snd_es1968_control_switches); i++) { - err = snd_ctl_add(card, snd_ctl_new1(&snd_es1968_control_switches[i], chip)); - if (err < 0) { - snd_card_free(card); - return err; - } +#ifdef SUPPORT_JOYSTICK +#define JOYSTICK_ADDR 0x200 + if (joystick[dev] && + (chip->res_joystick = request_region(JOYSTICK_ADDR, 8, "ES1968 gameport")) != NULL) { + u16 val; + pci_read_config_word(pci, ESM_LEGACY_AUDIO_CONTROL, &val); + pci_write_config_word(pci, ESM_LEGACY_AUDIO_CONTROL, val | 0x04); + chip->gameport.io = JOYSTICK_ADDR; + gameport_register_port(&chip->gameport); } +#endif snd_es1968_start_irq(chip); @@ -2834,7 +2817,8 @@ pcm_substreams_c, clock, use_pm, - enable_mpu + enable_mpu, + joystick */ static int __init alsa_card_es1968_setup(char *str) @@ -2851,7 +2835,11 @@ get_option(&str,&pcm_substreams_c[nr_dev]) == 2 && get_option(&str,&clock[nr_dev]) == 2 && get_option(&str,&use_pm[nr_dev]) == 2 && - get_option(&str,&enable_mpu[nr_dev]) == 2); + get_option(&str,&enable_mpu[nr_dev]) == 2 +#ifdef SUPPORT_JOYSTICK + && get_option(&str,&joystick[nr_dev]) == 2 +#endif + ); nr_dev++; return 1; } diff -Nru a/sound/pci/fm801.c b/sound/pci/fm801.c --- a/sound/pci/fm801.c Mon Feb 2 22:07:58 2004 +++ b/sound/pci/fm801.c Mon Feb 2 22:07:58 2004 @@ -147,6 +147,7 @@ unsigned int cap_size; unsigned int cap_pos; + ac97_bus_t *ac97_bus; ac97_t *ac97; ac97_t *ac97_sec; @@ -844,6 +845,12 @@ FM801_SINGLE("IEC958 Playback Switch", FM801_GEN_CTRL, 2, 1, 0), }; +static void snd_fm801_mixer_free_ac97_bus(ac97_bus_t *bus) +{ + fm801_t *chip = snd_magic_cast(fm801_t, bus->private_data, return); + chip->ac97_bus = NULL; +} + static void snd_fm801_mixer_free_ac97(ac97_t *ac97) { fm801_t *chip = snd_magic_cast(fm801_t, ac97->private_data, return); @@ -856,21 +863,28 @@ static int __devinit snd_fm801_mixer(fm801_t *chip) { + ac97_bus_t bus; ac97_t ac97; unsigned int i; int err; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_fm801_codec_write; + bus.read = snd_fm801_codec_read; + bus.private_data = chip; + bus.private_free = snd_fm801_mixer_free_ac97_bus; + if ((err = snd_ac97_bus(chip->card, &bus, &chip->ac97_bus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_fm801_codec_write; - ac97.read = snd_fm801_codec_read; ac97.private_data = chip; ac97.private_free = snd_fm801_mixer_free_ac97; - if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0) + if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) return err; if (chip->secondary) { ac97.num = 1; ac97.addr = chip->secondary_addr; - if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97_sec)) < 0) + if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97_sec)) < 0) return err; } for (i = 0; i < FM801_CONTROLS; i++) @@ -1040,6 +1054,8 @@ return err; } + snd_card_set_dev(card, &pci->dev); + *rchip = chip; return 0; } @@ -1067,6 +1083,13 @@ snd_card_free(card); return err; } + + strcpy(card->driver, "FM801"); + strcpy(card->shortname, "ForteMedia FM801-"); + strcat(card->shortname, chip->multichannel ? "AU" : "AS"); + sprintf(card->longname, "%s at 0x%lx, irq %i", + card->shortname, chip->port, chip->irq); + if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) { snd_card_free(card); return err; @@ -1091,12 +1114,6 @@ snd_card_free(card); return err; } - - strcpy(card->driver, "FM801"); - strcpy(card->shortname, "ForteMedia FM801-"); - strcat(card->shortname, chip->multichannel ? "AU" : "AS"); - sprintf(card->longname, "%s at 0x%lx, irq %i", - card->shortname, chip->port, chip->irq); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); diff -Nru a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile --- a/sound/pci/ice1712/Makefile Mon Feb 2 22:07:56 2004 +++ b/sound/pci/ice1712/Makefile Mon Feb 2 22:07:56 2004 @@ -5,7 +5,7 @@ snd-ice17xx-ak4xxx-objs := ak4xxx.o snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o -snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o +snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o prodigy.o # Toplevel Module Dependency obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o diff -Nru a/sound/pci/ice1712/ak4xxx.c b/sound/pci/ice1712/ak4xxx.c --- a/sound/pci/ice1712/ak4xxx.c Mon Feb 2 22:07:55 2004 +++ b/sound/pci/ice1712/ak4xxx.c Mon Feb 2 22:07:55 2004 @@ -175,6 +175,18 @@ return 0; } +static int __init alsa_ice1712_akm4xxx_module_init(void) +{ + return 0; +} + +static void __exit alsa_ice1712_akm4xxx_module_exit(void) +{ +} + +module_init(alsa_ice1712_akm4xxx_module_init) +module_exit(alsa_ice1712_akm4xxx_module_exit) + EXPORT_SYMBOL(snd_ice1712_akm4xxx_init); EXPORT_SYMBOL(snd_ice1712_akm4xxx_free); EXPORT_SYMBOL(snd_ice1712_akm4xxx_build_controls); diff -Nru a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c --- a/sound/pci/ice1712/aureon.c Mon Feb 2 22:07:56 2004 +++ b/sound/pci/ice1712/aureon.c Mon Feb 2 22:07:56 2004 @@ -185,7 +185,7 @@ if (nvol <= 0x1a && ovol <= 0x1a) change = 0; else - wm_put(ice, idx, nvol | 0x100); + wm_put(ice, idx, nvol | 0x180); /* update on zero detect */ } snd_ice1712_restore_gpio_status(ice); return change; @@ -366,9 +366,15 @@ static int __devinit aureon_init(ice1712_t *ice) { static unsigned short wm_inits[] = { + /* These come first to reduce init pop noise */ + 0x1b, 0x000, /* ADC Mux */ + 0x1c, 0x009, /* Out Mux1 */ + 0x1d, 0x009, /* Out Mux2 */ + + 0x18, 0x000, /* All power-up */ + 0x16, 0x122, /* I2S, normal polarity, 24bit */ 0x17, 0x022, /* 256fs, slave mode */ - 0x18, 0x000, /* All power-up */ 0x00, 0, /* DAC1 analog mute */ 0x01, 0, /* DAC2 analog mute */ 0x02, 0, /* DAC3 analog mute */ @@ -393,9 +399,6 @@ 0x15, 0x000, /* no deemphasis, no ZFLG */ 0x19, 0x000, /* -12dB ADC/L */ 0x1a, 0x000, /* -12dB ADC/R */ - 0x1b, 0x000, /* ADC Mux */ - 0x1c, 0x009, /* Out Mux1 */ - 0x1d, 0x009, /* Out Mux2 */ }; static unsigned short cs_inits[] = { 0x0441, /* RUN */ diff -Nru a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c --- a/sound/pci/ice1712/delta.c Mon Feb 2 22:07:55 2004 +++ b/sound/pci/ice1712/delta.c Mon Feb 2 22:07:55 2004 @@ -257,6 +257,26 @@ } /* + * change the DFS bit according rate for Delta1010 + */ +static void delta_1010_set_rate_val(ice1712_t *ice, unsigned int rate) +{ + unsigned char tmp, tmp2; + + if (rate == 0) /* no hint - S/PDIF input is master, simply return */ + return; + + down(&ice->gpio_mutex); + tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA); + tmp2 = tmp & ~ICE1712_DELTA_DFS; + if (rate > 48000) + tmp2 |= ICE1712_DELTA_DFS; + if (tmp != tmp2) + snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp2); + up(&ice->gpio_mutex); +} + +/* * change the rate of AK4524 on Delta 44/66, AP, 1010LT */ static void delta_ak4524_set_rate_val(akm4xxx_t *ak, unsigned int rate) @@ -271,8 +291,7 @@ down(&ice->gpio_mutex); tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA); up(&ice->gpio_mutex); - tmp2 = tmp; - tmp2 &= ~ICE1712_DELTA_DFS; + tmp2 = tmp & ~ICE1712_DELTA_DFS; if (rate > 48000) tmp2 |= ICE1712_DELTA_DFS; if (tmp == tmp2) @@ -454,7 +473,11 @@ return err; break; case ICE1712_SUBDEVICE_DELTA1010: + ice->gpio.set_pro_rate = delta_1010_set_rate_val; + break; case ICE1712_SUBDEVICE_DELTADIO2496: + ice->gpio.set_pro_rate = delta_1010_set_rate_val; + /* fall thru */ case ICE1712_SUBDEVICE_DELTA66: ice->spdif.ops.open = delta_open_spdif; ice->spdif.ops.setup_rate = delta_setup_spdif; diff -Nru a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c --- a/sound/pci/ice1712/ice1712.c Mon Feb 2 22:07:56 2004 +++ b/sound/pci/ice1712/ice1712.c Mon Feb 2 22:07:56 2004 @@ -1040,16 +1040,21 @@ default: snd_BUG(); val = 0; + rate = 48000; break; } outb(val, ICEMT(ice, RATE)); spin_unlock_irqrestore(&ice->reg_lock, flags); + if (ice->gpio.set_pro_rate) + ice->gpio.set_pro_rate(ice, rate); for (i = 0; i < ice->akm_codecs; i++) { if (ice->akm[i].ops.set_rate_val) ice->akm[i].ops.set_rate_val(&ice->akm[i], rate); } + if (ice->spdif.ops.setup_rate) + ice->spdif.ops.setup_rate(ice, rate); } static int snd_ice1712_playback_pro_prepare(snd_pcm_substream_t * substream) @@ -1072,8 +1077,6 @@ ice1712_t *ice = snd_pcm_substream_chip(substream); snd_ice1712_set_pro_rate(ice, params_rate(hw_params), 0); - if (ice->spdif.ops.setup_rate) - ice->spdif.ops.setup_rate(ice, params_rate(hw_params)); return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); } @@ -1449,13 +1452,17 @@ int err; if (ice_has_con_ac97(ice)) { + ac97_bus_t bus, *pbus; ac97_t ac97; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_ice1712_ac97_write; + bus.read = snd_ice1712_ac97_read; + if ((err = snd_ac97_bus(ice->card, &bus, &pbus)) < 0) + return err; memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_ice1712_ac97_write; - ac97.read = snd_ice1712_ac97_read; ac97.private_data = ice; ac97.private_free = snd_ice1712_mixer_free_ac97; - if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0) + if ((err = snd_ac97_mixer(pbus, &ac97, &ice->ac97)) < 0) printk(KERN_WARNING "ice1712: cannot initialize ac97 for consumer, skipped\n"); else { if ((err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, ice))) < 0) @@ -1465,13 +1472,17 @@ } if (! (ice->eeprom.data[ICE_EEP1_ACLINK] & ICE1712_CFG_PRO_I2S)) { + ac97_bus_t bus, *pbus; ac97_t ac97; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_ice1712_pro_ac97_write; + bus.read = snd_ice1712_pro_ac97_read; + if ((err = snd_ac97_bus(ice->card, &bus, &pbus)) < 0) + return err; memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_ice1712_pro_ac97_write; - ac97.read = snd_ice1712_pro_ac97_read; ac97.private_data = ice; ac97.private_free = snd_ice1712_mixer_free_ac97; - if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0) + if ((err = snd_ac97_mixer(pbus, &ac97, &ice->ac97)) < 0) printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n"); else return 0; @@ -1532,7 +1543,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(ice->card, "ice1712", &entry)) - snd_info_set_text_ops(entry, ice, snd_ice1712_proc_read); + snd_info_set_text_ops(entry, ice, 1024, snd_ice1712_proc_read); } /* @@ -2352,11 +2363,11 @@ if ((err = pci_enable_device(pci)) < 0) return err; /* check, if we can restrict PCI DMA transfers to 28 bits */ - if (!pci_dma_supported(pci, 0x0fffffff)) { + if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || + pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { snd_printk("architecture does not support 28bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x0fffffff); ice = snd_magic_kcalloc(ice1712_t, 0, GFP_KERNEL); if (ice == NULL) @@ -2433,6 +2444,8 @@ snd_ice1712_free(ice); return err; } + + snd_card_set_dev(card, &pci->dev); *r_ice1712 = ice; return 0; diff -Nru a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h --- a/sound/pci/ice1712/ice1712.h Mon Feb 2 22:07:55 2004 +++ b/sound/pci/ice1712/ice1712.h Mon Feb 2 22:07:55 2004 @@ -353,6 +353,8 @@ void (*set_dir)(ice1712_t *ice, unsigned int data); void (*set_data)(ice1712_t *ice, unsigned int data); unsigned int (*get_data)(ice1712_t *ice); + /* misc operators - move to another place? */ + void (*set_pro_rate)(ice1712_t *ice, unsigned int rate); } gpio; struct semaphore gpio_mutex; }; diff -Nru a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c --- a/sound/pci/ice1712/ice1724.c Mon Feb 2 22:07:56 2004 +++ b/sound/pci/ice1712/ice1724.c Mon Feb 2 22:07:56 2004 @@ -43,6 +43,8 @@ #include "amp.h" #include "revo.h" #include "aureon.h" +#include "prodigy.h" + MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("ICEnsemble ICE1724 (Envy24HT)"); @@ -52,6 +54,7 @@ REVO_DEVICE_DESC AMP_AUDIO2000_DEVICE_DESC AUREON_DEVICE_DESC + PRODIGY_DEVICE_DESC "{VIA,VT1724}," "{ICEnsemble,Generic ICE1724}," "{ICEnsemble,Generic Envy24HT}}"); @@ -908,17 +911,21 @@ int err; if (! (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S)) { + ac97_bus_t bus, *pbus; ac97_t ac97; /* cold reset */ outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD)); mdelay(5); /* FIXME */ outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD)); + memset(&bus, 0, sizeof(bus)); + bus.write = snd_vt1724_ac97_write; + bus.read = snd_vt1724_ac97_read; + if ((err = snd_ac97_bus(ice->card, &bus, &pbus)) < 0) + return err; memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_vt1724_ac97_write; - ac97.read = snd_vt1724_ac97_read; ac97.private_data = ice; - if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0) + if ((err = snd_ac97_mixer(pbus, &ac97, &ice->ac97)) < 0) printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n"); else return 0; @@ -975,7 +982,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(ice->card, "ice1724", &entry)) - snd_info_set_text_ops(entry, ice, snd_vt1724_proc_read); + snd_info_set_text_ops(entry, ice, 1024, snd_vt1724_proc_read); } /* @@ -1576,6 +1583,7 @@ snd_vt1724_revo_cards, snd_vt1724_amp_cards, snd_vt1724_aureon_cards, + snd_vt1724_prodigy_cards, 0, }; @@ -1793,7 +1801,6 @@ /* enable PCI device */ if ((err = pci_enable_device(pci)) < 0) return err; - pci_set_dma_mask(pci, 0xffffffff); ice = snd_magic_kcalloc(ice1712_t, 0, GFP_KERNEL); if (ice == NULL) @@ -1856,6 +1863,8 @@ snd_vt1724_free(ice); return err; } + + snd_card_set_dev(card, &pci->dev); *r_ice1712 = ice; return 0; diff -Nru a/sound/pci/ice1712/prodigy.c b/sound/pci/ice1712/prodigy.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/ice1712/prodigy.c Mon Feb 2 22:07:58 2004 @@ -0,0 +1,662 @@ +/* + * ALSA driver for ICEnsemble VT1724 (Envy24HT) + * + * Lowlevel functions for AudioTrak Prodigy 7.1 (and possibly 192) cards + * Copyright (c) 2003 Dimitromanolakis Apostolos + * based on the aureon.c code (c) 2003 by Takashi Iwai + * + * version 0.82: Stable / not all features work yet (no communication with AC97 secondary) + * added 64x/128x oversampling switch (should be 64x only for 96khz) + * fixed some recording labels (still need to check the rest) + * recording is working probably thanks to correct wm8770 initialization + * + * version 0.5: Initial release: + * working: analog output, mixer, headphone amplifier switch + * not working: prety much everything else, at least i could verify that + * we have no digital output, no capture, pretty bad clicks and poops + * on mixer switch and other coll stuff. + * + * 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 + * + * + * NOTES: + * + * + * + * - we reuse the akm4xxx_t record for storing the wm8770 codec data. + * both wm and akm codecs are pretty similar, so we can integrate + * both controls in the future, once if wm codecs are reused in + * many boards. + * + * - writing over SPI is implemented but reading is not yet. + * the SPDIF-in channel status, etc. can be read from CS chip. + * + * - DAC digital volumes are not implemented in the mixer. + * if they show better response than DAC analog volumes, we can use them + * instead. + * + * - Prodigy boards are equipped with AC97 STAC9744 chip , too. it's used to do + * the analog mixing but not easily controllable (it's not connected + * directly from envy24ht chip). so let's leave it as it is. + * + */ + +#define REVISION 0.82b + +#include +#include +#include +#include +#include +#include +#include + +#include "ice1712.h" +#include "envy24ht.h" +#include "prodigy.h" + + +static int prodigy_set_headphone_amp(ice1712_t *ice, int enable) +{ + unsigned int tmp, tmp2; + + tmp2 = tmp = snd_ice1712_gpio_read(ice); + if (enable) + tmp |= PRODIGY_HP_AMP_EN; + else + tmp &= ~ PRODIGY_HP_AMP_EN; + if (tmp != tmp2) { + snd_ice1712_gpio_write(ice, tmp); + return 1; + } + return 0; +} + + +static int prodigy_get_headphone_amp(ice1712_t *ice) +{ + unsigned int tmp = snd_ice1712_gpio_read(ice); + + return ( tmp & PRODIGY_HP_AMP_EN )!= 0; +} + + +/* + * write data in the SPI mode + */ +static void prodigy_spi_write(ice1712_t *ice, unsigned int cs, unsigned int data, int bits) +{ + unsigned int tmp; + int i; + + tmp = snd_ice1712_gpio_read(ice); + + snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_WM_RW|PRODIGY_WM_DATA|PRODIGY_WM_CLK| + PRODIGY_WM_CS|PRODIGY_CS8415_CS|PRODIGY_HP_AMP_EN)); + tmp |= PRODIGY_WM_RW; + tmp &= ~cs; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + + for (i = bits - 1; i >= 0; i--) { + tmp &= ~PRODIGY_WM_CLK; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + if (data & (1 << i)) + tmp |= PRODIGY_WM_DATA; + else + tmp &= ~PRODIGY_WM_DATA; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= PRODIGY_WM_CLK; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + } + + tmp &= ~PRODIGY_WM_CLK; + tmp |= cs; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= PRODIGY_WM_CLK; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); +} + + +/* + * get the current register value of WM codec + */ +static unsigned short wm_get(ice1712_t *ice, int reg) +{ + reg <<= 1; + return ((unsigned short)ice->akm[0].images[reg] << 8) | + ice->akm[0].images[reg + 1]; +} + +/* + * set the register value of WM codec and remember it + */ +static void wm_put(ice1712_t *ice, int reg, unsigned short val) +{ + prodigy_spi_write(ice, PRODIGY_WM_CS, (reg << 9) | (val & 0x1ff), 16); + reg <<= 1; + ice->akm[0].images[reg] = val >> 8; + ice->akm[0].images[reg + 1] = val; +} + + +/********************************* + ********* Controls section ****** + *********************************/ + +#define PRODIGY_CON_HPAMP \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Headphone Amplifier", \ + .info = prodigy_hpamp_info, \ + .get = prodigy_hpamp_get, \ + .put = prodigy_hpamp_put \ + } + +static int prodigy_hpamp_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[2] = { + "Off", "On" + }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + + return 0; +} + + +static int prodigy_hpamp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = prodigy_get_headphone_amp(ice); + return 0; +} + + +static int prodigy_hpamp_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + + return prodigy_set_headphone_amp(ice,ucontrol->value.integer.value[0]); +} + + + +#define PRODIGY_CON_DEEMP \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "DAC De-emphasis", \ + .info = prodigy_deemp_info, \ + .get = prodigy_deemp_get, \ + .put = prodigy_deemp_put \ + } + +static int prodigy_deemp_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[2] = { "Off", "On" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int prodigy_deemp_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = (wm_get(ice, 0x15) & 0xf) == 0xf; + return 0; +} + +static int prodigy_deemp_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int temp, temp2; + temp2 = temp = wm_get(ice, 0x15); + temp = (temp & ~0xf) | ((ucontrol->value.integer.value[0])*0xf); + if (temp != temp2) { + wm_put(ice,0x15,temp); + return 1; + } + return 0; +} + + +#define PRODIGY_CON_OVERSAMPLING \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "ADC Oversampling", \ + .info = prodigy_oversampling_info, \ + .get = prodigy_oversampling_get, \ + .put = prodigy_oversampling_put \ + } + +static int prodigy_oversampling_info(snd_kcontrol_t *k, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[2] = { "128x", "64x" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int prodigy_oversampling_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = (wm_get(ice, 0x17) & 0x8) == 0x8; + return 0; +} + +static int prodigy_oversampling_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + int temp, temp2; + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + + temp2 = temp = wm_get(ice, 0x17); + + if( ucontrol->value.integer.value[0] ) { + temp |= 0x8; + } else { + temp &= ~0x8; + } + + if (temp != temp2) { + wm_put(ice,0x17,temp); + return 1; + } + return 0; +} + + + + +/* + * DAC volume attenuation mixer control + */ +static int wm_dac_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; /* mute */ + uinfo->value.integer.max = 101; /* 0dB */ + return 0; +} + +static int wm_dac_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int idx; + unsigned short vol; + + down(&ice->gpio_mutex); + if (kcontrol->private_value) + idx = WM_DAC_MASTER_ATTEN; + else + idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN; + vol = wm_get(ice, idx) & 0x7f; + if (vol <= 0x1a) + ucontrol->value.integer.value[0] = 0; + else + ucontrol->value.integer.value[0] = vol - 0x1a; + up(&ice->gpio_mutex); + + return 0; +} + +static int wm_dac_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int idx; + unsigned short ovol, nvol; + int change; + + snd_ice1712_save_gpio_status(ice); + if (kcontrol->private_value) + idx = WM_DAC_MASTER_ATTEN; + else + idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN; + nvol = ucontrol->value.integer.value[0] + 0x1a; + ovol = wm_get(ice, idx) & 0x7f; + change = (ovol != nvol); + if (change) { + if (nvol <= 0x1a && ovol <= 0x1a) + change = 0; + else + wm_put(ice, idx, nvol | 0x180); /* update on zero detect */ + } + snd_ice1712_restore_gpio_status(ice); + return change; +} + +/* + * ADC gain mixer control + */ +static int wm_adc_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; /* -12dB */ + uinfo->value.integer.max = 0x1f; /* 19dB */ + return 0; +} + +static int wm_adc_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int idx; + unsigned short vol; + + down(&ice->gpio_mutex); + idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN; + vol = wm_get(ice, idx) & 0x1f; + ucontrol->value.integer.value[0] = vol; + up(&ice->gpio_mutex); + return 0; +} + +static int wm_adc_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int idx; + unsigned short ovol, nvol; + int change; + + snd_ice1712_save_gpio_status(ice); + idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN; + nvol = ucontrol->value.integer.value[0]; + ovol = wm_get(ice, idx) & 0x1f; + change = (ovol != nvol); + if (change) + wm_put(ice, idx, nvol); + snd_ice1712_restore_gpio_status(ice); + return change; +} + +/* + * ADC input mux mixer control + */ +static int wm_adc_mux_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[] = { + "CD Left", + "CD Right", + "Line Left", + "Line Right", + "Aux Left", + "Aux Right", + "Mic Left", + "Mic Right", + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 2; + uinfo->value.enumerated.items = 8; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int wm_adc_mux_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + unsigned short val; + + down(&ice->gpio_mutex); + val = wm_get(ice, WM_ADC_MUX); + ucontrol->value.integer.value[0] = val & 7; + ucontrol->value.integer.value[1] = (val >> 4) & 7; + up(&ice->gpio_mutex); + return 0; +} + +static int wm_adc_mux_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + unsigned short oval, nval; + int change; + + snd_ice1712_save_gpio_status(ice); + oval = wm_get(ice, WM_ADC_MUX); + nval = oval & ~0x77; + nval |= ucontrol->value.integer.value[0] & 7; + nval |= (ucontrol->value.integer.value[1] & 7) << 4; + change = (oval != nval); + if (change) + wm_put(ice, WM_ADC_MUX, nval); + snd_ice1712_restore_gpio_status(ice); + return 0; +} + +/* + * mixers + */ + +static snd_kcontrol_new_t prodigy71_dac_control __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DAC Volume", + .count = 8, + .info = wm_dac_vol_info, + .get = wm_dac_vol_get, + .put = wm_dac_vol_put, +}; + +static snd_kcontrol_new_t wm_controls[] __devinitdata = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .info = wm_dac_vol_info, + .get = wm_dac_vol_get, + .put = wm_dac_vol_put, + .private_value = 1, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "ADC Volume", + .count = 2, + .info = wm_adc_vol_info, + .get = wm_adc_vol_get, + .put = wm_adc_vol_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Route", + .info = wm_adc_mux_info, + .get = wm_adc_mux_get, + .put = wm_adc_mux_put, + }, + PRODIGY_CON_HPAMP , + PRODIGY_CON_DEEMP , + PRODIGY_CON_OVERSAMPLING +}; + + +static int __devinit prodigy_add_controls(ice1712_t *ice) +{ + unsigned int i; + int err; + + err = snd_ctl_add(ice->card, snd_ctl_new1(&prodigy71_dac_control, ice)); + if (err < 0) + return err; + + for (i = 0; i < ARRAY_SIZE(wm_controls); i++) { + err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice)); + if (err < 0) + return err; + } + return 0; +} + + +/* + * initialize the chip + */ +static int __devinit prodigy_init(ice1712_t *ice) +{ + static unsigned short wm_inits[] = { + + /* These come first to reduce init pop noise */ + 0x1b, 0x000, /* ADC Mux */ + 0x1c, 0x009, /* Out Mux1 */ + 0x1d, 0x009, /* Out Mux2 */ + + 0x18, 0x000, /* All power-up */ + + 0x16, 0x022, /* I2S, normal polarity, 24bit, high-pass on */ + 0x17, 0x006, /* 128fs, slave mode */ + + 0x00, 0, /* DAC1 analog mute */ + 0x01, 0, /* DAC2 analog mute */ + 0x02, 0, /* DAC3 analog mute */ + 0x03, 0, /* DAC4 analog mute */ + 0x04, 0, /* DAC5 analog mute */ + 0x05, 0, /* DAC6 analog mute */ + 0x06, 0, /* DAC7 analog mute */ + 0x07, 0, /* DAC8 analog mute */ + 0x08, 0x100, /* master analog mute */ + + 0x09, 0x7f, /* DAC1 digital full */ + 0x0a, 0x7f, /* DAC2 digital full */ + 0x0b, 0x7f, /* DAC3 digital full */ + 0x0c, 0x7f, /* DAC4 digital full */ + 0x0d, 0x7f, /* DAC5 digital full */ + 0x0e, 0x7f, /* DAC6 digital full */ + 0x0f, 0x7f, /* DAC7 digital full */ + 0x10, 0x7f, /* DAC8 digital full */ + 0x11, 0x1FF, /* master digital full */ + + 0x12, 0x000, /* phase normal */ + 0x13, 0x090, /* unmute DAC L/R */ + 0x14, 0x000, /* all unmute */ + 0x15, 0x000, /* no deemphasis, no ZFLG */ + + 0x19, 0x000, /* -12dB ADC/L */ + 0x1a, 0x000 /* -12dB ADC/R */ + + }; + + static unsigned short cs_inits[] = { + 0x0441, /* RUN */ + 0x0100, /* no mute */ + 0x0200, /* */ + 0x0600, /* slave, 24bit */ + }; + + unsigned int tmp; + unsigned int i; + + printk(KERN_INFO "ice1724: AudioTrak Prodigy 7.1 driver rev. 0.82b\n"); + printk(KERN_INFO "ice1724: This driver is in beta stage. Forsuccess/failure reporting contact\n"); + printk(KERN_INFO "ice1724: Apostolos Dimitromanolakis \n"); + + ice->num_total_dacs = 8; + + /* to remeber the register values */ + ice->akm = snd_kcalloc(sizeof(akm4xxx_t), GFP_KERNEL); + if (! ice->akm) + return -ENOMEM; + ice->akm_codecs = 1; + + snd_ice1712_gpio_set_dir(ice, 0xbfffff); /* fix this for the time being */ + + /* reset the wm codec as the SPI mode */ + snd_ice1712_save_gpio_status(ice); + snd_ice1712_gpio_set_mask(ice,~( PRODIGY_WM_RESET|PRODIGY_WM_CS| + PRODIGY_CS8415_CS|PRODIGY_HP_AMP_EN )); + + tmp = snd_ice1712_gpio_read(ice); + tmp &= ~PRODIGY_WM_RESET; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= PRODIGY_WM_CS | PRODIGY_CS8415_CS; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= PRODIGY_WM_RESET; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + + /* initialize WM8770 codec */ + for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2) + wm_put(ice, wm_inits[i], wm_inits[i+1]); + + /* initialize CS8415A codec */ + for (i = 0; i < ARRAY_SIZE(cs_inits); i++) + prodigy_spi_write(ice, PRODIGY_CS8415_CS, + cs_inits[i] | 0x200000, 24); + + + prodigy_set_headphone_amp(ice, 1); + + snd_ice1712_restore_gpio_status(ice); + + return 0; +} + +/* + * Prodigy boards don't provide the EEPROM data except for the vendor IDs. + * hence the driver needs to sets up it properly. + */ + +static unsigned char prodigy71_eeprom[] __devinitdata = { + 0x2b, /* SYSCONF: clock 512, mpu401, spdif-in/ADC, 4DACs */ + 0x80, /* ACLINK: I2S */ + 0xf8, /* I2S: vol, 96k, 24bit, 192k */ + 0xc3, /* SPDIF: out-en, out-int, spdif-in */ + 0xff, /* GPIO_DIR */ + 0xff, /* GPIO_DIR1 */ + 0xbf, /* GPIO_DIR2 */ + 0x00, /* GPIO_MASK */ + 0x00, /* GPIO_MASK1 */ + 0x00, /* GPIO_MASK2 */ + 0x00, /* GPIO_STATE */ + 0x00, /* GPIO_STATE1 */ + 0x00, /* GPIO_STATE2 */ +}; + +/* entry point */ +struct snd_ice1712_card_info snd_vt1724_prodigy_cards[] __devinitdata = { + { + .subvendor = VT1724_SUBDEVICE_PRODIGY71, + .name = "Audiotrak Prodigy 7.1", + .chip_init = prodigy_init, + .build_controls = prodigy_add_controls, + .eeprom_size = sizeof(prodigy71_eeprom), + .eeprom_data = prodigy71_eeprom, + }, + { } /* terminator */ +}; diff -Nru a/sound/pci/ice1712/prodigy.h b/sound/pci/ice1712/prodigy.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/ice1712/prodigy.h Mon Feb 2 22:07:58 2004 @@ -0,0 +1,67 @@ +#ifndef __SOUND_PRODIGY_H +#define __SOUND_PRODIGY_H + +/* + * ALSA driver for VIA VT1724 (Envy24HT) + * + * Lowlevel functions for Terratec PRODIGY cards + * + * Copyright (c) 2003 Takashi Iwai + * + * 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 + * + */ + +#define PRODIGY_DEVICE_DESC "{AudioTrak,Prodigy 7.1}," + +#define VT1724_SUBDEVICE_PRODIGY71 0x33495345 /* PRODIGY 7.1 */ + +extern struct snd_ice1712_card_info snd_vt1724_prodigy_cards[]; + +/* GPIO bits */ +#define PRODIGY_CS8415_CS (1 << 23) +#define PRODIGY_CS8415_CDTO (1 << 22) +#define PRODIGY_WM_RESET (1 << 20) +#define PRODIGY_WM_CLK (1 << 19) +#define PRODIGY_WM_DATA (1 << 18) +#define PRODIGY_WM_RW (1 << 17) +#define PRODIGY_AC97_RESET (1 << 16) +#define PRODIGY_DIGITAL_SEL1 (1 << 15) +// #define PRODIGY_HP_SEL (1 << 14) +#define PRODIGY_WM_CS (1 << 12) + +#define PRODIGY_HP_AMP_EN (1 << 14) + + +/* WM8770 registers */ +#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ +#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */ +#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */ +#define WM_DAC_DIG_MATER_ATTEN 0x11 /* DAC master digital attenuation */ +#define WM_PHASE_SWAP 0x12 /* DAC phase */ +#define WM_DAC_CTRL1 0x13 /* DAC control bits */ +#define WM_MUTE 0x14 /* mute controls */ +#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */ +#define WM_INT_CTRL 0x16 /* interface control */ +#define WM_MASTER 0x17 /* master clock and mode */ +#define WM_POWERDOWN 0x18 /* power-down controls */ +#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */ +#define WM_ADC_MUX 0x1b /* input MUX */ +#define WM_OUT_MUX1 0x1c /* output MUX */ +#define WM_OUT_MUX2 0x1e /* output MUX */ +#define WM_RESET 0x1f /* software reset */ + + +#endif /* __SOUND_PRODIGY_H */ diff -Nru a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c --- a/sound/pci/intel8x0.c Mon Feb 2 22:07:57 2004 +++ b/sound/pci/intel8x0.c Mon Feb 2 22:07:57 2004 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,9 @@ #include #define SNDRV_GET_ID #include +/* for 440MX workaround */ +#include +#include MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455"); @@ -59,7 +63,9 @@ "{AMD,AMD8111}," "{ALI,M5455}}"); +#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) #define SUPPORT_JOYSTICK 1 +#endif #define SUPPORT_MIDI 1 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ @@ -67,12 +73,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; #ifdef SUPPORT_JOYSTICK -static int joystick_port[SNDRV_CARDS] = -#ifdef CONFIG_ISA - {0x200}; /* enable as default */ -#else - {0}; /* disabled */ -#endif +static int joystick[SNDRV_CARDS]; #endif #ifdef SUPPORT_MIDI static int mpu_port[SNDRV_CARDS]; /* disabled */ @@ -91,9 +92,9 @@ MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect)."); MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:0"); #ifdef SUPPORT_JOYSTICK -MODULE_PARM(joystick_port, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); -MODULE_PARM_DESC(joystick_port, "Joystick port address for Intel i8x0 soundcard. (0 = disabled)"); -MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED ",allows:{{0},{0x200}},dialog:list"); +MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(joystick, "Enable joystick for Intel i8x0 soundcard."); +MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); #endif #ifdef SUPPORT_MIDI MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); @@ -368,9 +369,8 @@ unsigned int roff_picb; unsigned int int_sta_mask; /* interrupt status mask */ unsigned int ali_slot; /* ALI DMA slot */ - ac97_t *ac97; - unsigned short ac97_rate_regs[3]; - int ac97_rates_idx; + struct ac97_pcm *pcm; + int pcm_open_flag; } ichdev_t; typedef struct _snd_intel8x0 intel8x0_t; @@ -404,7 +404,9 @@ smp20bit: 1; int in_ac97_init: 1, in_sdin_init: 1; + int fix_nocache: 1; /* workaround for 440MX */ + ac97_bus_t *ac97_bus; ac97_t *ac97[3]; unsigned int ac97_sdin[3]; @@ -723,6 +725,23 @@ iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI); } +#ifdef __i386__ +/* + * Intel 82443MX running a 100MHz processor system bus has a hardware bug, + * which aborts PCI busmaster for audio transfer. A workaround is to set + * the pages as non-cached. For details, see the errata in + * http://www.intel.com/design/chipsets/specupdt/245051.htm + */ +static void fill_nocache(void *buf, int size, int nocache) +{ + size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + change_page_attr(virt_to_page(buf), size, nocache ? PAGE_KERNEL_NOCACHE : PAGE_KERNEL); + global_flush_tlb(); +} +#else +#define fill_nocache(buf,size,nocache) +#endif + /* * Interrupt handler */ @@ -888,11 +907,46 @@ static int snd_intel8x0_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params) { - return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + intel8x0_t *chip = snd_pcm_substream_chip(substream); + ichdev_t *ichdev = get_ichdev(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + size_t size = params_buffer_bytes(hw_params); + int err; + + if (chip->fix_nocache && runtime->dma_area && runtime->dma_bytes < size) + fill_nocache(runtime->dma_area, runtime->dma_bytes, 0); /* clear */ + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + if (err < 0) + return err; + if (chip->fix_nocache && err > 0) + fill_nocache(runtime->dma_area, runtime->dma_bytes, 1); + if (ichdev->pcm_open_flag) { + snd_ac97_pcm_close(ichdev->pcm); + ichdev->pcm_open_flag = 0; + } + err = snd_ac97_pcm_open(ichdev->pcm, params_rate(hw_params), + params_channels(hw_params), + ichdev->pcm->r[0].slots); + if (err >= 0) { + ichdev->pcm_open_flag = 1; + /* FIXME: hack to enable spdif support */ + if (ichdev->ichd == ICHD_PCMOUT && chip->device_type == DEVICE_SIS) + snd_ac97_set_rate(ichdev->pcm->r[0].codec[0], AC97_SPDIF, params_rate(hw_params)); + } + return err; } static int snd_intel8x0_hw_free(snd_pcm_substream_t * substream) { + intel8x0_t *chip = snd_pcm_substream_chip(substream); + ichdev_t *ichdev = get_ichdev(substream); + + if (ichdev->pcm_open_flag) { + snd_ac97_pcm_close(ichdev->pcm); + ichdev->pcm_open_flag = 0; + } + if (chip->fix_nocache && substream->runtime->dma_area) + fill_nocache(substream->runtime->dma_area, substream->runtime->dma_bytes, 0); return snd_pcm_lib_free_pages(substream); } @@ -925,6 +979,13 @@ cnt |= ICH_PCM_4; else if (chip->multi6 && channels == 6) cnt |= ICH_PCM_6; + if (chip->device_type == DEVICE_NFORCE) { + /* reset to 2ch once to keep the 6 channel data in alignment, + * to start from Front Left always + */ + iputdword(chip, ICHREG(GLOB_CNT), (cnt & 0xcfffff)); + mdelay(50); /* grrr... */ + } iputdword(chip, ICHREG(GLOB_CNT), cnt); break; } @@ -935,7 +996,6 @@ intel8x0_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; ichdev_t *ichdev = get_ichdev(substream); - int i; ichdev->physbuf = runtime->dma_addr; ichdev->size = snd_pcm_lib_buffer_bytes(substream); @@ -945,14 +1005,6 @@ snd_intel8x0_setup_multi_channels(chip, runtime->channels); spin_unlock(&chip->reg_lock); } - if (ichdev->ac97) { - for (i = 0; i < 3; i++) - if (ichdev->ac97_rate_regs[i]) - snd_ac97_set_rate(ichdev->ac97, ichdev->ac97_rate_regs[i], runtime->rate); - /* FIXME: hack to enable spdif support */ - if (ichdev->ichd == ICHD_PCMOUT && chip->device_type == DEVICE_SIS) - snd_ac97_set_rate(ichdev->ac97, AC97_SPDIF, runtime->rate); - } snd_intel8x0_setup_periods(chip, ichdev); return 0; } @@ -1031,13 +1083,11 @@ ichdev->substream = substream; runtime->hw = snd_intel8x0_stream; - if (ichdev->ac97 && ichdev->ac97_rates_idx >= 0) { - runtime->hw.rates = ichdev->ac97->rates[ichdev->ac97_rates_idx]; - for (i = 0; i < ARRAY_SIZE(rates); i++) { - if (runtime->hw.rates & (1 << i)) { - runtime->hw.rate_min = rates[i]; - break; - } + runtime->hw.rates = ichdev->pcm->rates; + for (i = 0; i < ARRAY_SIZE(rates); i++) { + if (runtime->hw.rates & (1 << i)) { + runtime->hw.rate_min = rates[i]; + break; } } if (chip->device_type == DEVICE_SIS) { @@ -1513,7 +1563,7 @@ rec = tbl + i; if (i > 0 && rec->ac97_idx) { /* activate PCM only when associated AC'97 codec */ - if (! chip->ichd[rec->ac97_idx].ac97) + if (! chip->ichd[rec->ac97_idx].pcm) continue; } err = snd_intel8x0_pcm1(chip, device, rec); @@ -1531,76 +1581,100 @@ * Mixer part */ +static void snd_intel8x0_mixer_free_ac97_bus(ac97_bus_t *bus) +{ + intel8x0_t *chip = snd_magic_cast(intel8x0_t, bus->private_data, return); + chip->ac97_bus = NULL; +} + static void snd_intel8x0_mixer_free_ac97(ac97_t *ac97) { intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return); chip->ac97[ac97->num] = NULL; } -struct _ac97_rate_regs { - unsigned int ichd; - unsigned short regs[3]; - short rates_idx; -}; - -static struct _ac97_rate_regs intel_ac97_rate_regs[] __devinitdata = { - { ICHD_PCMOUT, { AC97_PCM_FRONT_DAC_RATE, AC97_PCM_SURR_DAC_RATE, AC97_PCM_LFE_DAC_RATE }, AC97_RATES_FRONT_DAC }, - { ICHD_PCMIN, { AC97_PCM_LR_ADC_RATE, 0, 0 }, AC97_RATES_ADC }, - { ICHD_MIC, { AC97_PCM_MIC_ADC_RATE, 0, 0 }, AC97_RATES_MIC_ADC }, - { ICHD_MIC2, { AC97_PCM_MIC_ADC_RATE, 0, 0 }, AC97_RATES_MIC_ADC }, - { ICHD_PCM2IN, { AC97_PCM_LR_ADC_RATE, 0, 0 }, AC97_RATES_ADC }, - { ICHD_SPBAR, { AC97_SPDIF, 0, 0 }, AC97_RATES_SPDIF }, -}; - -static struct _ac97_rate_regs nforce_ac97_rate_regs[] __devinitdata = { - { NVD_PCMOUT, { AC97_PCM_FRONT_DAC_RATE, AC97_PCM_SURR_DAC_RATE, AC97_PCM_LFE_DAC_RATE }, AC97_RATES_FRONT_DAC }, - { NVD_PCMIN, { AC97_PCM_LR_ADC_RATE, 0, 0 }, AC97_RATES_ADC }, - { NVD_MIC, { AC97_PCM_MIC_ADC_RATE, 0, 0 }, AC97_RATES_MIC_ADC }, - { NVD_SPBAR, { AC97_SPDIF, AC97_PCM_FRONT_DAC_RATE, 0 }, -1 }, /* spdif is 48k only */ -}; - -static struct _ac97_rate_regs ali_ac97_rate_regs[] __devinitdata = { -#if 0 /* FIXME: my test board doens't work well with VRA... */ - { ALID_PCMOUT, { AC97_PCM_FRONT_DAC_RATE, AC97_PCM_SURR_DAC_RATE, AC97_PCM_LFE_DAC_RATE }, AC97_RATES_FRONT_DAC }, - { ALID_PCMIN, { AC97_PCM_LR_ADC_RATE, 0, 0 }, AC97_RATES_ADC }, - { ALID_MIC, { AC97_PCM_MIC_ADC_RATE, 0, 0 }, AC97_RATES_MIC_ADC }, - { ALID_AC97SPDIFOUT, { AC97_SPDIF, 0, 0 }, AC97_RATES_SPDIF }, - { ALID_SPDIFOUT, { 0, 0, 0 }, -1 }, - { ALID_SPDIFIN, { 0, 0, 0 }, -1 }, -#else - { ALID_PCMOUT, { AC97_PCM_FRONT_DAC_RATE }, -1 }, - { ALID_PCMIN, { AC97_PCM_LR_ADC_RATE }, -1 }, - { ALID_MIC, { AC97_PCM_MIC_ADC_RATE }, -1 }, - { ALID_AC97SPDIFOUT, { AC97_SPDIF }, -1 }, - { ALID_SPDIFOUT, { }, -1 }, - { ALID_SPDIFIN, { }, -1 }, -#endif +static struct ac97_pcm ac97_pcm_defs[] __devinitdata = { + /* front PCM */ + { + .exclusive = 1, + .r = { { + .slots = (1 << AC97_SLOT_PCM_LEFT) | + (1 << AC97_SLOT_PCM_RIGHT) | + (1 << AC97_SLOT_PCM_CENTER) | + (1 << AC97_SLOT_PCM_SLEFT) | + (1 << AC97_SLOT_PCM_SRIGHT) | + (1 << AC97_SLOT_LFE) + } + } + }, + /* PCM IN #1 */ + { + .stream = 1, + .exclusive = 1, + .r = { { + .slots = (1 << AC97_SLOT_PCM_LEFT) | + (1 << AC97_SLOT_PCM_RIGHT) + } + } + }, + /* MIC IN #1 */ + { + .stream = 1, + .exclusive = 1, + .r = { { + .slots = (1 << AC97_SLOT_MIC) + } + } + }, + /* S/PDIF PCM */ + { + .exclusive = 1, + .spdif = 1, + .r = { { + .slots = (1 << AC97_SLOT_SPDIF_LEFT2) | + (1 << AC97_SLOT_SPDIF_RIGHT2) + } + } + }, + /* PCM IN #2 */ + { + .stream = 1, + .exclusive = 1, + .r = { { + .slots = (1 << AC97_SLOT_PCM_LEFT) | + (1 << AC97_SLOT_PCM_RIGHT) + } + } + }, + /* MIC IN #2 */ + { + .stream = 1, + .exclusive = 1, + .r = { { + .slots = (1 << AC97_SLOT_MIC) + } + } + }, }; static struct ac97_quirk ac97_quirks[] __devinitdata = { { .vendor = 0x1028, .device = 0x00d8, - .name = "Dell Precision 530", + .name = "Dell Precision 530", /* AD1885 */ .type = AC97_TUNE_HP_ONLY }, { .vendor = 0x1028, .device = 0x0126, - .name = "Dell Optiplex GX260", + .name = "Dell Optiplex GX260", /* AD1981A */ .type = AC97_TUNE_HP_ONLY }, - { - .vendor = 0x1028, - .device = 0x0157, - .name = "Dell Dimension 8300", - .type = AC97_TUNE_SWAP_SURROUND - }, - { - .vendor = 0x1043, - .device =0x80b0, - .name = "ASUS P4PE Mobo", - .type = AC97_TUNE_SWAP_SURROUND + { /* FIXME: which codec? */ + .vendor = 0x103c, + .device = 0x00c3, + .name = "Hewlett-Packard onboard", + .type = AC97_TUNE_HP_ONLY }, { .vendor = 0x1043, @@ -1611,13 +1685,13 @@ { .vendor = 0x10f1, .device = 0x2665, - .name = "Fujitsu-Siemens Celcius", + .name = "Fujitsu-Siemens Celsius", /* AD1981? */ .type = AC97_TUNE_HP_ONLY }, { .vendor = 0x110a, .device = 0x0056, - .name = "Fujitsu-Siemens Scenic", + .name = "Fujitsu-Siemens Scenic", /* AD1981? */ .type = AC97_TUNE_HP_ONLY }, { @@ -1629,24 +1703,15 @@ { .vendor = 0x1734, .device = 0x0088, - .name = "Fujitsu-Siemens D1522", + .name = "Fujitsu-Siemens D1522", /* AD1981 */ .type = AC97_TUNE_HP_ONLY }, -#if 0 - /* FIXME: this seems invalid */ - { - .vendor = 0x4144, - .device = 0x5360, - .type = "AMD64 Motherboard", - .name = AC97_TUNE_HP_ONLY - }, -#endif { .vendor = 0x8086, .device = 0x2000, .mask = 0xfff0, - .name = "Intel ICH5/AD1985 (discrete)", - .type = AC97_TUNE_HP_ONLY + .name = "Intel ICH5/AD1985", + .type = AC97_TUNE_AD_SHARING }, { .vendor = 0x8086, @@ -1658,7 +1723,7 @@ { .vendor = 0x8086, .device = 0x4d44, - .name = "Intel D850EMV2", + .name = "Intel D850EMV2", /* AD1885 */ .type = AC97_TUNE_HP_ONLY }, { @@ -1679,13 +1744,7 @@ .vendor = 0x8086, .device = 0xa000, .mask = 0xfff0, - .name = "Intel ICH5/AD1985 (discrete)", - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x103c, - .device = 0x00c3, - .name = "Hewlett-Packard onboard", + .name = "Intel ICH5/AD1985", .type = AC97_TUNE_HP_ONLY }, { } /* terminator */ @@ -1693,50 +1752,42 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) { + ac97_bus_t bus, *pbus; ac97_t ac97, *x97; - ichdev_t *ichdev; int err; - unsigned int i, num, codecs, _codecs; + unsigned int i, codecs; unsigned int glob_sta = 0; - struct _ac97_rate_regs *tbl; int spdif_idx = -1; /* disabled */ switch (chip->device_type) { case DEVICE_NFORCE: - tbl = nforce_ac97_rate_regs; spdif_idx = NVD_SPBAR; break; case DEVICE_ALI: - tbl = ali_ac97_rate_regs; spdif_idx = ALID_AC97SPDIFOUT; break; default: - tbl = intel_ac97_rate_regs; if (chip->device_type == DEVICE_INTEL_ICH4) spdif_idx = ICHD_SPBAR; break; }; - for (i = 0; i < chip->bdbars_count; i++) { - struct _ac97_rate_regs *aregs = tbl + i; - ichdev = &chip->ichd[aregs->ichd]; - ichdev->ac97_rate_regs[0] = aregs->regs[0]; - ichdev->ac97_rate_regs[1] = aregs->regs[1]; - ichdev->ac97_rate_regs[2] = aregs->regs[2]; - ichdev->ac97_rates_idx = aregs->rates_idx; - } chip->in_ac97_init = 1; + memset(&bus, 0, sizeof(bus)); + bus.private_data = chip; + bus.private_free = snd_intel8x0_mixer_free_ac97_bus; + if (ac97_clock >= 8000 && ac97_clock <= 48000) + bus.clock = ac97_clock; + else + bus.clock = 48000; + memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; ac97.private_free = snd_intel8x0_mixer_free_ac97; - if (ac97_clock >= 8000 && ac97_clock <= 48000) - ac97.clock = ac97_clock; - else - ac97.clock = 48000; if (chip->device_type != DEVICE_ALI) { glob_sta = igetdword(chip, ICHREG(GLOB_STA)); - ac97.write = snd_intel8x0_codec_write; - ac97.read = snd_intel8x0_codec_read; + bus.write = snd_intel8x0_codec_write; + bus.read = snd_intel8x0_codec_read; if (chip->device_type == DEVICE_INTEL_ICH4) { codecs = 0; if (glob_sta & ICH_PCR) @@ -1756,9 +1807,10 @@ } else { codecs = glob_sta & ICH_SCR ? 2 : 1; } + bus.vra = 1; } else { - ac97.write = snd_intel8x0_ali_codec_write; - ac97.read = snd_intel8x0_ali_codec_read; + bus.write = snd_intel8x0_ali_codec_write; + bus.read = snd_intel8x0_ali_codec_read; codecs = 1; /* detect the secondary codec */ for (i = 0; i < 100; i++) { @@ -1770,144 +1822,82 @@ iputdword(chip, ICHREG(ALI_RTSR), reg | 0x40); udelay(1); } + /* FIXME: my test board doens't work well with VRA... */ + bus.vra = 0; } + if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0) + goto __err; + chip->ac97_bus = pbus; ac97.pci = chip->pci; - if ((err = snd_ac97_mixer(chip->card, &ac97, &x97)) < 0) { - /* clear the cold-reset bit for the next chance */ - if (chip->device_type != DEVICE_ALI) - iputdword(chip, ICHREG(GLOB_CNT), igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_AC97COLD); - return err; + for (i = 0; i < codecs; i++) { + ac97.num = i; + if ((err = snd_ac97_mixer(pbus, &ac97, &x97)) < 0) { + snd_printk(KERN_ERR "Unable to initialize codec #%d\n", i); + if (i == 0) + goto __err; + continue; + } + chip->ac97[i] = x97; } - chip->ac97[0] = x97; /* tune up the primary codec */ snd_ac97_tune_hardware(chip->ac97[0], ac97_quirks); - /* the following three entries are common among all devices */ - chip->ichd[ICHD_PCMOUT].ac97 = x97; - chip->ichd[ICHD_PCMIN].ac97 = x97; - if (x97->ext_id & AC97_EI_VRM) - chip->ichd[ICHD_MIC].ac97 = x97; - /* spdif */ - if ((x97->ext_id & AC97_EI_SPDIF) && spdif_idx >= 0) - chip->ichd[spdif_idx].ac97 = x97; - /* make sure, that we have DACs at right slot for rev2.2 */ - if (ac97_is_rev22(x97)) - snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 0); - /* AnalogDevices CNR boards uses special codec chaining */ - /* skip standard test method for secondary codecs in this case */ - if (x97->flags & AC97_AD_MULTI) - codecs = 1; - if (codecs < 2) - goto __skip_secondary; - for (i = 1, num = 1, _codecs = codecs; num < _codecs; num++) { - ac97.num = num; - if ((err = snd_ac97_mixer(chip->card, &ac97, &x97)) < 0) { - snd_printk("Unable to initialize codec #%i [device = %i, GLOB_STA = 0x%x]\n", i, chip->device_type, glob_sta); - codecs--; - continue; - } - chip->ac97[i++] = x97; - if (!ac97_is_audio(x97)) - continue; - switch (chip->device_type) { - case DEVICE_INTEL_ICH4: - if (chip->ichd[ICHD_PCM2IN].ac97 == NULL) - chip->ichd[ICHD_PCM2IN].ac97 = x97; - if (x97->ext_id & AC97_EI_VRM) { - if (chip->ichd[ICHD_MIC].ac97 == NULL) - chip->ichd[ICHD_MIC].ac97 = x97; - else if (chip->ichd[ICHD_MIC2].ac97 == NULL && - chip->ichd[ICHD_PCM2IN].ac97 == x97) - chip->ichd[ICHD_MIC2].ac97 = x97; - } - break; - default: - if (x97->ext_id & AC97_EI_VRM) { - if (chip->ichd[ICHD_MIC].ac97 == NULL) - chip->ichd[ICHD_MIC].ac97 = x97; - } - break; - } - if ((x97->ext_id & AC97_EI_SPDIF) && spdif_idx >= 0) { - if (chip->ichd[spdif_idx].ac97 == NULL) - chip->ichd[spdif_idx].ac97 = x97; - } + /* enable separate SDINs for ICH4 */ + if (chip->device_type == DEVICE_INTEL_ICH4) + pbus->isdin = 1; + /* find the available PCM streams */ + i = ARRAY_SIZE(ac97_pcm_defs); + if (chip->device_type != DEVICE_INTEL_ICH4) + i -= 2; /* do not allocate PCM2IN and MIC2 */ + if (spdif_idx < 0) + i--; /* do not allocate S/PDIF */ + err = snd_ac97_pcm_assign(pbus, i, ac97_pcm_defs); + if (err < 0) + goto __err; + chip->ichd[ICHD_PCMOUT].pcm = &pbus->pcms[0]; + chip->ichd[ICHD_PCMIN].pcm = &pbus->pcms[1]; + chip->ichd[ICHD_MIC].pcm = &pbus->pcms[2]; + if (spdif_idx >= 0) + chip->ichd[spdif_idx].pcm = &pbus->pcms[3]; + if (chip->device_type == DEVICE_INTEL_ICH4) { + chip->ichd[ICHD_PCM2IN].pcm = &pbus->pcms[4]; + chip->ichd[ICHD_MIC2].pcm = &pbus->pcms[5]; } - - __skip_secondary: + /* enable separate SDINs for ICH4 */ if (chip->device_type == DEVICE_INTEL_ICH4) { + struct ac97_pcm *pcm = chip->ichd[ICHD_PCM2IN].pcm; u8 tmp = igetbyte(chip, ICHREG(SDM)); tmp &= ~(ICH_DI2L_MASK|ICH_DI1L_MASK); - if (chip->ichd[ICHD_PCM2IN].ac97) { + if (pcm) { tmp |= ICH_SE; /* steer enable for multiple SDINs */ tmp |= chip->ac97_sdin[0] << ICH_DI1L_SHIFT; - tmp |= chip->ac97_sdin[chip->ichd[ICHD_PCM2IN].ac97->num] << ICH_DI2L_SHIFT; + for (i = 1; i < 4; i++) { + if (pcm->r[0].codec[i]) { + tmp |= chip->ac97_sdin[pcm->r[0].codec[1]->num] << ICH_DI2L_SHIFT; + break; + } + } } else { - tmp &= ~ICH_SE; + tmp &= ~ICH_SE; /* steer disable */ } iputbyte(chip, ICHREG(SDM), tmp); } - for (i = 0; i < codecs; i++) { - x97 = chip->ac97[i]; - if (!ac97_is_audio(x97)) - continue; - if (x97->scaps & AC97_SCAP_SURROUND_DAC) - chip->multi4 = 1; - } - for (i = 0; i < codecs && chip->multi4; i++) { - x97 = chip->ac97[i]; - if (!ac97_is_audio(x97)) - continue; - if (x97->scaps & AC97_SCAP_CENTER_LFE_DAC) + if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_PCM_SLEFT)) { + chip->multi4 = 1; + if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_LFE)) chip->multi6 = 1; } - if (chip->device_type == DEVICE_ALI && chip->ac97[1]) { - /* set secondary codec id */ - iputdword(chip, ICHREG(ALI_SSR), - (igetdword(chip, ICHREG(ALI_SSR)) & ~ICH_ALI_SS_SEC_ID) | - (chip->ac97[1]->addr << 5)); - } - if (codecs > 1 && !chip->multi6) { - /* assign right slots for rev2.2 codecs */ - i = 1; - for ( ; i < codecs && !chip->multi4; i++) { - x97 = chip->ac97[i]; - if (!ac97_is_audio(x97)) - continue; - if (ac97_is_rev22(x97)) { - snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 1); - chip->multi4 = 1; - } - } - for ( ; i < codecs && chip->multi4; i++) { - x97 = chip->ac97[i]; - if (!ac97_is_audio(x97)) - continue; - if (ac97_is_rev22(x97)) { - snd_ac97_update_bits(x97, AC97_EXTENDED_ID, AC97_EI_DACS_SLOT_MASK, 2); - chip->multi6 = 1; - break; - } - } - /* ok, some older codecs might support only AMAP */ - if (!chip->multi4) { - int cnums = 0; - for (i = 1; i < codecs; i++) { - x97 = chip->ac97[i]; - if (!ac97_is_audio(x97)) - continue; - if (ac97_can_amap(x97)) { - if (x97->addr > 0) - cnums++; - } - } - if (cnums >= 2) - chip->multi6 = 1; - if (cnums >= 1) - chip->multi4 = 1; - } + if (chip->device_type == DEVICE_NFORCE) { + /* 48kHz only */ + chip->ichd[spdif_idx].pcm->rates = SNDRV_PCM_RATE_48000; } chip->in_ac97_init = 0; return 0; + + __err: + /* clear the cold-reset bit for the next chance */ + if (chip->device_type != DEVICE_ALI) + iputdword(chip, ICHREG(GLOB_CNT), igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_AC97COLD); + return err; } @@ -2107,8 +2097,11 @@ /* --- */ synchronize_irq(chip->irq); __hw_end: - if (chip->bdbars) + if (chip->bdbars) { + if (chip->fix_nocache) + fill_nocache(chip->bdbars, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, 0); snd_free_pci_pages(chip->pci, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, chip->bdbars, chip->bdbars_addr); + } if (chip->remap_addr) iounmap((void *) chip->remap_addr); if (chip->remap_bmaddr) @@ -2212,7 +2205,7 @@ unsigned long flags; struct timeval start_time, stop_time; - if (chip->ac97[0]->clock != 48000) + if (chip->ac97_bus->clock != 48000) return; /* specified in module option */ subs = chip->pcm[0]->streams[0].substream; @@ -2227,7 +2220,7 @@ /* set rate */ if (snd_ac97_set_rate(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 48000) < 0) { - snd_printk(KERN_ERR "cannot set ac97 rate: clock = %d\n", chip->ac97[0]->clock); + snd_printk(KERN_ERR "cannot set ac97 rate: clock = %d\n", chip->ac97_bus->clock); return; } snd_intel8x0_setup_periods(chip, ichdev); @@ -2286,8 +2279,8 @@ printk(KERN_INFO "intel8x0: measured clock %ld rejected\n", pos); else if (pos < 47500 || pos > 48500) /* not 48000Hz, tuning the clock.. */ - chip->ac97[0]->clock = (chip->ac97[0]->clock * 48000) / pos; - printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97[0]->clock); + chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos; + printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock); } static void snd_intel8x0_proc_read(snd_info_entry_t * entry, @@ -2321,7 +2314,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(chip->card, "intel8x0", &entry)) - snd_info_set_text_ops(entry, chip, snd_intel8x0_proc_read); + snd_info_set_text_ops(entry, chip, 1024, snd_intel8x0_proc_read); } static int snd_intel8x0_dev_free(snd_device_t *device) @@ -2397,6 +2390,9 @@ snd_intel8x0_proc_init(chip); sprintf(chip->ac97_name, "%s - AC'97", card->shortname); sprintf(chip->ctrl_name, "%s - Controller", card->shortname); + if (pci->vendor == PCI_VENDOR_ID_INTEL && + pci->device == PCI_DEVICE_ID_INTEL_440MX) + chip->fix_nocache = 1; /* enable workaround */ if (device_type == DEVICE_ALI) { /* ALI5455 has no ac97 region */ chip->bmaddr = pci_resource_start(pci, 0); @@ -2505,6 +2501,9 @@ } /* tables must be aligned to 8 bytes here, but the kernel pages are much bigger, so we don't care (on i386) */ + /* workaround for 440MX */ + if (chip->fix_nocache) + fill_nocache(chip->bdbars, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, 1); int_sta_masks = 0; for (i = 0; i < chip->bdbars_count; i++) { ichdev = &chip->ichd[i]; @@ -2530,6 +2529,8 @@ return err; } + snd_card_set_dev(card, &pci->dev); + *r_intel8x0 = chip; return 0; } @@ -2591,7 +2592,6 @@ break; } } - card->dev = &pci->dev; if ((err = snd_intel8x0_create(card, pci, pci_id->driver_data, &chip)) < 0) { snd_card_free(card); @@ -2657,9 +2657,16 @@ * initialize joystick/midi addresses */ +#ifdef SUPPORT_JOYSTICK +/* there is only one available device, so we keep it here */ +static struct pci_dev *ich_gameport_pci; +static struct gameport ich_gameport = { .io = 0x200 }; +#endif + static int __devinit snd_intel8x0_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id) { + u16 val; static int dev; if (dev >= SNDRV_CARDS) return -ENODEV; @@ -2668,17 +2675,24 @@ return -ENOENT; } - if (joystick_port[dev] > 0 || mpu_port[dev] > 0) { - u16 val; - pci_read_config_word(pci, 0xe6, &val); - if (joystick_port[dev] > 0) + pci_read_config_word(pci, 0xe6, &val); +#ifdef SUPPORT_JOYSTICK + if (joystick[dev]) { + if (! request_region(ich_gameport.io, 8, "ICH gameport")) { + printk(KERN_WARNING "intel8x0: cannot grab gameport 0x%x\n", ich_gameport.io); + joystick[dev] = 0; + } else { + ich_gameport_pci = pci; + gameport_register_port(&ich_gameport); val |= 0x100; - if (mpu_port[dev] == 0x300 || mpu_port[dev] == 0x330) - val |= 0x20; - pci_write_config_word(pci, 0xe6, val | 0x100); - + } + } +#endif +#ifdef SUPPORT_MIDI + if (mpu_port[dev] > 0) { if (mpu_port[dev] == 0x300 || mpu_port[dev] == 0x330) { u8 b; + val |= 0x20; pci_read_config_byte(pci, 0xe2, &b); if (mpu_port[dev] == 0x300) b |= 0x08; @@ -2687,9 +2701,27 @@ pci_write_config_byte(pci, 0xe2, b); } } +#endif + pci_write_config_word(pci, 0xe6, val); return 0; } +static void __devexit snd_intel8x0_joystick_remove(struct pci_dev *pci) +{ + u16 val; +#ifdef SUPPORT_JOYSTICK + if (ich_gameport_pci == pci) { + gameport_unregister_port(&ich_gameport); + release_region(ich_gameport.io, 8); + ich_gameport_pci = NULL; + } +#endif + /* disable joystick and MIDI */ + pci_read_config_word(pci, 0xe6, &val); + val &= ~0x120; + pci_write_config_word(pci, 0xe6, val); +} + static struct pci_device_id snd_intel8x0_joystick_ids[] = { { 0x8086, 0x2410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 82801AA */ { 0x8086, 0x2420, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 82901AB */ @@ -2708,6 +2740,7 @@ .name = "Intel ICH Joystick", .id_table = snd_intel8x0_joystick_ids, .probe = snd_intel8x0_joystick_probe, + .remove = __devexit_p(snd_intel8x0_joystick_remove), }; static int have_joystick; @@ -2750,7 +2783,7 @@ #ifndef MODULE -/* format is: snd-intel8x0=enable,index,id,ac97_clock */ +/* format is: snd-intel8x0=enable,index,id,ac97_clock,mpu_port,joystick */ static int __init alsa_card_intel8x0_setup(char *str) { @@ -2761,7 +2794,14 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,&ac97_clock[nr_dev]) == 2); + get_option(&str,&ac97_clock[nr_dev]) == 2 +#ifdef SUPPORT_MIDI + && get_option(&str,&mpu_port[nr_dev]) == 2 +#endif +#ifdef SUPPORT_JOYSTICK + && get_option(&str,&joystick[nr_dev]) == 2 +#endif + ); nr_dev++; return 1; } diff -Nru a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c --- a/sound/pci/korg1212/korg1212.c Mon Feb 2 22:07:55 2004 +++ b/sound/pci/korg1212/korg1212.c Mon Feb 2 22:07:55 2004 @@ -2093,7 +2093,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(korg1212->card, "korg1212", &entry)) - snd_info_set_text_ops(entry, korg1212, snd_korg1212_proc_read); + snd_info_set_text_ops(entry, korg1212, 1024, snd_korg1212_proc_read); } static int @@ -2461,6 +2461,8 @@ return err; } + snd_card_set_dev(card, &pci->dev); + * rchip = korg1212; return 0; diff -Nru a/sound/pci/maestro3.c b/sound/pci/maestro3.c --- a/sound/pci/maestro3.c Mon Feb 2 22:07:57 2004 +++ b/sound/pci/maestro3.c Mon Feb 2 22:07:57 2004 @@ -1981,14 +1981,19 @@ static int __devinit snd_m3_mixer(m3_t *chip) { + ac97_bus_t bus, *pbus; ac97_t ac97; int err; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_m3_ac97_write; + bus.read = snd_m3_ac97_read; + if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_m3_ac97_write; - ac97.read = snd_m3_ac97_read; ac97.private_data = chip; - if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0) + if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97)) < 0) return err; /* seems ac97 PCM needs initialization.. hack hack.. */ @@ -2349,7 +2354,8 @@ { unsigned long io = chip->iobase; - outw(ASSP_INT_ENABLE | MPU401_INT_ENABLE, io + HOST_INT_CTRL); + /* TODO: MPU401 not supported yet */ + outw(ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL); outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, io + ASSP_CONTROL_C); } @@ -2541,11 +2547,11 @@ return -EIO; /* check, if we can restrict PCI DMA transfers to 28 bits */ - if (!pci_dma_supported(pci, 0x0fffffff)) { + if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || + pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { snd_printk("architecture does not support 28bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x0fffffff); chip = snd_magic_kcalloc(m3_t, 0, GFP_KERNEL); if (chip == NULL) @@ -2658,6 +2664,8 @@ snd_m3_enable_ints(chip); snd_m3_assp_continue(chip); + + snd_card_set_dev(card, &pci->dev); *chip_ret = chip; diff -Nru a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c --- a/sound/pci/nm256/nm256.c Mon Feb 2 22:07:58 2004 +++ b/sound/pci/nm256/nm256.c Mon Feb 2 22:07:58 2004 @@ -335,7 +335,7 @@ return; } #endif - memcpy_toio(chip->buffer + offset, src, size); + memcpy_toio((void *)chip->buffer + offset, src, size); } /* @@ -1195,6 +1195,7 @@ static int __devinit snd_nm256_mixer(nm256_t *chip) { + ac97_bus_t bus, *pbus; ac97_t ac97; int i, err; /* looks like nm256 hangs up when unexpected registers are touched... */ @@ -1208,16 +1209,20 @@ -1 }; + memset(&bus, 0, sizeof(bus)); + bus.reset = snd_nm256_ac97_reset; + bus.write = snd_nm256_ac97_write; + bus.read = snd_nm256_ac97_read; + if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.reset = snd_nm256_ac97_reset; - ac97.write = snd_nm256_ac97_write; - ac97.read = snd_nm256_ac97_read; ac97.scaps = AC97_SCAP_AUDIO; /* we support audio! */ ac97.limited_regs = 1; for (i = 0; mixer_regs[i] >= 0; i++) set_bit(mixer_regs[i], ac97.reg_accessed); ac97.private_data = chip; - err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97); + err = snd_ac97_mixer(pbus, &ac97, &chip->ac97); if (err < 0) return err; if (! (chip->ac97->id & (0xf0000000))) { @@ -1554,6 +1559,8 @@ if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) goto __error; + + snd_card_set_dev(card, &pci->dev); *chip_ret = chip; return 0; diff -Nru a/sound/pci/rme32.c b/sound/pci/rme32.c --- a/sound/pci/rme32.c Mon Feb 2 22:07:58 2004 +++ b/sound/pci/rme32.c Mon Feb 2 22:07:58 2004 @@ -1191,18 +1191,18 @@ } bytes = diff << rme32->playback_frlog; if (bytes > RME32_BUFFER_SIZE - rme32->playback_ptr) { - memcpy_toio(rme32->iobase + RME32_IO_DATA_BUFFER + rme32->playback_ptr, + memcpy_toio((void *)(rme32->iobase + RME32_IO_DATA_BUFFER + rme32->playback_ptr), runtime->dma_area + rme32->playback_ptr, RME32_BUFFER_SIZE - rme32->playback_ptr); bytes -= RME32_BUFFER_SIZE - rme32->playback_ptr; if (bytes > RME32_BUFFER_SIZE) { bytes = RME32_BUFFER_SIZE; } - memcpy_toio(rme32->iobase + RME32_IO_DATA_BUFFER, + memcpy_toio((void *)(rme32->iobase + RME32_IO_DATA_BUFFER), runtime->dma_area, bytes); rme32->playback_ptr = bytes; } else if (bytes != 0) { - memcpy_toio(rme32->iobase + RME32_IO_DATA_BUFFER + rme32->playback_ptr, + memcpy_toio((void *)(rme32->iobase + RME32_IO_DATA_BUFFER + rme32->playback_ptr), runtime->dma_area + rme32->playback_ptr, bytes); rme32->playback_ptr += bytes; } @@ -1223,17 +1223,17 @@ ptr = frameptr << rme32->capture_frlog; if (ptr > rme32->capture_ptr) { memcpy_fromio(runtime->dma_area + rme32->capture_ptr, - rme32->iobase + RME32_IO_DATA_BUFFER + - rme32->capture_ptr, + (void *)(rme32->iobase + RME32_IO_DATA_BUFFER + + rme32->capture_ptr), ptr - rme32->capture_ptr); rme32->capture_ptr += ptr - rme32->capture_ptr; } else if (ptr < rme32->capture_ptr) { memcpy_fromio(runtime->dma_area + rme32->capture_ptr, - rme32->iobase + RME32_IO_DATA_BUFFER + - rme32->capture_ptr, + (void *)(rme32->iobase + RME32_IO_DATA_BUFFER + + rme32->capture_ptr), RME32_BUFFER_SIZE - rme32->capture_ptr); memcpy_fromio(runtime->dma_area, - rme32->iobase + RME32_IO_DATA_BUFFER, + (void *)(rme32->iobase + RME32_IO_DATA_BUFFER), ptr); rme32->capture_ptr = ptr; } @@ -1545,7 +1545,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(rme32->card, "rme32", &entry)) - snd_info_set_text_ops(entry, rme32, snd_rme32_proc_read); + snd_info_set_text_ops(entry, rme32, 1024, snd_rme32_proc_read); } /* @@ -1948,6 +1948,7 @@ rme32 = (rme32_t *) card->private_data; rme32->card = card; rme32->pci = pci; + snd_card_set_dev(card, &pci->dev); if ((err = snd_rme32_create(rme32)) < 0) { snd_card_free(card); return err; diff -Nru a/sound/pci/rme96.c b/sound/pci/rme96.c --- a/sound/pci/rme96.c Mon Feb 2 22:07:56 2004 +++ b/sound/pci/rme96.c Mon Feb 2 22:07:56 2004 @@ -1524,21 +1524,21 @@ bytes = diff << rme96->playback_frlog; if (bytes > RME96_BUFFER_SIZE - rme96->playback_ptr) { - memcpy_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + - rme96->playback_ptr, + memcpy_toio((void *)(rme96->iobase + RME96_IO_PLAY_BUFFER + + rme96->playback_ptr), runtime->dma_area + rme96->playback_ptr, RME96_BUFFER_SIZE - rme96->playback_ptr); bytes -= RME96_BUFFER_SIZE - rme96->playback_ptr; if (bytes > RME96_BUFFER_SIZE) { bytes = RME96_BUFFER_SIZE; } - memcpy_toio(rme96->iobase + RME96_IO_PLAY_BUFFER, + memcpy_toio((void *)(rme96->iobase + RME96_IO_PLAY_BUFFER), runtime->dma_area, bytes); rme96->playback_ptr = bytes; } else if (bytes != 0) { - memcpy_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + - rme96->playback_ptr, + memcpy_toio((void *)(rme96->iobase + RME96_IO_PLAY_BUFFER + + rme96->playback_ptr), runtime->dma_area + rme96->playback_ptr, bytes); rme96->playback_ptr += bytes; @@ -1560,17 +1560,17 @@ ptr = frameptr << rme96->capture_frlog; if (ptr > rme96->capture_ptr) { memcpy_fromio(runtime->dma_area + rme96->capture_ptr, - rme96->iobase + RME96_IO_REC_BUFFER + - rme96->capture_ptr, + (void *)(rme96->iobase + RME96_IO_REC_BUFFER + + rme96->capture_ptr), ptr - rme96->capture_ptr); rme96->capture_ptr += ptr - rme96->capture_ptr; } else if (ptr < rme96->capture_ptr) { memcpy_fromio(runtime->dma_area + rme96->capture_ptr, - rme96->iobase + RME96_IO_REC_BUFFER + - rme96->capture_ptr, + (void *)(rme96->iobase + RME96_IO_REC_BUFFER + + rme96->capture_ptr), RME96_BUFFER_SIZE - rme96->capture_ptr); memcpy_fromio(runtime->dma_area, - rme96->iobase + RME96_IO_REC_BUFFER, + (void *)(rme96->iobase + RME96_IO_REC_BUFFER), ptr); rme96->capture_ptr = ptr; } @@ -1930,7 +1930,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(rme96->card, "rme96", &entry)) - snd_info_set_text_ops(entry, rme96, snd_rme96_proc_read); + snd_info_set_text_ops(entry, rme96, 1024, snd_rme96_proc_read); } /* @@ -2504,6 +2504,7 @@ rme96 = (rme96_t *)card->private_data; rme96->card = card; rme96->pci = pci; + snd_card_set_dev(card, &pci->dev); if ((err = snd_rme96_create(rme96)) < 0) { snd_card_free(card); return err; diff -Nru a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c --- a/sound/pci/rme9652/hdsp.c Mon Feb 2 22:07:56 2004 +++ b/sound/pci/rme9652/hdsp.c Mon Feb 2 22:07:56 2004 @@ -69,15 +69,24 @@ MODULE_LICENSE("GPL"); MODULE_CLASSES("{sound}"); MODULE_DEVICES("{{RME Hammerfall-DSP}," - "{RME HDSP-9652}}"); + "{RME HDSP-9652}," + "{RME HDSP-9632}}"); #define HDSP_MAX_CHANNELS 26 +#define HDSP_MAX_DS_CHANNELS 14 +#define HDSP_MAX_QS_CHANNELS 8 #define DIGIFACE_SS_CHANNELS 26 #define DIGIFACE_DS_CHANNELS 14 #define MULTIFACE_SS_CHANNELS 18 #define MULTIFACE_DS_CHANNELS 14 #define H9652_SS_CHANNELS 26 #define H9652_DS_CHANNELS 14 +/* This does not include possible Analog Extension Boards + AEBs are detected at card initialization +*/ +#define H9632_SS_CHANNELS 12 +#define H9632_DS_CHANNELS 8 +#define H9632_QS_CHANNELS 4 /* Write registers. These are defined as byte-offsets from the iobase value. */ @@ -121,7 +130,21 @@ #define HDSP_playbackRmsLevel 4612 /* 26 * 64 bit values */ #define HDSP_inputRmsLevel 4868 /* 26 * 64 bit values */ -#define HDSP_IO_EXTENT 5192 + +/* This is for H9652 cards + Peak values are read downward from the base + Rms values are read upward + There are rms values for the outputs too + 26*3 values are read in ss mode + 14*3 in ds mode, with no gap between values +*/ +#define HDSP_9652_peakBase 7164 +#define HDSP_9652_rmsBase 4096 + +/* c.f. the hdsp_9632_meters_t struct */ +#define HDSP_9632_metersBase 4096 + +#define HDSP_IO_EXTENT 7168 /* control2 register bits */ @@ -137,6 +160,7 @@ #define HDSP_BIGENDIAN_MODE 0x200 #define HDSP_RD_MULTIPLE 0x400 #define HDSP_9652_ENABLE_MIXER 0x800 +#define HDSP_TDO 0x10000000 #define HDSP_S_PROGRAM (HDSP_PROGRAM|HDSP_CONFIG_MODE_0) #define HDSP_S_LOAD (HDSP_PROGRAM|HDSP_CONFIG_MODE_1) @@ -146,11 +170,11 @@ #define HDSP_Start (1<<0) /* start engine */ #define HDSP_Latency0 (1<<1) /* buffer size = 2^n where n is defined by Latency{2,1,0} */ #define HDSP_Latency1 (1<<2) /* [ see above ] */ -#define HDSP_Latency2 (1<<3) /* ] see above ] */ +#define HDSP_Latency2 (1<<3) /* [ see above ] */ #define HDSP_ClockModeMaster (1<<4) /* 1=Master, 0=Slave/Autosync */ #define HDSP_AudioInterruptEnable (1<<5) /* what do you think ? */ -#define HDSP_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz 1=48kHz/96kHz */ -#define HDSP_Frequency1 (1<<7) /* 0=32kHz/64kHz */ +#define HDSP_Frequency0 (1<<6) /* 0=44.1kHz/88.2kHz/176.4kHz 1=48kHz/96kHz/192kHz */ +#define HDSP_Frequency1 (1<<7) /* 0=32kHz/64kHz/128kHz */ #define HDSP_DoubleSpeed (1<<8) /* 0=normal speed, 1=double speed */ #define HDSP_SPDIFProfessional (1<<9) /* 0=consumer, 1=professional */ #define HDSP_SPDIFEmphasis (1<<10) /* 0=none, 1=on */ @@ -160,21 +184,46 @@ #define HDSP_SPDIFInputSelect0 (1<<14) #define HDSP_SPDIFInputSelect1 (1<<15) #define HDSP_SyncRef0 (1<<16) -#define HDSP_SyncRef1 (1<<17) +#define HDSP_SyncRef1 (1<<17) +#define HDSP_AnalogExtensionBoard (1<<18) /* For H9632 cards */ +#define HDSP_XLRBreakoutCable (1<<20) /* For H9632 cards */ #define HDSP_Midi0InterruptEnable (1<<22) #define HDSP_Midi1InterruptEnable (1<<23) #define HDSP_LineOut (1<<24) +#define HDSP_ADGain0 (1<<25) /* From here : H9632 specific */ +#define HDSP_ADGain1 (1<<26) +#define HDSP_DAGain0 (1<<27) +#define HDSP_DAGain1 (1<<28) +#define HDSP_PhoneGain0 (1<<29) +#define HDSP_PhoneGain1 (1<<30) +#define HDSP_QuadSpeed (1<<31) + +#define HDSP_ADGainMask (HDSP_ADGain0|HDSP_ADGain1) +#define HDSP_ADGainMinus10dBV HDSP_ADGainMask +#define HDSP_ADGainPlus4dBu (HDSP_ADGain0) +#define HDSP_ADGainLowGain 0 + +#define HDSP_DAGainMask (HDSP_DAGain0|HDSP_DAGain1) +#define HDSP_DAGainHighGain HDSP_DAGainMask +#define HDSP_DAGainPlus4dBu (HDSP_DAGain0) +#define HDSP_DAGainMinus10dBV 0 + +#define HDSP_PhoneGainMask (HDSP_PhoneGain0|HDSP_PhoneGain1) +#define HDSP_PhoneGain0dB HDSP_PhoneGainMask +#define HDSP_PhoneGainMinus6dB (HDSP_PhoneGain0) +#define HDSP_PhoneGainMinus12dB 0 #define HDSP_LatencyMask (HDSP_Latency0|HDSP_Latency1|HDSP_Latency2) -#define HDSP_FrequencyMask (HDSP_Frequency0|HDSP_Frequency1|HDSP_DoubleSpeed) +#define HDSP_FrequencyMask (HDSP_Frequency0|HDSP_Frequency1|HDSP_DoubleSpeed|HDSP_QuadSpeed) #define HDSP_SPDIFInputMask (HDSP_SPDIFInputSelect0|HDSP_SPDIFInputSelect1) #define HDSP_SPDIFInputADAT1 0 -#define HDSP_SPDIFInputCoaxial (HDSP_SPDIFInputSelect1) -#define HDSP_SPDIFInputCDROM (HDSP_SPDIFInputSelect0|HDSP_SPDIFInputSelect1) +#define HDSP_SPDIFInputCoaxial (HDSP_SPDIFInputSelect0) +#define HDSP_SPDIFInputCdrom (HDSP_SPDIFInputSelect1) +#define HDSP_SPDIFInputAES (HDSP_SPDIFInputSelect0|HDSP_SPDIFInputSelect1) #define HDSP_SyncRefMask (HDSP_SyncRef0|HDSP_SyncRef1|HDSP_SyncRef2) -#define HDSP_SyncRef_ADAT1 0 +#define HDSP_SyncRef_ADAT1 0 #define HDSP_SyncRef_ADAT2 (HDSP_SyncRef0) #define HDSP_SyncRef_ADAT3 (HDSP_SyncRef1) #define HDSP_SyncRef_SPDIF (HDSP_SyncRef0|HDSP_SyncRef1) @@ -183,20 +232,23 @@ /* Sample Clock Sources */ -#define HDSP_CLOCK_SOURCE_AUTOSYNC 0 -#define HDSP_CLOCK_SOURCE_INTERNAL_32KHZ 1 -#define HDSP_CLOCK_SOURCE_INTERNAL_44_1KHZ 2 -#define HDSP_CLOCK_SOURCE_INTERNAL_48KHZ 3 -#define HDSP_CLOCK_SOURCE_INTERNAL_64KHZ 4 -#define HDSP_CLOCK_SOURCE_INTERNAL_88_2KHZ 5 -#define HDSP_CLOCK_SOURCE_INTERNAL_96KHZ 6 +#define HDSP_CLOCK_SOURCE_AUTOSYNC 0 +#define HDSP_CLOCK_SOURCE_INTERNAL_32KHZ 1 +#define HDSP_CLOCK_SOURCE_INTERNAL_44_1KHZ 2 +#define HDSP_CLOCK_SOURCE_INTERNAL_48KHZ 3 +#define HDSP_CLOCK_SOURCE_INTERNAL_64KHZ 4 +#define HDSP_CLOCK_SOURCE_INTERNAL_88_2KHZ 5 +#define HDSP_CLOCK_SOURCE_INTERNAL_96KHZ 6 +#define HDSP_CLOCK_SOURCE_INTERNAL_128KHZ 7 +#define HDSP_CLOCK_SOURCE_INTERNAL_176_4KHZ 8 +#define HDSP_CLOCK_SOURCE_INTERNAL_192KHZ 9 /* Preferred sync reference choices - used by "pref_sync_ref" control switch */ #define HDSP_SYNC_FROM_WORD 0 -#define HDSP_SYNC_FROM_ADAT_SYNC 1 -#define HDSP_SYNC_FROM_SPDIF 2 -#define HDSP_SYNC_FROM_ADAT1 3 +#define HDSP_SYNC_FROM_SPDIF 1 +#define HDSP_SYNC_FROM_ADAT1 2 +#define HDSP_SYNC_FROM_ADAT_SYNC 3 #define HDSP_SYNC_FROM_ADAT2 4 #define HDSP_SYNC_FROM_ADAT3 5 @@ -218,16 +270,21 @@ /* Possible sources of S/PDIF input */ -#define HDSP_SPDIFIN_OPTICAL 0 /* optical (ADAT1) */ -#define HDSP_SPDIFIN_COAXIAL 1 /* coaxial (RCA) */ -#define HDSP_SPDIFIN_INTERN 2 /* internal (CDROM) */ +#define HDSP_SPDIFIN_OPTICAL 0 /* optical (ADAT1) */ +#define HDSP_SPDIFIN_COAXIAL 1 /* coaxial (RCA) */ +#define HDSP_SPDIFIN_INTERNAL 2 /* internal (CDROM) */ +#define HDSP_SPDIFIN_AES 3 /* xlr for H9632 (AES)*/ #define HDSP_Frequency32KHz HDSP_Frequency0 #define HDSP_Frequency44_1KHz HDSP_Frequency1 -#define HDSP_Frequency48KHz (HDSP_Frequency1|HDSP_Frequency0) -#define HDSP_Frequency64KHz (HDSP_DoubleSpeed|HDSP_Frequency0) -#define HDSP_Frequency88_2KHz (HDSP_DoubleSpeed|HDSP_Frequency1) -#define HDSP_Frequency96KHz (HDSP_DoubleSpeed|HDSP_Frequency1|HDSP_Frequency0) +#define HDSP_Frequency48KHz (HDSP_Frequency1|HDSP_Frequency0) +#define HDSP_Frequency64KHz (HDSP_DoubleSpeed|HDSP_Frequency0) +#define HDSP_Frequency88_2KHz (HDSP_DoubleSpeed|HDSP_Frequency1) +#define HDSP_Frequency96KHz (HDSP_DoubleSpeed|HDSP_Frequency1|HDSP_Frequency0) +/* For H9632 cards */ +#define HDSP_Frequency128KHz (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency0) +#define HDSP_Frequency176_4KHz (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency1) +#define HDSP_Frequency192KHz (HDSP_QuadSpeed|HDSP_DoubleSpeed|HDSP_Frequency1|HDSP_Frequency0) #define hdsp_encode_latency(x) (((x)<<1) & HDSP_LatencyMask) #define hdsp_decode_latency(x) (((x) & HDSP_LatencyMask)>>1) @@ -238,7 +295,8 @@ /* Status Register bits */ #define HDSP_audioIRQPending (1<<0) -#define HDSP_Lock2 (1<<1) +#define HDSP_Lock2 (1<<1) /* this is for Digiface and H9652 */ +#define HDSP_spdifFrequency3 HDSP_Lock2 /* this is for H9632 only */ #define HDSP_Lock1 (1<<2) #define HDSP_Lock0 (1<<3) #define HDSP_SPDIFSync (1<<4) @@ -256,8 +314,9 @@ #define HDSP_SPDIFErrorFlag (1<<25) #define HDSP_BufferID (1<<26) #define HDSP_TimecodeSync (1<<27) -#define HDSP_CIN (1<<28) -#define HDSP_midi0IRQPending (1<<30) /* notice the gap at bit 29 */ +#define HDSP_AEBO (1<<28) /* H9632 specific Analog Extension Boards */ +#define HDSP_AEBI (1<<29) /* 0 = present, 1 = absent */ +#define HDSP_midi0IRQPending (1<<30) #define HDSP_midi1IRQPending (1<<31) #define HDSP_spdifFrequencyMask (HDSP_spdifFrequency0|HDSP_spdifFrequency1|HDSP_spdifFrequency2) @@ -270,6 +329,11 @@ #define HDSP_spdifFrequency88_2KHz (HDSP_spdifFrequency0|HDSP_spdifFrequency2) #define HDSP_spdifFrequency96KHz (HDSP_spdifFrequency2|HDSP_spdifFrequency1) +/* This is for H9632 cards */ +#define HDSP_spdifFrequency128KHz HDSP_spdifFrequencyMask +#define HDSP_spdifFrequency176_4KHz HDSP_spdifFrequency3 +#define HDSP_spdifFrequency192KHz (HDSP_spdifFrequency3|HDSP_spdifFrequency0) + /* Status2 Register bits */ #define HDSP_version0 (1<<0) @@ -293,6 +357,7 @@ #define HDSP_systemFrequency64 (HDSP_inp_freq2) #define HDSP_systemFrequency88_2 (HDSP_inp_freq0|HDSP_inp_freq2) #define HDSP_systemFrequency96 (HDSP_inp_freq1|HDSP_inp_freq2) +/* FIXME : more values for 9632 cards ? */ #define HDSP_SelSyncRefMask (HDSP_SelSyncRef0|HDSP_SelSyncRef1|HDSP_SelSyncRef2) #define HDSP_SelSyncRef_ADAT1 0 @@ -340,8 +405,25 @@ #define HDSP_DMA_AREA_BYTES ((HDSP_MAX_CHANNELS+1) * HDSP_CHANNEL_BUFFER_BYTES) #define HDSP_DMA_AREA_KILOBYTES (HDSP_DMA_AREA_BYTES/1024) -typedef struct _hdsp hdsp_t; -typedef struct _hdsp_midi hdsp_midi_t; +typedef struct _hdsp hdsp_t; +typedef struct _hdsp_midi hdsp_midi_t; +typedef struct _hdsp_9632_meters hdsp_9632_meters_t; + +struct _hdsp_9632_meters { + u32 input_peak[16]; + u32 playback_peak[16]; + u32 output_peak[16]; + u32 xxx_peak[16]; + u32 padding[64]; + u32 input_rms_low[16]; + u32 playback_rms_low[16]; + u32 output_rms_low[16]; + u32 xxx_rms_low[16]; + u32 input_rms_high[16]; + u32 playback_rms_high[16]; + u32 output_rms_high[16]; + u32 xxx_rms_high[16]; +}; struct _hdsp_midi { hdsp_t *hdsp; @@ -372,8 +454,13 @@ unsigned short state; /* stores state bits */ u32 firmware_cache[24413]; /* this helps recover from accidental iobox power failure */ size_t period_bytes; /* guess what this is */ - unsigned char ds_channels; - unsigned char ss_channels; /* different for multiface/digiface */ + unsigned char max_channels; + unsigned char qs_in_channels; /* quad speed mode for H9632 */ + unsigned char ds_in_channels; + unsigned char ss_in_channels; /* different for multiface/digiface */ + unsigned char qs_out_channels; + unsigned char ds_out_channels; + unsigned char ss_out_channels; void *capture_buffer_unaligned; /* original buffer addresses */ void *playback_buffer_unaligned; /* original buffer addresses */ unsigned char *capture_buffer; /* suitably aligned address */ @@ -384,9 +471,6 @@ pid_t playback_pid; int running; int passthru; /* non-zero if doing pass-thru */ - int last_spdif_sample_rate;/* for information reporting */ - int last_external_sample_rate; - int last_internal_sample_rate; int system_sample_rate; char *channel_map; int dev; @@ -399,7 +483,6 @@ snd_hwdep_t *hwdep; struct pci_dev *pci; snd_kcontrol_t *spdif_ctl; - snd_kcontrol_t *playback_mixer_ctls[HDSP_MAX_CHANNELS]; unsigned short mixer_matrix[HDSP_MATRIX_MIXER_SIZE]; }; @@ -423,7 +506,7 @@ 16, 17, 18, 19, 20, 21, 22, 23, /* SPDIF */ 24, 25, - -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; static char channel_map_ds[HDSP_MAX_CHANNELS] = { @@ -432,7 +515,49 @@ /* channels 12 and 13 are S/PDIF */ 24, 25, /* others don't exist */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +static char channel_map_H9632_ss[HDSP_MAX_CHANNELS] = { + /* ADAT channels */ + 0, 1, 2, 3, 4, 5, 6, 7, + /* SPDIF */ + 8, 9, + /* Analog */ + 10, 11, + /* AO4S-192 and AI4S-192 extension boards */ + 12, 13, 14, 15, + /* others don't exist */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1 +}; + +static char channel_map_H9632_ds[HDSP_MAX_CHANNELS] = { + /* ADAT */ + 1, 3, 5, 7, + /* SPDIF */ + 8, 9, + /* Analog */ + 10, 11, + /* AO4S-192 and AI4S-192 extension boards */ + 12, 13, 14, 15, + /* others don't exist */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1 +}; + +static char channel_map_H9632_qs[HDSP_MAX_CHANNELS] = { + /* ADAT is disabled in this mode */ + /* SPDIF */ + 8, 9, + /* Analog */ + 10, 11, + /* AO4S-192 and AI4S-192 extension boards */ + 12, 13, 14, 15, + /* others don't exist */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1 }; #define HDSP_PREALLOCATE_MEMORY /* via module snd-hdsp_mem */ @@ -492,15 +617,17 @@ static inline void snd_hdsp_initialize_midi_flush (hdsp_t *hdsp); static inline void snd_hdsp_initialize_channels (hdsp_t *hdsp); static inline int hdsp_fifo_wait(hdsp_t *hdsp, int count, int timeout); -static int hdsp_update_simple_mixer_controls(hdsp_t *hdsp); static int hdsp_autosync_ref(hdsp_t *hdsp); static int snd_hdsp_set_defaults(hdsp_t *hdsp); +static inline void snd_hdsp_9652_enable_mixer (hdsp_t *hdsp); static inline int hdsp_playback_to_output_key (hdsp_t *hdsp, int in, int out) { switch (hdsp->firmware_rev) { case 0xa: return (64 * out) + (32 + (in)); + case 0x96: + return (32 * out) + (16 + (in)); default: return (52 * out) + (26 + (in)); } @@ -511,6 +638,8 @@ switch (hdsp->firmware_rev) { case 0xa: return (64 * out) + in; + case 0x96: + return (32 * out) + in; default: return (52 * out) + in; } @@ -529,7 +658,7 @@ static inline int hdsp_check_for_iobox (hdsp_t *hdsp) { - if (hdsp->io_type == H9652) return 0; + if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0; if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_ConfigError) { snd_printk ("Hammerfall-DSP: no Digiface or Multiface connected!\n"); hdsp->state &= ~HDSP_FirmwareLoaded; @@ -565,6 +694,13 @@ return -EIO; } } + + if ((1000 / HZ) < 3000) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((3000 * HZ + 999) / 1000); + } else { + mdelay(3000); + } if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) { snd_printk ("timeout at end of firmware loading\n"); @@ -579,12 +715,6 @@ hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register); snd_printk ("finished firmware loading\n"); - if ((1000 / HZ) < 3000) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((3000 * HZ + 999) / 1000); - } else { - mdelay(3000); - } } if (hdsp->state & HDSP_InitializationComplete) { snd_printk("firmware loaded from cache, restoring defaults\n"); @@ -643,7 +773,7 @@ static inline int hdsp_check_for_firmware (hdsp_t *hdsp) { - if (hdsp->io_type == H9652) return 0; + if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0; if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) { snd_printk("firmware not present.\n"); hdsp->state &= ~HDSP_FirmwareLoaded; @@ -692,8 +822,8 @@ if (addr >= HDSP_MATRIX_MIXER_SIZE) return -1; - - if (hdsp->io_type == H9652) { + + if (hdsp->io_type == H9652 || hdsp->io_type == H9632) { /* from martin björnsen: @@ -707,8 +837,17 @@ memory." */ + if (hdsp->io_type == H9632 && addr >= 512) { + return 0; + } + + if (hdsp->io_type == H9652 && addr >= 1352) { + return 0; + } + hdsp->mixer_matrix[addr] = data; + /* `addr' addresses a 16-bit wide address, but the address space accessed via hdsp_write uses byte offsets. put another way, addr @@ -716,8 +855,9 @@ corresponding memory location, we need to access 0 to 2703 ... */ - - hdsp_write (hdsp, 4096 + (addr*2), + ad = addr/2; + + hdsp_write (hdsp, 4096 + (ad*4), (hdsp->mixer_matrix[(addr&0x7fe)+1] << 16) + hdsp->mixer_matrix[addr&0x7fe]); @@ -786,10 +926,20 @@ case HDSP_spdifFrequency64KHz: return 64000; case HDSP_spdifFrequency88_2KHz: return 88200; case HDSP_spdifFrequency96KHz: return 96000; + case HDSP_spdifFrequency128KHz: + if (hdsp->io_type == H9632) return 128000; + break; + case HDSP_spdifFrequency176_4KHz: + if (hdsp->io_type == H9632) return 176400; + break; + case HDSP_spdifFrequency192KHz: + if (hdsp->io_type == H9632) return 192000; + break; default: - snd_printk ("unknown spdif frequency status; bits = 0x%x, status = 0x%x\n", rate_bits, status); - return 0; + break; } + snd_printk ("unknown spdif frequency status; bits = 0x%x, status = 0x%x\n", rate_bits, status); + return 0; } static inline void hdsp_compute_period_size(hdsp_t *hdsp) @@ -867,7 +1017,7 @@ int current_rate; int rate_bits; - /* ASSUMPTION: hdsp->lock is either help, or + /* ASSUMPTION: hdsp->lock is either held, or there is no need for it (e.g. during module initialization). */ @@ -884,6 +1034,8 @@ if ((spdif_freq == external_freq*2) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1)) { snd_printk("Detected ADAT in double speed mode\n"); + } else if (hdsp->io_type == H9632 && (spdif_freq == external_freq*4) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1)) { + snd_printk("Detected ADAT in quad speed mode\n"); } else if (rate != external_freq) { snd_printk("No AutoSync source for requested rate\n"); return -1; @@ -903,6 +1055,10 @@ exists for externally-driven rate changes. All we can do is to flag rate changes in the read/write routines. */ + if (rate > 96000 && hdsp->io_type != H9632) { + return -EINVAL; + } + switch (rate) { case 32000: if (current_rate > 48000) { @@ -923,29 +1079,47 @@ rate_bits = HDSP_Frequency48KHz; break; case 64000: - if (current_rate <= 48000) { + if (current_rate <= 48000 || current_rate > 96000) { reject_if_open = 1; } rate_bits = HDSP_Frequency64KHz; break; case 88200: - if (current_rate <= 48000) { + if (current_rate <= 48000 || current_rate > 96000) { reject_if_open = 1; } rate_bits = HDSP_Frequency88_2KHz; break; case 96000: - if (current_rate <= 48000) { + if (current_rate <= 48000 || current_rate > 96000) { reject_if_open = 1; } rate_bits = HDSP_Frequency96KHz; break; + case 128000: + if (current_rate < 128000) { + reject_if_open = 1; + } + rate_bits = HDSP_Frequency128KHz; + break; + case 176400: + if (current_rate < 128000) { + reject_if_open = 1; + } + rate_bits = HDSP_Frequency176_4KHz; + break; + case 192000: + if (current_rate < 128000) { + reject_if_open = 1; + } + rate_bits = HDSP_Frequency192KHz; + break; default: return -EINVAL; } if (reject_if_open && (hdsp->capture_pid >= 0 || hdsp->playback_pid >= 0)) { - snd_printk ("cannot change between single- and double-speed mode (capture PID = %d, playback PID = %d)\n", + snd_printk ("cannot change speed mode (capture PID = %d, playback PID = %d)\n", hdsp->capture_pid, hdsp->playback_pid); return -EBUSY; @@ -955,8 +1129,14 @@ hdsp->control_register |= rate_bits; hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - if (rate > 48000) { - hdsp->channel_map = channel_map_ds; + if (rate >= 128000) { + hdsp->channel_map = channel_map_H9632_qs; + } else if (rate > 48000) { + if (hdsp->io_type == H9632) { + hdsp->channel_map = channel_map_H9632_ds; + } else { + hdsp->channel_map = channel_map_ds; + } } else { switch (hdsp->io_type) { case Multiface: @@ -966,6 +1146,9 @@ case H9652: hdsp->channel_map = channel_map_df_ss; break; + case H9632: + hdsp->channel_map = channel_map_H9632_ss; + break; default: /* should never happen */ break; @@ -973,10 +1156,6 @@ } hdsp->system_sample_rate = rate; - - if (reject_if_open) { - hdsp_update_simple_mixer_controls (hdsp); - } return 0; } @@ -993,11 +1172,11 @@ /* set thru for all channels */ if (enable) { - for (i = 0; i < 26; i++) { + for (i = 0; i < hdsp->max_channels; i++) { hdsp_write_gain (hdsp, hdsp_input_to_output_key(hdsp,i,i), UNITY_GAIN); } } else { - for (i = 0; i < 26; i++) { + for (i = 0; i < hdsp->max_channels; i++) { hdsp_write_gain (hdsp, hdsp_input_to_output_key(hdsp,i,i), MINUS_INFINITY_GAIN); } } @@ -1005,7 +1184,7 @@ } else { int mapped_channel; - snd_assert(channel < HDSP_MAX_CHANNELS, return); + snd_assert(channel < hdsp->max_channels, return); mapped_channel = hdsp->channel_map[channel]; @@ -1463,13 +1642,14 @@ static int snd_hdsp_info_spdif_in(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - static char *texts[3] = {"ADAT1", "Coaxial", "Internal"}; + static char *texts[4] = {"Optical", "Coaxial", "Internal", "AES"}; + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 3; - if (uinfo->value.enumerated.item > 2) - uinfo->value.enumerated.item = 2; + uinfo->value.enumerated.items = ((hdsp->io_type == H9632) ? 4 : 3); + if (uinfo->value.enumerated.item > ((hdsp->io_type == H9632) ? 3 : 2)) + uinfo->value.enumerated.item = ((hdsp->io_type == H9632) ? 3 : 2); strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); return 0; } @@ -1491,7 +1671,7 @@ if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; - val = ucontrol->value.enumerated.item[0] % 3; + val = ucontrol->value.enumerated.item[0] % ((hdsp->io_type == H9632) ? 4 : 3); spin_lock_irqsave(&hdsp->lock, flags); change = val != hdsp_spdif_in(hdsp); if (change) @@ -1704,10 +1884,12 @@ static int snd_hdsp_info_spdif_sample_rate(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None"}; + static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None", "128000", "176400", "192000"}; + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 7 ; + uinfo->value.enumerated.items = (hdsp->io_type == H9632) ? 10 : 7; if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); @@ -1737,6 +1919,15 @@ case 96000: ucontrol->value.enumerated.item[0] = 5; break; + case 128000: + ucontrol->value.enumerated.item[0] = 7; + break; + case 176400: + ucontrol->value.enumerated.item[0] = 8; + break; + case 192000: + ucontrol->value.enumerated.item[0] = 9; + break; default: ucontrol->value.enumerated.item[0] = 6; } @@ -1778,10 +1969,11 @@ static int snd_hdsp_info_autosync_sample_rate(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None"}; + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None", "128000", "176400", "192000"}; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 7 ; + uinfo->value.enumerated.items = (hdsp->io_type == H9632) ? 10 : 7 ; if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); @@ -1811,6 +2003,15 @@ case 96000: ucontrol->value.enumerated.item[0] = 5; break; + case 128000: + ucontrol->value.enumerated.item[0] = 7; + break; + case 176400: + ucontrol->value.enumerated.item[0] = 8; + break; + case 192000: + ucontrol->value.enumerated.item[0] = 9; + break; default: ucontrol->value.enumerated.item[0] = 6; } @@ -1882,6 +2083,12 @@ return 5; case 96000: return 6; + case 128000: + return 7; + case 176400: + return 8; + case 192000: + return 9; default: return 3; } @@ -1896,9 +2103,11 @@ switch (mode) { case HDSP_CLOCK_SOURCE_AUTOSYNC: if (hdsp_external_sample_rate(hdsp) != 0) { - hdsp->control_register &= ~HDSP_ClockModeMaster; - hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - return 0; + if (!hdsp_set_rate(hdsp, hdsp_external_sample_rate(hdsp), 1)) { + hdsp->control_register &= ~HDSP_ClockModeMaster; + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + return 0; + } } return -1; case HDSP_CLOCK_SOURCE_INTERNAL_32KHZ: @@ -1919,6 +2128,15 @@ case HDSP_CLOCK_SOURCE_INTERNAL_96KHZ: rate = 96000; break; + case HDSP_CLOCK_SOURCE_INTERNAL_128KHZ: + rate = 128000; + break; + case HDSP_CLOCK_SOURCE_INTERNAL_176_4KHZ: + rate = 176400; + break; + case HDSP_CLOCK_SOURCE_INTERNAL_192KHZ: + rate = 192000; + break; default: rate = 48000; } @@ -1930,11 +2148,15 @@ static int snd_hdsp_info_clock_source(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - static char *texts[] = {"AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz", "Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz", "Internal 96.0 kHz" }; + static char *texts[] = {"AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz", "Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz", "Internal 96.0 kHz", "Internal 128 kHz", "Internal 176.4 kHz", "Internal 192.0 KHz" }; + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 7; + if (hdsp->io_type == H9632) + uinfo->value.enumerated.items = 10; + else + uinfo->value.enumerated.items = 7; if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); @@ -1960,7 +2182,11 @@ return -EBUSY; val = ucontrol->value.enumerated.item[0]; if (val < 0) val = 0; - if (val > 6) val = 6; + if (hdsp->io_type == H9632) { + if (val > 9) val = 9; + } else { + if (val > 6) val = 6; + } spin_lock_irqsave(&hdsp->lock, flags); if (val != hdsp_clock_source(hdsp)) { change = (hdsp_set_clock_source(hdsp, val) == 0) ? 1 : 0; @@ -1971,6 +2197,395 @@ return change; } +#define HDSP_DA_GAIN(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdsp_info_da_gain, \ + .get = snd_hdsp_get_da_gain, \ + .put = snd_hdsp_put_da_gain \ +} + +static int hdsp_da_gain(hdsp_t *hdsp) +{ + switch (hdsp->control_register & HDSP_DAGainMask) { + case HDSP_DAGainHighGain: + return 0; + case HDSP_DAGainPlus4dBu: + return 1; + case HDSP_DAGainMinus10dBV: + return 2; + default: + return 1; + } +} + +static int hdsp_set_da_gain(hdsp_t *hdsp, int mode) +{ + hdsp->control_register &= ~HDSP_DAGainMask; + switch (mode) { + case 0: + hdsp->control_register |= HDSP_DAGainHighGain; + break; + case 1: + hdsp->control_register |= HDSP_DAGainPlus4dBu; + break; + case 2: + hdsp->control_register |= HDSP_DAGainMinus10dBV; + break; + default: + return -1; + + } + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + return 0; +} + +static int snd_hdsp_info_da_gain(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = {"Hi Gain", "+4 dBu", "-10 dbV"}; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_hdsp_get_da_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdsp_da_gain(hdsp); + return 0; +} + +static int snd_hdsp_put_da_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + unsigned long flags; + int change; + int val; + + if (!snd_hdsp_use_is_exclusive(hdsp)) + return -EBUSY; + val = ucontrol->value.enumerated.item[0]; + if (val < 0) val = 0; + if (val > 2) val = 2; + spin_lock_irqsave(&hdsp->lock, flags); + if (val != hdsp_da_gain(hdsp)) { + change = (hdsp_set_da_gain(hdsp, val) == 0) ? 1 : 0; + } else { + change = 0; + } + spin_unlock_irqrestore(&hdsp->lock, flags); + return change; +} + +#define HDSP_AD_GAIN(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdsp_info_ad_gain, \ + .get = snd_hdsp_get_ad_gain, \ + .put = snd_hdsp_put_ad_gain \ +} + +static int hdsp_ad_gain(hdsp_t *hdsp) +{ + switch (hdsp->control_register & HDSP_ADGainMask) { + case HDSP_ADGainMinus10dBV: + return 0; + case HDSP_ADGainPlus4dBu: + return 1; + case HDSP_ADGainLowGain: + return 2; + default: + return 1; + } +} + +static int hdsp_set_ad_gain(hdsp_t *hdsp, int mode) +{ + hdsp->control_register &= ~HDSP_ADGainMask; + switch (mode) { + case 0: + hdsp->control_register |= HDSP_ADGainMinus10dBV; + break; + case 1: + hdsp->control_register |= HDSP_ADGainPlus4dBu; + break; + case 2: + hdsp->control_register |= HDSP_ADGainLowGain; + break; + default: + return -1; + + } + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + return 0; +} + +static int snd_hdsp_info_ad_gain(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = {"-10 dBV", "+4 dBu", "Lo Gain"}; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_hdsp_get_ad_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdsp_ad_gain(hdsp); + return 0; +} + +static int snd_hdsp_put_ad_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + unsigned long flags; + int change; + int val; + + if (!snd_hdsp_use_is_exclusive(hdsp)) + return -EBUSY; + val = ucontrol->value.enumerated.item[0]; + if (val < 0) val = 0; + if (val > 2) val = 2; + spin_lock_irqsave(&hdsp->lock, flags); + if (val != hdsp_ad_gain(hdsp)) { + change = (hdsp_set_ad_gain(hdsp, val) == 0) ? 1 : 0; + } else { + change = 0; + } + spin_unlock_irqrestore(&hdsp->lock, flags); + return change; +} + +#define HDSP_PHONE_GAIN(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdsp_info_phone_gain, \ + .get = snd_hdsp_get_phone_gain, \ + .put = snd_hdsp_put_phone_gain \ +} + +static int hdsp_phone_gain(hdsp_t *hdsp) +{ + switch (hdsp->control_register & HDSP_PhoneGainMask) { + case HDSP_PhoneGain0dB: + return 0; + case HDSP_PhoneGainMinus6dB: + return 1; + case HDSP_PhoneGainMinus12dB: + return 2; + default: + return 0; + } +} + +static int hdsp_set_phone_gain(hdsp_t *hdsp, int mode) +{ + hdsp->control_register &= ~HDSP_PhoneGainMask; + switch (mode) { + case 0: + hdsp->control_register |= HDSP_PhoneGain0dB; + break; + case 1: + hdsp->control_register |= HDSP_PhoneGainMinus6dB; + break; + case 2: + hdsp->control_register |= HDSP_PhoneGainMinus12dB; + break; + default: + return -1; + + } + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + return 0; +} + +static int snd_hdsp_info_phone_gain(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = {"0 dB", "-6 dB", "-12 dB"}; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_hdsp_get_phone_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdsp_phone_gain(hdsp); + return 0; +} + +static int snd_hdsp_put_phone_gain(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + unsigned long flags; + int change; + int val; + + if (!snd_hdsp_use_is_exclusive(hdsp)) + return -EBUSY; + val = ucontrol->value.enumerated.item[0]; + if (val < 0) val = 0; + if (val > 2) val = 2; + spin_lock_irqsave(&hdsp->lock, flags); + if (val != hdsp_phone_gain(hdsp)) { + change = (hdsp_set_phone_gain(hdsp, val) == 0) ? 1 : 0; + } else { + change = 0; + } + spin_unlock_irqrestore(&hdsp->lock, flags); + return change; +} + +#define HDSP_XLR_BREAKOUT_CABLE(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdsp_info_xlr_breakout_cable, \ + .get = snd_hdsp_get_xlr_breakout_cable, \ + .put = snd_hdsp_put_xlr_breakout_cable \ +} + +static int hdsp_xlr_breakout_cable(hdsp_t *hdsp) +{ + if (hdsp->control_register & HDSP_XLRBreakoutCable) { + return 1; + } + return 0; +} + +static int hdsp_set_xlr_breakout_cable(hdsp_t *hdsp, int mode) +{ + if (mode) { + hdsp->control_register |= HDSP_XLRBreakoutCable; + } else { + hdsp->control_register &= ~HDSP_XLRBreakoutCable; + } + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + return 0; +} + +static int snd_hdsp_info_xlr_breakout_cable(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_hdsp_get_xlr_breakout_cable(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdsp_xlr_breakout_cable(hdsp); + return 0; +} + +static int snd_hdsp_put_xlr_breakout_cable(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + unsigned long flags; + int change; + int val; + + if (!snd_hdsp_use_is_exclusive(hdsp)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irqsave(&hdsp->lock, flags); + change = (int)val != hdsp_xlr_breakout_cable(hdsp); + hdsp_set_xlr_breakout_cable(hdsp, val); + spin_unlock_irqrestore(&hdsp->lock, flags); + return change; +} + +/* (De)activates old RME Analog Extension Board + These are connected to the internal ADAT connector + Switching this on desactivates external ADAT +*/ +#define HDSP_AEB(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdsp_info_aeb, \ + .get = snd_hdsp_get_aeb, \ + .put = snd_hdsp_put_aeb \ +} + +static int hdsp_aeb(hdsp_t *hdsp) +{ + if (hdsp->control_register & HDSP_AnalogExtensionBoard) { + return 1; + } + return 0; +} + +static int hdsp_set_aeb(hdsp_t *hdsp, int mode) +{ + if (mode) { + hdsp->control_register |= HDSP_AnalogExtensionBoard; + } else { + hdsp->control_register &= ~HDSP_AnalogExtensionBoard; + } + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + return 0; +} + +static int snd_hdsp_info_aeb(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_hdsp_get_aeb(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdsp_aeb(hdsp); + return 0; +} + +static int snd_hdsp_put_aeb(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + unsigned long flags; + int change; + int val; + + if (!snd_hdsp_use_is_exclusive(hdsp)) + return -EBUSY; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irqsave(&hdsp->lock, flags); + change = (int)val != hdsp_aeb(hdsp); + hdsp_set_aeb(hdsp, val); + spin_unlock_irqrestore(&hdsp->lock, flags); + return change; +} + #define HDSP_PREF_SYNC_REF(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ .name = xname, \ @@ -2036,7 +2651,7 @@ static int snd_hdsp_info_pref_sync_ref(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - static char *texts[] = {"Word", "ADAT Sync", "IEC958", "ADAT1", "ADAT2", "ADAT3" }; + static char *texts[] = {"Word", "IEC958", "ADAT1", "ADAT Sync", "ADAT2", "ADAT3" }; hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; @@ -2049,6 +2664,10 @@ break; case Multiface: uinfo->value.enumerated.items = 4; + break; + case H9632: + uinfo->value.enumerated.items = 3; + break; default: uinfo->value.enumerated.items = 0; break; @@ -2086,6 +2705,9 @@ case Multiface: max = 4; break; + case H9632: + max = 3; + break; default: return -EIO; } @@ -2296,9 +2918,9 @@ source = ucontrol->value.integer.value[0]; destination = ucontrol->value.integer.value[1]; - - if (source > 25) { - addr = hdsp_playback_to_output_key(hdsp,source-26,destination); + + if (source >= hdsp->max_channels) { + addr = hdsp_playback_to_output_key(hdsp,source-hdsp->max_channels,destination); } else { addr = hdsp_input_to_output_key(hdsp,source, destination); } @@ -2325,8 +2947,8 @@ source = ucontrol->value.integer.value[0]; destination = ucontrol->value.integer.value[1]; - if (source > 25) { - addr = hdsp_playback_to_output_key(hdsp,source-26, destination); + if (source >= hdsp->max_channels) { + addr = hdsp_playback_to_output_key(hdsp,source-hdsp->max_channels, destination); } else { addr = hdsp_input_to_output_key(hdsp,source, destination); } @@ -2341,87 +2963,6 @@ return change; } -/* The simple mixer control(s) provide gain control for the - basic 1:1 mappings of playback streams to output - streams. -*/ - -#define HDSP_PLAYBACK_MIXER \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | \ - SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ - .info = snd_hdsp_info_playback_mixer, \ - .get = snd_hdsp_get_playback_mixer, \ - .put = snd_hdsp_put_playback_mixer \ -} - -static int snd_hdsp_info_playback_mixer(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 65536; - uinfo->value.integer.step = 1; - return 0; -} - -static int snd_hdsp_get_playback_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); - unsigned long flags; - int addr; - int channel; - int mapped_channel; - - channel = ucontrol->id.index - 1; - - snd_assert(channel >= 0 || channel < HDSP_MAX_CHANNELS, return -EINVAL); - - if ((mapped_channel = hdsp->channel_map[channel]) < 0) { - return -EINVAL; - } - - addr = hdsp_playback_to_output_key(hdsp,mapped_channel, mapped_channel); - - spin_lock_irqsave(&hdsp->lock, flags); - ucontrol->value.integer.value[0] = hdsp_read_gain (hdsp, addr); - spin_unlock_irqrestore(&hdsp->lock, flags); - return 0; -} - -static int snd_hdsp_put_playback_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); - unsigned long flags; - int change; - int addr; - int channel; - int mapped_channel; - int gain; - - if (!snd_hdsp_use_is_exclusive(hdsp)) - return -EBUSY; - - channel = ucontrol->id.index - 1; - - snd_assert(channel >= 0 || channel < HDSP_MAX_CHANNELS, return -EINVAL); - - if ((mapped_channel = hdsp->channel_map[channel]) < 0) { - return -EINVAL; - } - - addr = hdsp_playback_to_output_key(hdsp,mapped_channel, mapped_channel); - gain = ucontrol->value.integer.value[0]; - - - spin_lock_irqsave(&hdsp->lock, flags); - change = gain != hdsp_read_gain(hdsp, addr); - if (change) - hdsp_write_gain(hdsp, addr, gain); - spin_unlock_irqrestore(&hdsp->lock, flags); - return change; -} - #define HDSP_WC_SYNC_CHECK(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ .name = xname, \ @@ -2566,6 +3107,7 @@ return -EINVAL; break; case Multiface: + case H9632: if (offset >= 1) return -EINVAL; break; @@ -2577,6 +3119,13 @@ return 0; } +static snd_kcontrol_new_t snd_hdsp_9632_controls[] = { +HDSP_DA_GAIN("DA Gain", 0), +HDSP_AD_GAIN("AD Gain", 0), +HDSP_PHONE_GAIN("Phones Gain", 0), +HDSP_XLR_BREAKOUT_CABLE("XLR Breakout Cable", 0) +}; + static snd_kcontrol_new_t snd_hdsp_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -2637,34 +3186,14 @@ #define HDSP_CONTROLS (sizeof(snd_hdsp_controls)/sizeof(snd_kcontrol_new_t)) -static snd_kcontrol_new_t snd_hdsp_playback_mixer = HDSP_PLAYBACK_MIXER; -static snd_kcontrol_new_t snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK; - - -static int hdsp_update_simple_mixer_controls(hdsp_t *hdsp) -{ - int i; - - for (i = hdsp->ds_channels; i < hdsp->ss_channels; ++i) { - if (hdsp->system_sample_rate > 48000) { - hdsp->playback_mixer_ctls[i]->vd[0].access = SNDRV_CTL_ELEM_ACCESS_INACTIVE | - SNDRV_CTL_ELEM_ACCESS_READ | - SNDRV_CTL_ELEM_ACCESS_VOLATILE; - } else { - hdsp->playback_mixer_ctls[i]->vd[0].access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_VOLATILE; - } - snd_ctl_notify(hdsp->card, SNDRV_CTL_EVENT_MASK_VALUE | - SNDRV_CTL_EVENT_MASK_INFO, &hdsp->playback_mixer_ctls[i]->id); - } - - return 0; -} +#define HDSP_9632_CONTROLS (sizeof(snd_hdsp_9632_controls)/sizeof(snd_kcontrol_new_t)) +static snd_kcontrol_new_t snd_hdsp_96xx_aeb = HDSP_AEB("Analog Extension Board", 0); +static snd_kcontrol_new_t snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK; int snd_hdsp_create_controls(snd_card_t *card, hdsp_t *hdsp) { - unsigned int idx, limit; + unsigned int idx; int err; snd_kcontrol_t *kctl; @@ -2676,38 +3205,8 @@ hdsp->spdif_ctl = kctl; } - snd_hdsp_playback_mixer.name = "Chn"; - snd_hdsp_adat_sync_check.name = "ADAT Lock Status"; - - switch (hdsp->io_type) { - case Digiface: - limit = DIGIFACE_SS_CHANNELS; - break; - case H9652: - limit = H9652_SS_CHANNELS; - break; - case Multiface: - limit = MULTIFACE_SS_CHANNELS; - break; - default: - return -EIO; - } - - /* The index values are one greater than the channel ID so that alsamixer - will display them correctly. We want to use the index for fast lookup - of the relevant channel, but if we use it at all, most ALSA software - does the wrong thing with it ... - */ - - for (idx = 0; idx < limit; ++idx) { - snd_hdsp_playback_mixer.index = idx+1; - if ((err = snd_ctl_add (card, kctl = snd_ctl_new1(&snd_hdsp_playback_mixer, hdsp)))) { - return err; - } - hdsp->playback_mixer_ctls[idx] = kctl; - } - /* ADAT SyncCheck status */ + snd_hdsp_adat_sync_check.name = "ADAT Lock Status"; snd_hdsp_adat_sync_check.index = 1; if ((err = snd_ctl_add (card, kctl = snd_ctl_new1(&snd_hdsp_adat_sync_check, hdsp)))) { return err; @@ -2720,6 +3219,22 @@ } } } + + /* DA, AD and Phone gain and XLR breakout cable controls for H9632 cards */ + if (hdsp->io_type == H9632) { + for (idx = 0; idx < HDSP_9632_CONTROLS; idx++) { + if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_9632_controls[idx], hdsp))) < 0) { + return err; + } + } + } + + /* AEB control for H96xx card */ + if (hdsp->io_type == H9632 || hdsp->io_type == H9652) { + if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_hdsp_96xx_aeb, hdsp))) < 0) { + return err; + } + } return 0; } @@ -2812,6 +3327,15 @@ case HDSP_CLOCK_SOURCE_INTERNAL_96KHZ: clock_source = "Internal 96 kHz"; break; + case HDSP_CLOCK_SOURCE_INTERNAL_128KHZ: + clock_source = "Internal 128 kHz"; + break; + case HDSP_CLOCK_SOURCE_INTERNAL_176_4KHZ: + clock_source = "Internal 176.4 kHz"; + break; + case HDSP_CLOCK_SOURCE_INTERNAL_192KHZ: + clock_source = "Internal 192 kHz"; + break; default: clock_source = "Error"; } @@ -2884,16 +3408,19 @@ snd_iprintf(buffer, "\n"); - switch ((hdsp->control_register & HDSP_SPDIFInputMask) >> 14) { + switch (hdsp_spdif_in(hdsp)) { case HDSP_SPDIFIN_OPTICAL: - snd_iprintf(buffer, "IEC958 input: ADAT1\n"); + snd_iprintf(buffer, "IEC958 input: Optical\n"); break; case HDSP_SPDIFIN_COAXIAL: snd_iprintf(buffer, "IEC958 input: Coaxial\n"); break; - case HDSP_SPDIFIN_INTERN: + case HDSP_SPDIFIN_INTERNAL: snd_iprintf(buffer, "IEC958 input: Internal\n"); break; + case HDSP_SPDIFIN_AES: + snd_iprintf(buffer, "IEC958 input: AES\n"); + break; default: snd_iprintf(buffer, "IEC958 input: ???\n"); break; @@ -2980,13 +3507,60 @@ } snd_iprintf(buffer, "\n"); + + /* Informations about H9632 specific controls */ + if (hdsp->io_type == H9632) { + char *tmp; + + switch (hdsp_ad_gain(hdsp)) { + case 0: + tmp = "-10 dBV"; + break; + case 1: + tmp = "+4 dBu"; + break; + default: + tmp = "Lo Gain"; + break; + } + snd_iprintf(buffer, "AD Gain : %s\n", tmp); + + switch (hdsp_da_gain(hdsp)) { + case 0: + tmp = "Hi Gain"; + break; + case 1: + tmp = "+4 dBu"; + break; + default: + tmp = "-10 dBV"; + break; + } + snd_iprintf(buffer, "DA Gain : %s\n", tmp); + + switch (hdsp_phone_gain(hdsp)) { + case 0: + tmp = "0 dB"; + break; + case 1: + tmp = "-6 dB"; + break; + default: + tmp = "-12 dB"; + break; + } + snd_iprintf(buffer, "Phones Gain : %s\n", tmp); -#if 0 - for (x = 0; x < 26; x++) { - unsigned int val = hdsp_read (hdsp, HDSP_inputPeakLevel + (4 * x)); - snd_iprintf (buffer, "%d: input peak = %d overs = %d\n", x, val&0xffffff00, val&0xf); + snd_iprintf(buffer, "XLR Breakout Cable : %s\n", hdsp_xlr_breakout_cable(hdsp) ? "yes" : "no"); + + if (hdsp->control_register & HDSP_AnalogExtensionBoard) { + snd_iprintf(buffer, "AEB : on (ADAT1 internal)\n"); + } else { + snd_iprintf(buffer, "AEB : off (ADAT1 external)\n"); + } + snd_iprintf(buffer, "\n"); } -#endif + } static void __devinit snd_hdsp_proc_init(hdsp_t *hdsp) @@ -2994,7 +3568,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(hdsp->card, "hdsp", &entry)) - snd_info_set_text_ops(entry, hdsp, snd_hdsp_proc_read); + snd_info_set_text_ops(entry, hdsp, 1024, snd_hdsp_proc_read); } static void snd_hdsp_free_buffers(hdsp_t *hdsp) @@ -3078,8 +3652,21 @@ HDSP_SPDIFInputCoaxial | hdsp_encode_latency(7) | HDSP_LineOut; + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + +#ifdef SNDRV_BIG_ENDIAN + hdsp->control2_register = HDSP_BIGENDIAN_MODE; +#else + hdsp->control2_register = 0; +#endif + if (hdsp->io_type == H9652) { + snd_hdsp_9652_enable_mixer (hdsp); + } else { + hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register); + } + hdsp_reset_hw_pointer(hdsp); hdsp_compute_period_size(hdsp); @@ -3089,7 +3676,7 @@ hdsp->mixer_matrix[i] = MINUS_INFINITY_GAIN; } - for (i = 0; i < (hdsp->io_type == H9652 ? 1352 : HDSP_MATRIX_MIXER_SIZE); i++) { + for (i = 0; i < ((hdsp->io_type == H9652 || hdsp->io_type == H9632) ? 1352 : HDSP_MATRIX_MIXER_SIZE); ++i) { if (hdsp_write_gain (hdsp, i, MINUS_INFINITY_GAIN)) { return -EIO; } @@ -3097,21 +3684,30 @@ if ((hdsp->io_type != H9652) && line_outs_monitor[hdsp->dev]) { + int lineouts_base; + snd_printk ("sending all inputs and playback streams to line outs.\n"); /* route all inputs to the line outs for easy monitoring. send odd numbered channels to right, even to left. */ + if (hdsp->io_type == H9632) { + /* this is the phones/analog output */ + lineouts_base = 10; + } else { + lineouts_base = 26; + } - for (i = 0; i < HDSP_MAX_CHANNELS; i++) { + for (i = 0; i < hdsp->max_channels; i++) { if (i & 1) { - if (hdsp_write_gain (hdsp, hdsp_input_to_output_key (hdsp, i, 26), UNITY_GAIN) || - hdsp_write_gain (hdsp, hdsp_playback_to_output_key (hdsp, i, 26), UNITY_GAIN)) { + if (hdsp_write_gain (hdsp, hdsp_input_to_output_key (hdsp, i, lineouts_base), UNITY_GAIN) || + hdsp_write_gain (hdsp, hdsp_playback_to_output_key (hdsp, i, lineouts_base), UNITY_GAIN)) { return -EIO; } } else { - if (hdsp_write_gain (hdsp, hdsp_input_to_output_key (hdsp, i, 27), UNITY_GAIN) || - hdsp_write_gain (hdsp, hdsp_playback_to_output_key (hdsp, i, 27), UNITY_GAIN)) { + if (hdsp_write_gain (hdsp, hdsp_input_to_output_key (hdsp, i, lineouts_base+1), UNITY_GAIN) || + hdsp_write_gain (hdsp, hdsp_playback_to_output_key (hdsp, i, lineouts_base+1), UNITY_GAIN)) { + return -EIO; } } @@ -3120,6 +3716,12 @@ hdsp->passthru = 0; + /* H9632 specific defaults */ + if (hdsp->io_type == H9632) { + hdsp->control_register |= (HDSP_DAGainPlus4dBu | HDSP_ADGainPlus4dBu | HDSP_PhoneGain0dB); + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + } + /* set a default rate so that the channel map is set up. */ @@ -3208,7 +3810,7 @@ { int mapped_channel; - snd_assert(channel >= 0 || channel < HDSP_MAX_CHANNELS, return NULL); + snd_assert(channel >= 0 || channel < hdsp->max_channels, return NULL); if ((mapped_channel = hdsp->channel_map[channel]) < 0) { return NULL; @@ -3378,7 +3980,7 @@ hdsp_t *hdsp = _snd_pcm_substream_chip(substream); int mapped_channel; - snd_assert(info->channel < HDSP_MAX_CHANNELS, return -EINVAL); + snd_assert(info->channel < hdsp->max_channels, return -EINVAL); if ((mapped_channel = hdsp->channel_map[info->channel]) < 0) { return -EINVAL; @@ -3567,42 +4169,118 @@ .fifo_size = 0 }; -static unsigned int period_sizes[] = { 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; +static unsigned int hdsp_period_sizes[] = { 64, 128, 256, 512, 1024, 2048, 4096, 8192 }; + +#define HDSP_PERIOD_SIZES sizeof(hdsp_period_sizes) / sizeof(hdsp_period_sizes[0]) + +static snd_pcm_hw_constraint_list_t hdsp_hw_constraints_period_sizes = { + .count = HDSP_PERIOD_SIZES, + .list = hdsp_period_sizes, + .mask = 0 +}; + +static unsigned int hdsp_9632_sample_rates[] = { 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000 }; -#define PERIOD_SIZES sizeof(period_sizes) / sizeof(period_sizes[0]) +#define HDSP_9632_SAMPLE_RATES sizeof(hdsp_9632_sample_rates) / sizeof(hdsp_9632_sample_rates[0]) -static snd_pcm_hw_constraint_list_t hw_constraints_period_sizes = { - .count = PERIOD_SIZES, - .list = period_sizes, +static snd_pcm_hw_constraint_list_t hdsp_hw_constraints_9632_sample_rates = { + .count = HDSP_9632_SAMPLE_RATES, + .list = hdsp_9632_sample_rates, .mask = 0 }; -static int snd_hdsp_hw_rule_channels(snd_pcm_hw_params_t *params, +static int snd_hdsp_hw_rule_in_channels(snd_pcm_hw_params_t *params, + snd_pcm_hw_rule_t *rule) +{ + hdsp_t *hdsp = rule->private; + snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + if (hdsp->io_type == H9632) { + unsigned int list[3]; + list[0] = hdsp->qs_in_channels; + list[1] = hdsp->ds_in_channels; + list[2] = hdsp->ss_in_channels; + return snd_interval_list(c, 3, list, 0); + } else { + unsigned int list[2]; + list[0] = hdsp->ds_in_channels; + list[1] = hdsp->ss_in_channels; + return snd_interval_list(c, 2, list, 0); + } +} + +static int snd_hdsp_hw_rule_out_channels(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule) { + unsigned int list[3]; hdsp_t *hdsp = rule->private; snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - unsigned int list[2] = { hdsp->ds_channels, hdsp->ss_channels }; + if (hdsp->io_type == H9632) { + list[0] = hdsp->qs_out_channels; + list[1] = hdsp->ds_out_channels; + list[2] = hdsp->ss_out_channels; + return snd_interval_list(c, 3, list, 0); + } else { + list[0] = hdsp->ds_out_channels; + list[1] = hdsp->ss_out_channels; + } return snd_interval_list(c, 2, list, 0); } -static int snd_hdsp_hw_rule_channels_rate(snd_pcm_hw_params_t *params, +static int snd_hdsp_hw_rule_in_channels_rate(snd_pcm_hw_params_t *params, + snd_pcm_hw_rule_t *rule) +{ + hdsp_t *hdsp = rule->private; + snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + if (r->min > 96000 && hdsp->io_type == H9632) { + snd_interval_t t = { + .min = hdsp->qs_in_channels, + .max = hdsp->qs_in_channels, + .integer = 1, + }; + return snd_interval_refine(c, &t); + } else if (r->min > 48000 && r->max <= 96000) { + snd_interval_t t = { + .min = hdsp->ds_in_channels, + .max = hdsp->ds_in_channels, + .integer = 1, + }; + return snd_interval_refine(c, &t); + } else if (r->max < 64000) { + snd_interval_t t = { + .min = hdsp->ss_in_channels, + .max = hdsp->ss_in_channels, + .integer = 1, + }; + return snd_interval_refine(c, &t); + } + return 0; +} + +static int snd_hdsp_hw_rule_out_channels_rate(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule) { hdsp_t *hdsp = rule->private; snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - if (r->min > 48000) { + if (r->min > 96000 && hdsp->io_type == H9632) { snd_interval_t t = { - .min = hdsp->ds_channels, - .max = hdsp->ds_channels, + .min = hdsp->qs_out_channels, + .max = hdsp->qs_out_channels, + .integer = 1, + }; + return snd_interval_refine(c, &t); + } else if (r->min > 48000 && r->max <= 96000) { + snd_interval_t t = { + .min = hdsp->ds_out_channels, + .max = hdsp->ds_out_channels, .integer = 1, }; return snd_interval_refine(c, &t); } else if (r->max < 64000) { snd_interval_t t = { - .min = hdsp->ss_channels, - .max = hdsp->ss_channels, + .min = hdsp->ss_out_channels, + .max = hdsp->ss_out_channels, .integer = 1, }; return snd_interval_refine(c, &t); @@ -3610,20 +4288,58 @@ return 0; } -static int snd_hdsp_hw_rule_rate_channels(snd_pcm_hw_params_t *params, +static int snd_hdsp_hw_rule_rate_out_channels(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule) { hdsp_t *hdsp = rule->private; snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); - if (c->min >= hdsp->ss_channels) { + if (c->min >= hdsp->ss_out_channels) { snd_interval_t t = { .min = 32000, .max = 48000, .integer = 1, }; return snd_interval_refine(r, &t); - } else if (c->max <= hdsp->ds_channels) { + } else if (c->max <= hdsp->qs_out_channels && hdsp->io_type == H9632) { + snd_interval_t t = { + .min = 128000, + .max = 192000, + .integer = 1, + }; + return snd_interval_refine(r, &t); + } else if (c->max <= hdsp->ds_out_channels) { + snd_interval_t t = { + .min = 64000, + .max = 96000, + .integer = 1, + }; + return snd_interval_refine(r, &t); + } + return 0; +} + +static int snd_hdsp_hw_rule_rate_in_channels(snd_pcm_hw_params_t *params, + snd_pcm_hw_rule_t *rule) +{ + hdsp_t *hdsp = rule->private; + snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + snd_interval_t *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + if (c->min >= hdsp->ss_in_channels) { + snd_interval_t t = { + .min = 32000, + .max = 48000, + .integer = 1, + }; + return snd_interval_refine(r, &t); + } else if (c->max <= hdsp->qs_in_channels && hdsp->io_type == H9632) { + snd_interval_t t = { + .min = 128000, + .max = 192000, + .integer = 1, + }; + return snd_interval_refine(r, &t); + } else if (c->max <= hdsp->ds_in_channels) { snd_interval_t t = { .min = 64000, .max = 96000, @@ -3674,15 +4390,23 @@ spin_unlock_irqrestore(&hdsp->lock, flags); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_period_sizes); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hdsp_hw_constraints_period_sizes); + if (hdsp->io_type == H9632) { + runtime->hw.channels_min = hdsp->qs_out_channels; + runtime->hw.channels_max = hdsp->ss_out_channels; + runtime->hw.rate_max = 192000; + runtime->hw.rates = SNDRV_PCM_RATE_KNOT; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdsp_hw_constraints_9632_sample_rates); + } + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - snd_hdsp_hw_rule_channels, hdsp, + snd_hdsp_hw_rule_out_channels, hdsp, SNDRV_PCM_HW_PARAM_CHANNELS, -1); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - snd_hdsp_hw_rule_channels_rate, hdsp, + snd_hdsp_hw_rule_out_channels_rate, hdsp, SNDRV_PCM_HW_PARAM_RATE, -1); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - snd_hdsp_hw_rule_rate_channels, hdsp, + snd_hdsp_hw_rule_rate_out_channels, hdsp, SNDRV_PCM_HW_PARAM_CHANNELS, -1); hdsp->creg_spdif_stream = hdsp->creg_spdif; @@ -3751,15 +4475,22 @@ spin_unlock_irqrestore(&hdsp->lock, flags); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hw_constraints_period_sizes); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, &hdsp_hw_constraints_period_sizes); + if (hdsp->io_type == H9632) { + runtime->hw.channels_min = hdsp->qs_in_channels; + runtime->hw.channels_max = hdsp->ss_in_channels; + runtime->hw.rate_max = 192000; + runtime->hw.rates = SNDRV_PCM_RATE_KNOT; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hdsp_hw_constraints_9632_sample_rates); + } snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - snd_hdsp_hw_rule_channels, hdsp, + snd_hdsp_hw_rule_in_channels, hdsp, SNDRV_PCM_HW_PARAM_CHANNELS, -1); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - snd_hdsp_hw_rule_channels_rate, hdsp, + snd_hdsp_hw_rule_in_channels_rate, hdsp, SNDRV_PCM_HW_PARAM_RATE, -1); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - snd_hdsp_hw_rule_rate_channels, hdsp, + snd_hdsp_hw_rule_rate_in_channels, hdsp, SNDRV_PCM_HW_PARAM_CHANNELS, -1); return 0; } @@ -3780,42 +4511,117 @@ static int snd_hdsp_hwdep_dummy_op(snd_hwdep_t *hw, struct file *file) { - /* we have nothing to initialize but the call is required */ - return 0; + /* we have nothing to initialize but the call is required */ + return 0; } static int snd_hdsp_hwdep_ioctl(snd_hwdep_t *hw, struct file *file, unsigned int cmd, unsigned long arg) { hdsp_t *hdsp = (hdsp_t *)hw->private_data; - + switch (cmd) { case SNDRV_HDSP_IOCTL_GET_PEAK_RMS: { hdsp_peak_rms_t *peak_rms; - + int i; + if (hdsp->io_type == H9652) { - snd_printk("hardware metering isn't supported yet for hdsp9652 cards\n"); - return -EINVAL; + unsigned long rms_low, rms_high; + int doublespeed = 0; + if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DoubleSpeedStatus) + doublespeed = 1; + peak_rms = (hdsp_peak_rms_t *)arg; + for (i = 0; i < 26; ++i) { + if (!(doublespeed && (i & 4))) { + if (copy_to_user_fromio((void *)peak_rms->input_peaks+i*4, hdsp->iobase+HDSP_9652_peakBase-i*4, 4) != 0) + return -EFAULT; + if (copy_to_user_fromio((void *)peak_rms->playback_peaks+i*4, hdsp->iobase+HDSP_9652_peakBase-(doublespeed ? 14 : 26)*4-i*4, 4) != 0) + return -EFAULT; + if (copy_to_user_fromio((void *)peak_rms->output_peaks+i*4, hdsp->iobase+HDSP_9652_peakBase-2*(doublespeed ? 14 : 26)*4-i*4, 4) != 0) + return -EFAULT; + rms_low = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+i*8) & 0xFFFFFF00; + rms_high = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+i*8+4) & 0xFFFFFF00; + rms_high += (rms_low >> 24); + rms_low <<= 8; + if (copy_to_user((void *)peak_rms->input_rms+i*8, &rms_low, 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->input_rms+i*8+4, &rms_high, 4) != 0) + return -EFAULT; + rms_low = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+(doublespeed ? 14 : 26)*8+i*8) & 0xFFFFFF00; + rms_high = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+(doublespeed ? 14 : 26)*8+i*8+4) & 0xFFFFFF00; + rms_high += (rms_low >> 24); + rms_low <<= 8; + if (copy_to_user((void *)peak_rms->playback_rms+i*8, &rms_low, 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->playback_rms+i*8+4, &rms_high, 4) != 0) + return -EFAULT; + rms_low = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+2*(doublespeed ? 14 : 26)*8+i*8) & 0xFFFFFF00; + rms_high = *(u32 *)(hdsp->iobase+HDSP_9652_rmsBase+2*(doublespeed ? 14 : 26)*8+i*8+4) & 0xFFFFFF00; + rms_high += (rms_low >> 24); + rms_low <<= 8; + if (copy_to_user((void *)peak_rms->output_rms+i*8, &rms_low, 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->output_rms+i*8+4, &rms_high, 4) != 0) + return -EFAULT; + } + } + return 0; + } + if (hdsp->io_type == H9632) { + int j; + hdsp_9632_meters_t *m; + int doublespeed = 0; + if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DoubleSpeedStatus) + doublespeed = 1; + m = (hdsp_9632_meters_t *)(hdsp->iobase+HDSP_9632_metersBase); + peak_rms = (hdsp_peak_rms_t *)arg; + for (i = 0, j = 0; i < 16; ++i, ++j) { + if (copy_to_user((void *)peak_rms->input_peaks+i*4, &(m->input_peak[j]), 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->playback_peaks+i*4, &(m->playback_peak[j]), 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->output_peaks+i*4, &(m->output_peak[j]), 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->input_rms+i*8, &(m->input_rms_low[j]), 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->playback_rms+i*8, &(m->playback_rms_low[j]), 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->output_rms+i*8, &(m->output_rms_low[j]), 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->input_rms+i*8+4, &(m->input_rms_high[j]), 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->playback_rms+i*8+4, &(m->playback_rms_high[j]), 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->output_rms+i*8+4, &(m->output_rms_high[j]), 4) != 0) + return -EFAULT; + if (doublespeed && i == 3) i += 4; + } + return 0; } if (!(hdsp->state & HDSP_FirmwareLoaded)) { snd_printk("firmware needs to be uploaded to the card.\n"); return -EINVAL; } peak_rms = (hdsp_peak_rms_t *)arg; - if (copy_to_user_fromio((void *)peak_rms->playback_peaks, hdsp->iobase+HDSP_playbackPeakLevel, 26*4) != 0) { - return -EFAULT; - } - if (copy_to_user_fromio((void *)peak_rms->input_peaks, hdsp->iobase+HDSP_inputPeakLevel, 26*4) != 0) { - return -EFAULT; - } - if (copy_to_user_fromio((void *)peak_rms->output_peaks, hdsp->iobase+HDSP_outputPeakLevel, 28*4) != 0) { - return -EFAULT; - } - if (copy_to_user_fromio((void *)peak_rms->playback_rms, hdsp->iobase+HDSP_playbackRmsLevel, 26*8) != 0) { - return -EFAULT; - } - if (copy_to_user_fromio((void *)peak_rms->input_rms, hdsp->iobase+HDSP_inputRmsLevel, 26*8) != 0) { - return -EFAULT; + for (i = 0; i < 26; ++i) { + if (copy_to_user((void *)peak_rms->playback_peaks+i*4, (void *)hdsp->iobase+HDSP_playbackPeakLevel+i*4, 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->input_peaks+i*4, (void *)hdsp->iobase+HDSP_inputPeakLevel+i*4, 4) != 0) + return -EFAULT; + } + for (i = 0; i < 26; ++i) { + if (copy_to_user((void *)peak_rms->playback_rms+i*8+4, (void *)hdsp->iobase+HDSP_playbackRmsLevel+i*8, 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->playback_rms+i*8, (void *)hdsp->iobase+HDSP_playbackRmsLevel+i*8+4, 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->input_rms+i*8+4, (void *)hdsp->iobase+HDSP_inputRmsLevel+i*8, 4) != 0) + return -EFAULT; + if (copy_to_user((void *)peak_rms->input_rms+i*8, (void *)hdsp->iobase+HDSP_inputRmsLevel+i*8+4, 4) != 0) + return -EFAULT; + } + for (i = 0; i < 28; ++i) { + if (copy_to_user((void *)peak_rms->output_peaks+i*4, (void *)hdsp->iobase+HDSP_outputPeakLevel+i*4, 4) != 0) + return -EFAULT; } break; } @@ -3823,7 +4629,7 @@ hdsp_config_info_t info; unsigned long flags; int i; - + if (!(hdsp->state & HDSP_FirmwareLoaded)) { snd_printk("Firmware needs to be uploaded to the card.\n"); return -EINVAL; @@ -3831,9 +4637,11 @@ spin_lock_irqsave(&hdsp->lock, flags); info.pref_sync_ref = (unsigned char)hdsp_pref_sync_ref(hdsp); info.wordclock_sync_check = (unsigned char)hdsp_wc_sync_check(hdsp); - info.adatsync_sync_check = (unsigned char)hdsp_adatsync_sync_check(hdsp); + if (hdsp->io_type != H9632) { + info.adatsync_sync_check = (unsigned char)hdsp_adatsync_sync_check(hdsp); + } info.spdif_sync_check = (unsigned char)hdsp_spdif_sync_check(hdsp); - for (i = 0; i < ((hdsp->io_type != Multiface) ? 3 : 1); ++i) { + for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != H9632) ? 3 : 1); ++i) { info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i); } info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp); @@ -3849,16 +4657,36 @@ info.autosync_ref = (unsigned char)hdsp_autosync_ref(hdsp); info.line_out = (unsigned char)hdsp_line_out(hdsp); info.passthru = (unsigned char)hdsp->passthru; + if (hdsp->io_type == H9632) { + info.da_gain = (unsigned char)hdsp_da_gain(hdsp); + info.ad_gain = (unsigned char)hdsp_ad_gain(hdsp); + info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp); + info.xlr_breakout_cable = (unsigned char)hdsp_xlr_breakout_cable(hdsp); + + } + if (hdsp->io_type == H9632 || hdsp->io_type == H9652) { + info.analog_extension_board = (unsigned char)hdsp_aeb(hdsp); + } spin_unlock_irqrestore(&hdsp->lock, flags); if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; break; } + case SNDRV_HDSP_IOCTL_GET_9632_AEB: { + hdsp_9632_aeb_t h9632_aeb; + + if (hdsp->io_type != H9632) return -EINVAL; + h9632_aeb.aebi = hdsp->ss_in_channels - H9632_SS_CHANNELS; + h9632_aeb.aebo = hdsp->ss_out_channels - H9632_SS_CHANNELS; + if (copy_to_user((void *)arg, &h9632_aeb, sizeof(h9632_aeb))) + return -EFAULT; + break; + } case SNDRV_HDSP_IOCTL_GET_VERSION: { hdsp_version_t hdsp_version; int err; - - if (hdsp->io_type == H9652) return -EINVAL; + + if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return -EINVAL; if (hdsp->io_type == Undefined) { if ((err = hdsp_get_iobox_version(hdsp)) < 0) { return err; @@ -3875,17 +4703,18 @@ hdsp_firmware_t *firmware; unsigned long *firmware_data; int err; - - if (hdsp->io_type == H9652) return -EINVAL; + + if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return -EINVAL; /* SNDRV_HDSP_IOCTL_GET_VERSION must have been called */ if (hdsp->io_type == Undefined) return -EINVAL; snd_printk("initializing firmware upload\n"); firmware = (hdsp_firmware_t *)arg; + if (get_user(firmware_data, &firmware->firmware_data)) { return -EFAULT; } - + if (hdsp_check_for_iobox (hdsp)) { return -EIO; } @@ -3900,7 +4729,6 @@ return err; } - if (!(hdsp->state & HDSP_InitializationComplete)) { snd_hdsp_initialize_channels(hdsp); @@ -3914,8 +4742,8 @@ break; } case SNDRV_HDSP_IOCTL_GET_MIXER: { - hdsp_mixer_t *mixer; - + hdsp_mixer_t *mixer; + mixer = (hdsp_mixer_t *)arg; if (copy_to_user(mixer->matrix, hdsp->mixer_matrix, sizeof(unsigned short)*HDSP_MATRIX_MIXER_SIZE)) return -EFAULT; @@ -4011,7 +4839,7 @@ return -EIO; } - for (i = 0; i < HDSP_MAX_CHANNELS; ++i) { + for (i = 0; i < hdsp->max_channels; ++i) { hdsp_write (hdsp, HDSP_inputEnable + (4 * i), 1); hdsp_write (hdsp, HDSP_outputEnable + (4 * i), 1); } @@ -4021,24 +4849,41 @@ static inline void snd_hdsp_initialize_channels(hdsp_t *hdsp) { + int status, aebi_channels, aebo_channels; + switch (hdsp->io_type) { case Digiface: hdsp->card_name = "RME Hammerfall DSP + Digiface"; - hdsp->ss_channels = DIGIFACE_SS_CHANNELS; - hdsp->ds_channels = DIGIFACE_DS_CHANNELS; + hdsp->ss_in_channels = hdsp->ss_out_channels = DIGIFACE_SS_CHANNELS; + hdsp->ds_in_channels = hdsp->ds_out_channels = DIGIFACE_DS_CHANNELS; break; case H9652: hdsp->card_name = "RME Hammerfall HDSP 9652"; - hdsp->ss_channels = H9652_SS_CHANNELS; - hdsp->ds_channels = H9652_DS_CHANNELS; + hdsp->ss_in_channels = hdsp->ss_out_channels = H9652_SS_CHANNELS; + hdsp->ds_in_channels = hdsp->ds_out_channels = H9652_DS_CHANNELS; + break; + + case H9632: + status = hdsp_read(hdsp, HDSP_statusRegister); + /* HDSP_AEBx bits are low when AEB are connected */ + aebi_channels = (status & HDSP_AEBI) ? 0 : 4; + aebo_channels = (status & HDSP_AEBO) ? 0 : 4; + hdsp->card_name = "RME Hammerfall HDSP 9632"; + hdsp->ss_in_channels = H9632_SS_CHANNELS+aebi_channels; + hdsp->ds_in_channels = H9632_DS_CHANNELS+aebi_channels; + hdsp->qs_in_channels = H9632_QS_CHANNELS+aebi_channels; + hdsp->ss_out_channels = H9632_SS_CHANNELS+aebo_channels; + hdsp->ds_out_channels = H9632_DS_CHANNELS+aebo_channels; + hdsp->qs_out_channels = H9632_QS_CHANNELS+aebo_channels; break; case Multiface: hdsp->card_name = "RME Hammerfall DSP + Multiface"; - hdsp->ss_channels = MULTIFACE_SS_CHANNELS; - hdsp->ds_channels = MULTIFACE_DS_CHANNELS; - + hdsp->ss_in_channels = hdsp->ss_out_channels = MULTIFACE_SS_CHANNELS; + hdsp->ds_in_channels = hdsp->ds_out_channels = MULTIFACE_DS_CHANNELS; + break; + default: /* should never get here */ break; @@ -4056,38 +4901,40 @@ int err; if ((err = snd_hdsp_create_pcm(card, hdsp)) < 0) { + snd_printk("Error creating pcm interface\n"); return err; } + if ((err = snd_hdsp_create_midi(card, hdsp, 0)) < 0) { + snd_printk("Error creating first midi interface\n"); return err; } + if ((err = snd_hdsp_create_midi(card, hdsp, 1)) < 0) { + snd_printk("Error creating second midi interface\n"); return err; } if ((err = snd_hdsp_create_controls(card, hdsp)) < 0) { + snd_printk("Error creating ctl interface\n"); return err; } snd_hdsp_proc_init(hdsp); - hdsp->last_spdif_sample_rate = -1; hdsp->system_sample_rate = -1; - hdsp->last_external_sample_rate = -1; - hdsp->last_internal_sample_rate = -1; hdsp->playback_pid = -1; hdsp->capture_pid = -1; hdsp->capture_substream = NULL; hdsp->playback_substream = NULL; if ((err = snd_hdsp_set_defaults(hdsp)) < 0) { + snd_printk("Error setting default values\n"); return err; } - hdsp_update_simple_mixer_controls(hdsp); - if (!(hdsp->state & HDSP_InitializationComplete)) { sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name, hdsp->port, hdsp->irq); @@ -4108,8 +4955,8 @@ { struct pci_dev *pci = hdsp->pci; int err; - int i; int is_9652 = 0; + int is_9632 = 0; hdsp->irq = -1; hdsp->state = 0; @@ -4123,9 +4970,10 @@ spin_lock_init(&hdsp->midi[1].lock); hdsp->iobase = 0; hdsp->res_port = 0; + hdsp->control_register = 0; + hdsp->control2_register = 0; hdsp->io_type = Undefined; - for (i = 0; i < HDSP_MAX_CHANNELS; ++i) - hdsp->playback_mixer_ctls[i] = 0; + hdsp->max_channels = 26; hdsp->card = card; @@ -4134,6 +4982,16 @@ tasklet_init(&hdsp->midi_tasklet, hdsp_midi_tasklet, (unsigned long)hdsp); pci_read_config_word(hdsp->pci, PCI_CLASS_REVISION, &hdsp->firmware_rev); + + /* From Martin Bjoernsen : + "It is important that the card's latency timer register in + the PCI configuration space is set to a value much larger + than 0 by the computer's BIOS or the driver. + The windows driver always sets this 8 bit register [...] + to its maximum 255 to avoid problems with some computers." + */ + pci_write_config_byte(hdsp->pci, PCI_LATENCY_TIMER, 0xFF); + strcpy(card->driver, "H-DSP"); strcpy(card->mixername, "Xilinx FPGA"); @@ -4150,7 +5008,11 @@ hdsp->card_name = "RME HDSP 9652"; is_9652 = 1; break; - + case 0x96: + hdsp->card_name = "RME HDSP 9632"; + hdsp->max_channels = 16; + is_9632 = 1; + break; default: return -ENODEV; } @@ -4185,7 +5047,7 @@ return err; } - if (!is_9652 && hdsp_check_for_iobox (hdsp)) { + if (!is_9652 && !is_9632 && hdsp_check_for_iobox (hdsp)) { /* no iobox connected, we defer initialization */ snd_printk("card initialization pending : waiting for firmware\n"); if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) { @@ -4216,7 +5078,10 @@ if (is_9652) { hdsp->io_type = H9652; - snd_hdsp_9652_enable_mixer (hdsp); + } + + if (is_9632) { + hdsp->io_type = H9632; } if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) { @@ -4289,6 +5154,7 @@ card->private_free = snd_hdsp_card_free; hdsp->dev = dev; hdsp->pci = pci; + snd_card_set_dev(card, &pci->dev); if ((err = snd_hdsp_create(card, hdsp, precise_ptr[dev])) < 0) { snd_card_free(card); diff -Nru a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c --- a/sound/pci/rme9652/rme9652.c Mon Feb 2 22:07:56 2004 +++ b/sound/pci/rme9652/rme9652.c Mon Feb 2 22:07:56 2004 @@ -1618,7 +1618,6 @@ RME9652_SPDIF_RATE("IEC958 Sample Rate", 0), RME9652_ADAT_SYNC("ADAT1 Sync Check", 0, 0), RME9652_ADAT_SYNC("ADAT2 Sync Check", 0, 1), -RME9652_ADAT_SYNC("ADAT3 Sync Check", 0, 2), RME9652_TC_VALID("Timecode Valid", 0), RME9652_PASSTHRU("Passthru", 0) }; @@ -1835,7 +1834,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(rme9652->card, "rme9652", &entry)) - snd_info_set_text_ops(entry, rme9652, snd_rme9652_proc_read); + snd_info_set_text_ops(entry, rme9652, 1024, snd_rme9652_proc_read); } static void snd_rme9652_free_buffers(rme9652_t *rme9652) @@ -2705,6 +2704,7 @@ card->private_free = snd_rme9652_card_free; rme9652->dev = dev; rme9652->pci = pci; + snd_card_set_dev(card, &pci->dev); if ((err = snd_rme9652_create(card, rme9652, precise_ptr[dev])) < 0) { snd_card_free(card); diff -Nru a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c --- a/sound/pci/sonicvibes.c Mon Feb 2 22:07:57 2004 +++ b/sound/pci/sonicvibes.c Mon Feb 2 22:07:57 2004 @@ -1177,7 +1177,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(sonic->card, "sonicvibes", &entry)) - snd_info_set_text_ops(entry, sonic, snd_sonicvibes_proc_read); + snd_info_set_text_ops(entry, sonic, 1024, snd_sonicvibes_proc_read); } /* @@ -1249,11 +1249,11 @@ if ((err = pci_enable_device(pci)) < 0) return err; /* check, if we can restrict PCI DMA transfers to 24 bits */ - if (!pci_dma_supported(pci, 0x00ffffff)) { + if (pci_set_dma_mask(pci, 0x00ffffff) < 0 || + pci_set_consistent_dma_mask(pci, 0x00ffffff) < 0) { snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x00ffffff); sonic = snd_magic_kcalloc(sonicvibes_t, 0, GFP_KERNEL); if (sonic == NULL) @@ -1384,6 +1384,8 @@ return err; } + snd_card_set_dev(card, &pci->dev); + *rsonic = sonic; return 0; } @@ -1467,6 +1469,15 @@ snd_card_free(card); return err; } + + strcpy(card->driver, "SonicVibes"); + strcpy(card->shortname, "S3 SonicVibes"); + sprintf(card->longname, "%s rev %i at 0x%lx, irq %i", + card->shortname, + sonic->revision, + pci_resource_start(pci, 1), + sonic->irq); + if ((err = snd_sonicvibes_pcm(sonic, 0, NULL)) < 0) { snd_card_free(card); return err; @@ -1497,13 +1508,6 @@ sonic->gameport.io = sonic->game_port; gameport_register_port(&sonic->gameport); #endif - strcpy(card->driver, "SonicVibes"); - strcpy(card->shortname, "S3 SonicVibes"); - sprintf(card->longname, "%s rev %i at 0x%lx, irq %i", - card->shortname, - sonic->revision, - pci_resource_start(pci, 1), - sonic->irq); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); diff -Nru a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c --- a/sound/pci/trident/trident.c Mon Feb 2 22:07:55 2004 +++ b/sound/pci/trident/trident.c Mon Feb 2 22:07:55 2004 @@ -106,6 +106,30 @@ snd_card_free(card); return err; } + + switch (trident->device) { + case TRIDENT_DEVICE_ID_DX: + str = "TRID4DWAVEDX"; + break; + case TRIDENT_DEVICE_ID_NX: + str = "TRID4DWAVENX"; + break; + case TRIDENT_DEVICE_ID_SI7018: + str = "SI7018"; + break; + default: + str = "Unknown"; + } + strcpy(card->driver, str); + if (trident->device == TRIDENT_DEVICE_ID_SI7018) { + strcpy(card->shortname, "SiS "); + } else { + strcpy(card->shortname, "Trident "); + } + strcat(card->shortname, card->driver); + sprintf(card->longname, "%s PCI Audio at 0x%lx, irq %d", + card->shortname, trident->port, trident->irq); + if ((err = snd_trident_pcm(trident, pcm_dev++, NULL)) < 0) { snd_card_free(card); return err; @@ -140,29 +164,6 @@ #endif snd_trident_gameport(trident); - - switch (trident->device) { - case TRIDENT_DEVICE_ID_DX: - str = "TRID4DWAVEDX"; - break; - case TRIDENT_DEVICE_ID_NX: - str = "TRID4DWAVENX"; - break; - case TRIDENT_DEVICE_ID_SI7018: - str = "SI7018"; - break; - default: - str = "Unknown"; - } - strcpy(card->driver, str); - if (trident->device == TRIDENT_DEVICE_ID_SI7018) { - strcpy(card->shortname, "SiS "); - } else { - strcpy(card->shortname, "Trident "); - } - strcat(card->shortname, card->driver); - sprintf(card->longname, "%s PCI Audio at 0x%lx, irq %d", - card->shortname, trident->port, trident->irq); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); diff -Nru a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c --- a/sound/pci/trident/trident_main.c Mon Feb 2 22:07:57 2004 +++ b/sound/pci/trident/trident_main.c Mon Feb 2 22:07:57 2004 @@ -2955,6 +2955,7 @@ static int __devinit snd_trident_mixer(trident_t * trident, int pcm_spdif_device) { + ac97_bus_t _bus; ac97_t _ac97; snd_card_t * card = trident->card; snd_kcontrol_t *kctl; @@ -2965,14 +2966,18 @@ if (!uctl) return -ENOMEM; + memset(&_bus, 0, sizeof(_bus)); + _bus.write = snd_trident_codec_write; + _bus.read = snd_trident_codec_read; + if ((err = snd_ac97_bus(trident->card, &_bus, &trident->ac97_bus)) < 0) + goto __out; + memset(&_ac97, 0, sizeof(_ac97)); - _ac97.write = snd_trident_codec_write; - _ac97.read = snd_trident_codec_read; _ac97.private_data = trident; trident->ac97_detect = 1; __again: - if ((err = snd_ac97_mixer(trident->card, &_ac97, &trident->ac97)) < 0) { + if ((err = snd_ac97_mixer(trident->ac97_bus, &_ac97, &trident->ac97)) < 0) { if (trident->device == TRIDENT_DEVICE_ID_SI7018) { if ((err = snd_trident_sis_reset(trident)) < 0) goto __out; @@ -2987,7 +2992,7 @@ if (trident->device == TRIDENT_DEVICE_ID_SI7018 && (inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL)) & SI_AC97_PRIMARY_READY) != 0) { _ac97.num = 1; - err = snd_ac97_mixer(trident->card, &_ac97, &trident->ac97_sec); + err = snd_ac97_mixer(trident->ac97_bus, &_ac97, &trident->ac97_sec); if (err < 0) snd_printk("SI7018: the secondary codec - invalid access\n"); #if 0 // only for my testing purpose --jk @@ -3295,7 +3300,7 @@ if (trident->device == TRIDENT_DEVICE_ID_SI7018) s = "sis7018"; if (! snd_card_proc_new(trident->card, s, &entry)) - snd_info_set_text_ops(entry, trident, snd_trident_proc_read); + snd_info_set_text_ops(entry, trident, 1024, snd_trident_proc_read); } static int snd_trident_dev_free(snd_device_t *device) @@ -3518,11 +3523,11 @@ if ((err = pci_enable_device(pci)) < 0) return err; /* check, if we can restrict PCI DMA transfers to 30 bits */ - if (!pci_dma_supported(pci, 0x3fffffff)) { + if (pci_set_dma_mask(pci, 0x3fffffff) < 0 || + pci_set_consistent_dma_mask(pci, 0x3fffffff) < 0) { snd_printk("architecture does not support 30bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x3fffffff); trident = snd_magic_kcalloc(trident_t, 0, GFP_KERNEL); if (trident == NULL) @@ -3624,6 +3629,7 @@ snd_trident_free(trident); return err; } + snd_card_set_dev(card, &pci->dev); *rtrident = trident; return 0; } @@ -3947,7 +3953,9 @@ return; pci_enable_device(trident->pci); - pci_set_dma_mask(trident->pci, 0x3fffffff); /* to be sure */ + if (pci_set_dma_mask(trident->pci, 0x3fffffff) < 0 || + pci_set_consistent_dma_mask(trident->pci, 0x3fffffff) < 0) + snd_printk(KERN_WARNING "trident: can't set the proper DMA mask\n"); pci_set_master(trident->pci); /* to be sure */ switch (trident->device) { diff -Nru a/sound/pci/via82xx.c b/sound/pci/via82xx.c --- a/sound/pci/via82xx.c Mon Feb 2 22:07:58 2004 +++ b/sound/pci/via82xx.c Mon Feb 2 22:07:58 2004 @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -69,10 +70,17 @@ MODULE_CLASSES("{sound}"); MODULE_DEVICES("{{VIA,VT82C686A/B/C,pci},{VIA,VT8233A/C,8235}}"); +#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#define SUPPORT_JOYSTICK 1 +#endif + 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_PNP; /* Enable this card */ -static long mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1}; +static long mpu_port[SNDRV_CARDS]; +#ifdef SUPPORT_JOYSTICK +static int joystick[SNDRV_CARDS]; +#endif static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000}; static int dxs_support[SNDRV_CARDS]; @@ -86,14 +94,19 @@ MODULE_PARM_DESC(enable, "Enable audio part of VIA 82xx bridge."); MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); MODULE_PARM(mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); -MODULE_PARM_DESC(mpu_port, "MPU-401 port."); +MODULE_PARM_DESC(mpu_port, "MPU-401 port. (VT82C686x only)"); MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT_DESC); +#ifdef SUPPORT_JOYSTICK +MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(joystick, "Enable joystick. (VT82C686x only)"); +MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLE_DESC "," SNDRV_BOOLEAN_FALSE_DESC); +#endif MODULE_PARM(ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:48000"); MODULE_PARM(dxs_support, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); -MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only)"); -MODULE_PARM_SYNTAX(dxs_support, SNDRV_ENABLED ",allows:{{0,3}},dialog:list"); +MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA)"); +MODULE_PARM_SYNTAX(dxs_support, SNDRV_ENABLED ",allows:{{0,4}},dialog:list"); /* pci ids */ @@ -235,6 +248,8 @@ #define VIA_REG_OFS_CAPTURE_FIFO 0x02 /* byte - bit 6 = fifo enable */ #define VIA_REG_CAPTURE_FIFO_ENABLE 0x40 +#define VIA_DXS_MAX_VOLUME 31 /* max. volume (attenuation) of reg 0x32/33 */ + #define VIA_REG_CAPTURE_CHANNEL 0x63 /* byte - input select */ #define VIA_REG_CAPTURE_CHANNEL_MIC 0x4 #define VIA_REG_CAPTURE_CHANNEL_LINE 0 @@ -290,6 +305,7 @@ #define VIA_DXS_ENABLE 1 #define VIA_DXS_DISABLE 2 #define VIA_DXS_48K 3 +#define VIA_DXS_NO_VRA 4 /* @@ -449,9 +465,11 @@ viadev_t devs[VIA_MAX_DEVS]; struct via_rate_lock rates[2]; /* playback and capture */ unsigned int dxs_fixed: 1; /* DXS channel accepts only 48kHz */ + unsigned int no_vra: 1; /* no need to set VRA on DXS channels */ snd_rawmidi_t *rmidi; + ac97_bus_t *ac97_bus; ac97_t *ac97; unsigned int ac97_clock; unsigned int ac97_secondary; /* secondary AC'97 codec is present */ @@ -459,6 +477,11 @@ spinlock_t reg_lock; spinlock_t ac97_lock; snd_info_entry_t *proc_entry; + +#ifdef SUPPORT_JOYSTICK + struct gameport gameport; + struct resource *res_joystick; +#endif }; static struct pci_device_id snd_via82xx_ids[] = { @@ -509,7 +532,6 @@ if ((val = snd_via82xx_codec_xread(chip)) & stat) return val & 0xffff; } - snd_printk(KERN_ERR "codec_valid: codec %i is not valid [0x%x]\n", secondary, snd_via82xx_codec_xread(chip)); return -EIO; } @@ -554,6 +576,7 @@ while (1) { if (again++ > 3) { spin_unlock(&chip->ac97_lock); + snd_printk(KERN_ERR "codec_read: codec %i is not valid [0x%x]\n", ac97->num, snd_via82xx_codec_xread(chip)); return 0xffff; } snd_via82xx_codec_xwrite(chip, xval); @@ -865,12 +888,12 @@ spin_lock(&rec->lock); if (rec->rate != rate) { - if (rec->rate && rec->used > 1) { /* already set */ - spin_unlock(&rec->lock); - return -EINVAL; + if (rec->rate && rec->used > 1) /* already set */ + changed = -EINVAL; + else { + rec->rate = rate; + changed = 1; } - rec->rate = rate; - changed = 1; } spin_unlock(&rec->lock); return changed; @@ -890,9 +913,8 @@ if ((rate_changed = via_lock_rate(&chip->rates[0], runtime->rate)) < 0) return rate_changed; if (rate_changed) { - snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate); - snd_ac97_set_rate(chip->ac97, AC97_PCM_SURR_DAC_RATE, runtime->rate); - snd_ac97_set_rate(chip->ac97, AC97_PCM_LFE_DAC_RATE, runtime->rate); + snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, + chip->no_vra ? 48000 : runtime->rate); snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate); } #if 0 @@ -1382,7 +1404,7 @@ static int snd_via8233_capture_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { via82xx_t *chip = snd_kcontrol_chip(kcontrol); - unsigned long port = chip->port + kcontrol->id.index ? (VIA_REG_CAPTURE_CHANNEL + 0x10) : VIA_REG_CAPTURE_CHANNEL; + unsigned long port = chip->port + (kcontrol->id.index ? (VIA_REG_CAPTURE_CHANNEL + 0x10) : VIA_REG_CAPTURE_CHANNEL); ucontrol->value.enumerated.item[0] = inb(port) & VIA_REG_CAPTURE_CHANNEL_MIC ? 1 : 0; return 0; } @@ -1390,7 +1412,7 @@ static int snd_via8233_capture_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { via82xx_t *chip = snd_kcontrol_chip(kcontrol); - unsigned long port = chip->port + kcontrol->id.index ? (VIA_REG_CAPTURE_CHANNEL + 0x10) : VIA_REG_CAPTURE_CHANNEL; + unsigned long port = chip->port + (kcontrol->id.index ? (VIA_REG_CAPTURE_CHANNEL + 0x10) : VIA_REG_CAPTURE_CHANNEL); unsigned long flags; u8 val, oval; @@ -1461,7 +1483,7 @@ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; - uinfo->value.integer.max = 0xff; + uinfo->value.integer.max = VIA_DXS_MAX_VOLUME; return 0; } @@ -1469,8 +1491,8 @@ { via82xx_t *chip = snd_kcontrol_chip(kcontrol); unsigned int idx = snd_ctl_get_ioff(kcontrol, &ucontrol->id); - ucontrol->value.integer.value[0] = 0xff - chip->playback_volume[idx][0]; - ucontrol->value.integer.value[1] = 0xff - chip->playback_volume[idx][1]; + ucontrol->value.integer.value[0] = VIA_DXS_MAX_VOLUME - chip->playback_volume[idx][0]; + ucontrol->value.integer.value[1] = VIA_DXS_MAX_VOLUME - chip->playback_volume[idx][1]; return 0; } @@ -1480,19 +1502,18 @@ unsigned int idx = snd_ctl_get_ioff(kcontrol, &ucontrol->id); unsigned long port = chip->port + 0x10 * idx; unsigned char val; - int change; + int i, change = 0; - val = 0xff - ucontrol->value.integer.value[0]; - change = val != chip->playback_volume[idx][0]; - if (change) { - chip->playback_volume[idx][0] = val; - outb(val, port + VIA_REG_OFS_PLAYBACK_VOLUME_L); - } - val = 0xff - ucontrol->value.integer.value[1]; - change |= val != chip->playback_volume[idx][1]; - if (change) { - chip->playback_volume[idx][1] = val; - outb(val, port + VIA_REG_OFS_PLAYBACK_VOLUME_R); + for (i = 0; i < 2; i++) { + val = ucontrol->value.integer.value[i]; + if (val > VIA_DXS_MAX_VOLUME) + val = VIA_DXS_MAX_VOLUME; + val = VIA_DXS_MAX_VOLUME - val; + change |= val != chip->playback_volume[idx][i]; + if (change) { + chip->playback_volume[idx][i] = val; + outb(val, port + VIA_REG_OFS_PLAYBACK_VOLUME_L + i); + } } return change; } @@ -1509,6 +1530,12 @@ /* */ +static void snd_via82xx_mixer_free_ac97_bus(ac97_bus_t *bus) +{ + via82xx_t *chip = snd_magic_cast(via82xx_t, bus->private_data, return); + chip->ac97_bus = NULL; +} + static void snd_via82xx_mixer_free_ac97(ac97_t *ac97) { via82xx_t *chip = snd_magic_cast(via82xx_t, ac97->private_data, return); @@ -1516,29 +1543,42 @@ } static struct ac97_quirk ac97_quirks[] = { - { + { /* FIXME: which codec? */ .vendor = 0x1106, .device = 0x4161, .name = "ASRock K7VT2", .type = AC97_TUNE_HP_ONLY }, + { + .vendor = 0x1849, + .device = 0x3059, + .name = "ASRock K7VM2", + .type = AC97_TUNE_HP_ONLY /* VT1616 */ + }, { } /* terminator */ }; static int __devinit snd_via82xx_mixer_new(via82xx_t *chip) { + ac97_bus_t bus; ac97_t ac97; int err; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_via82xx_codec_write; + bus.read = snd_via82xx_codec_read; + bus.wait = snd_via82xx_codec_wait; + bus.private_data = chip; + bus.private_free = snd_via82xx_mixer_free_ac97_bus; + bus.clock = chip->ac97_clock; + if ((err = snd_ac97_bus(chip->card, &bus, &chip->ac97_bus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_via82xx_codec_write; - ac97.read = snd_via82xx_codec_read; - ac97.wait = snd_via82xx_codec_wait; ac97.private_data = chip; ac97.private_free = snd_via82xx_mixer_free_ac97; - ac97.clock = chip->ac97_clock; ac97.pci = chip->pci; - if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0) + if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) return err; snd_ac97_tune_hardware(chip->ac97, ac97_quirks); @@ -1552,53 +1592,6 @@ } /* - * joystick - */ - -static int snd_via82xx_joystick_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int snd_via82xx_joystick_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - via82xx_t *chip = snd_kcontrol_chip(kcontrol); - u16 val; - - pci_read_config_word(chip->pci, VIA_FUNC_ENABLE, &val); - ucontrol->value.integer.value[0] = (val & VIA_FUNC_ENABLE_GAME) ? 1 : 0; - return 0; -} - -static int snd_via82xx_joystick_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - via82xx_t *chip = snd_kcontrol_chip(kcontrol); - u16 val, oval; - - pci_read_config_word(chip->pci, VIA_FUNC_ENABLE, &oval); - val = oval & ~VIA_FUNC_ENABLE_GAME; - if (ucontrol->value.integer.value[0]) - val |= VIA_FUNC_ENABLE_GAME; - if (val != oval) { - pci_write_config_word(chip->pci, VIA_FUNC_ENABLE, val); - return 1; - } - return 0; -} - -static snd_kcontrol_new_t snd_via82xx_joystick_control __devinitdata = { - .name = "Joystick", - .iface = SNDRV_CTL_ELEM_IFACE_CARD, - .info = snd_via82xx_joystick_info, - .get = snd_via82xx_joystick_get, - .put = snd_via82xx_joystick_put, -}; - -/* * */ @@ -1653,7 +1646,7 @@ "VIA82xx MPU401")) != NULL) { legacy |= VIA_FUNC_ENABLE_MIDI; } else { - mpu_port[dev] = -1; + mpu_port[dev] = 0; legacy &= ~VIA_FUNC_ENABLE_MIDI; } } else { @@ -1680,8 +1673,18 @@ if (rev_h) legacy &= ~VIA_FUNC_MIDI_PNP; /* disable PCI I/O 2 */ legacy &= ~VIA_FUNC_ENABLE_MIDI; - mpu_port[dev] = -1; + mpu_port[dev] = 0; + } + +#ifdef SUPPORT_JOYSTICK +#define JOYSTICK_ADDR 0x200 + if (joystick[dev] && + (chip->res_joystick = request_region(JOYSTICK_ADDR, 8, "VIA686 gameport")) != NULL) { + legacy |= VIA_FUNC_ENABLE_GAME; + chip->gameport.io = JOYSTICK_ADDR; } +#endif + pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, legacy); pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, legacy_cfg); if (chip->mpu_res) { @@ -1695,9 +1698,13 @@ } pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, legacy); } - - /* card switches */ - return snd_ctl_add(chip->card, snd_ctl_new1(&snd_via82xx_joystick_control, chip)); + +#ifdef SUPPORT_JOYSTICK + if (chip->res_joystick) + gameport_register_port(&chip->gameport); +#endif + + return 0; } @@ -1711,7 +1718,7 @@ snd_iprintf(buffer, "%s\n\n", chip->card->longname); for (i = 0; i < 0xa0; i += 4) { - snd_iprintf(buffer, "%02x: %08x", i, inl(chip->port + i)); + snd_iprintf(buffer, "%02x: %08x\n", i, inl(chip->port + i)); } } @@ -1720,7 +1727,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(chip->card, "via82xx", &entry)) - snd_info_set_text_ops(entry, chip, snd_via82xx_proc_read); + snd_info_set_text_ops(entry, chip, 1024, snd_via82xx_proc_read); } /* @@ -1859,6 +1866,13 @@ if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); if (chip->chip_type == TYPE_VIA686) { +#ifdef SUPPORT_JOYSTICK + if (chip->res_joystick) { + gameport_unregister_port(&chip->gameport); + release_resource(chip->res_joystick); + kfree_nocheck(chip->res_joystick); + } +#endif pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, chip->old_legacy); pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, chip->old_legacy_cfg); } @@ -1937,6 +1951,8 @@ * We call pci_set_master here because it does not hurt. */ pci_set_master(pci); + snd_card_set_dev(card, &pci->dev); + *r_via = chip; return 0; } @@ -1967,8 +1983,22 @@ static int __devinit check_dxs_list(struct pci_dev *pci) { static struct dxs_whitelist whitelist[] = { + { .vendor = 0x1005, .device = 0x4710, .action = VIA_DXS_ENABLE }, /* Avance Logic Mobo */ { .vendor = 0x1019, .device = 0x0996, .action = VIA_DXS_48K }, + { .vendor = 0x1043, .device = 0x8095, .action = VIA_DXS_ENABLE }, /* ASUS A7V8X */ + { .vendor = 0x1043, .device = 0x80a1, .action = VIA_DXS_NO_VRA }, /* ASUS A7V8-X */ + { .vendor = 0x1043, .device = 0x80b0, .action = VIA_DXS_ENABLE }, /* ASUS A7V600 */ + { .vendor = 0x10cf, .device = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ + { .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ + { .vendor = 0x1297, .device = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */ { .vendor = 0x1297, .device = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */ + { .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */ + { .vendor = 0x147b, .device = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */ + { .vendor = 0x14ff, .device = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */ + { .vendor = 0x1462, .device = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */ + { .vendor = 0x1631, .device = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */ + { .vendor = 0x1695, .device = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */ + { .vendor = 0x1849, .device = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ { } /* terminator */ }; struct dxs_whitelist *w; @@ -1994,7 +2024,8 @@ * not detected, try 48k rate only to be sure. */ printk(KERN_INFO "via82xx: Assuming DXS channels with 48k fixed sample rate.\n"); - printk(KERN_INFO " Please try dxs_support=1 option and report if it works on your machine.\n"); + printk(KERN_INFO " Please try dxs_support=1 or dxs_support=4 option\n"); + printk(KERN_INFO " and report if it works on your machine.\n"); return VIA_DXS_48K; }; @@ -2073,12 +2104,14 @@ if (chip_type == TYPE_VIA8233A) { if ((err = snd_via8233a_pcm_new(chip)) < 0) goto __error; - chip->dxs_fixed = 1; /* use 48k for DXS #3 */ + // chip->dxs_fixed = 1; /* FIXME: use 48k for DXS #3? */ } else { if ((err = snd_via8233_pcm_new(chip)) < 0) goto __error; if (dxs_support[dev] == VIA_DXS_48K) chip->dxs_fixed = 1; + else if (dxs_support[dev] == VIA_DXS_NO_VRA) + chip->no_vra = 1; } if ((err = snd_via8233_init_misc(chip, dev)) < 0) goto __error; @@ -2142,7 +2175,7 @@ #ifndef MODULE /* format is: snd-via82xx=enable,index,id, - mpu_port,ac97_clock,dxs_support */ + mpu_port,joystick,ac97_clock,dxs_support */ static int __init alsa_card_via82xx_setup(char *str) { @@ -2153,7 +2186,10 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2 && +#ifdef SUPPORT_JOYSTICK + get_option(&str,&joystick[nr_dev]) == 2 && +#endif get_option(&str,&ac97_clock[nr_dev]) == 2 && get_option(&str,&dxs_support[nr_dev]) == 2); nr_dev++; diff -Nru a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c --- a/sound/pci/vx222/vx222.c Mon Feb 2 22:07:56 2004 +++ b/sound/pci/vx222/vx222.c Mon Feb 2 22:07:56 2004 @@ -192,6 +192,8 @@ return err; } + snd_card_set_dev(card, &pci->dev); + *rchip = vx; return 0; } diff -Nru a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c --- a/sound/pci/ymfpci/ymfpci.c Mon Feb 2 22:07:56 2004 +++ b/sound/pci/ymfpci/ymfpci.c Mon Feb 2 22:07:56 2004 @@ -44,8 +44,11 @@ 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_PNP; /* Enable this card */ -static long fm_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1}; -static long mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1}; +static long fm_port[SNDRV_CARDS]; +static long mpu_port[SNDRV_CARDS]; +#ifdef SUPPORT_JOYSTICK +static long joystick_port[SNDRV_CARDS]; +#endif static int rear_switch[SNDRV_CARDS]; MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); @@ -63,6 +66,11 @@ MODULE_PARM(fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); MODULE_PARM_DESC(fm_port, "FM OPL-3 Port."); MODULE_PARM_SYNTAX(fm_port, SNDRV_ENABLED); +#ifdef SUPPORT_JOYSTICK +MODULE_PARM(joystick_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); +MODULE_PARM_DESC(joystick_port, "Joystick port address"); +MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED); +#endif MODULE_PARM(rear_switch, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch"); MODULE_PARM_SYNTAX(rear_switch, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); @@ -86,6 +94,9 @@ snd_card_t *card; struct resource *fm_res = NULL; struct resource *mpu_res = NULL; +#ifdef SUPPORT_JOYSTICK + struct resource *joystick_res = NULL; +#endif ymfpci_t *chip; opl3_t *opl3; char *str; @@ -117,51 +128,92 @@ legacy_ctrl2 = 0x0800; /* SBEN = 0, SMOD = 01, LAD = 0 */ if (pci_id->device >= 0x0010) { /* YMF 744/754 */ - if (fm_port[dev] < 0) { + if (fm_port[dev] == 1) { + /* auto-detect */ fm_port[dev] = pci_resource_start(pci, 1); } - if (fm_port[dev] >= 0 && + if (fm_port[dev] > 0 && (fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3")) != NULL) { legacy_ctrl |= YMFPCI_LEGACY_FMEN; pci_write_config_word(pci, PCIR_DSXG_FMBASE, fm_port[dev]); } - if (mpu_port[dev] < 0) { + if (mpu_port[dev] == 1) { + /* auto-detect */ mpu_port[dev] = pci_resource_start(pci, 1) + 0x20; } - if (mpu_port[dev] >= 0 && + if (mpu_port[dev] > 0 && (mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401")) != NULL) { legacy_ctrl |= YMFPCI_LEGACY_MEN; pci_write_config_word(pci, PCIR_DSXG_MPU401BASE, mpu_port[dev]); } +#ifdef SUPPORT_JOYSTICK + if (joystick_port[dev] == 1) { + /* auto-detect */ + joystick_port[dev] = pci_resource_start(pci, 2); + } + if (joystick_port[dev] > 0 && + (joystick_res = request_region(joystick_port[dev], 1, "YMFPCI gameport")) != NULL) { + legacy_ctrl |= YMFPCI_LEGACY_JPEN; + pci_write_config_word(pci, PCIR_DSXG_JOYBASE, joystick_port[dev]); + } +#endif } else { switch (fm_port[dev]) { case 0x388: legacy_ctrl2 |= 0; break; case 0x398: legacy_ctrl2 |= 1; break; case 0x3a0: legacy_ctrl2 |= 2; break; case 0x3a8: legacy_ctrl2 |= 3; break; - default: fm_port[dev] = -1; break; + default: fm_port[dev] = 0; break; } if (fm_port[dev] > 0 && (fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3")) != NULL) { legacy_ctrl |= YMFPCI_LEGACY_FMEN; } else { legacy_ctrl2 &= ~YMFPCI_LEGACY2_FMIO; - fm_port[dev] = -1; + fm_port[dev] = 0; } switch (mpu_port[dev]) { case 0x330: legacy_ctrl2 |= 0 << 4; break; case 0x300: legacy_ctrl2 |= 1 << 4; break; case 0x332: legacy_ctrl2 |= 2 << 4; break; case 0x334: legacy_ctrl2 |= 3 << 4; break; - default: mpu_port[dev] = -1; break; + default: mpu_port[dev] = 0; break; } if (mpu_port[dev] > 0 && (mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401")) != NULL) { legacy_ctrl |= YMFPCI_LEGACY_MEN; } else { legacy_ctrl2 &= ~YMFPCI_LEGACY2_MPUIO; - mpu_port[dev] = -1; + mpu_port[dev] = 0; } +#ifdef SUPPORT_JOYSTICK + if (joystick_port[dev] == 1) { + /* auto-detect */ + long p; + for (p = 0x201; p <= 0x205; p++) { + if (p == 0x203) continue; + if ((joystick_res = request_region(p, 1, "YMFPCI gameport")) != NULL) + break; + } + if (joystick_res) + joystick_port[dev] = p; + } + switch (joystick_port[dev]) { + case 0x201: legacy_ctrl2 |= 0 << 6; break; + case 0x202: legacy_ctrl2 |= 1 << 6; break; + case 0x204: legacy_ctrl2 |= 2 << 6; break; + case 0x205: legacy_ctrl2 |= 3 << 6; break; + default: joystick_port[dev] = 0; break; + } + if (! joystick_res && joystick_port[dev] > 0) + joystick_res = request_region(joystick_port[dev], 1, "YMFPCI gameport"); + if (joystick_res) { + legacy_ctrl |= YMFPCI_LEGACY_JPEN; + } else { + legacy_ctrl2 &= ~YMFPCI_LEGACY2_JSIO; + joystick_port[dev] = 0; + } +#endif } if (mpu_res) { legacy_ctrl |= YMFPCI_LEGACY_MIEN; @@ -182,10 +234,25 @@ release_resource(fm_res); kfree_nocheck(fm_res); } +#ifdef SUPPORT_JOYSTICK + if (joystick_res) { + release_resource(joystick_res); + kfree_nocheck(joystick_res); + } +#endif return err; } chip->fm_res = fm_res; chip->mpu_res = mpu_res; +#ifdef SUPPORT_JOYSTICK + chip->joystick_res = joystick_res; +#endif + strcpy(card->driver, str); + sprintf(card->shortname, "Yamaha DS-XG (%s)", str); + sprintf(card->longname, "%s at 0x%lx, irq %i", + card->shortname, + chip->reg_area_phys, + chip->irq); if ((err = snd_ymfpci_pcm(chip, 0, NULL)) < 0) { snd_card_free(card); return err; @@ -206,6 +273,10 @@ snd_card_free(card); return err; } + if ((err = snd_ymfpci_timer(chip, 0)) < 0) { + snd_card_free(card); + return err; + } if (chip->mpu_res) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_YMFPCI, mpu_port[dev], 1, @@ -229,17 +300,12 @@ return err; } } -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) - if ((err = snd_ymfpci_joystick(chip)) < 0) { - printk(KERN_WARNING "ymfpci: cannot initialize joystick, skipping...\n"); +#ifdef SUPPORT_JOYSTICK + if (chip->joystick_res) { + chip->gameport.io = joystick_port[dev]; + gameport_register_port(&chip->gameport); } #endif - strcpy(card->driver, str); - sprintf(card->shortname, "Yamaha DS-XG PCI (%s)", str); - sprintf(card->longname, "%s at 0x%lx, irq %i", - card->shortname, - chip->reg_area_phys, - chip->irq); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); @@ -319,8 +385,8 @@ (void)(get_option(&str,&enable[nr_dev]) == 2 && get_option(&str,&index[nr_dev]) == 2 && get_id(&str,&id[nr_dev]) == 2 && - get_option(&str,(int *)&fm_port[nr_dev]) == 2 && - get_option(&str,(int *)&mpu_port[nr_dev]) == 2); + get_option_long(&str,&fm_port[nr_dev]) == 2 && + get_option_long(&str,&mpu_port[nr_dev]) == 2); nr_dev++; return 1; } diff -Nru a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c --- a/sound/pci/ymfpci/ymfpci_main.c Mon Feb 2 22:07:58 2004 +++ b/sound/pci/ymfpci/ymfpci_main.c Mon Feb 2 22:07:58 2004 @@ -779,7 +779,8 @@ status = snd_ymfpci_readw(chip, YDSXGR_INTFLAG); if (status & 1) { - /* timer handler */ + if (chip->timer) + snd_timer_interrupt(chip->timer, chip->timer->sticks); } snd_ymfpci_writew(chip, YDSXGR_INTFLAG, status); @@ -1135,7 +1136,7 @@ if (rpcm) *rpcm = NULL; - if ((err = snd_pcm_new(chip->card, "YMFPCI - AC'97", device, 0, 1, &pcm)) < 0) + if ((err = snd_pcm_new(chip->card, "YMFPCI - PCM2", device, 0, 1, &pcm)) < 0) return err; pcm->private_data = chip; pcm->private_free = snd_ymfpci_pcm2_free; @@ -1144,7 +1145,8 @@ /* global setup */ pcm->info_flags = 0; - strcpy(pcm->name, "YMFPCI - AC'97"); + sprintf(pcm->name, "YMFPCI - %s", + chip->device_id == PCI_DEVICE_ID_YAMAHA_754 ? "Direct Recording" : "AC'97"); chip->pcm2 = pcm; snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024); @@ -1368,6 +1370,61 @@ .put = snd_ymfpci_spdif_stream_put }; +static int snd_ymfpci_drec_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *info) +{ + static char *texts[3] = {"AC'97", "IEC958", "ZV Port"}; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 3; + if (info->value.enumerated.item > 2) + info->value.enumerated.item = 2; + strcpy(info->value.enumerated.name, texts[info->value.enumerated.item]); + return 0; +} + +static int snd_ymfpci_drec_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value) +{ + ymfpci_t *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + u16 reg; + + spin_lock_irqsave(&chip->reg_lock, flags); + reg = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL); + spin_unlock_irqrestore(&chip->reg_lock, flags); + if (!(reg & 0x100)) + value->value.enumerated.item[0] = 0; + else + value->value.enumerated.item[0] = 1 + ((reg & 0x200) != 0); + return 0; +} + +static int snd_ymfpci_drec_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value) +{ + ymfpci_t *chip = snd_kcontrol_chip(kcontrol); + unsigned long flags; + u16 reg, old_reg; + + spin_lock_irqsave(&chip->reg_lock, flags); + old_reg = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL); + if (value->value.enumerated.item[0] == 0) + reg = old_reg & ~0x100; + else + reg = (old_reg & ~0x300) | 0x100 | ((value->value.enumerated.item[0] == 2) << 9); + snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, reg); + spin_unlock_irqrestore(&chip->reg_lock, flags); + return reg != old_reg; +} + +static snd_kcontrol_new_t snd_ymfpci_drec_source __devinitdata = { + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Direct Recording Source", + .info = snd_ymfpci_drec_source_info, + .get = snd_ymfpci_drec_source_get, + .put = snd_ymfpci_drec_source_put +}; + /* * Mixer controls */ @@ -1651,6 +1708,12 @@ * Mixer routines */ +static void snd_ymfpci_mixer_free_ac97_bus(ac97_bus_t *bus) +{ + ymfpci_t *chip = snd_magic_cast(ymfpci_t, bus->private_data, return); + chip->ac97_bus = NULL; +} + static void snd_ymfpci_mixer_free_ac97(ac97_t *ac97) { ymfpci_t *chip = snd_magic_cast(ymfpci_t, ac97->private_data, return); @@ -1659,17 +1722,24 @@ int __devinit snd_ymfpci_mixer(ymfpci_t *chip, int rear_switch) { + ac97_bus_t bus; ac97_t ac97; snd_kcontrol_t *kctl; unsigned int idx; int err; + memset(&bus, 0, sizeof(bus)); + bus.write = snd_ymfpci_codec_write; + bus.read = snd_ymfpci_codec_read; + bus.private_data = chip; + bus.private_free = snd_ymfpci_mixer_free_ac97_bus; + if ((err = snd_ac97_bus(chip->card, &bus, &chip->ac97_bus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); - ac97.write = snd_ymfpci_codec_write; - ac97.read = snd_ymfpci_codec_read; ac97.private_data = chip; ac97.private_free = snd_ymfpci_mixer_free_ac97; - if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0) + if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) return err; for (idx = 0; idx < YMFPCI_CONTROLS; idx++) { @@ -1690,6 +1760,11 @@ kctl->id.device = chip->pcm_spdif->device; chip->spdif_pcm_ctl = kctl; + /* direct recording source */ + if (chip->device_id == PCI_DEVICE_ID_YAMAHA_754 && + (err = snd_ctl_add(chip->card, kctl = snd_ctl_new1(&snd_ymfpci_drec_source, chip))) < 0) + return err; + /* * shared rear/line-in */ @@ -1703,174 +1778,74 @@ /* - * joystick support + * timer */ -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) -static int ymfpci_joystick_ports[4] = { - 0x201, 0x202, 0x204, 0x205 -}; - -static int snd_ymfpci_get_joystick_port(ymfpci_t *chip, int index) -{ - if (index < 4) - return ymfpci_joystick_ports[index]; - else - return pci_resource_start(chip->pci, 2); -} - -static void setup_joystick_base(ymfpci_t *chip) -{ - if (chip->device_id >= 0x0010) /* YMF 744/754 */ - pci_write_config_word(chip->pci, PCIR_DSXG_JOYBASE, - snd_ymfpci_get_joystick_port(chip, chip->joystick_port)); - else { - u16 legacy_ctrl2; - pci_read_config_word(chip->pci, PCIR_DSXG_ELEGACY, &legacy_ctrl2); - legacy_ctrl2 &= ~YMFPCI_LEGACY2_JSIO; - legacy_ctrl2 |= chip->joystick_port << 6; - pci_write_config_word(chip->pci, PCIR_DSXG_ELEGACY, legacy_ctrl2); - } -} - -static int snd_ymfpci_enable_joystick(ymfpci_t *chip) -{ - u16 val; - - chip->gameport.io = snd_ymfpci_get_joystick_port(chip, chip->joystick_port); - chip->joystick_res = request_region(chip->gameport.io, 1, "YMFPCI gameport"); - if (!chip->joystick_res) { - snd_printk(KERN_WARNING "gameport port %#x in use\n", chip->gameport.io); - return 0; - } - setup_joystick_base(chip); - pci_read_config_word(chip->pci, PCIR_DSXG_LEGACY, &val); - val |= YMFPCI_LEGACY_JPEN; - pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY, val); - gameport_register_port(&chip->gameport); - return 1; -} - -static int snd_ymfpci_disable_joystick(ymfpci_t *chip) -{ - u16 val; - - gameport_unregister_port(&chip->gameport); - pci_read_config_word(chip->pci, PCIR_DSXG_LEGACY, &val); - val &= ~YMFPCI_LEGACY_JPEN; - pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY, val); - release_resource(chip->joystick_res); - kfree_nocheck(chip->joystick_res); - chip->joystick_res = NULL; - return 1; -} - -static int snd_ymfpci_joystick_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; -} - -static int snd_ymfpci_joystick_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +static int snd_ymfpci_timer_start(snd_timer_t *timer) { - ymfpci_t *chip = snd_kcontrol_chip(kcontrol); - u16 val; + ymfpci_t *chip; + unsigned long flags; + unsigned int count; - pci_read_config_word(chip->pci, PCIR_DSXG_LEGACY, &val); - ucontrol->value.integer.value[0] = (val & YMFPCI_LEGACY_JPEN) ? 1 : 0; + chip = snd_timer_chip(timer); + count = timer->sticks - 1; + if (count == 0) /* minimum time is 20.8 us */ + count = 1; + spin_lock_irqsave(&chip->reg_lock, flags); + snd_ymfpci_writew(chip, YDSXGR_TIMERCOUNT, count); + snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x03); + spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } -static int snd_ymfpci_joystick_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - ymfpci_t *chip = snd_kcontrol_chip(kcontrol); - int enabled, change; - - down(&chip->joystick_mutex); - enabled = chip->joystick_res != NULL; - change = enabled != !! ucontrol->value.integer.value[0]; - if (change) { - if (!enabled) - change = snd_ymfpci_enable_joystick(chip); - else - change = snd_ymfpci_disable_joystick(chip); - } - up(&chip->joystick_mutex); - return change; -} - -static int snd_ymfpci_joystick_addr_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +static int snd_ymfpci_timer_stop(snd_timer_t *timer) { - ymfpci_t *chip = snd_kcontrol_chip(kcontrol); - int ports = chip->device_id >= 0x0010 ? 5 : 4; + ymfpci_t *chip; + unsigned long flags; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = ports; - if (uinfo->value.enumerated.item >= ports) - uinfo->value.enumerated.item = ports - 1; - sprintf(uinfo->value.enumerated.name, "port 0x%x", - snd_ymfpci_get_joystick_port(chip, uinfo->value.enumerated.item)); + chip = snd_timer_chip(timer); + spin_lock_irqsave(&chip->reg_lock, flags); + snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x00); + spin_unlock_irqrestore(&chip->reg_lock, flags); return 0; } -static int snd_ymfpci_joystick_addr_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +static int snd_ymfpci_timer_precise_resolution(snd_timer_t *timer, + unsigned long *num, unsigned long *den) { - ymfpci_t *chip = snd_kcontrol_chip(kcontrol); - ucontrol->value.enumerated.item[0] = chip->joystick_port; + *num = 1; + *den = 96000; return 0; } -static int snd_ymfpci_joystick_addr_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - ymfpci_t *chip = snd_kcontrol_chip(kcontrol); - int change, enabled; - - down(&chip->joystick_mutex); - change = ucontrol->value.enumerated.item[0] != chip->joystick_port; - if (change) { - enabled = chip->joystick_res != NULL; - if (enabled) - snd_ymfpci_disable_joystick(chip); - chip->joystick_port = ucontrol->value.enumerated.item[0]; - if (enabled) - snd_ymfpci_enable_joystick(chip); - } - up(&chip->joystick_mutex); - return change; -} - -static snd_kcontrol_new_t snd_ymfpci_control_joystick __devinitdata = { - .name = "Joystick", - .iface = SNDRV_CTL_ELEM_IFACE_CARD, - .info = snd_ymfpci_joystick_info, - .get = snd_ymfpci_joystick_get, - .put = snd_ymfpci_joystick_put, +static struct _snd_timer_hardware snd_ymfpci_timer_hw = { + .flags = SNDRV_TIMER_HW_AUTO, + .resolution = 10417, /* 1/2fs = 10.41666...us */ + .ticks = 65536, + .start = snd_ymfpci_timer_start, + .stop = snd_ymfpci_timer_stop, + .precise_resolution = snd_ymfpci_timer_precise_resolution, }; -static snd_kcontrol_new_t snd_ymfpci_control_joystick_addr __devinitdata = { - .name = "Joystick Address", - .iface = SNDRV_CTL_ELEM_IFACE_CARD, - .info = snd_ymfpci_joystick_addr_info, - .get = snd_ymfpci_joystick_addr_get, - .put = snd_ymfpci_joystick_addr_put, -}; - -int __devinit snd_ymfpci_joystick(ymfpci_t *chip) +int __devinit snd_ymfpci_timer(ymfpci_t *chip, int device) { + snd_timer_t *timer = NULL; + snd_timer_id_t tid; int err; - chip->joystick_port = 0; /* default */ - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_control_joystick, chip))) < 0) - return err; - if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_control_joystick_addr, chip))) < 0) - return err; - return 0; + tid.dev_class = SNDRV_TIMER_CLASS_CARD; + tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; + tid.card = chip->card->number; + tid.device = device; + tid.subdevice = 0; + if ((err = snd_timer_new(chip->card, "YMFPCI", &tid, &timer)) >= 0) { + strcpy(timer->name, "YMFPCI timer"); + timer->private_data = chip; + timer->hw = snd_ymfpci_timer_hw; + } + chip->timer = timer; + return err; } -#endif /* CONFIG_GAMEPORT */ /* @@ -1893,7 +1868,7 @@ snd_info_entry_t *entry; if (! snd_card_proc_new(card, "ymfpci", &entry)) - snd_info_set_text_ops(entry, chip, snd_ymfpci_proc_read); + snd_info_set_text_ops(entry, chip, 1024, snd_ymfpci_proc_read); return 0; } @@ -2122,9 +2097,13 @@ release_resource(chip->fm_res); kfree_nocheck(chip->fm_res); } -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) - if (chip->joystick_res) - snd_ymfpci_disable_joystick(chip); +#ifdef SUPPORT_JOYSTICK + if (chip->joystick_res) { + if (chip->gameport.io) + gameport_unregister_port(&chip->gameport); + release_resource(chip->joystick_res); + kfree_nocheck(chip->joystick_res); + } #endif if (chip->reg_area_virt) iounmap((void *)chip->reg_area_virt); @@ -2221,10 +2200,11 @@ /* start hw again */ if (chip->start_count > 0) { - spin_lock(&chip->reg_lock); + unsigned long flags; + spin_lock_irqsave(&chip->reg_lock, flags); snd_ymfpci_writel(chip, YDSXGR_MODE, chip->saved_ydsxgr_mode); chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT); - spin_unlock(&chip->reg_lock); + spin_unlock_irqrestore(&chip->reg_lock, flags); } snd_power_change_state(card, SNDRV_CTL_POWER_D0); } @@ -2275,9 +2255,6 @@ spin_lock_init(&chip->voice_lock); init_waitqueue_head(&chip->interrupt_sleep); atomic_set(&chip->interrupt_sleep_count, 0); -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) - init_MUTEX(&chip->joystick_mutex); -#endif chip->card = card; chip->pci = pci; chip->irq = -1; @@ -2335,6 +2312,8 @@ snd_ymfpci_free(chip); return err; } + + snd_card_set_dev(card, &pci->dev); *rchip = chip; return 0; diff -Nru a/sound/pcmcia/Kconfig b/sound/pcmcia/Kconfig --- a/sound/pcmcia/Kconfig Mon Feb 2 22:07:56 2004 +++ b/sound/pcmcia/Kconfig Mon Feb 2 22:07:56 2004 @@ -5,13 +5,13 @@ config SND_VXPOCKET tristate "Digigram VXpocket" - depends on SND && PCMCIA + depends on SND && PCMCIA && ISA help Say 'Y' or 'M' to include support for Digigram VXpocket soundcard. config SND_VXP440 tristate "Digigram VXpocket 440" - depends on SND && PCMCIA + depends on SND && PCMCIA && ISA help Say 'Y' or 'M' to include support for Digigram VXpocket 440 soundcard. diff -Nru a/sound/pcmcia/vx/vx_entry.c b/sound/pcmcia/vx/vx_entry.c --- a/sound/pcmcia/vx/vx_entry.c Mon Feb 2 22:07:55 2004 +++ b/sound/pcmcia/vx/vx_entry.c Mon Feb 2 22:07:55 2004 @@ -27,6 +27,10 @@ #include +MODULE_AUTHOR("Takashi Iwai "); +MODULE_DESCRIPTION("Common routines for Digigram PCMCIA VX drivers"); +MODULE_LICENSE("GPL"); + /* * prototypes */ diff -Nru a/sound/ppc/daca.c b/sound/ppc/daca.c --- a/sound/ppc/daca.c Mon Feb 2 22:07:55 2004 +++ b/sound/ppc/daca.c Mon Feb 2 22:07:55 2004 @@ -249,7 +249,8 @@ pmac_daca_t *mix; #ifdef CONFIG_KMOD - request_module("i2c-keywest"); + if (current->fs->root) + request_module("i2c-keywest"); #endif /* CONFIG_KMOD */ mix = kmalloc(sizeof(*mix), GFP_KERNEL); diff -Nru a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c --- a/sound/ppc/tumbler.c Mon Feb 2 22:07:55 2004 +++ b/sound/ppc/tumbler.c Mon Feb 2 22:07:55 2004 @@ -666,6 +666,10 @@ pmac_tumbler_t *mix; pmac_gpio_t *gp; int val; +#ifdef PMAC_SUPPORT_AUTOMUTE + if (chip->update_automute && chip->auto_mute) + return 0; /* don't touch in the auto-mute mode */ +#endif if (! (mix = chip->mixer_data)) return -ENODEV; gp = (kcontrol->private_value == TUMBLER_MUTE_HP) ? &mix->hp_mute : &mix->amp_mute; @@ -993,7 +997,8 @@ char *chipname; #ifdef CONFIG_KMOD - request_module("i2c-keywest"); + if (current->fs->root) + request_module("i2c-keywest"); #endif /* CONFIG_KMOD */ mix = kmalloc(sizeof(*mix), GFP_KERNEL); diff -Nru a/sound/synth/emux/Makefile b/sound/synth/emux/Makefile --- a/sound/synth/emux/Makefile Mon Feb 2 22:07:56 2004 +++ b/sound/synth/emux/Makefile Mon Feb 2 22:07:56 2004 @@ -4,7 +4,7 @@ # snd-emux-synth-objs := emux.o emux_synth.o emux_seq.o emux_nrpn.o \ - emux_effect.o emux_proc.o soundfont.o \ + emux_effect.o emux_proc.o emux_hwdep.o soundfont.o \ $(if $(CONFIG_SND_SEQUENCER_OSS),emux_oss.o) # diff -Nru a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c --- a/sound/synth/emux/emux.c Mon Feb 2 22:07:56 2004 +++ b/sound/synth/emux/emux.c Mon Feb 2 22:07:56 2004 @@ -67,6 +67,7 @@ */ int snd_emux_register(snd_emux_t *emu, snd_card_t *card, int index, char *name) { + int err; snd_sf_callback_t sf_cb; snd_assert(emu->hw != NULL, return -EINVAL); @@ -90,6 +91,9 @@ if (emu->sflist == NULL) return -ENOMEM; + if ((err = snd_emux_init_hwdep(emu)) < 0) + return err; + snd_emux_init_voices(emu); snd_emux_init_seq(emu, card, index); @@ -127,6 +131,8 @@ snd_emux_detach_seq_oss(emu); #endif snd_emux_detach_seq(emu); + + snd_emux_delete_hwdep(emu); if (emu->sflist) snd_sf_free(emu->sflist); diff -Nru a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/synth/emux/emux_hwdep.c Mon Feb 2 22:07:58 2004 @@ -0,0 +1,171 @@ +/* + * Interface for hwdep device + * + * Copyright (C) 2004 Takashi Iwai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include "emux_voice.h" + +/* + * open the hwdep device + */ +static int +snd_emux_hwdep_open(snd_hwdep_t *hw, struct file *file) +{ + return 0; +} + + +/* + * close the device + */ +static int +snd_emux_hwdep_release(snd_hwdep_t *hw, struct file *file) +{ + return 0; +} + + +#define TMP_CLIENT_ID 0x1001 + +/* + * load patch + */ +static int +snd_emux_hwdep_load_patch(snd_emux_t *emu, void __user *arg) +{ + int err; + soundfont_patch_info_t patch; + + if (copy_from_user(&patch, arg, sizeof(patch))) + return -EFAULT; + + if (patch.type >= SNDRV_SFNT_LOAD_INFO && + patch.type <= SNDRV_SFNT_PROBE_DATA) { + err = snd_soundfont_load(emu->sflist, arg, patch.len + sizeof(patch), TMP_CLIENT_ID); + if (err < 0) + return err; + } else { + if (emu->ops.load_fx) + return emu->ops.load_fx(emu, patch.type, patch.optarg, arg, patch.len + sizeof(patch)); + else + return -EINVAL; + } + return 0; +} + +/* + * set misc mode + */ +static int +snd_emux_hwdep_misc_mode(snd_emux_t *emu, void __user *arg) +{ + struct sndrv_emux_misc_mode info; + int i; + + if (copy_from_user(&info, arg, sizeof(info))) + return -EFAULT; + if (info.mode < 0 || info.mode >= EMUX_MD_END) + return -EINVAL; + + if (info.port < 0) { + for (i = 0; i < emu->num_ports; i++) + emu->portptrs[i]->ctrls[info.mode] = info.value; + } else { + if (info.port < emu->num_ports) + emu->portptrs[info.port]->ctrls[info.mode] = info.value; + } + return 0; +} + + +/* + * ioctl + */ +static int +snd_emux_hwdep_ioctl(snd_hwdep_t * hw, struct file *file, unsigned int cmd, unsigned long arg) +{ + snd_emux_t *emu = snd_magic_cast(snd_emux_t, hw->private_data, return -ENXIO); + + switch (cmd) { + case SNDRV_EMUX_IOCTL_VERSION: + return put_user(SNDRV_EMUX_VERSION, (unsigned int __user *)arg); + case SNDRV_EMUX_IOCTL_LOAD_PATCH: + return snd_emux_hwdep_load_patch(emu, (void __user *)arg); + case SNDRV_EMUX_IOCTL_RESET_SAMPLES: + snd_soundfont_remove_samples(emu->sflist); + break; + case SNDRV_EMUX_IOCTL_REMOVE_LAST_SAMPLES: + snd_soundfont_remove_unlocked(emu->sflist); + break; + case SNDRV_EMUX_IOCTL_MEM_AVAIL: + if (emu->memhdr) { + int size = snd_util_mem_avail(emu->memhdr); + return put_user(size, (unsigned int __user *)arg); + } + break; + case SNDRV_EMUX_IOCTL_MISC_MODE: + return snd_emux_hwdep_misc_mode(emu, (void __user *)arg); + } + + return 0; +} + + +/* + * register hwdep device + */ + +int +snd_emux_init_hwdep(snd_emux_t *emu) +{ + snd_hwdep_t *hw; + int err; + + if ((err = snd_hwdep_new(emu->card, SNDRV_EMUX_HWDEP_NAME, emu->hwdep_idx, &hw)) < 0) + return err; + emu->hwdep = hw; + strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME); + hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE; + hw->ops.open = snd_emux_hwdep_open; + hw->ops.release = snd_emux_hwdep_release; + hw->ops.ioctl = snd_emux_hwdep_ioctl; + hw->exclusive = 1; + hw->private_data = emu; + if ((err = snd_card_register(emu->card)) < 0) + return err; + + return 0; +} + + +/* + * unregister + */ +void +snd_emux_delete_hwdep(snd_emux_t *emu) +{ + if (emu->hwdep) { + snd_device_free(emu->card, emu->hwdep); + emu->hwdep = NULL; + } +} diff -Nru a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c --- a/sound/synth/emux/emux_seq.c Mon Feb 2 22:07:56 2004 +++ b/sound/synth/emux/emux_seq.c Mon Feb 2 22:07:56 2004 @@ -107,6 +107,7 @@ p->port_mode = SNDRV_EMUX_PORT_MODE_MIDI; snd_emux_init_port(p); emu->ports[i] = p->chset.port; + emu->portptrs[i] = p; } return 0; diff -Nru a/sound/synth/emux/emux_voice.h b/sound/synth/emux/emux_voice.h --- a/sound/synth/emux/emux_voice.h Mon Feb 2 22:07:55 2004 +++ b/sound/synth/emux/emux_voice.h Mon Feb 2 22:07:55 2004 @@ -81,4 +81,8 @@ #define STATE_IS_PLAYING(s) ((s) & SNDRV_EMUX_ST_ON) +/* emux_hwdep.c */ +int snd_emux_init_hwdep(snd_emux_t *emu); +void snd_emux_delete_hwdep(snd_emux_t *emu); + #endif diff -Nru a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c --- a/sound/synth/emux/soundfont.c Mon Feb 2 22:07:57 2004 +++ b/sound/synth/emux/soundfont.c Mon Feb 2 22:07:57 2004 @@ -30,6 +30,7 @@ #include #include #include +#include /* Prototypes for static functions */ @@ -43,14 +44,14 @@ static void set_sample_counter(snd_sf_list_t *sflist, snd_soundfont_t *sf, snd_sf_sample_t *sp); static snd_sf_sample_t *sf_sample_new(snd_sf_list_t *sflist, snd_soundfont_t *sf); static void sf_sample_delete(snd_sf_list_t *sflist, snd_soundfont_t *sf, snd_sf_sample_t *sp); -static int load_map(snd_sf_list_t *sflist, const void *data, int count); -static int load_info(snd_sf_list_t *sflist, const void *data, long count); +static int load_map(snd_sf_list_t *sflist, const void __user *data, int count); +static int load_info(snd_sf_list_t *sflist, const void __user *data, long count); static int remove_info(snd_sf_list_t *sflist, snd_soundfont_t *sf, int bank, int instr); static void init_voice_info(soundfont_voice_info_t *avp); static void init_voice_parm(soundfont_voice_parm_t *pp); static snd_sf_sample_t *set_sample(snd_soundfont_t *sf, soundfont_voice_info_t *avp); static snd_sf_sample_t *find_sample(snd_soundfont_t *sf, int sample_id); -static int load_data(snd_sf_list_t *sflist, const void *data, long count); +static int load_data(snd_sf_list_t *sflist, const void __user *data, long count); static void rebuild_presets(snd_sf_list_t *sflist); static void add_preset(snd_sf_list_t *sflist, snd_sf_zone_t *cur); static void delete_preset(snd_sf_list_t *sflist, snd_sf_zone_t *zp); @@ -111,7 +112,7 @@ * it wants to do with it. */ int -snd_soundfont_load(snd_sf_list_t *sflist, const void *data, long count, int client) +snd_soundfont_load(snd_sf_list_t *sflist, const void __user *data, long count, int client) { soundfont_patch_info_t patch; unsigned long flags; @@ -211,7 +212,7 @@ /* open patch; create sf list */ static int -open_patch(snd_sf_list_t *sflist, const char *data, int count, int client) +open_patch(snd_sf_list_t *sflist, const char __user *data, int count, int client) { soundfont_open_parm_t parm; snd_soundfont_t *sf; @@ -394,7 +395,7 @@ /* load voice map */ static int -load_map(snd_sf_list_t *sflist, const void *data, int count) +load_map(snd_sf_list_t *sflist, const void __user *data, int count) { snd_sf_zone_t *zp, *prevp; snd_soundfont_t *sf; @@ -490,7 +491,7 @@ * open soundfont. */ static int -load_info(snd_sf_list_t *sflist, const void *data, long count) +load_info(snd_sf_list_t *sflist, const void __user *data, long count) { snd_soundfont_t *sf; snd_sf_zone_t *zone; @@ -674,7 +675,7 @@ * routine. */ static int -load_data(snd_sf_list_t *sflist, const void *data, long count) +load_data(snd_sf_list_t *sflist, const void __user *data, long count) { snd_soundfont_t *sf; soundfont_sample_info_t sample_info; @@ -912,7 +913,7 @@ /* load GUS patch */ static int -load_guspatch(snd_sf_list_t *sflist, const char *data, long count, int client) +load_guspatch(snd_sf_list_t *sflist, const char __user *data, long count, int client) { struct patch_info patch; snd_soundfont_t *sf; @@ -1085,7 +1086,7 @@ /* load GUS patch */ int -snd_soundfont_load_guspatch(snd_sf_list_t *sflist, const char *data, +snd_soundfont_load_guspatch(snd_sf_list_t *sflist, const char __user *data, long count, int client) { int rc; diff -Nru a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c --- a/sound/usb/usbaudio.c Mon Feb 2 22:07:57 2004 +++ b/sound/usb/usbaudio.c Mon Feb 2 22:07:57 2004 @@ -23,6 +23,18 @@ * 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 + * + * + * NOTES: + * + * - async unlink should be used for avoiding the sleep inside lock. + * 2.4.22 usb-uhci seems buggy for async unlinking and results in + * oops. in such a cse, pass async_unlink=0 option. + * - the linked URBs would be preferred but not used so far because of + * the instability of unlinking. + * - type II is not supported properly. there is no device which supports + * this type *correctly*. SB extigy looks as if it supports, but it's + * indeed an AC3 stream packed in SPDIF frames (i.e. no real AC3 stream). */ @@ -57,6 +69,7 @@ static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */ static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */ static int nrpacks = 4; /* max. number of packets per urb */ +static int async_unlink = 1; MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); @@ -76,21 +89,9 @@ MODULE_PARM(nrpacks, "i"); MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB."); MODULE_PARM_SYNTAX(nrpacks, SNDRV_ENABLED ",allows:{{2,10}}"); - - -/* - * for using ASYNC unlink mode, define the following. - * this will make the driver quicker response for request to STOP-trigger, - * but it may cause oops by some unknown reason (bug of usb driver?), - * so turning off might be sure. - */ -/* #define SND_USE_ASYNC_UNLINK */ - -#ifdef SND_USB_ASYNC_UNLINK -#define UNLINK_FLAGS URB_ASYNC_UNLINK -#else -#define UNLINK_FLAGS 0 -#endif +MODULE_PARM(async_unlink, "i"); +MODULE_PARM_DESC(async_unlink, "Use async unlink mode."); +MODULE_PARM_SYNTAX(async_unlink, SNDRV_BOOLEAN_TRUE_DESC); /* @@ -572,20 +573,18 @@ snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; snd_usb_substream_t *subs = ctx->subs; snd_pcm_substream_t *substream = ctx->subs->pcm_substream; - int err; + int err = 0; - clear_bit(ctx->index, &subs->active_mask); - if (subs->running && subs->ops.retire(subs, substream->runtime, urb)) - return; - if (! subs->running) /* can be stopped during retire callback */ - return; - if ((err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 || + if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) || + ! subs->running || /* can be stopped during retire callback */ + (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 || (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err); - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - return; + clear_bit(ctx->index, &subs->active_mask); + if (err < 0) { + snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err); + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + } } - set_bit(ctx->index, &subs->active_mask); } @@ -597,63 +596,66 @@ snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context; snd_usb_substream_t *subs = ctx->subs; snd_pcm_substream_t *substream = ctx->subs->pcm_substream; - int err; + int err = 0; - clear_bit(ctx->index + 16, &subs->active_mask); - if (subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) - return; - if (! subs->running) /* can be stopped during retire callback */ - return; - if ((err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 || + if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) || + ! subs->running || /* can be stopped during retire callback */ + (err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 || (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err); - snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - return; + clear_bit(ctx->index + 16, &subs->active_mask); + if (err < 0) { + snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err); + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + } } - set_bit(ctx->index + 16, &subs->active_mask); } /* * unlink active urbs. - * return the number of active urbs. */ -static int deactivate_urbs(snd_usb_substream_t *subs, int force) +static int deactivate_urbs(snd_usb_substream_t *subs, int force, int can_sleep) { unsigned int i; - int alive; + int async; subs->running = 0; if (!force && subs->stream->chip->shutdown) /* to be sure... */ return 0; -#ifndef SND_USB_ASYNC_UNLINK - if (in_interrupt()) + async = !can_sleep && async_unlink; + + if (! async && in_interrupt()) return 0; -#endif - alive = 0; + for (i = 0; i < subs->nurbs; i++) { if (test_bit(i, &subs->active_mask)) { - alive++; - if (! test_and_set_bit(i, &subs->unlink_mask)) - usb_unlink_urb(subs->dataurb[i].urb); + if (! test_and_set_bit(i, &subs->unlink_mask)) { + struct urb *u = subs->dataurb[i].urb; + if (async) + u->transfer_flags |= URB_ASYNC_UNLINK; + else + u->transfer_flags &= ~URB_ASYNC_UNLINK; + usb_unlink_urb(u); + } } } if (subs->syncpipe) { for (i = 0; i < SYNC_URBS; i++) { if (test_bit(i+16, &subs->active_mask)) { - alive++; - if (! test_and_set_bit(i+16, &subs->unlink_mask)) - usb_unlink_urb(subs->syncurb[i].urb); + if (! test_and_set_bit(i+16, &subs->unlink_mask)) { + struct urb *u = subs->syncurb[i].urb; + if (async) + u->transfer_flags |= URB_ASYNC_UNLINK; + else + u->transfer_flags &= ~URB_ASYNC_UNLINK; + usb_unlink_urb(u); + } } } } -#ifdef SND_USB_ASYNC_UNLINK - return alive; -#else return 0; -#endif } @@ -682,9 +684,11 @@ } } + subs->active_mask = 0; + subs->unlink_mask = 0; subs->running = 1; for (i = 0; i < subs->nurbs; i++) { - if ((err = usb_submit_urb(subs->dataurb[i].urb, GFP_KERNEL)) < 0) { + if ((err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC)) < 0) { snd_printk(KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err); goto __error; } @@ -692,7 +696,7 @@ } if (subs->syncpipe) { for (i = 0; i < SYNC_URBS; i++) { - if ((err = usb_submit_urb(subs->syncurb[i].urb, GFP_KERNEL)) < 0) { + if ((err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC)) < 0) { snd_printk(KERN_ERR "cannot submit syncpipe for urb %d, err = %d\n", i, err); goto __error; } @@ -703,7 +707,7 @@ __error: // snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN); - deactivate_urbs(subs, 0); + deactivate_urbs(subs, 0, 0); return -EPIPE; } @@ -763,7 +767,7 @@ err = start_urbs(subs, substream->runtime); break; case SNDRV_PCM_TRIGGER_STOP: - err = deactivate_urbs(subs, 0); + err = deactivate_urbs(subs, 0, 0); break; default: err = -EINVAL; @@ -796,8 +800,8 @@ int i; /* stop urbs (to be sure) */ - if (deactivate_urbs(subs, force) > 0) - wait_clear_urbs(subs); + deactivate_urbs(subs, force, 1); + wait_clear_urbs(subs); for (i = 0; i < MAX_URBS; i++) release_urb_ctx(&subs->dataurb[i]); @@ -825,14 +829,6 @@ subs->freqmax = subs->freqn + (subs->freqn >> 2); /* max. allowed frequency */ subs->phase = 0; - /* reset the pointer */ - subs->hwptr = 0; - subs->hwptr_done = 0; - subs->transfer_sched = 0; - subs->transfer_done = 0; - subs->active_mask = 0; - subs->unlink_mask = 0; - /* calculate the max. size of packet */ maxsize = ((subs->freqmax + 0x3fff) * (frame_bits >> 3)) >> 14; if (subs->maxpacksize && maxsize > subs->maxpacksize) { @@ -915,7 +911,7 @@ } u->urb->dev = subs->dev; u->urb->pipe = subs->datapipe; - u->urb->transfer_flags = URB_ISO_ASAP | UNLINK_FLAGS; + u->urb->transfer_flags = URB_ISO_ASAP; u->urb->number_of_packets = u->packets; u->urb->context = u; u->urb->complete = snd_usb_complete_callback(snd_complete_urb); @@ -937,7 +933,7 @@ u->urb->transfer_buffer_length = nrpacks * 3; u->urb->dev = subs->dev; u->urb->pipe = subs->syncpipe; - u->urb->transfer_flags = URB_ISO_ASAP | UNLINK_FLAGS; + u->urb->transfer_flags = URB_ISO_ASAP; u->urb->number_of_packets = u->packets; u->urb->context = u; u->urb->complete = snd_usb_complete_callback(snd_complete_sync_urb); @@ -955,6 +951,7 @@ { struct list_head *p; struct audioformat *found = NULL; + int cur_attr = 0, attr; list_for_each(p, &subs->fmt_list) { struct audioformat *fp; @@ -971,9 +968,37 @@ if (i >= fp->nr_rates) continue; } + attr = fp->ep_attr & EP_ATTR_MASK; + if (! found) { + found = fp; + cur_attr = attr; + continue; + } + /* avoid async out and adaptive in if the other method + * supports the same format. + * this is a workaround for the case like + * M-audio audiophile USB. + */ + if (attr != cur_attr) { + if ((attr == EP_ATTR_ASYNC && + subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || + (attr == EP_ATTR_ADAPTIVE && + subs->direction == SNDRV_PCM_STREAM_CAPTURE)) + continue; + if ((cur_attr == EP_ATTR_ASYNC && + subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || + (cur_attr == EP_ATTR_ADAPTIVE && + subs->direction == SNDRV_PCM_STREAM_CAPTURE)) { + found = fp; + cur_attr = attr; + continue; + } + } /* find the format with the largest max. packet size */ - if (! found || fp->maxpacksize > found->maxpacksize) + if (fp->maxpacksize > found->maxpacksize) { found = fp; + cur_attr = attr; + } } return found; } @@ -1241,6 +1266,17 @@ subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize); subs->curframesize = bytes_to_frames(runtime, subs->curpacksize); + /* reset the pointer */ + subs->hwptr = 0; + subs->hwptr_done = 0; + subs->transfer_sched = 0; + subs->transfer_done = 0; + subs->phase = 0; + + /* clear urbs (to be sure) */ + deactivate_urbs(subs, 0, 1); + wait_clear_urbs(subs); + return 0; } @@ -1430,7 +1466,7 @@ fp = list_entry(p, struct audioformat, list); if (! hw_check_valid_format(params, fp)) continue; - fbits |= (1UL << fp->format); + fbits |= (1ULL << fp->format); } oldbits[0] = fmt->bits[0]; @@ -1455,6 +1491,7 @@ u32 channels[64]; u32 rates[64]; u32 cmaster, rmaster; + u32 rate_min = 0, rate_max = 0; struct list_head *p; memset(channels, 0, sizeof(channels)); @@ -1466,6 +1503,15 @@ /* unconventional channels? */ if (f->channels > 32) return 1; + /* continuous rate min/max matches? */ + if (f->rates & SNDRV_PCM_RATE_CONTINUOUS) { + if (rate_min && f->rate_min != rate_min) + return 1; + if (rate_max && f->rate_max != rate_max) + return 1; + rate_min = f->rate_min; + rate_max = f->rate_max; + } /* combination of continuous rates and fixed rates? */ if (rates[f->format] & SNDRV_PCM_RATE_CONTINUOUS) { if (f->rates != rates[f->format]) @@ -1820,7 +1866,7 @@ sprintf(name, "stream%d", stream->pcm_index); if (! snd_card_proc_new(card, name, &entry)) - snd_info_set_text_ops(entry, stream, proc_pcm_format_read); + snd_info_set_text_ops(entry, stream, 1024, proc_pcm_format_read); } @@ -1956,7 +2002,7 @@ as->pcm = pcm; pcm->private_data = as; pcm->private_free = snd_usb_audio_pcm_free; - pcm->info_flags = 0; + pcm->info_flags = SNDRV_PCM_INFO_NONATOMIC_OPS; if (chip->pcm_devs > 0) sprintf(pcm->name, "USB Audio #%d", chip->pcm_devs); else @@ -2009,10 +2055,20 @@ pcm_format = SNDRV_PCM_FORMAT_S8; break; case 2: - pcm_format = SNDRV_PCM_FORMAT_S16_LE; + /* M-Audio audiophile USB workaround */ + if (dev->descriptor.idVendor == 0x0763 && + dev->descriptor.idProduct == 0x2003) + pcm_format = SNDRV_PCM_FORMAT_S16_BE; /* grrr, big endian!! */ + else + pcm_format = SNDRV_PCM_FORMAT_S16_LE; break; case 3: - pcm_format = SNDRV_PCM_FORMAT_S24_3LE; + /* M-Audio audiophile USB workaround */ + if (dev->descriptor.idVendor == 0x0763 && + dev->descriptor.idProduct == 0x2003) + pcm_format = SNDRV_PCM_FORMAT_S24_3BE; /* grrr, big endian!! */ + else + pcm_format = SNDRV_PCM_FORMAT_S24_3LE; break; case 4: pcm_format = SNDRV_PCM_FORMAT_S32_LE; @@ -2606,6 +2662,32 @@ /* + * common proc files to show the usb device info + */ +static void proc_audio_usbbus_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) +{ + snd_usb_audio_t *chip = snd_magic_cast(snd_usb_audio_t, entry->private_data, return); + if (! chip->shutdown) + snd_iprintf(buffer, "%03d/%03d\n", chip->dev->bus->busnum, chip->dev->devnum); +} + +static void proc_audio_usbid_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) +{ + snd_usb_audio_t *chip = snd_magic_cast(snd_usb_audio_t, entry->private_data, return); + if (! chip->shutdown) + snd_iprintf(buffer, "%04x:%04x\n", chip->dev->descriptor.idVendor, chip->dev->descriptor.idProduct); +} + +static void snd_usb_audio_create_proc(snd_usb_audio_t *chip) +{ + snd_info_entry_t *entry; + if (! snd_card_proc_new(chip->card, "usbbus", &entry)) + snd_info_set_text_ops(entry, chip, 1024, proc_audio_usbbus_read); + if (! snd_card_proc_new(chip->card, "usbid", &entry)) + snd_info_set_text_ops(entry, chip, 1024, proc_audio_usbid_read); +} + +/* * free the chip instance * * here we have to do not much, since pcm and controls are already freed @@ -2637,6 +2719,7 @@ { snd_usb_audio_t *chip; int err, len; + char component[14]; static snd_device_ops_t ops = { .dev_free = snd_usb_audio_dev_free, }; @@ -2657,52 +2740,48 @@ } strcpy(card->driver, "USB-Audio"); + sprintf(component, "USB%04x:%04x", + dev->descriptor.idVendor, dev->descriptor.idProduct); + snd_component_add(card, component); /* retrieve the device string as shortname */ - if (dev->descriptor.iProduct) - len = usb_string(dev, dev->descriptor.iProduct, - card->shortname, sizeof(card->shortname)); - else - len = 0; - if (len <= 0) { - if (quirk && quirk->product_name) { - strlcpy(card->shortname, quirk->product_name, sizeof(card->shortname)); - } else { + if (quirk && quirk->product_name) { + strlcpy(card->shortname, quirk->product_name, sizeof(card->shortname)); + } else { + if (!dev->descriptor.iProduct || + usb_string(dev, dev->descriptor.iProduct, + card->shortname, sizeof(card->shortname)) <= 0) { + /* no name available from anywhere, so use ID */ sprintf(card->shortname, "USB Device %#04x:%#04x", dev->descriptor.idVendor, dev->descriptor.idProduct); } } /* retrieve the vendor and device strings as longname */ - if (dev->descriptor.iManufacturer) - len = usb_string(dev, dev->descriptor.iManufacturer, - card->longname, sizeof(card->longname)); - else - len = 0; - if (len <= 0) { - if (quirk && quirk->vendor_name) { - len = strlcpy(card->longname, quirk->vendor_name, sizeof(card->longname)); - } else { + if (quirk && quirk->vendor_name) { + len = strlcpy(card->longname, quirk->vendor_name, sizeof(card->longname)); + } else { + if (dev->descriptor.iManufacturer) + len = usb_string(dev, dev->descriptor.iManufacturer, + card->longname, sizeof(card->longname)); + else len = 0; - } + /* we don't really care if there isn't any vendor string */ } if (len > 0) strlcat(card->longname, " ", sizeof(card->longname)); - len = strlen(card->longname); - - if ((!dev->descriptor.iProduct - || usb_string(dev, dev->descriptor.iProduct, - card->longname + len, sizeof(card->longname) - len) <= 0) - && quirk && quirk->product_name) { - strlcat(card->longname, quirk->product_name, sizeof(card->longname)); - } + strlcat(card->longname, card->shortname, sizeof(card->longname)); len = strlcat(card->longname, " at ", sizeof(card->longname)); if (len < sizeof(card->longname)) usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); + snd_usb_audio_create_proc(chip); + + snd_card_set_dev(card, &dev->dev); + *rchip = chip; return 0; } @@ -2733,7 +2812,7 @@ alts = &intf->altsetting[0]; ifnum = get_iface_desc(alts)->bInterfaceNumber; - if (quirk && quirk->ifnum != QUIRK_ANY_INTERFACE && ifnum != quirk->ifnum) + if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) goto __err_val; /* SB Extigy needs special boot-up sequence */ @@ -2794,7 +2873,7 @@ } err = 1; /* continue */ - if (quirk) { + if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { /* need some special handlings */ if ((err = snd_usb_create_quirk(chip, intf, quirk)) < 0) goto __error; diff -Nru a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h --- a/sound/usb/usbaudio.h Mon Feb 2 22:07:57 2004 +++ b/sound/usb/usbaudio.h Mon Feb 2 22:07:57 2004 @@ -142,7 +142,8 @@ * Information about devices with broken descriptors */ -#define QUIRK_ANY_INTERFACE -1 +#define QUIRK_NO_INTERFACE -2 +#define QUIRK_ANY_INTERFACE -1 #define QUIRK_MIDI_FIXED_ENDPOINT 0 #define QUIRK_MIDI_YAMAHA 1 diff -Nru a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c --- a/sound/usb/usbmidi.c Mon Feb 2 22:07:58 2004 +++ b/sound/usb/usbmidi.c Mon Feb 2 22:07:58 2004 @@ -142,8 +142,7 @@ { if (status == -ENOENT) return status; /* killed */ - if (status == -ENODEV || - status == -EILSEQ || + if (status == -EILSEQ || status == -ETIMEDOUT) return -ENODEV; /* device removed */ snd_printk(KERN_ERR "urb status %d\n", status); diff -Nru a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h --- a/sound/usb/usbquirks.h Mon Feb 2 22:07:56 2004 +++ b/sound/usb/usbquirks.h Mon Feb 2 22:07:56 2004 @@ -39,202 +39,72 @@ .idProduct = prod, \ .bInterfaceClass = USB_CLASS_VENDOR_SPEC -/* Yamaha devices */ -{ - USB_DEVICE(0x0499, 0x1000), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "UX256", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1001), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "MU1000", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1002), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "MU2000", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1003), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "MU500", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE_VENDOR_SPEC(0x0499, 0x1004), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "UW500", - .ifnum = 3, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1005), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "MOTIF6", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1006), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "MOTIF7", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1007), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "MOTIF8", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1008), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "UX96", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1009), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "UX16", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE_VENDOR_SPEC(0x0499, 0x100a), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "EOS BX", - .ifnum = 3, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x100e), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "S08", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x100f), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "CLP-150", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1010), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "CLP-170", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1011), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "P-250", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1012), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "TYROS", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1013), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "PF-500", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x1014), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "S90", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x5002), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "DME32", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x5003), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "DM2000", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, -{ - USB_DEVICE(0x0499, 0x5004), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "Yamaha", - .product_name = "02R96", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_MIDI_YAMAHA - } -}, +/* + * Yamaha devices + */ + +#define YAMAHA_DEVICE(id, name) { \ + USB_DEVICE(0x0499, id), \ + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { \ + .vendor_name = "Yamaha", \ + .product_name = name, \ + .ifnum = QUIRK_ANY_INTERFACE, \ + .type = QUIRK_MIDI_YAMAHA \ + } \ +} +#define YAMAHA_INTERFACE(id, intf, name) { \ + USB_DEVICE_VENDOR_SPEC(0x0499, id), \ + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { \ + .vendor_name = "Yamaha", \ + .product_name = name, \ + .ifnum = intf, \ + .type = QUIRK_MIDI_YAMAHA \ + } \ +} +YAMAHA_DEVICE(0x1000, "UX256"), +YAMAHA_DEVICE(0x1001, "MU1000"), +YAMAHA_DEVICE(0x1002, "MU2000"), +YAMAHA_DEVICE(0x1003, "MU500"), +YAMAHA_INTERFACE(0x1004, 3, "UW500"), +YAMAHA_DEVICE(0x1005, "MOTIF6"), +YAMAHA_DEVICE(0x1006, "MOTIF7"), +YAMAHA_DEVICE(0x1007, "MOTIF8"), +YAMAHA_DEVICE(0x1008, "UX96"), +YAMAHA_DEVICE(0x1009, "UX16"), +YAMAHA_INTERFACE(0x100a, 3, "EOS BX"), +YAMAHA_DEVICE(0x100e, "S08"), +YAMAHA_DEVICE(0x100f, "CLP-150"), +YAMAHA_DEVICE(0x1010, "CLP-170"), +YAMAHA_DEVICE(0x1011, "P-250"), +YAMAHA_DEVICE(0x1012, "TYROS"), +YAMAHA_DEVICE(0x1013, "PF-500"), +YAMAHA_DEVICE(0x1014, "S90"), +YAMAHA_DEVICE(0x1015, "MOTIF-R"), +YAMAHA_DEVICE(0x1017, "CVP-204"), +YAMAHA_DEVICE(0x1018, "CVP-206"), +YAMAHA_DEVICE(0x1019, "CVP-208"), +YAMAHA_DEVICE(0x101a, "CVP-210"), +YAMAHA_DEVICE(0x101b, "PSR-1100"), +YAMAHA_DEVICE(0x101c, "PSR-2100"), +YAMAHA_DEVICE(0x101e, "PSR-K1"), +YAMAHA_DEVICE(0x1020, "EZ-250i"), +YAMAHA_DEVICE(0x1021, "MOTIF ES 6"), +YAMAHA_DEVICE(0x1022, "MOTIF ES 7"), +YAMAHA_DEVICE(0x1023, "MOTIF ES 8"), +YAMAHA_DEVICE(0x5000, "CS1D"), +YAMAHA_DEVICE(0x5001, "DSP1D"), +YAMAHA_DEVICE(0x5002, "DME32"), +YAMAHA_DEVICE(0x5003, "DM2000"), +YAMAHA_DEVICE(0x5004, "02R96"), +YAMAHA_DEVICE(0x5005, "ACU16-C"), +YAMAHA_DEVICE(0x5006, "NHB32-C"), +YAMAHA_DEVICE(0x5007, "DM1000"), +YAMAHA_DEVICE(0x5008, "01V96"), +#undef YAMAHA_DEVICE +#undef YAMAHA_INTERFACE /* * Roland/RolandED/Edirol devices - * - * The USB MIDI Specification has been written by Roland, - * but a 100% conforming Roland device has yet to be found. */ { USB_DEVICE(0x0582, 0x0000), @@ -631,6 +501,15 @@ } } }, +{ + USB_DEVICE(0x0582, 0x0052), + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { + .vendor_name = "EDIROL", + .product_name = "UM-1SX", + .ifnum = 0, + .type = QUIRK_MIDI_STANDARD_INTERFACE + } +}, /* Midiman/M-Audio devices */ { @@ -768,6 +647,19 @@ } } }, +{ + USB_DEVICE_VENDOR_SPEC(0x0763, 0x200d), + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { + .vendor_name = "M-Audio", + .product_name = "OmniStudio", + .ifnum = 9, + .type = QUIRK_MIDI_MIDIMAN, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + } +}, /* Mark of the Unicorn devices */ { @@ -783,6 +675,17 @@ .in_cables = 0x0003 } } +}, + +{ + /* Creative Sound Blaster MP3+ */ + USB_DEVICE(0x041e, 0x3010), + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { + .vendor_name = "Creative Labs", + .product_name = "Sound Blaster MP3+", + .ifnum = QUIRK_NO_INTERFACE + } + }, #undef USB_DEVICE_VENDOR_SPEC