From: Jaroslav Kysela - use pci_set_consistent_dma_mask() - control midlevel - added user control elements, fixes - timer midlevel - fixes - OSS PCM emulation - fixes and updates - joystick support selectable using module parameter - AC'97 code - introduced ac97_bus_t and pcm support code - USB audio driver updated - VIA82xx driver updated - EMU10K1 driver updated - ICE1712 driver updated - CMIPCI driver updated - AD1848 driver updated - Digigram VX library updated - HDSP driver updated (04/01/08 1.1575) ALSA CVS update - Takashi Iwai VIA82xx driver - added the DXS support for ABIT KD7(-RAID) (04/01/08 1.1574) ALSA CVS update - Takashi Iwai ALSA sequencer - new e-mail address of Frank van de Pol. (04/01/08 1.1573) ALSA CVS update - Takashi Iwai Documentation,CMIPCI driver - changed joystick option to joystick_port option for cmipci driver. - mentioning alsa-firmware package together with alsa-tools package for firmware loading. - fixed the description of auto-invokation of vxloader for 2.6 kernels. (04/01/08 1.1572) ALSA CVS update - Takashi Iwai VIA82xx driver - added the white list for avance logic mobo. (04/01/08 1.1571) ALSA CVS update - Jaroslav Kysela EMU10K1/EMU10K2 driver Georgi Georgiev Line2 LiveDrive Capture Volume control fix (04/01/08 1.1570) ALSA - added missing module_init and module_exit functions to cs8427 and ak4xxx modules (03/12/30 1.1531.3.18) ALSA 1.0.1 (03/12/30 1.1531.3.17) ALSA CVS update - Jaroslav Kysela Documentation More complete PCM device example (03/12/30 1.1531.3.16) ALSA CVS update - Jaroslav Kysela VIA82xx driver Added Easy Note 3171, Packard Bell - VIA_DXS_ENABLE (03/12/30 1.1531.3.15) ALSA CVS update - Jaroslav Kysela Documentation,ALSA<-OSS emulation - changed whole-frag (default again) => partial-frag - small corrections in snd_pcm_oss_get_ptr() - atomic hw_ptr and info.bytes (03/12/30 1.1531.3.14) ALSA CVS update - Jaroslav Kysela ICE1712 driver DFS bit must be handled also for Delta1010 and Delta2496 (03/12/30 1.1531.3.13) ALSA CVS update - Jaroslav Kysela ALSA Core petter wahlman vsnprintf does not copy more than 'size' bytes _including_ '\0' (03/12/30 1.1531.3.12) ALSA CVS update - Jaroslav Kysela Documentation Added read_size comment for snd_info_set_text_ops() (03/12/30 1.1531.3.11) ALSA CVS update - Jaroslav Kysela ALSA Core A try to fix get_id() function - use alloc_bootmem() (03/12/30 1.1531.3.10) ALSA CVS update - Jaroslav Kysela ALSA sequencer Fixed typo (03/12/30 1.1531.3.9) ALSA CVS update - Jaroslav Kysela GUS Library Fixed race - scheduling in interrupt (03/12/30 1.1531.3.8) ALSA CVS update - Jaroslav Kysela Control Midlevel Added snd_ctl_find_hole() function. Added printk when control already exists. (03/12/30 1.1531.3.7) ALSA CVS update - Jaroslav Kysela RME9652 driver Removed duplicated ADAT3 Sync control (03/12/30 1.1531.3.6) ALSA CVS update - Jaroslav Kysela USB generic driver Clemens Ladisch deactivate_urbs didn't return the number of still-active URBs when not unlinking asynchronously, which would prevent calling wait_clear_urbs when some URBs actually are being unlinked asynchronously, so these URBs would be freed while still in use. I removed deactivate_urb's return value because wait_clear_urbs does its own counting anyway. (03/12/30 1.1531.3.5) ALSA CVS update - Jaroslav Kysela Timer Midlevel An attempt to fix the system timer behaviour (lost jiffy ticks) (03/12/30 1.1531.3.4) ALSA CVS update - Jaroslav Kysela AMD InterWave driver Fixed typo (03/12/30 1.1531.3.3) ALSA CVS update - Jaroslav Kysela EMU10K1/EMU10K2 driver Center is initialized to analog to prevent noise at startup (SB Live) (03/12/30 1.1531.3.2) ALSA CVS update - Jaroslav Kysela ALSA<-OSS emulation - added OSS_ALSAEMULVER ioctl - cleanups for put_user() (03/12/05 1.1496.11.14) ALSA version 1.0.0rc2 (03/12/04 1.1496.11.13) ALSA CVS update - Jaroslav Kysela AC97 Codec Core Commented out debugging printk (03/12/04 1.1496.11.12) ALSA CVS update - Takashi Iwai VIA82xx driver - added a quirk for ASRock K7VM2. (03/12/04 1.1496.11.11) ALSA CVS update - Takashi Iwai VIA82xx driver - dxs_support=4 seems ok for the ASRock board. (03/12/04 1.1496.11.10) ALSA CVS update - Takashi Iwai VIA82xx driver - added a dxs_support list entry for ASRock K7VM2. (03/12/04 1.1496.11.9) ALSA CVS update - Takashi Iwai AC97 Codec Core - fixed the detection of rates due to collision with the spdif slots. - fixed the typo in the error message. - replaced the numbers with constants. (03/12/04 1.1496.11.8) ALSA CVS update - Takashi Iwai AC97 Codec Core - don't break the probing even when ac97_reset_wait() returns error. in many cases, it's not critical (e.g. SB audigy). (03/12/04 1.1496.11.7) ALSA CVS update - Takashi Iwai AC97 Codec Core,Intel8x0 driver - added spdif field to struct ac97_pcm. - snd_ac97_set_rate() accepts AC97_SPDIF. - allow fixed rate mic capture. - optimized the loop in snd_ac97_pcm_open. (03/12/04 1.1496.11.6) ALSA CVS update - Takashi Iwai Memalloc module - replaced 8 with SNDRV_CARDS. (03/12/04 1.1496.11.5) ALSA CVS update - Takashi Iwai Generic drivers Steve deRosier : * There is a user selectable flag droponfull. Set to 1 and any new bytes delivered to the driver after the buffer fills up will be discarded until the buffer is able to flush some bytes. * If droponfull==0 (or is not set, the default is 0), the driver proceeds to block further input by not calling snd_rawmidi_transmit_ack() and aborting the attempt. It will try again later. * I've redone a bit of the interface for the buffer routines. This was done to support the proper blocking/non-blocking methods as spelled out above, and to try to protect the buffer data a bit. (03/12/04 1.1496.11.4) ALSA CVS update - Takashi Iwai VIA82xx driver - added the missing '\n' to proc output. (03/12/04 1.1496.11.3) ALSA CVS update - Takashi Iwai VIA82xx driver - added quirks for another ASUS board and FSC notebook. (03/12/04 1.1496.11.2) ALSA CVS update - Takashi Iwai ALSA<-OSS emulation - fixed the bytes field of GETxPTR ioctl in the mmap mode. - fixed the bytes field of GETxSPACE ioctl. - don't count the negative delay values. (03/12/01 1.1489.3.106) ALSA 1.0.0rc1 (03/12/01 1.1489.3.105) ALSA CVS update - Jaroslav Kysela AC97 Codec Core Fixed AC97 slot allocation for 2nd+ PCM in assign function (03/12/01 1.1489.3.104) ALSA CVS update - Takashi Iwai AC97 Codec Core fixed typo (03/12/01 1.1489.3.103) ALSA CVS update - Takashi Iwai AC97 Codec Core - fixed the rates detection for capture. (03/12/01 1.1489.3.102) ALSA CVS update - Takashi Iwai Documentation - fixed for the new ac97_bus struct. (03/12/01 1.1489.3.101) ALSA CVS update - Takashi Iwai ICE1712 driver fixes by Apostolos Dimitromanolakis : - fixed the pop noise at the start up of aureon boards. - update of prodigy driver (modifed by ti). (03/12/01 1.1489.3.100) ALSA CVS update - Takashi Iwai RME HDSP driver fix by Thomas Charbonnel : The attach patch fixes problems with speed modes for H9632 cards (many thanks to Pentti Ala-Vannesluoma for testing the driver and helping finding bugs), and the AutoSync mode issue (for all cards) reported by Anders Torger at the end of september. (03/12/01 1.1489.3.99) ALSA CVS update - Jaroslav Kysela AC97 Codec Core Clemens Ladisch fix compiler warnings (03/12/01 1.1489.3.98) ALSA CVS update - Takashi Iwai AC97 Codec Core,Intel8x0 driver - fixed the wrong sized allocation of snd_ac97_pcm. - fixed the probing of multiple codecs on intel8x0. - fixed the computation of rates bits. (03/12/01 1.1489.3.97) ALSA CVS update - Takashi Iwai AC97 Codec Core - fixed oops. (03/12/01 1.1489.3.96) ALSA CVS update - Jaroslav Kysela AC97 Codec Core,Intel8x0 driver Moved AC97 slot allocation from intel8x0 to ac97_pcm.c. (03/12/01 1.1489.3.95) ALSA CVS update - Takashi Iwai ICE1712 driver removed unnecessary codes, which causes compilation error with gcc-2.9.x. (03/12/01 1.1489.3.94) ALSA CVS update - Takashi Iwai ICE1712 driver,ICE1724 driver Apostolos Dimitromanolakis : - added the partial support of AudioTrak prodigy 7.1 (03/12/01 1.1489.3.93) ALSA CVS update - Takashi Iwai RME HDSP driver Thomas Charbonnel : The attached patch at last fixes the long lasting firmware loading error after boot, and includes a small cosmetic fix for H9632 cards (fixes SPDIF external rate reporting in /proc/asound/cardX/hdsp and amixer outputs). (03/12/01 1.1489.3.92) ALSA CVS update - Takashi Iwai RME HDSP driver Thomas Charbonnel : The attached patch fixes matrix mixer and metering problems spotted by Pentti Ala-Vannesluoma for H9632 cards and gcc 2.9x compile errors reported by Martin Langer. (03/12/01 1.1489.3.91) ALSA CVS update - Takashi Iwai RME HDSP driver Thomas Charbonnel : - include support for hdsp 9632 cards and bugfixes for hdsp 9652 cards. (03/12/01 1.1489.3.90) ALSA CVS update - Takashi Iwai ES1968 driver,AC97 Codec Core fixed the compilation with the recent ac97 and info changes. (03/12/01 1.1489.3.89) ALSA CVS update - Jaroslav Kysela HWDEP Midlevel,ALSA Core,PCM Midlevel,RawMidi Midlevel,Timer Midlevel Digigram VX core,L3 drivers,AC97 Codec Core,CS46xx driver Trident driver,YMFPCI driver,GUS Library,SB16/AWE driver,CMIPCI driver CS4281 driver,ENS1370/1+ driver,FM801 driver,Intel8x0 driver Maestro3 driver,RME32 driver,RME96 driver,SonicVibes driver VIA82xx driver,AK4531 codec,ALI5451 driver,EMU10K1/EMU10K2 driver ICE1712 driver,ICE1724 driver,KORG1212 driver,NM256 driver RME HDSP driver,RME9652 driver,USB generic driver - AC97 code - introduced ac97_bus_t structure - moved attached codecs to /proc/asound/card?/codec97#? directory - merged snd_ac97_modem() to snd_ac97_mixer() - proc cleanups - removed already initialized variables - enhanced snd_info_set_text_ops() syntax (03/12/01 1.1489.3.88) ALSA CVS update - Jaroslav Kysela Control Midlevel,ALSA Core,EMU8000 driver,SB16/AWE driver EMU10K1/EMU10K2 driver - added support for user control elements (untested) - fixed locking for snd_ctl_remove() function (03/12/01 1.1489.3.87) ALSA CVS update - Takashi Iwai YMFPCI driver Clemens Ladisch : - This patch adds a control to enable S/PDIF direct recording (without resampling) on the YMF754. (03/12/01 1.1489.3.86) ALSA CVS update - Takashi Iwai YMFPCI driver Clemens Ladisch : - added the support for the timer on ymfpci chips. (03/12/01 1.1489.3.85) ALSA CVS update - version 1.0.0pre3 (03/12/01 1.1489.3.84) ALSA CVS update - Jaroslav Kysela VIA82xx driver Added EPoX EP-8K9A default settings (VIA_DXS_ENABLE) (03/12/01 1.1489.3.83) ALSA CVS update - Takashi Iwai ALSA<-OSS emulation - reset auto-silence in the OSS mmap mode. (03/12/01 1.1489.3.82) ALSA CVS update - Takashi Iwai ALSA<-OSS emulation fixed the calculation of bytes. this will fix GETxSPACE, GETxPTR, GETODELAY ioctls. (03/12/01 1.1489.3.81) ALSA CVS update - Takashi Iwai AMD InterWave driver - fixed the detection of STB board via pnp. (03/12/01 1.1489.3.80) ALSA CVS update - Takashi Iwai EMU10K1/EMU10K2 driver - fixed double entries of the same controls. (03/12/01 1.1489.3.79) ALSA CVS update - Takashi Iwai Digigram VX Pocket driver - added the missing licesne and descriptions. (03/11/26 1.1489.3.78) ALSA CVS update - Takashi Iwai USB generic driver - added the proc files to show ids. (03/11/26 1.1489.3.77) ALSA CVS update - Takashi Iwai PCM Midlevel,ALSA Core,USB generic driver - prepare callback can sleep if a flag is given in pcm->info_flags. - usbaudio driver uses non-atomic prepare callback for synchronization of pending unlinked urbs. - async_unlink option of usbaudio driver is enabled as default now. - fixed the initialization of pseudo-dma pointers in usbaudio. (03/11/26 1.1489.3.76) ALSA CVS update - Takashi Iwai PCM Midlevel - clear the status record before calling snd_pcm_status() in proc read. this will prevent to show bogus values when status = OPEN. (03/11/26 1.1489.3.75) ALSA CVS update - Takashi Iwai Digigram VX core - added hw_constraint to align 4bytes. this will solve the 24bit problem on vx222. (03/11/26 1.1489.3.74) ALSA CVS update - Takashi Iwai USB generic driver fix by Clemens Ladisch : - don't clear active_mask bits until it's clear that the URB is _not_ resubmitted, to prevent a race with unlinking - initialize active_mask and unlink_mask each time before URBs are started - don't call sleeping functions in trigger callback (03/11/26 1.1489.3.73) ALSA CVS update - Takashi Iwai USB generic driver - clear unlink_mask bit in the complete callback. - make sure to deactivate urbs before starting streams. (03/11/26 1.1489.3.72) ALSA CVS update - Takashi Iwai AC97 Codec Core - added new patch codes for ALC655/658. - fixed reset wait loop in the resume phase. - fixed resume of AD1981 multi codecs. (03/11/26 1.1489.3.71) ALSA CVS update - Takashi Iwai Documentation,Memalloc module,ALS4000 driver,AZT3328 driver ES1938 driver,ES1968 driver,Maestro3 driver,SonicVibes driver ALI5451 driver,EMU10K1/EMU10K2 driver,ICE1712 driver,ICE1724 driver Trident driver - use pci_set_consistent_dma_mask(). (03/11/26 1.1489.3.70) ALSA CVS update - Takashi Iwai YMFPCI driver - fixed possible (but rare) deadlock. (03/11/26 1.1489.3.69) ALSA CVS update - Takashi Iwai VIA82xx driver - fixed the (syntax) description of dxs_support module option. (03/11/26 1.1489.3.68) ALSA CVS update - Jaroslav Kysela GUS Library Omited to remove old code (03/11/26 1.1489.3.67) ALSA CVS update - Jaroslav Kysela GUS Library Fixed duplicate control IDs (PCM Playback Volume) for cards with the codec chip (03/11/26 1.1489.3.66) ALSA CVS update - Takashi Iwai USB generic driver - added a workaround for M-Audio Audiophile USB. - avoid async out and adaptive in if other methods are available. - fixed the hw_constraint check for 24bit formats. (03/11/26 1.1489.3.65) ALSA CVS update - Takashi Iwai USB generic driver - added async_unlink option. the default bahevior is not changed yet. - added some comments. (03/11/26 1.1489.3.64) ALSA CVS update - Takashi Iwai I2C lib core - fixed sleep in lock. use mutex for the locking. (03/11/26 1.1489.3.63) ALSA CVS update - Takashi Iwai CS4236+ driver - fixed the detection of combination of pnp and non-pnp devices. (03/11/26 1.1489.3.62) ALSA CVS update - Jaroslav Kysela AC97 Codec Core Added IC Ensemble/KS Waves ID for stereo enhancement (03/11/26 1.1489.3.61) ALSA CVS update - Takashi Iwai CMIPCI driver - set XCHGDAC bit implicitly on MC4/6 models for fixing wrong playback on some boards. - removed 'Exchange DAC' control from such a model. (03/11/26 1.1489.3.60) ALSA CVS update - Takashi Iwai EMU10K1/EMU10K2 driver Peter Zubaj : - disable routing from AC97 line out to front speakers. - AC97 ADC is used only for Mic playback and recording - Philips ADC is used for other analog playback and recording (Analog Mix Playback Volume, Analog Mix Capture Volume) - removes unused AC97 controls (is phone used ???) Takashi Iwai : - removed the duplicated IEC958 control on Dell's board. (03/11/26 1.1489.3.59) ALSA CVS update - Jaroslav Kysela ALSA<-OSS emulation Fixed semantics in snd_pcm_oss_bytes() function. (03/11/26 1.1489.3.58) ALSA CVS update - Jaroslav Kysela OPL4 Clemens Ladisch oops - use vfree in error paths, too (03/11/26 1.1489.3.57) ALSA CVS update - Jaroslav Kysela AC97 Codec Core Fixed cut & paste bug (03/11/26 1.1489.3.56) ALSA CVS update - Takashi Iwai VIA82xx driver added the quirk for ASUS A7V600. (03/11/26 1.1489.3.55) ALSA CVS update - Jaroslav Kysela AC97 Codec Core Clemens Ladisch new controls for AD1981A/B/1980/1985 (03/11/26 1.1489.3.54) ALSA CVS update - Jaroslav Kysela OPL4 Clemens Ladisch use vmalloc instead of kmalloc for temp buffer in proc read()/write() (03/11/26 1.1489.3.53) ALSA CVS update - Takashi Iwai Opti9xx drivers - fixed the detection of opti92x-ad1848 pnp. (03/11/26 1.1489.3.52) ALSA CVS update - Takashi Iwai OSS device core,ALSA Core - take MODULE_ALIAS_CHARDEV_MAJOR() back. - added missing inclusion of linux/device.h. (03/11/26 1.1489.3.51) ALSA CVS update - Takashi Iwai ALSA Core,ALS100 driver,AZT2320 driver,DT019x driver,CS4231 driver CS4236+ driver,PC98(CS423x) driver,Opti9xx drivers,SB16/AWE driver Wavefront drivers use the standard port address, 0 = disable, 1 = auto-probe, others manual. negative values are accepted as disable, too. (03/11/26 1.1489.3.50) ALSA CVS update - Takashi Iwai OSS device core,Documentation,ALSA Core,ALSA<-OSS emulation ALSA<-OSS sequencer,ALSA Minor Numbers Rusty Russell : - added MODULE_ALIAS for sound services. clean up the document. modified by Takashi Iwai (03/11/26 1.1489.3.49) ALSA CVS update - Takashi Iwai Documentation,ALSA Core - cards_limit=1 as default instead of 8. - cards_limit means the number of auto-loaded cards. not limits the actual card numbers for manual loading (e.g. hotplug). (03/11/26 1.1489.3.48) ALSA CVS update - Jaroslav Kysela ALSA<-OSS emulation Fixed read for partial OSS period buffer contents (03/11/26 1.1489.3.47) ALSA CVS update - Jaroslav Kysela AD1848 driver Robert Harris Fixed spinlocks (03/11/26 1.1489.3.46) ALSA CVS update - Jaroslav Kysela ALSA<-OSS emulation - avail_min is now 1 - fixed read1() function for avail_min == 1 - fixed conversion between ALSA and OSS position - fixed info.blocks computing in get_ptr() (included fixup) - fixed get_space() function (included fixup) (03/11/26 1.1489.3.45) ALSA CVS update - Takashi Iwai Documentation,ALS4000 driver,AZT3328 driver,CMIPCI driver ENS1370/1+ driver,VIA82xx driver,YMFPCI driver - use consistent values for specifying the port address (0 = disable, 1 = auto-detect, others = manual) - fixed the auto-detection of joystick port. (03/11/26 1.1489.3.44) ALSA CVS update - Takashi Iwai YMFPCI driver fixed the auto-detection of joystick port. (03/11/26 1.1489.3.43) ALSA CVS update - Takashi Iwai CS46xx driver fixed the 4channel mode of another CS429x codec (0x592b). (03/11/26 1.1489.3.42) ALSA CVS update - Takashi Iwai AC97 Codec Core Ted.Wen@ite.com.tw: - added patch for IT2646. (03/11/26 1.1489.3.41) ALSA CVS update - Takashi Iwai ALSA Core - fixed oops at resume. - block also the non-blocking devices until the resume is finished. (03/11/26 1.1489.3.40) ALSA CVS update - Takashi Iwai Documentation,ALS4000 driver,ENS1370/1+ driver,YMFPCI driver added auto-detection of joystick port. (03/11/26 1.1489.3.39) ALSA CVS update - Takashi Iwai VIA82xx driver Zinx Verituse : fixed the calculation of the port for 'Capture Source' control switch. (03/11/26 1.1489.3.38) ALSA CVS update - Jaroslav Kysela PCM Midlevel - don't print debug messages for low count of periods - added right path for one period to the update pointer routine (interrupt) (03/11/26 1.1489.3.37) ALSA CVS update - Takashi Iwai HWDEP Midlevel allow dsp_load callback without dsp_status callback. (03/11/26 1.1489.3.36) ALSA CVS update - Takashi Iwai PCM Midlevel - don't hold power lock while draining - call trigger callback when suspending/resuming a draining substream (03/11/26 1.1489.3.35) ALSA CVS update - Takashi Iwai PCM Midlevel removed the export of snd_pcm_lock(). replaced with the normal mutex. (03/11/26 1.1489.3.34) ALSA CVS update - Takashi Iwai Documentation minor corrections for the recent updates. (03/11/26 1.1489.3.33) ALSA CVS update - Takashi Iwai Timer Midlevel fixed the unbalanced spinlock at the error path. (03/11/26 1.1489.3.32) ALSA CVS update - Takashi Iwai EMU10K1/EMU10K2 driver - take back the old definition of FXBUS_PCM_LEFT/RIGHT for sb live. - fixed the audigy routing with the new definition. (03/11/26 1.1489.3.31) ALSA CVS update - Takashi Iwai PCM Midlevel don't call kfree with NULL pointer (constraint rules is not always allocated). (03/11/26 1.1489.3.30) ALSA CVS update - Jaroslav Kysela Timer Midlevel - fixed problem with hw slave source (PCM timer & dmix plugin) - fixes for slave instances - moved active callback check to snd_timer_close() function (03/11/26 1.1489.3.29) ALSA CVS update - Takashi Iwai VIA82xx driver added the DXS whitelist for twinhead mobo. (03/11/26 1.1489.3.28) ALSA CVS update - Takashi Iwai AC97 Codec Core fixed typo in the last AD198x fix. (03/11/26 1.1489.3.27) ALSA CVS update - Takashi Iwai Intel8x0 driver,VIA82xx driver,AC97 Codec Core - use ADI-compatible mode on AD1980 for more better controls. - swap master and headphone on AD1980 and AD1985 as default. - export remove_ctl, swap_ctl and rename_ctl for patch functions. - removed AD1980/AD1985 master-swap quirks (since it's set as default). (03/11/26 1.1489.3.26) ALSA CVS update - Takashi Iwai ALSA<-OSS emulation added fallback device selection for OSS mixer. (03/11/26 1.1489.3.25) ALSA CVS update - Takashi Iwai Maestro3 driver don't enable MPU401 irq. (03/11/26 1.1489.3.24) ALSA CVS update - Takashi Iwai AC97 Codec Core added ALC655 entry (compatible with ALC650). (03/11/26 1.1489.3.23) ALSA CVS update - Takashi Iwai CS4281 driver,RME32 driver,RME96 driver,CS46xx driver,NM256 driver - fixed compile warnings with cast for memcpy_fromio/toio. - use copy_to_user_fromio() in proc output. (03/11/26 1.1489.3.22) ALSA CVS update - Takashi Iwai Documentation,SB drivers,YMFPCI driver,ALS4000 driver,AZT3328 driver CMIPCI driver,ENS1370/1+ driver,ES1968 driver,Intel8x0 driver VIA82xx driver - removed joystick control from the card control API. added joystick (or joystick_port) module option instead. - updated documents for this joystick fix. - moved resource management for ALS4000 from sb-common header to the als4000 local code. (03/11/26 1.1489.3.21) ALSA CVS update - Takashi Iwai Generic drivers,MPU401 UART,ALSA Core,ALS100 driver,AZT2320 driver CMI8330 driver,DT019x driver,ES18xx driver,OPL3SA2 driver Sound Galaxy driver,Sound Scape driver,AD1816A driver,AD1848 driver CS4231 driver,CS4236+ driver,PC98(CS423x) driver,ES1688 driver GUS Classic driver,GUS Extreme driver,GUS MAX driver AMD InterWave driver,Opti9xx drivers,ES968 driver,SB16/AWE driver SB8 driver,Wavefront drivers,CMIPCI driver,VIA82xx driver,YMFPCI driver - fixed the boot parameters with long ints for non-intel architectures. - added get_option_long() for parsing the parameter. (03/11/26 1.1489.3.20) ALSA CVS update - Jaroslav Kysela Intel8x0 driver Added mpu_port initialization from the kernel command line (03/11/26 1.1489.3.19) ALSA CVS update - Takashi Iwai EMU10K1/EMU10K2 driver Peter Zubaj : - redesigned the default DSP routing of audigy1/2 boards. the normal PCM output is sent through 'Stereo Mix', while the independent pcm streams can be attenuated by 'PCM Front', 'PCM Rear', and 'PCM Center/LFE' volumes. (03/11/26 1.1489.3.18) ALSA CVS update - Takashi Iwai OPL3,Raw OPL FM,ES1968 driver removed obsolete __SND_OSS_COMPAT__. (03/11/26 1.1489.3.17) ALSA CVS update - Jaroslav Kysela Sound Scape driver Chris Rankin - use #define rather than value for the microcode size (03/11/26 1.1489.3.16) ALSA CVS update - Takashi Iwai VIA82xx driver removed a wrong entry for gigabyte mobos. (03/11/26 1.1489.3.15) ALSA CVS update - Takashi Iwai USB generic driver Clemens Ladisch : - add support for M-Audio OmniStudio MIDI (03/11/26 1.1489.3.14) ALSA CVS update - Takashi Iwai Memalloc module - fixed the compilation without PCI support. added ifdef CONFIG_PCI around preallocate_cards(). (03/11/26 1.1489.3.13) ALSA CVS update - Takashi Iwai Documentation,PCMCIA Kconfig - added CONFIG_ISA restriction to vxpocket and vxp440 drivers. (03/11/26 1.1489.3.12) ALSA CVS update - Takashi Iwai USB generic driver Clemens Ladisch : - fix Edirol comment - use special macros for Yamaha devices - add support for Yamaha MOTIF-R, CVP-204, CVP-206, CVP-208, CVP-210, PSR-1100, PSR-2100, PSR-K1, EZ-250i, MOTIF ES 6, MOTIF ES 7, MOTIF ES 8, CS1D, DSP1D, ACU16-C, NHB32-C, DM1000, 01V96 (03/11/26 1.1489.3.11) ALSA CVS update - Takashi Iwai VIA82xx driver - clean up the rate lock routine. - added another gigabyte mobo entry. (03/11/26 1.1489.3.10) ALSA CVS update - Takashi Iwai ALSA Core,Timer Midlevel,ALSA sequencer,PPC DACA driver PPC Tumbler driver - check rootfs before calling request_module() to avoid annoying error messages at the boot time. (03/11/26 1.1489.3.9) ALSA CVS update - Takashi Iwai Timer Midlevel,ALSA sequencer Clemens Ladisch : - fixed timer resolution calculations Some functions assumed that timer->hw.resolution is in Hz, while it's actually in ns/tick. (03/11/26 1.1489.3.8) ALSA CVS update - Takashi Iwai Documentation,VIA82xx driver - added dxs_support=4 option. no VRA is used for DXS channels in this case. - fixed the quirk for ASUS A7V8-X. - added the quirk for Gigabyte mobo. - removed the error message in codec_valid(). (03/11/26 1.1489.3.7) ALSA CVS update - Takashi Iwai VIA82xx driver - fixed the misuse of long pointer for getting the int value in boot parameter. (03/11/26 1.1489.3.6) ALSA CVS update - Jaroslav Kysela PCM Midlevel Simplified snd_pcm_update_hw_ptr*() functions (03/11/26 1.1489.3.5) ALSA CVS update - Takashi Iwai AC97 Codec Core fixes by James Courtier-Dutton : - fixed the wrong detection of SPDIF output. SPDIF-out is enabled on all chip revisions. - fixed the ac97 codec name shown in proc file, using ac97->id. (03/11/26 1.1489.3.4) ALSA CVS update - Takashi Iwai VIA82xx driver,AC97 Codec Core - fixed typos in the last change to snd_ac97_set_rate(). the correct flag to check is ac97->scaps. - removed dxs_fixed=1 on VIA8233A (for SPDIF). - added quirks for ASUS A7V8-X and MSI KT4V. (03/11/26 1.1489.3.3) ALSA CVS update - Takashi Iwai AC97 Codec Core fixed snd_ac97_set_rate() to accept surround and LFE sample rates, too. (03/11/26 1.1489.3.2) ALSA CVS update - Takashi Iwai EMU10K1/EMU10K2 driver use the standard control names for RCA and optical spdif on audigy. (03/11/26 1.1489.3.1) ALSA CVS update - Jaroslav Kysela ICE1712 driver Moved spdif.setup_rate to snd_ice1712_set_pro_rate() function --- Documentation/sound/alsa/ALSA-Configuration.txt | 248 - Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl | 123 Documentation/sound/alsa/Joystick.txt | 87 Documentation/sound/alsa/OSS-Emulation.txt | 3 include/sound/ac97_codec.h | 101 include/sound/asequencer.h | 2 include/sound/asound.h | 7 include/sound/asound_fm.h | 4 include/sound/cs46xx.h | 1 include/sound/emu10k1.h | 18 include/sound/hdsp.h | 21 include/sound/i2c.h | 10 include/sound/info.h | 5 include/sound/initval.h | 36 include/sound/minors.h | 3 include/sound/pcm.h | 2 include/sound/pcm_oss.h | 2 include/sound/sb.h | 3 include/sound/seq_kernel.h | 2 include/sound/sndmagic.h | 2 include/sound/sscape_ioctl.h | 4 include/sound/trident.h | 1 include/sound/version.h | 4 include/sound/ymfpci.h | 13 sound/core/control.c | 308 + sound/core/hwdep.c | 3 sound/core/info_oss.c | 1 sound/core/init.c | 24 sound/core/memalloc.c | 28 sound/core/memory.c | 1 sound/core/misc.c | 6 sound/core/oss/mixer_oss.c | 44 sound/core/oss/pcm_oss.c | 109 sound/core/pcm.c | 78 sound/core/pcm_lib.c | 102 sound/core/pcm_native.c | 71 sound/core/rawmidi.c | 1 sound/core/seq/oss/seq_oss.c | 3 sound/core/seq/seq.c | 4 sound/core/seq/seq_clientmgr.c | 4 sound/core/seq/seq_clientmgr.h | 2 sound/core/seq/seq_device.c | 3 sound/core/seq/seq_dummy.c | 2 sound/core/seq/seq_fifo.c | 2 sound/core/seq/seq_fifo.h | 2 sound/core/seq/seq_info.c | 2 sound/core/seq/seq_info.h | 2 sound/core/seq/seq_memory.c | 2 sound/core/seq/seq_memory.h | 2 sound/core/seq/seq_midi.c | 4 sound/core/seq/seq_ports.c | 2 sound/core/seq/seq_ports.h | 2 sound/core/seq/seq_prioq.c | 2 sound/core/seq/seq_prioq.h | 2 sound/core/seq/seq_queue.c | 2 sound/core/seq/seq_queue.h | 2 sound/core/seq/seq_system.c | 2 sound/core/seq/seq_system.h | 2 sound/core/seq/seq_timer.c | 4 sound/core/seq/seq_timer.h | 4 sound/core/sound.c | 18 sound/core/sound_oss.c | 1 sound/core/timer.c | 116 sound/drivers/mpu401/mpu401.c | 2 sound/drivers/mtpav.c | 2 sound/drivers/opl3/opl3_synth.c | 1 sound/drivers/opl4/opl4_proc.c | 13 sound/drivers/serial-u16550.c | 120 sound/drivers/vx/vx_core.c | 2 sound/drivers/vx/vx_pcm.c | 8 sound/i2c/cs8427.c | 13 sound/i2c/i2c.c | 2 sound/i2c/l3/uda1341.c | 6 sound/i2c/other/ak4xxx-adda.c | 12 sound/isa/ad1816a/ad1816a.c | 6 sound/isa/ad1848/ad1848.c | 2 sound/isa/ad1848/ad1848_lib.c | 2 sound/isa/als100.c | 10 sound/isa/azt2320.c | 10 sound/isa/cmi8330.c | 4 sound/isa/cs423x/cs4231.c | 13 sound/isa/cs423x/cs4236.c | 40 sound/isa/cs423x/pc98.c | 14 sound/isa/dt019x.c | 14 sound/isa/es1688/es1688.c | 4 sound/isa/es18xx.c | 6 sound/isa/gus/gus_irq.c | 2 sound/isa/gus/gus_mem.c | 2 sound/isa/gus/gus_pcm.c | 23 sound/isa/gus/gusclassic.c | 2 sound/isa/gus/gusextreme.c | 6 sound/isa/gus/gusmax.c | 2 sound/isa/gus/interwave.c | 14 sound/isa/opl3sa2.c | 10 sound/isa/opti9xx/opti92x-ad1848.c | 39 sound/isa/sb/emu8000.c | 2 sound/isa/sb/es968.c | 2 sound/isa/sb/sb16.c | 17 sound/isa/sb/sb16_csp.c | 4 sound/isa/sb/sb8.c | 2 sound/isa/sb/sb_common.c | 4 sound/isa/sgalaxy.c | 8 sound/isa/sscape.c | 9 sound/isa/wavefront/wavefront.c | 23 sound/pci/ac97/Makefile | 2 sound/pci/ac97/ac97_codec.c | 557 +-- sound/pci/ac97/ac97_local.h | 8 sound/pci/ac97/ac97_patch.c | 348 +- sound/pci/ac97/ac97_patch.h | 4 sound/pci/ac97/ac97_pcm.c | 593 +++ sound/pci/ac97/ac97_proc.c | 77 sound/pci/ac97/ak4531_codec.c | 2 sound/pci/ali5451/ali5451.c | 22 sound/pci/als4000.c | 75 sound/pci/azt3328.c | 92 sound/pci/cmipci.c | 95 sound/pci/cs4281.c | 68 sound/pci/cs46xx/cs46xx_lib.c | 62 sound/pci/emu10k1/emu10k1_main.c | 16 sound/pci/emu10k1/emufx.c | 186 - sound/pci/emu10k1/emumixer.c | 56 sound/pci/emu10k1/emupcm.c | 2 sound/pci/emu10k1/emuproc.c | 2 sound/pci/ens1370.c | 218 - sound/pci/es1938.c | 2 sound/pci/es1968.c | 116 sound/pci/fm801.c | 22 sound/pci/ice1712/Makefile | 2 sound/pci/ice1712/ak4xxx.c | 12 sound/pci/ice1712/aureon.c | 13 sound/pci/ice1712/delta.c | 27 sound/pci/ice1712/ice1712.c | 31 sound/pci/ice1712/ice1712.h | 2 sound/pci/ice1712/ice1724.c | 18 sound/pci/ice1712/prodigy.c | 662 ++++ sound/pci/ice1712/prodigy.h | 67 sound/pci/intel8x0.c | 515 +-- sound/pci/korg1212/korg1212.c | 2 sound/pci/maestro3.c | 16 sound/pci/nm256/nm256.c | 15 sound/pci/rme32.c | 18 sound/pci/rme96.c | 22 sound/pci/rme9652/hdsp.c | 1767 ++++++++--- sound/pci/rme9652/rme9652.c | 3 sound/pci/sonicvibes.c | 4 sound/pci/trident/trident_main.c | 19 sound/pci/via82xx.c | 189 - sound/pci/ymfpci/ymfpci.c | 96 sound/pci/ymfpci/ymfpci_main.c | 299 - sound/pcmcia/Kconfig | 4 sound/pcmcia/vx/vx_entry.c | 4 sound/ppc/daca.c | 3 sound/ppc/tumbler.c | 3 sound/usb/usbaudio.c | 236 - sound/usb/usbquirks.h | 269 - 155 files changed, 6168 insertions(+), 2923 deletions(-) diff -puN Documentation/sound/alsa/ALSA-Configuration.txt~alsa-101 Documentation/sound/alsa/ALSA-Configuration.txt --- 25/Documentation/sound/alsa/ALSA-Configuration.txt~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/Documentation/sound/alsa/ALSA-Configuration.txt 2004-01-19 22:19:00.000000000 -0800 @@ -55,9 +55,10 @@ Module parameters 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 parameters 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 parameters 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 parameters 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 @@ Module parameters * 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 @@ Module parameters * 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 @@ Module parameters 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 parameters 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 @@ Module parameters * 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 @@ Module parameters 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 @@ Module parameters 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 parameters 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 /usr/bin/vxload + (for 2.2/2.4 kernels, add "post-install /usr/bin/vxload" 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 @@ Module parameters 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 @@ Module parameters 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 @@ Module parameters 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 @@ Module parameters 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 @@ When the kernel is configured without IS 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 -puN Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl~alsa-101 Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl --- 25/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl 2004-01-19 22:19:00.000000000 -0800 @@ -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. -
@@ -1299,7 +1295,7 @@ printk(KERN_ERR "error to set 28bit mask DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x0fffffff); + pci_set_consistent_dma_mask(pci, 0x0fffffff); chip = snd_magic_kcalloc(mychip_t, 0, GFP_KERNEL); if (chip == NULL) @@ -1417,7 +1413,7 @@ printk(KERN_ERR "error to set 28bit mask DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x0fffffff); + pci_set_consistent_dma_mask(pci, 0x0fffffff); ]]> @@ -1914,8 +1910,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 +1941,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 +2040,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 +4029,18 @@ struct _snd_pcm_runtime { 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 +4052,29 @@ struct _snd_pcm_runtime {
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 +4083,16 @@ struct _snd_pcm_runtime { 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 +4166,11 @@ struct _snd_pcm_runtime { 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 +4743,7 @@ struct _snd_pcm_runtime { - 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 +4971,8 @@ struct _snd_pcm_runtime { 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 +5067,14 @@ struct _snd_pcm_runtime { 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 -puN /dev/null Documentation/sound/alsa/Joystick.txt --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25-akpm/Documentation/sound/alsa/Joystick.txt 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN Documentation/sound/alsa/OSS-Emulation.txt~alsa-101 Documentation/sound/alsa/OSS-Emulation.txt --- 25/Documentation/sound/alsa/OSS-Emulation.txt~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/Documentation/sound/alsa/OSS-Emulation.txt 2004-01-19 22:19:00.000000000 -0800 @@ -152,8 +152,7 @@ available: 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 diff -puN include/sound/ac97_codec.h~alsa-101 include/sound/ac97_codec.h --- 25/include/sound/ac97_codec.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/ac97_codec.h 2004-01-19 22:19:00.000000000 -0800 @@ -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) */ @@ -274,10 +301,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 +328,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 +365,39 @@ struct snd_ac97_build_ops { 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 +409,6 @@ struct _snd_ac97 { 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 +446,14 @@ static inline int ac97_can_amap(ac97_t * } /* 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 +476,13 @@ struct ac97_quirk { }; 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 -puN include/sound/asequencer.h~alsa-101 include/sound/asequencer.h --- 25/include/sound/asequencer.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/asequencer.h 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN include/sound/asound_fm.h~alsa-101 include/sound/asound_fm.h --- 25/include/sound/asound_fm.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/asound_fm.h 2004-01-19 22:19:00.000000000 -0800 @@ -105,8 +105,6 @@ typedef struct snd_dm_fm_params { /* 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 @@ -114,6 +112,4 @@ typedef struct snd_dm_fm_params { #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 -puN include/sound/asound.h~alsa-101 include/sound/asound.h --- 25/include/sound/asound.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/asound.h 2004-01-19 22:19:00.000000000 -0800 @@ -272,6 +272,7 @@ enum sndrv_pcm_subformat { #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 */ @@ -683,7 +684,7 @@ struct sndrv_timer_tread { * * ****************************************************************************/ -#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 +729,7 @@ enum sndrv_ctl_elem_iface { #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 +826,9 @@ enum { 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 -puN include/sound/cs46xx.h~alsa-101 include/sound/cs46xx.h --- 25/include/sound/cs46xx.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/cs46xx.h 2004-01-19 22:19:00.000000000 -0800 @@ -1712,6 +1712,7 @@ struct _snd_cs46xx { int nr_ac97_codecs; + ac97_bus_t *ac97_bus; ac97_t *ac97[MAX_NR_AC97]; struct pci_dev *pci; diff -puN include/sound/emu10k1.h~alsa-101 include/sound/emu10k1.h --- 25/include/sound/emu10k1.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/emu10k1.h 2004-01-19 22:19:00.000000000 -0800 @@ -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 @@ -1152,10 +1155,12 @@ int snd_emu10k1_proc_init(emu10k1_t * em #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 @@ int snd_emu10k1_proc_init(emu10k1_t * em #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 @@ int snd_emu10k1_proc_init(emu10k1_t * em #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 @@ int snd_emu10k1_proc_init(emu10k1_t * em #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 -puN include/sound/hdsp.h~alsa-101 include/sound/hdsp.h --- 25/include/sound/hdsp.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/hdsp.h 2004-01-19 22:19:00.000000000 -0800 @@ -25,17 +25,20 @@ typedef enum { 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 @@ struct _snd_hdsp_config_info { 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) @@ -90,4 +98,13 @@ struct _snd_hdsp_mixer { #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 -puN include/sound/i2c.h~alsa-101 include/sound/i2c.h --- 25/include/sound/i2c.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/i2c.h 2004-01-19 22:19:00.000000000 -0800 @@ -58,7 +58,7 @@ struct _snd_i2c_bus { 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 @@ int snd_i2c_device_free(snd_i2c_device_t 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 -puN include/sound/info.h~alsa-101 include/sound/info.h --- 25/include/sound/info.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/info.h 2004-01-19 22:19:00.000000000 -0800 @@ -134,12 +134,13 @@ void snd_remove_proc_entry(struct proc_d /* 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 -puN include/sound/initval.h~alsa-101 include/sound/initval.h --- 25/include/sound/initval.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/initval.h 2004-01-19 22:19:00.000000000 -0800 @@ -35,7 +35,7 @@ static const char __module_generic_strin #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 @@ static const char __module_generic_strin #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 @@ static int snd_legacy_find_free_dma(int #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 -puN include/sound/minors.h~alsa-101 include/sound/minors.h --- 25/include/sound/minors.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/minors.h 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN include/sound/pcm.h~alsa-101 include/sound/pcm.h --- 25/include/sound/pcm.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/pcm.h 2004-01-19 22:19:00.000000000 -0800 @@ -461,8 +461,6 @@ typedef struct _snd_pcm_notify { 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, snd_pcm_t **rpcm); diff -puN include/sound/pcm_oss.h~alsa-101 include/sound/pcm_oss.h --- 25/include/sound/pcm_oss.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/pcm_oss.h 2004-01-19 22:19:00.000000000 -0800 @@ -31,7 +31,7 @@ struct _snd_pcm_oss_setup { direct:1, block:1, nonblock:1, - wholefrag:1, + partialfrag:1, nosilence:1; unsigned int periods; unsigned int period_size; diff -puN include/sound/sb.h~alsa-101 include/sound/sb.h --- 25/include/sound/sb.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/sb.h 2004-01-19 22:19:00.000000000 -0800 @@ -63,8 +63,6 @@ enum sb_hw_type { 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 @@ struct _snd_sb { 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 -puN include/sound/seq_kernel.h~alsa-101 include/sound/seq_kernel.h --- 25/include/sound/seq_kernel.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/seq_kernel.h 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN include/sound/sndmagic.h~alsa-101 include/sound/sndmagic.h --- 25/include/sound/sndmagic.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/sndmagic.h 2004-01-19 22:19:00.000000000 -0800 @@ -133,6 +133,7 @@ static inline int _snd_magic_bad(void *o #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 @@ static inline int _snd_magic_bad(void *o #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 -puN include/sound/sscape_ioctl.h~alsa-101 include/sound/sscape_ioctl.h --- 25/include/sound/sscape_ioctl.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/sscape_ioctl.h 2004-01-19 22:19:00.000000000 -0800 @@ -8,9 +8,11 @@ struct sscape_bootblock 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 -puN include/sound/trident.h~alsa-101 include/sound/trident.h --- 25/include/sound/trident.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/trident.h 2004-01-19 22:19:00.000000000 -0800 @@ -443,6 +443,7 @@ struct _snd_trident { snd_rawmidi_t *rmidi; snd_seq_device_t *seq_dev; + ac97_bus_t *ac97_bus; ac97_t *ac97; ac97_t *ac97_sec; diff -puN include/sound/version.h~alsa-101 include/sound/version.h --- 25/include/sound/version.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/version.h 2004-01-19 22:19:00.000000000 -0800 @@ -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)" +#define CONFIG_SND_VERSION "1.0.1" +#define CONFIG_SND_DATE " (Tue Dec 30 10:04:14 2003 UTC)" diff -puN include/sound/ymfpci.h~alsa-101 include/sound/ymfpci.h --- 25/include/sound/ymfpci.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/include/sound/ymfpci.h 2004-01-19 22:19:00.000000000 -0800 @@ -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 @@ struct _snd_ymfpci { 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 @@ struct _snd_ymfpci { 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_pcm2(ymfpci_t *chip, int 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); @@ -401,4 +400,8 @@ 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 -puN sound/core/control.c~alsa-101 sound/core/control.c --- 25/sound/core/control.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/control.c 2004-01-19 22:19:00.000000000 -0800 @@ -37,6 +37,9 @@ typedef struct _snd_kctl_ioctl { #define snd_kctl_ioctl(n) list_entry(n, snd_kctl_ioctl_t, list) +/* find id without lock */ +static snd_kcontrol_t *_ctl_find_id(snd_card_t * card, snd_ctl_elem_id_t *id); + static DECLARE_RWSEM(snd_ioctl_rwsem); static LIST_HEAD(snd_control_ioctls); @@ -253,15 +256,51 @@ void snd_ctl_free_one(snd_kcontrol_t * k } } +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 +309,29 @@ int snd_ctl_add(snd_card_t * card, snd_k 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 (_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 +343,8 @@ int snd_ctl_add(snd_card_t * card, snd_k * @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 +354,8 @@ int snd_ctl_remove(snd_card_t * card, sn 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 +376,50 @@ int snd_ctl_remove(snd_card_t * card, sn int snd_ctl_remove_id(snd_card_t * card, snd_ctl_elem_id_t *id) { snd_kcontrol_t *kctl; + int ret; - kctl = snd_ctl_find_id(card, id); - if (kctl == NULL) + down_write(&card->controls_rwsem); + kctl = _ctl_find_id(card, id); + 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 = _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 @@ -564,7 +653,6 @@ static int snd_ctl_elem_info(snd_ctl_fil 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; @@ -711,6 +799,196 @@ static int snd_ctl_elem_unlock(snd_ctl_f 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 = _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 +1039,12 @@ static int snd_ctl_ioctl(struct inode *i 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 +1279,11 @@ int snd_ctl_unregister(snd_card_t *card) 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 -puN sound/core/hwdep.c~alsa-101 sound/core/hwdep.c --- 25/sound/core/hwdep.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/hwdep.c 2004-01-19 22:19:00.000000000 -0800 @@ -214,7 +214,7 @@ static int snd_hwdep_dsp_load(snd_hwdep_ 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 @@ static int __init alsa_hwdep_init(void) 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 -puN sound/core/info_oss.c~alsa-101 sound/core/info_oss.c --- 25/sound/core/info_oss.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/info_oss.c 2004-01-19 22:19:00.000000000 -0800 @@ -114,7 +114,6 @@ int snd_info_minor_register(void) 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 -puN sound/core/init.c~alsa-101 sound/core/init.c --- 25/sound/core/init.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/init.c 2004-01-19 22:19:00.000000000 -0800 @@ -442,7 +442,6 @@ int snd_card_register(snd_card_t * card) 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 @@ int __init snd_card_info_init(void) 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 @@ int __init snd_card_info_init(void) #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_card_file_remove(snd_card_t *car 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 @@ int snd_power_wait(snd_card_t *card, uns 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 -puN sound/core/memalloc.c~alsa-101 sound/core/memalloc.c --- 25/sound/core/memalloc.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/memalloc.c 2004-01-19 22:19:00.000000000 -0800 @@ -39,7 +39,7 @@ MODULE_LICENSE("GPL"); #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."); @@ -95,25 +95,25 @@ static void *snd_pci_hack_alloc_consiste { void *ret; u64 dma_mask; - unsigned long rmask; + unsigned long mask; if (hwdev == NULL) return pci_alloc_consistent(hwdev, size, dma_handle); - dma_mask = hwdev->dma_mask; - rmask = ~((unsigned long)dma_mask); - hwdev->dma_mask = 0xffffffff; /* do without masking */ + dma_mask = hwdev->consistent_dma_mask; + mask = (unsigned long)dma_mask; + 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 = dma_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; @@ -640,13 +640,13 @@ void *snd_malloc_pci_page(struct pci_dev { 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 +783,7 @@ void snd_free_sbus_pages(struct sbus_dev * allocation of buffers for pre-defined devices */ +#ifdef CONFIG_PCI /* FIXME: for pci only - other bus? */ struct prealloc_dev { unsigned short vendor; @@ -832,7 +833,7 @@ static void __init preallocate_cards(voi if (! enable[card++]) continue; - if (pci_set_dma_mask(pci, dev->dma_mask) < 0) { + if (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; } @@ -854,6 +855,9 @@ static void __init preallocate_cards(voi } } } +#else +#define preallocate_cards() /* NOP */ +#endif #ifdef CONFIG_PROC_FS diff -puN sound/core/memory.c~alsa-101 sound/core/memory.c --- 25/sound/core/memory.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/memory.c 2004-01-19 22:19:00.000000000 -0800 @@ -231,7 +231,6 @@ int __init snd_memory_info_init(void) 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 -puN sound/core/misc.c~alsa-101 sound/core/misc.c --- 25/sound/core/misc.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/misc.c 2004-01-19 22:19:00.000000000 -0800 @@ -51,9 +51,8 @@ void snd_verbose_printk(const char *file 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 @@ void snd_verbose_printd(const char *file 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 -puN sound/core/oss/mixer_oss.c~alsa-101 sound/core/oss/mixer_oss.c --- 25/sound/core/oss/mixer_oss.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/oss/mixer_oss.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 @@ static int snd_mixer_oss_ioctl1(snd_mixe 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 @@ static int snd_mixer_oss_ioctl1(snd_mixe 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; } @@ -872,7 +877,12 @@ static void mixer_slot_clear(snd_mixer_o 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,6 +890,10 @@ static int snd_mixer_oss_build_input(snd 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)); if (snd_mixer_oss_build_test(mixer, &slot, ptr->name, ptr->index, SNDRV_MIXER_OSS_ITEM_GLOBAL)) @@ -1084,7 +1098,7 @@ static void snd_mixer_oss_proc_write(snd 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 +1141,11 @@ static void snd_mixer_oss_build(snd_mixe { 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 +1153,7 @@ static void snd_mixer_oss_build(snd_mixe { 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 +1169,10 @@ static void snd_mixer_oss_build(snd_mixe { 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 -puN sound/core/oss/pcm_oss.c~alsa-101 sound/core/oss/pcm_oss.c --- 25/sound/core/oss/pcm_oss.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/oss/pcm_oss.c 2004-01-19 22:19:00.000000000 -0800 @@ -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_SYNTAX(adsp_map, "default:1, 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 @@ int snd_pcm_plugin_append(snd_pcm_plugin 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 @@ static int snd_pcm_oss_change_params(snd 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 @@ static int snd_pcm_oss_change_params(snd 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 @@ static int snd_pcm_oss_prepare(snd_pcm_s 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 @@ static ssize_t snd_pcm_oss_write1(snd_pc 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 @@ static ssize_t snd_pcm_oss_read1(snd_pcm 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; @@ -1306,11 +1311,11 @@ static int snd_pcm_oss_get_caps(snd_pcm_ 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 +1336,6 @@ static int snd_pcm_oss_set_trigger(snd_p 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 +1346,8 @@ static int snd_pcm_oss_set_trigger(snd_p 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 +1430,7 @@ static int snd_pcm_oss_get_ptr(snd_pcm_o 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 +1450,37 @@ static int snd_pcm_oss_get_ptr(snd_pcm_o } 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 +1492,7 @@ static int snd_pcm_oss_get_space(snd_pcm 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 +1511,8 @@ static int snd_pcm_oss_get_space(snd_pcm 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 +1520,22 @@ static int snd_pcm_oss_get_space(snd_pcm } 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 +1873,9 @@ static int snd_pcm_oss_ioctl(struct inod 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 +1904,48 @@ static int snd_pcm_oss_ioctl(struct inod 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 +1957,7 @@ static int snd_pcm_oss_ioctl(struct inod 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 +1966,7 @@ static int snd_pcm_oss_ioctl(struct inod 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 +1979,12 @@ static int snd_pcm_oss_ioctl(struct inod 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 +2015,7 @@ static int snd_pcm_oss_ioctl(struct inod 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 +2177,8 @@ static int snd_pcm_oss_mmap(struct file 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 +2207,7 @@ static void snd_pcm_oss_proc_read(snd_in 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 +2274,8 @@ static void snd_pcm_oss_proc_write(snd_i 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 -puN sound/core/pcm.c~alsa-101 sound/core/pcm.c --- 25/sound/core/pcm.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/pcm.c 2004-01-19 22:19:00.000000000 -0800 @@ -43,15 +43,6 @@ static int snd_pcm_dev_register(snd_devi 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 @@ static void snd_pcm_substream_proc_statu 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); @@ -416,11 +408,7 @@ static int snd_pcm_stream_proc_init(snd_ 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; @@ -463,11 +451,7 @@ static int snd_pcm_substream_proc_init(s 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 +460,7 @@ static int snd_pcm_substream_proc_init(s 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 +469,7 @@ static int snd_pcm_substream_proc_init(s 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 +478,7 @@ static int snd_pcm_substream_proc_init(s 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 +493,23 @@ static int snd_pcm_substream_proc_done(s { 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 +791,8 @@ void snd_pcm_release_substream(snd_pcm_s 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 +808,10 @@ static int snd_pcm_dev_register(snd_devi 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 +833,7 @@ static int snd_pcm_dev_register(snd_devi } 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 +844,7 @@ static int snd_pcm_dev_register(snd_devi notify = list_entry(list, snd_pcm_notify_t, list); notify->n_register(pcm); } - snd_pcm_lock(1); + up(®ister_mutex); return 0; } @@ -881,7 +854,7 @@ static int snd_pcm_dev_disconnect(snd_de struct list_head *list; int idx; - snd_pcm_lock(0); + down(®ister_mutex); idx = (pcm->card->number * SNDRV_PCM_DEVICES) + pcm->device; snd_pcm_devices[idx] = NULL; list_for_each(list, &snd_pcm_notify_list) { @@ -889,7 +862,7 @@ static int snd_pcm_dev_disconnect(snd_de notify = list_entry(list, snd_pcm_notify_t, list); notify->n_disconnect(pcm); } - snd_pcm_lock(1); + up(®ister_mutex); return 0; } @@ -901,7 +874,7 @@ static int snd_pcm_dev_unregister(snd_de 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 +896,7 @@ static int snd_pcm_dev_unregister(snd_de 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 +905,7 @@ int snd_pcm_notify(snd_pcm_notify_t *not 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 +921,7 @@ int snd_pcm_notify(snd_pcm_notify_t *not notify->n_register(snd_pcm_devices[idx]); } } - snd_pcm_lock(1); + up(®ister_mutex); return 0; } @@ -989,9 +962,7 @@ static int __init alsa_pcm_init(void) 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 +984,6 @@ static void __exit alsa_pcm_exit(void) 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 -puN sound/core/pcm_lib.c~alsa-101 sound/core/pcm_lib.c --- 25/sound/core/pcm_lib.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/pcm_lib.c 2004-01-19 22:19:00.000000000 -0800 @@ -125,15 +125,11 @@ void snd_pcm_playback_silence(snd_pcm_su } } -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,55 @@ static inline int snd_pcm_update_hw_ptr_ } 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); + 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 +201,7 @@ static inline int snd_pcm_update_hw_ptr_ 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 +210,19 @@ int snd_pcm_update_hw_ptr(snd_pcm_substr 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 +233,10 @@ int snd_pcm_update_hw_ptr(snd_pcm_substr 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 -puN sound/core/pcm_native.c~alsa-101 sound/core/pcm_native.c --- 25/sound/core/pcm_native.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/pcm_native.c 2004-01-19 22:19:00.000000000 -0800 @@ -620,7 +620,7 @@ struct action_ops { */ 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 @@ static int snd_pcm_action_group(struct a 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 @@ static int snd_pcm_action_group(struct a 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 @@ static int snd_pcm_action_group(struct a /* 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 @@ static int snd_pcm_action_single(struct /* * 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 @@ static int snd_pcm_action(struct action_ 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 @@ static int snd_pcm_action(struct action_ /* * 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 @@ static int snd_pcm_action_lock_irq(struc 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 @@ static int snd_pcm_do_suspend(snd_pcm_su 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 @@ static int snd_pcm_do_resume(snd_pcm_sub 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 @@ static int snd_pcm_resume(snd_pcm_substr 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 struct action_ops snd_pcm_action_ 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 @@ int snd_pcm_prepare(snd_pcm_substream_t 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 @@ static int snd_pcm_playback_drain(snd_pc } 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; @@ -2326,7 +2375,7 @@ static int snd_pcm_common_ioctl1(snd_pcm 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 -puN sound/core/rawmidi.c~alsa-101 sound/core/rawmidi.c --- 25/sound/core/rawmidi.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/rawmidi.c 2004-01-19 22:19:00.000000000 -0800 @@ -1507,7 +1507,6 @@ static int snd_rawmidi_dev_register(snd_ 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 -puN sound/core/seq/oss/seq_oss.c~alsa-101 sound/core/seq/oss/seq_oss.c --- 25/sound/core/seq/oss/seq_oss.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/seq/oss/seq_oss.c 2004-01-19 22:19:00.000000000 -0800 @@ -35,6 +35,9 @@ MODULE_AUTHOR("Takashi Iwai + * 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_device = SNDRV_TIM 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 -puN sound/core/seq/seq_clientmgr.c~alsa-101 sound/core/seq/seq_clientmgr.c --- 25/sound/core/seq/seq_clientmgr.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_clientmgr.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 @@ client_t *snd_seq_client_use_ptr(int cli 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 -puN sound/core/seq/seq_clientmgr.h~alsa-101 sound/core/seq/seq_clientmgr.h --- 25/sound/core/seq/seq_clientmgr.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_clientmgr.h 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/core/seq/seq_device.c~alsa-101 sound/core/seq/seq_device.c --- 25/sound/core/seq/seq_device.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_device.c 2004-01-19 22:19:00.000000000 -0800 @@ -132,6 +132,9 @@ void snd_seq_device_load_drivers(void) #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 -puN sound/core/seq/seq_dummy.c~alsa-101 sound/core/seq/seq_dummy.c --- 25/sound/core/seq/seq_dummy.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_dummy.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/core/seq/seq_fifo.c~alsa-101 sound/core/seq/seq_fifo.c --- 25/sound/core/seq/seq_fifo.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_fifo.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/core/seq/seq_fifo.h~alsa-101 sound/core/seq/seq_fifo.h --- 25/sound/core/seq/seq_fifo.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_fifo.h 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/core/seq/seq_info.c~alsa-101 sound/core/seq/seq_info.c --- 25/sound/core/seq/seq_info.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_info.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/core/seq/seq_info.h~alsa-101 sound/core/seq/seq_info.h --- 25/sound/core/seq/seq_info.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_info.h 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/core/seq/seq_memory.c~alsa-101 sound/core/seq/seq_memory.c --- 25/sound/core/seq/seq_memory.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_memory.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/core/seq/seq_memory.h~alsa-101 sound/core/seq/seq_memory.h --- 25/sound/core/seq/seq_memory.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_memory.h 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/core/seq/seq_midi.c~alsa-101 sound/core/seq/seq_midi.c --- 25/sound/core/seq/seq_midi.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_midi.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 @@ Possible options for midisynth module: #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 -puN sound/core/seq/seq_ports.c~alsa-101 sound/core/seq/seq_ports.c --- 25/sound/core/seq/seq_ports.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_ports.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/core/seq/seq_ports.h~alsa-101 sound/core/seq/seq_ports.h --- 25/sound/core/seq/seq_ports.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_ports.h 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/core/seq/seq_prioq.c~alsa-101 sound/core/seq/seq_prioq.c --- 25/sound/core/seq/seq_prioq.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_prioq.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/core/seq/seq_prioq.h~alsa-101 sound/core/seq/seq_prioq.h --- 25/sound/core/seq/seq_prioq.h~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_prioq.h 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/core/seq/seq_queue.c~alsa-101 sound/core/seq/seq_queue.c --- 25/sound/core/seq/seq_queue.c~alsa-101 2004-01-19 22:18:59.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_queue.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/core/seq/seq_queue.h~alsa-101 sound/core/seq/seq_queue.h --- 25/sound/core/seq/seq_queue.h~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_queue.h 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/core/seq/seq_system.c~alsa-101 sound/core/seq/seq_system.c --- 25/sound/core/seq/seq_system.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_system.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/core/seq/seq_system.h~alsa-101 sound/core/seq/seq_system.h --- 25/sound/core/seq/seq_system.h~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_system.h 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/core/seq/seq_timer.c~alsa-101 sound/core/seq/seq_timer.c --- 25/sound/core/seq/seq_timer.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_timer.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 @@ static int initialize_timer(seq_timer_t 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 -puN sound/core/seq/seq_timer.h~alsa-101 sound/core/seq/seq_timer.h --- 25/sound/core/seq/seq_timer.h~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/core/seq/seq_timer.h 2004-01-19 22:19:00.000000000 -0800 @@ -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 @@ typedef struct { 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 -puN sound/core/sound.c~alsa-101 sound/core/sound.c --- 25/sound/core/sound.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/core/sound.c 2004-01-19 22:20:46.000000000 -0800 @@ -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(major, "i"); 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(device_mode, "i"); 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 @@ void snd_request_card(int card) { 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 @@ static void snd_request_other(int minor) { 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; @@ -222,7 +231,7 @@ int snd_register_device(int type, snd_ca } 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 +266,7 @@ int snd_unregister_device(int type, snd_ return -EINVAL; } - if (strncmp(mptr->name, "controlC", 8)) { /* created in sound.c */ + if (strncmp(mptr->name, "controlC", 8) || card->number >= cards_limit) { devfs_remove("snd/%s", mptr->name); class_simple_device_remove(MKDEV(major, minor)); } @@ -303,7 +312,6 @@ int __init snd_minor_info_init(void) 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 -puN sound/core/sound_oss.c~alsa-101 sound/core/sound_oss.c --- 25/sound/core/sound_oss.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/core/sound_oss.c 2004-01-19 22:19:00.000000000 -0800 @@ -217,7 +217,6 @@ int __init snd_minor_info_oss_init(void) 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 -puN sound/core/timer.c~alsa-101 sound/core/timer.c --- 25/sound/core/timer.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/core/timer.c 2004-01-19 22:19:00.000000000 -0800 @@ -148,6 +148,8 @@ static snd_timer_t *snd_timer_find(snd_t 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 @@ int snd_timer_close(snd_timer_instance_t 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 @@ static int snd_timer_start1(snd_timer_t 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 @@ static int _snd_timer_stop(snd_timer_ins 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 @@ static int _snd_timer_stop(snd_timer_ins 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 @@ int snd_timer_global_unregister(snd_time * 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 @@ unsigned int snd_timer_system_resolution 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 void snd_timer_free_system(snd_ti 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 @@ static int snd_timer_user_gstatus(struct 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 @@ static ssize_t snd_timer_user_read(struc 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 @@ static ssize_t snd_timer_user_read(struc tu->qused--; } spin_unlock_irq(&tu->qlock); + _error: return result > 0 ? result : err; } @@ -1761,7 +1810,6 @@ static int __init alsa_timer_init(void) 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 -puN sound/drivers/mpu401/mpu401.c~alsa-101 sound/drivers/mpu401/mpu401.c --- 25/sound/drivers/mpu401/mpu401.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/drivers/mpu401/mpu401.c 2004-01-19 22:19:00.000000000 -0800 @@ -157,7 +157,7 @@ static int __init alsa_card_mpu401_setup #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 -puN sound/drivers/mtpav.c~alsa-101 sound/drivers/mtpav.c --- 25/sound/drivers/mtpav.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/drivers/mtpav.c 2004-01-19 22:19:00.000000000 -0800 @@ -813,7 +813,7 @@ static int __init alsa_card_mtpav_setup( (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 -puN sound/drivers/opl3/opl3_synth.c~alsa-101 sound/drivers/opl3/opl3_synth.c --- 25/sound/drivers/opl3/opl3_synth.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/drivers/opl3/opl3_synth.c 2004-01-19 22:19:00.000000000 -0800 @@ -20,7 +20,6 @@ */ #include -#define __SND_OSS_COMPAT__ #include /* diff -puN sound/drivers/opl4/opl4_proc.c~alsa-101 sound/drivers/opl4/opl4_proc.c --- 25/sound/drivers/opl4/opl4_proc.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/drivers/opl4/opl4_proc.c 2004-01-19 22:19:00.000000000 -0800 @@ -18,6 +18,7 @@ */ #include "opl4_local.h" +#include #include #ifdef CONFIG_PROC_FS @@ -59,15 +60,15 @@ static long snd_opl4_mem_proc_read(snd_i 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 @@ static long snd_opl4_mem_proc_write(snd_ 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 -puN sound/drivers/serial-u16550.c~alsa-101 sound/drivers/serial-u16550.c --- 25/sound/drivers/serial-u16550.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/drivers/serial-u16550.c 2004-01-19 22:19:00.000000000 -0800 @@ -63,6 +63,9 @@ static char *adaptor_names[] = { "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 base[SNDRV_CARDS] = {[0 ... ( 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(outs, "1-" __MODULE_STRING(S 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 @@ typedef struct _snd_uart16550 { 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_del_tim 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 @@ static void snd_uart16550_io_loop(snd_ua || 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 ? */ @@ -576,19 +588,31 @@ static int snd_uart16550_output_close(sn 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 +635,14 @@ static void snd_uart16550_output_byte(sn } } } 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 +686,38 @@ static void snd_uart16550_output_write(s } } 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 +778,7 @@ static int __init snd_uart16550_create(s unsigned int speed, unsigned int base, int adaptor, + int droponfull, snd_uart16550_t **ruart) { static snd_device_ops_t ops = { @@ -771,6 +795,7 @@ static int __init snd_uart16550_create(s 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 +925,7 @@ static int __init snd_serial_probe(int d speed[dev], base[dev], adaptor[dev], + droponfull[dev], &uart)) < 0) { snd_card_free(card); return err; @@ -910,7 +936,7 @@ static int __init snd_serial_probe(int d 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 +944,8 @@ static int __init snd_serial_probe(int d (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 +991,7 @@ module_exit(alsa_card_serial_exit) /* 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 +1002,14 @@ static int __init alsa_card_serial_setup (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 -puN sound/drivers/vx/vx_core.c~alsa-101 sound/drivers/vx/vx_core.c --- 25/sound/drivers/vx/vx_core.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/drivers/vx/vx_core.c 2004-01-19 22:19:00.000000000 -0800 @@ -641,7 +641,7 @@ static void vx_proc_init(vx_core_t *chip 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 -puN sound/drivers/vx/vx_pcm.c~alsa-101 sound/drivers/vx/vx_pcm.c --- 25/sound/drivers/vx/vx_pcm.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/drivers/vx/vx_pcm.c 2004-01-19 22:19:00.000000000 -0800 @@ -611,6 +611,10 @@ static int vx_pcm_playback_open(snd_pcm_ 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; } @@ -1015,6 +1019,10 @@ static int vx_pcm_capture_open(snd_pcm_s 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 -puN sound/i2c/cs8427.c~alsa-101 sound/i2c/cs8427.c --- 25/sound/i2c/cs8427.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/i2c/cs8427.c 2004-01-19 22:19:00.000000000 -0800 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -558,6 +559,18 @@ int snd_cs8427_iec958_pcm(snd_i2c_device 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); EXPORT_SYMBOL(snd_cs8427_reset); diff -puN sound/i2c/i2c.c~alsa-101 sound/i2c/i2c.c --- 25/sound/i2c/i2c.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/i2c/i2c.c 2004-01-19 22:19:00.000000000 -0800 @@ -84,7 +84,7 @@ int snd_i2c_bus_create(snd_card_t *card, 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 -puN sound/i2c/l3/uda1341.c~alsa-101 sound/i2c/l3/uda1341.c --- 25/sound/i2c/l3/uda1341.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/i2c/l3/uda1341.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 @@ static void __devinit snd_uda1341_proc_i 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 -puN sound/i2c/other/ak4xxx-adda.c~alsa-101 sound/i2c/other/ak4xxx-adda.c --- 25/sound/i2c/other/ak4xxx-adda.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/i2c/other/ak4xxx-adda.c 2004-01-19 22:19:00.000000000 -0800 @@ -445,6 +445,18 @@ int snd_akm4xxx_build_controls(akm4xxx_t 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 -puN sound/isa/ad1816a/ad1816a.c~alsa-101 sound/isa/ad1816a/ad1816a.c --- 25/sound/isa/ad1816a/ad1816a.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/ad1816a/ad1816a.c 2004-01-19 22:19:00.000000000 -0800 @@ -338,9 +338,9 @@ static int __init alsa_card_ad1816a_setu (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 -puN sound/isa/ad1848/ad1848.c~alsa-101 sound/isa/ad1848/ad1848.c --- 25/sound/isa/ad1848/ad1848.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/ad1848/ad1848.c 2004-01-19 22:19:00.000000000 -0800 @@ -174,7 +174,7 @@ static int __init alsa_card_ad1848_setup (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 -puN sound/isa/ad1848/ad1848_lib.c~alsa-101 sound/isa/ad1848/ad1848_lib.c --- 25/sound/isa/ad1848/ad1848_lib.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/ad1848/ad1848_lib.c 2004-01-19 22:19:00.000000000 -0800 @@ -736,11 +736,13 @@ static int snd_ad1848_probe(ad1848_t * c 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; } diff -puN sound/isa/als100.c~alsa-101 sound/isa/als100.c --- 25/sound/isa/als100.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/als100.c 2004-01-19 22:19:00.000000000 -0800 @@ -249,7 +249,7 @@ static int __init snd_card_als100_probe( 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 +257,7 @@ static int __init snd_card_als100_probe( 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) { @@ -359,9 +359,9 @@ static int __init alsa_card_als100_setup (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 -puN sound/isa/azt2320.c~alsa-101 sound/isa/azt2320.c --- 25/sound/isa/azt2320.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/azt2320.c 2004-01-19 22:19:00.000000000 -0800 @@ -283,7 +283,7 @@ static int __devinit snd_card_azt2320_pr 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 +291,7 @@ static int __devinit snd_card_azt2320_pr 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) { @@ -393,9 +393,9 @@ static int __init alsa_card_azt2320_setu (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 -puN sound/isa/cmi8330.c~alsa-101 sound/isa/cmi8330.c --- 25/sound/isa/cmi8330.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/cmi8330.c 2004-01-19 22:19:00.000000000 -0800 @@ -658,11 +658,11 @@ static int __init alsa_card_cmi8330_setu 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 -puN sound/isa/cs423x/cs4231.c~alsa-101 sound/isa/cs423x/cs4231.c --- 25/sound/isa/cs423x/cs4231.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/cs423x/cs4231.c 2004-01-19 22:19:00.000000000 -0800 @@ -103,8 +103,6 @@ static int __init snd_card_cs4231_probe( 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], @@ -128,10 +126,13 @@ static int __init snd_card_cs4231_probe( 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"); } @@ -194,8 +195,8 @@ static int __init alsa_card_cs4231_setup 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 -puN sound/isa/cs423x/cs4236.c~alsa-101 sound/isa/cs423x/cs4236.c --- 25/sound/isa/cs423x/cs4236.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/cs423x/cs4236.c 2004-01-19 22:19:00.000000000 -0800 @@ -307,7 +307,7 @@ static int __devinit snd_card_cs4236_pnp 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 @@ static int __devinit snd_card_cs4236_pnp 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 @@ static int __devinit snd_card_cs4236_pnp 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 @@ static int __devinit snd_card_cs4236_pnp 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 @@ static int __devinit snd_card_cs4236_pnp 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 */ @@ -435,13 +437,7 @@ static int __devinit snd_card_cs423x_pro return -ENXIO; } #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); @@ -498,7 +494,7 @@ static int __devinit snd_card_cs423x_pro 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,7 +507,9 @@ static int __devinit snd_card_cs423x_pro } } - 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], @@ -546,7 +544,7 @@ static int __devinit snd_cs423x_pnp_dete 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 +636,11 @@ static int __init alsa_card_cs423x_setup 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 -puN sound/isa/cs423x/pc98.c~alsa-101 sound/isa/cs423x/pc98.c --- 25/sound/isa/cs423x/pc98.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/cs423x/pc98.c 2004-01-19 22:19:00.000000000 -0800 @@ -327,10 +327,6 @@ static int __init snd_card_pc98_probe(in 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 @@ static int __init snd_card_pc98_probe(in 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 @@ static int __init snd_card_pc98_probe(in } } - 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 @@ static int __init alsa_card_pc98_setup(c (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 -puN sound/isa/dt019x.c~alsa-101 sound/isa/dt019x.c --- 25/sound/isa/dt019x.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/dt019x.c 2004-01-19 22:19:00.000000000 -0800 @@ -235,18 +235,20 @@ static int __devinit snd_card_dt019x_pro 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, @@ -347,9 +349,9 @@ static int __init alsa_card_dt019x_setup (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 -puN sound/isa/es1688/es1688.c~alsa-101 sound/isa/es1688/es1688.c --- 25/sound/isa/es1688/es1688.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/es1688/es1688.c 2004-01-19 22:19:00.000000000 -0800 @@ -226,8 +226,8 @@ static int __init alsa_card_es1688_setup (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 -puN sound/isa/es18xx.c~alsa-101 sound/isa/es18xx.c --- 25/sound/isa/es18xx.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/es18xx.c 2004-01-19 22:19:00.000000000 -0800 @@ -2286,9 +2286,9 @@ static int __init alsa_card_es18xx_setup 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 -puN sound/isa/gus/gusclassic.c~alsa-101 sound/isa/gus/gusclassic.c --- 25/sound/isa/gus/gusclassic.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/gus/gusclassic.c 2004-01-19 22:19:00.000000000 -0800 @@ -284,7 +284,7 @@ static int __init alsa_card_gusclassic_s (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 -puN sound/isa/gus/gusextreme.c~alsa-101 sound/isa/gus/gusextreme.c --- 25/sound/isa/gus/gusextreme.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/gus/gusextreme.c 2004-01-19 22:19:00.000000000 -0800 @@ -417,9 +417,9 @@ static int __init alsa_card_gusextreme_s (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 -puN sound/isa/gus/gus_irq.c~alsa-101 sound/isa/gus/gus_irq.c --- 25/sound/isa/gus/gus_irq.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/gus/gus_irq.c 2004-01-19 22:19:00.000000000 -0800 @@ -136,7 +136,7 @@ void snd_gus_irq_profile_init(snd_gus_ca 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 -puN sound/isa/gus/gusmax.c~alsa-101 sound/isa/gus/gusmax.c --- 25/sound/isa/gus/gusmax.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/gus/gusmax.c 2004-01-19 22:19:00.000000000 -0800 @@ -424,7 +424,7 @@ static int __init alsa_card_gusmax_setup (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 -puN sound/isa/gus/gus_mem.c~alsa-101 sound/isa/gus/gus_mem.c --- 25/sound/isa/gus/gus_mem.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/gus/gus_mem.c 2004-01-19 22:19:00.000000000 -0800 @@ -265,7 +265,7 @@ int snd_gf1_mem_init(snd_gus_card_t * gu 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 -puN sound/isa/gus/gus_pcm.c~alsa-101 sound/isa/gus/gus_pcm.c --- 25/sound/isa/gus/gus_pcm.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/gus/gus_pcm.c 2004-01-19 22:19:00.000000000 -0800 @@ -334,9 +334,11 @@ static int snd_gf1_pcm_poke_block(snd_gu 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 @@ static snd_kcontrol_new_t snd_gf1_pcm_vo .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 @@ int snd_gf1_pcm_new(snd_gus_card_t * gus 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 -puN sound/isa/gus/interwave.c~alsa-101 sound/isa/gus/interwave.c --- 25/sound/isa/gus/interwave.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/gus/interwave.c 2004-01-19 22:19:00.000000000 -0800 @@ -229,12 +229,12 @@ static int __devinit snd_interwave_detec 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) + return -ENODEV; + sprintf(name, "InterWave-%i", card->number); if ((err = snd_i2c_bus_create(card, name, NULL, &bus)) < 0) return err; @@ -626,7 +626,7 @@ static int __devinit snd_interwave_pnp(i 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); @@ -994,9 +994,9 @@ static int __init alsa_card_interwave_se 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 -puN sound/isa/opl3sa2.c~alsa-101 sound/isa/opl3sa2.c --- 25/sound/isa/opl3sa2.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/opl3sa2.c 2004-01-19 22:19:00.000000000 -0800 @@ -945,11 +945,11 @@ static int __init alsa_card_opl3sa2_setu 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 -puN sound/isa/opti9xx/opti92x-ad1848.c~alsa-101 sound/isa/opti9xx/opti92x-ad1848.c --- 25/sound/isa/opti9xx/opti92x-ad1848.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/opti9xx/opti92x-ad1848.c 2004-01-19 22:19:00.000000000 -0800 @@ -543,11 +543,11 @@ static int __devinit snd_opti9xx_configu __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_base: __skip_resources: if (chip->hardware > OPTi9XX_HW_82C928) { switch (chip->mpu_port) { + case 0: case -1: break; case 0x300: @@ -644,7 +645,7 @@ __skip_resources: } 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); } @@ -1734,15 +1735,23 @@ static int __devinit snd_card_opti9xx_pn #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 +1771,7 @@ static int __devinit snd_card_opti9xx_pn #endif /* CS4231 || OPTi93X */ pdev = chip->devmpu; - if (pdev) { + if (pdev && mpu_port > 0) { pnp_init_resource_table(cfg); if (mpu_port != SNDRV_AUTO_PORT) @@ -1985,9 +1994,6 @@ static int __devinit snd_card_opti9xx_pr 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 +2001,9 @@ static int __devinit snd_card_opti9xx_pr 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); @@ -2093,7 +2102,7 @@ static int __devinit snd_card_opti9xx_pr } #endif - 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 +2110,7 @@ static int __devinit snd_card_opti9xx_pr &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 || @@ -2240,9 +2249,9 @@ static int __init alsa_card_opti9xx_setu 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 -puN sound/isa/sb/emu8000.c~alsa-101 sound/isa/sb/emu8000.c --- 25/sound/isa/sb/emu8000.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/sb/emu8000.c 2004-01-19 22:19:00.000000000 -0800 @@ -1044,8 +1044,10 @@ snd_emu8000_create_mixer(snd_card_t *car __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; } diff -puN sound/isa/sb/es968.c~alsa-101 sound/isa/sb/es968.c --- 25/sound/isa/sb/es968.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/sb/es968.c 2004-01-19 22:19:00.000000000 -0800 @@ -257,7 +257,7 @@ static int __init alsa_card_es968_setup( (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 -puN sound/isa/sb/sb16.c~alsa-101 sound/isa/sb/sb16.c --- 25/sound/isa/sb/sb16.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/sb/sb16.c 2004-01-19 22:19:00.000000000 -0800 @@ -465,7 +465,7 @@ static int __init snd_sb16_probe(int dev return -ENXIO; } - if (chip->mpu_port) { + 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,7 +475,12 @@ static int __init snd_sb16_probe(int dev 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, @@ -696,9 +701,9 @@ static int __init alsa_card_sb16_setup(c 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 +714,7 @@ static int __init alsa_card_sb16_setup(c #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 -puN sound/isa/sb/sb16_csp.c~alsa-101 sound/isa/sb/sb16_csp.c --- 25/sound/isa/sb/sb16_csp.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/sb/sb16_csp.c 2004-01-19 22:19:00.000000000 -0800 @@ -1059,10 +1059,12 @@ static void snd_sb_qsound_destroy(snd_sb 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 @@ static int init_proc_entry(snd_sb_csp_t 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 -puN sound/isa/sb/sb8.c~alsa-101 sound/isa/sb/sb8.c --- 25/sound/isa/sb/sb8.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/sb/sb8.c 2004-01-19 22:19:00.000000000 -0800 @@ -242,7 +242,7 @@ static int __init alsa_card_sb8_setup(ch (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 -puN sound/isa/sb/sb_common.c~alsa-101 sound/isa/sb/sb_common.c --- 25/sound/isa/sb/sb_common.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/sb/sb_common.c 2004-01-19 22:19:00.000000000 -0800 @@ -185,10 +185,6 @@ static int snd_sbdsp_free(sb_t *chip) 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 diff -puN sound/isa/sgalaxy.c~alsa-101 sound/isa/sgalaxy.c --- 25/sound/isa/sgalaxy.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/sgalaxy.c 2004-01-19 22:19:00.000000000 -0800 @@ -341,10 +341,10 @@ static int __init alsa_card_sgalaxy_setu (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 -puN sound/isa/sscape.c~alsa-101 sound/isa/sscape.c --- 25/sound/isa/sscape.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/sscape.c 2004-01-19 22:19:00.000000000 -0800 @@ -31,6 +31,7 @@ #include #include #include +#define SNDRV_GET_ID #include #include @@ -616,10 +617,10 @@ static int sscape_upload_microcode(struc */ 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"); } @@ -1538,8 +1539,8 @@ static int __init builtin_sscape_setup(c 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 -puN sound/isa/wavefront/wavefront.c~alsa-101 sound/isa/wavefront/wavefront.c --- 25/sound/isa/wavefront/wavefront.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/isa/wavefront/wavefront.c 2004-01-19 22:19:00.000000000 -0800 @@ -418,13 +418,6 @@ snd_wavefront_probe (int dev, struct pnp 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 @@ -490,7 +483,7 @@ snd_wavefront_probe (int dev, struct pnp /* ---------- 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 +554,7 @@ snd_wavefront_probe (int dev, struct pnp /* ------ 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 +571,7 @@ snd_wavefront_probe (int dev, struct pnp /* ------ 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 +624,7 @@ snd_wavefront_probe (int dev, struct pnp 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 +749,13 @@ static int __init alsa_card_wavefront_se 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 -puN sound/pci/ac97/ac97_codec.c~alsa-101 sound/pci/ac97/ac97_codec.c --- 25/sound/pci/ac97/ac97_codec.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ac97/ac97_codec.c 2004-01-19 22:19:00.000000000 -0800 @@ -101,8 +101,8 @@ static const ac97_codec_id_t snd_ac97_co { 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 @@ static const ac97_codec_id_t snd_ac97_co { 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,6 +141,7 @@ static const ac97_codec_id_t snd_ac97_co { 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 }, @@ -202,7 +205,7 @@ const char *snd_ac97_stereo_enhancements /* 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 @@ void snd_ac97_write(ac97_t *ac97, unsign { if (!snd_ac97_valid_reg(ac97, reg)) return; - ac97->write(ac97, reg, value); + ac97->bus->write(ac97, reg, value); } /** @@ -288,7 +291,7 @@ unsigned short snd_ac97_read(ac97_t *ac9 { if (!snd_ac97_valid_reg(ac97, reg)) return 0; - return ac97->read(ac97, reg); + return ac97->bus->read(ac97, reg); } /** @@ -308,7 +311,7 @@ void snd_ac97_write_cache(ac97_t *ac97, 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 @@ int snd_ac97_update(ac97_t *ac97, unsign 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 @@ int snd_ac97_update_bits(ac97_t *ac97, u 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 @@ static int snd_ac97_ad18xx_update_pcm_bi 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 @@ AD18XX_PCM_BITS("LFE Playback Volume", 2 * */ +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 @@ static int snd_ac97_try_volume_mix(ac97_ } 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_cmix_new(snd_card_t 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; @@ -1500,7 +1525,7 @@ static int snd_ac97_test_rate(ac97_t *ac 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 +1630,62 @@ static int ac97_reset_wait(ac97_t *ac97, } /** - * 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 +1694,16 @@ static int ac97_reset_wait(ac97_t *ac97, * 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 +1713,42 @@ int snd_ac97_mixer(snd_card_t * card, ac 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 +1768,7 @@ int snd_ac97_mixer(snd_card_t * card, ac } /* 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 +1782,22 @@ int snd_ac97_mixer(snd_card_t * card, ac } /* 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 +1816,43 @@ int snd_ac97_mixer(snd_card_t * card, ac 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 +1891,8 @@ int snd_ac97_mixer(snd_card_t * card, ac 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 +1913,6 @@ int snd_ac97_mixer(snd_card_t * card, ac 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 +1926,12 @@ int snd_ac97_modem(snd_card_t * card, ac 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 +1940,6 @@ int snd_ac97_modem(snd_card_t * card, ac 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 +1973,8 @@ void snd_ac97_resume(ac97_t *ac97) { int i, is_ad18xx, codec; - if (ac97->reset) { - ac97->reset(ac97); + if (ac97->bus->reset) { + ac97->bus->reset(ac97); goto __reset_ready; } @@ -2155,29 +1985,29 @@ void snd_ac97_resume(ac97_t *ac97) 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 +2026,12 @@ __reset_ready: 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 +2061,13 @@ __reset_ready: /* */ -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 +2076,10 @@ static snd_kcontrol_t *ctl_find(ac97_t * 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 +2089,7 @@ static int rename_ctl(ac97_t *ac97, cons 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 +2106,22 @@ static int swap_headphone(ac97_t *ac97, { /* 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 +2131,7 @@ static int tune_ad_sharing(ac97_t *ac97) /* 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 +2183,13 @@ EXPORT_SYMBOL(snd_ac97_read); 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 -puN sound/pci/ac97/ac97_local.h~alsa-101 sound/pci/ac97/ac97_local.h --- 25/sound/pci/ac97/ac97_local.h~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ac97/ac97_local.h 2004-01-19 22:19:00.000000000 -0800 @@ -37,6 +37,12 @@ int snd_ac97_info_single(snd_kcontrol_t 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 -puN sound/pci/ac97/ac97_patch.c~alsa-101 sound/pci/ac97/ac97_patch.c --- 25/sound/pci/ac97/ac97_patch.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ac97/ac97_patch.c 2004-01-19 22:19:00.000000000 -0800 @@ -46,7 +46,7 @@ static int patch_build_controls(ac97_t * 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 @@ static int patch_yamaha_ymf753_3d(ac97_t 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 @@ static int patch_sigmatel_stac9700_3d(ac 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 @@ static int patch_sigmatel_stac9708_3d(ac 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 @@ int patch_ad1886(ac97_t * ac97) #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 @@ int patch_ad1886(ac97_t * ac97) #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 @@ static int snd_ac97_ad1980_spdif_source_ 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 @@ static int snd_ac97_ad1980_spdif_source_ 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 @@ static int snd_ac97_ad1980_spdif_source_ 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,22 +918,43 @@ int patch_ad1980(ac97_t * ac97) 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 */ @@ -820,6 +983,8 @@ static const snd_kcontrol_new_t snd_ac97 /* 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 @@ static struct snd_ac97_build_ops patch_a int patch_alc650(ac97_t * ac97) { unsigned short val; - int spdif = 0; ac97->build_ops = &patch_alc650_ops; @@ -907,22 +1071,16 @@ int patch_alc650(ac97_t * ac97) 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 @@ int patch_alc650(ac97_t * ac97) 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), @@ -1099,3 +1349,37 @@ 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; +} diff -puN sound/pci/ac97/ac97_patch.h~alsa-101 sound/pci/ac97/ac97_patch.h --- 25/sound/pci/ac97/ac97_patch.h~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ac97/ac97_patch.h 2004-01-19 22:19:00.000000000 -0800 @@ -42,8 +42,12 @@ int patch_ad1881(ac97_t * ac97); 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); diff -puN /dev/null sound/pci/ac97/ac97_pcm.c --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25-akpm/sound/pci/ac97/ac97_pcm.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/pci/ac97/ac97_proc.c~alsa-101 sound/pci/ac97/ac97_proc.c --- 25/sound/pci/ac97/ac97_proc.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ac97/ac97_proc.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 @@ static void snd_ac97_proc_regs_read(snd_ } } -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 -puN sound/pci/ac97/ak4531_codec.c~alsa-101 sound/pci/ac97/ak4531_codec.c --- 25/sound/pci/ac97/ak4531_codec.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ac97/ak4531_codec.c 2004-01-19 22:19:00.000000000 -0800 @@ -425,7 +425,7 @@ static void snd_ak4531_proc_init(snd_car 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 -puN sound/pci/ac97/Makefile~alsa-101 sound/pci/ac97/Makefile --- 25/sound/pci/ac97/Makefile~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ac97/Makefile 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/pci/ali5451/ali5451.c~alsa-101 sound/pci/ali5451/ali5451.c --- 25/sound/pci/ali5451/ali5451.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ali5451/ali5451.c 2004-01-19 22:19:00.000000000 -0800 @@ -265,6 +265,7 @@ struct snd_stru_ali { 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 @@ static snd_kcontrol_new_t snd_ali5451_mi 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 void snd_ali_mixer_free_ac97(ac97 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; } @@ -2096,7 +2110,7 @@ static int __devinit snd_ali_create(snd_ snd_printk("architecture does not support 31bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x7fffffff); + pci_set_consistent_dma_mask(pci, 0x7fffffff); if ((codec = snd_magic_kcalloc(ali_t, 0, GFP_KERNEL)) == NULL) return -ENOMEM; diff -puN sound/pci/als4000.c~alsa-101 sound/pci/als4000.c --- 25/sound/pci/als4000.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/als4000.c 2004-01-19 22:19:00.000000000 -0800 @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -78,14 +79,15 @@ MODULE_LICENSE("GPL"); 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 @@ MODULE_PARM_SYNTAX(joystick_port, SNDRV_ 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 int __devinit snd_als4000_pcm(sb_ /******************************************************************/ -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 @@ static void snd_card_als4000_free( snd_c 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 @@ static int __devinit snd_card_als4000_pr opl3_t *opl3; unsigned short word; int err; + int joystick = 0; if (dev >= SNDRV_CARDS) return -ENODEV; @@ -605,7 +625,7 @@ static int __devinit snd_card_als4000_pr snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x00ffffff); + pci_set_consistent_dma_mask(pci, 0x00ffffff); gcr = pci_resource_start(pci, 0); if ((res_gcr_port = request_region(gcr, 0x40, "ALS4000")) == NULL) { @@ -617,9 +637,6 @@ static int __devinit snd_card_als4000_pr 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 @@ static int __devinit snd_card_als4000_pr 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,15 +678,12 @@ static int __devinit snd_card_als4000_pr -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_als4000_configure(chip); @@ -680,6 +715,12 @@ static int __devinit snd_card_als4000_pr } } +#ifdef SUPPORT_JOYSTICK + if (acard->res_joystick) { + acard->gameport.io = joystick; + gameport_register_port(&acard->gameport); + } +#endif strcpy(card->driver, "ALS4000"); strcpy(card->shortname, "Avance Logic ALS4000"); sprintf(card->longname, "%s at 0x%lx, irq %i", @@ -730,7 +771,7 @@ module_exit(alsa_card_als4000_exit) #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 +781,11 @@ static int __init alsa_card_als4000_setu 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 -puN sound/pci/azt3328.c~alsa-101 sound/pci/azt3328.c --- 25/sound/pci/azt3328.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/azt3328.c 2004-01-19 22:19:00.000000000 -0800 @@ -97,6 +97,7 @@ #include #include #include +#include #include #include #include @@ -113,6 +114,10 @@ MODULE_LICENSE("GPL"); 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 @@ MODULE_DEVICES("{{Aztech,AZF3328}}"); 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_SYNTAX(id, SNDRV_ID_DESC); 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 _snd_azf3328 { 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 @@ static int snd_azf3328_free(azf3328_t *c 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); @@ -1343,7 +1365,7 @@ static int __devinit snd_azf3328_create( snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x00ffffff); + pci_set_consistent_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) { @@ -1419,53 +1441,27 @@ static int __devinit snd_azf3328_create( 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 +1533,9 @@ static int __devinit snd_azf3328_probe(s "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 +1596,7 @@ module_exit(alsa_card_azf3328_exit) #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 +1608,16 @@ static int __init alsa_card_azf3328_setu 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 -puN sound/pci/cmipci.c~alsa-101 sound/pci/cmipci.c --- 25/sound/pci/cmipci.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/cmipci.c 2004-01-19 22:19:00.000000000 -0800 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -52,14 +53,21 @@ MODULE_DEVICES("{{C-Media,CMI8738}," "{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_DESC(enable, "Enable C-Media 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 @@ MODULE_PARM_SYNTAX(soft_ac3, SNDRV_ENABL #define CM_EXTENT_MIDI 0x2 #define CM_EXTENT_SYNTH 0x4 + /* * pci ids */ @@ -480,6 +494,11 @@ struct snd_stru_cmipci { /* 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 @@ static int set_dac_channels(cmipci_t *cm 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 @@ static int set_dac_channels(cmipci_t *cm 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); } } @@ -2599,7 +2620,7 @@ DEFINE_SWITCH_ARG(exchange_dac, CM_REG_M 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 +2670,14 @@ static int snd_cmipci_spdout_enable_put( /* 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 +2717,7 @@ static snd_kcontrol_new_t snd_cmipci_ext /* 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 +2753,11 @@ static int __devinit snd_cmipci_mixer_ne 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 +2845,7 @@ static void __devinit snd_cmipci_proc_in 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 +2934,14 @@ static int snd_cmipci_free(cmipci_t *cm) 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 +2965,8 @@ static int __devinit snd_cmipci_create(s .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 +3147,31 @@ static int __devinit snd_cmipci_create(s 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 *rcmipci = cm; return 0; @@ -3218,7 +3280,7 @@ module_exit(alsa_card_cmipci_exit) #ifndef MODULE /* format is: snd-cmipci=enable,index,id, - mpu_port,fm_port */ + mpu_port,fm_port,soft_ac3,joystick */ static int __init alsa_card_cmipci_setup(char *str) { @@ -3229,8 +3291,15 @@ static int __init alsa_card_cmipci_setup (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[nr_dev]) == 2 +#endif + ); nr_dev++; return 1; } diff -puN sound/pci/cs4281.c~alsa-101 sound/pci/cs4281.c --- 25/sound/pci/cs4281.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/cs4281.c 2004-01-19 22:19:00.000000000 -0800 @@ -479,6 +479,7 @@ struct snd_cs4281 { int dual_codec; + ac97_bus_t *ac97_bus; ac97_t *ac97; ac97_t *ac97_secondary; @@ -564,7 +565,7 @@ static inline unsigned int snd_cs4281_pe } 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 void snd_cs4281_ac97_write(ac97_t } 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 @@ static snd_kcontrol_new_t snd_cs4281_pcm .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 void snd_cs4281_mixer_free_ac97(a 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 @@ static long snd_cs4281_BA0_read(snd_info 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 @@ static long snd_cs4281_BA1_read(snd_info 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 @@ static void __devinit snd_cs4281_proc_in 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; diff -puN sound/pci/cs46xx/cs46xx_lib.c~alsa-101 sound/pci/cs46xx/cs46xx_lib.c --- 25/sound/pci/cs46xx/cs46xx_lib.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/cs46xx/cs46xx_lib.c 2004-01-19 22:19:00.000000000 -0800 @@ -1804,6 +1804,13 @@ int __devinit snd_cs46xx_pcm_iec958(cs46 /* * 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 @@ static void snd_cs46xx_codec_reset (ac97 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 @@ int __devinit snd_cs46xx_mixer(cs46xx_t /* 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 @@ int __devinit snd_cs46xx_mixer(cs46xx_t 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 @@ int __devinit snd_cs46xx_mixer(cs46xx_t 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 @@ int __devinit snd_cs46xx_mixer(cs46xx_t /* 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 @@ int __devinit snd_cs46xx_mixer(cs46xx_t #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 @@ static long snd_cs46xx_io_read(snd_info_ 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 = { diff -puN sound/pci/emu10k1/emu10k1_main.c~alsa-101 sound/pci/emu10k1/emu10k1_main.c --- 25/sound/pci/emu10k1/emu10k1_main.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/emu10k1/emu10k1_main.c 2004-01-19 22:19:00.000000000 -0800 @@ -239,14 +239,9 @@ static int __devinit snd_emu10k1_init(em } } - 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 @@ static int __devinit snd_emu10k1_init(em * 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,7 @@ int __devinit snd_emu10k1_create(snd_car 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_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; diff -puN sound/pci/emu10k1/emufx.c~alsa-101 sound/pci/emu10k1/emufx.c --- 25/sound/pci/emu10k1/emufx.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/emu10k1/emufx.c 2004-01-19 22:19:00.000000000 -0800 @@ -1009,13 +1009,16 @@ static void snd_emu10k1_del_controls(emu 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 +1237,12 @@ static void __devinit snd_emu10k1_init_s * 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 +1266,52 @@ static int __devinit _snd_emu10k1_audigy 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 +1320,29 @@ static int __devinit _snd_emu10k1_audigy 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 +1352,19 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G 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 +1373,20 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G 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 +1394,30 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G 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 +1516,18 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G 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 +1536,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_G 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; @@ -1931,7 +1948,7 @@ static int __devinit _snd_emu10k1_init_e /* 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 +1957,9 @@ static int __devinit _snd_emu10k1_init_e 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 -puN sound/pci/emu10k1/emumixer.c~alsa-101 sound/pci/emu10k1/emumixer.c --- 25/sound/pci/emu10k1/emumixer.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/emu10k1/emumixer.c 2004-01-19 22:19:00.000000000 -0800 @@ -455,30 +455,51 @@ static int rename_ctl(snd_card_t *card, int __devinit snd_emu10k1_mixer(emu10k1_t *emu) { - ac97_t ac97; int err, pcm; snd_kcontrol_t *kctl; snd_card_t *card = emu->card; 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"); + if (emu->audigy) { + /* Master/PCM controls on ac97 of Audigy has no effect */ /* pcm controls are removed */ remove_ctl(card, "PCM Playback Switch"); remove_ctl(card, "PCM Playback Volume"); + remove_ctl(card, "Master Mono Playback Switch"); + remove_ctl(card, "Master Mono Playback Volume"); + remove_ctl(card, "Master Playback Switch"); + remove_ctl(card, "Master Playback Volume"); + remove_ctl(card, "PCM Out Path & Mute"); + remove_ctl(card, "Mono Output Select"); + + /* 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); + + /* remove unused AC97 capture controls */ + remove_ctl(card, "Capture Source"); + remove_ctl(card, "Capture Switch"); + remove_ctl(card, "Capture Volume"); + remove_ctl(card, "Mic Select"); + remove_ctl(card, "Video Playback Switch"); + remove_ctl(card, "Video Playback Volume"); + remove_ctl(card, "Mic Playback Switch"); + remove_ctl(card, "Mic Playback Volume"); } } else { if (emu->APS) @@ -489,12 +510,12 @@ int __devinit snd_emu10k1_mixer(emu10k1_ strcpy(emu->card->mixername, "Emu10k1"); } - if (emu->audigy && emu->revision == 4) { - /* Audigy2 and Audigy2 EX */ + if (emu->audigy) { /* 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 Capture Volume", "PCM Capture Volume"); */ rename_ctl(card, "Wave Master Playback Volume", "Master Playback Volume"); + rename_ctl(card, "AMic Playback Volume", "Mic Playback Volume"); } if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL) @@ -536,6 +557,11 @@ int __devinit snd_emu10k1_mixer(emu10k1_ 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 -puN sound/pci/emu10k1/emupcm.c~alsa-101 sound/pci/emu10k1/emupcm.c --- 25/sound/pci/emu10k1/emupcm.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/emu10k1/emupcm.c 2004-01-19 22:19:00.000000000 -0800 @@ -871,7 +871,7 @@ static int snd_emu10k1_capture_mic_open( 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 -puN sound/pci/emu10k1/emuproc.c~alsa-101 sound/pci/emu10k1/emuproc.c --- 25/sound/pci/emu10k1/emuproc.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/emu10k1/emuproc.c 2004-01-19 22:19:00.000000000 -0800 @@ -240,7 +240,7 @@ int __devinit snd_emu10k1_proc_init(emu1 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 -puN sound/pci/ens1370.c~alsa-101 sound/pci/ens1370.c --- 25/sound/pci/ens1370.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ens1370.c 2004-01-19 22:19:00.000000000 -0800 @@ -72,9 +72,20 @@ MODULE_DEVICES("{{Ensoniq,AudioPCI ES137 "{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_SYNTAX(id, SNDRV_ID_DESC); 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 @@ struct _snd_ensoniq { 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 }; @@ -1513,16 +1534,21 @@ static struct { 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 && @@ -1565,8 +1591,8 @@ static int snd_ensoniq_1371_mixer(ensoni #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 +1619,6 @@ static int snd_ensoniq_control_get(snd_k 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 +1636,11 @@ static int snd_ensoniq_control_put(snd_k 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) @@ -1660,129 +1682,45 @@ static int __devinit snd_ensoniq_1370_mi #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 +1750,7 @@ static void __devinit snd_ensoniq_proc_i 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 +1759,9 @@ static void __devinit snd_ensoniq_proc_i 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 +1957,6 @@ static int __devinit snd_ensoniq_create( 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) { @@ -2331,6 +2261,22 @@ static int __devinit snd_audiopci_probe( 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 +2332,7 @@ module_exit(alsa_card_ens137x_exit) #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 +2342,15 @@ static int __init alsa_card_ens137x_setu 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 -puN sound/pci/es1938.c~alsa-101 sound/pci/es1938.c --- 25/sound/pci/es1938.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/es1938.c 2004-01-19 22:19:00.000000000 -0800 @@ -1402,7 +1402,7 @@ static int __devinit snd_es1938_create(s snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x00ffffff); + pci_set_consistent_dma_mask(pci, 0x00ffffff); chip = snd_magic_kcalloc(es1938_t, 0, GFP_KERNEL); if (chip == NULL) diff -puN sound/pci/es1968.c~alsa-101 sound/pci/es1968.c --- 25/sound/pci/es1968.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/es1968.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 @@ MODULE_DEVICES("{{ESS,Maestro 2e}," "{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 pcm_substreams_c[SNDRV_CARDS] 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_SYNTAX(use_pm, SNDRV_ENABLED 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 @@ struct snd_es1968 { #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 irqreturn_t snd_es1968_interrupt( 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 @@ static int snd_es1968_free(es1968_t *chi 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; @@ -2538,7 +2567,7 @@ static int __devinit snd_es1968_create(s snd_printk("architecture does not support 28bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x0fffffff); + pci_set_consistent_dma_mask(pci, 0x0fffffff); chip = (es1968_t *) snd_magic_kcalloc(es1968_t, 0, GFP_KERNEL); if (! chip) @@ -2624,57 +2653,6 @@ static int __devinit snd_es1968_create(s /* - * 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; -} - -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; - - 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, - } -}; - -/* */ static int __devinit snd_es1968_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) @@ -2756,14 +2734,17 @@ static int __devinit snd_es1968_probe(st } } - /* 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 +2815,8 @@ module_exit(alsa_card_es1968_exit) pcm_substreams_c, clock, use_pm, - enable_mpu + enable_mpu, + joystick */ static int __init alsa_card_es1968_setup(char *str) @@ -2851,7 +2833,11 @@ static int __init alsa_card_es1968_setup 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 -puN sound/pci/fm801.c~alsa-101 sound/pci/fm801.c --- 25/sound/pci/fm801.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/fm801.c 2004-01-19 22:19:00.000000000 -0800 @@ -147,6 +147,7 @@ struct _snd_fm801 { 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 Raw Data Capture Sw 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 void snd_fm801_mixer_free_ac97(ac 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++) diff -puN sound/pci/ice1712/ak4xxx.c~alsa-101 sound/pci/ice1712/ak4xxx.c --- 25/sound/pci/ice1712/ak4xxx.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ice1712/ak4xxx.c 2004-01-19 22:19:00.000000000 -0800 @@ -175,6 +175,18 @@ int snd_ice1712_akm4xxx_build_controls(i 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 -puN sound/pci/ice1712/aureon.c~alsa-101 sound/pci/ice1712/aureon.c --- 25/sound/pci/ice1712/aureon.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ice1712/aureon.c 2004-01-19 22:19:00.000000000 -0800 @@ -185,7 +185,7 @@ static int wm_dac_vol_put(snd_kcontrol_t 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_add_controls 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 @@ static int __devinit aureon_init(ice1712 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 -puN sound/pci/ice1712/delta.c~alsa-101 sound/pci/ice1712/delta.c --- 25/sound/pci/ice1712/delta.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ice1712/delta.c 2004-01-19 22:19:00.000000000 -0800 @@ -257,6 +257,26 @@ static void delta1010lt_ak4524_lock(akm4 } /* + * 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 @@ static void delta_ak4524_set_rate_val(ak 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 @@ static int __devinit snd_ice1712_delta_i 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 -puN sound/pci/ice1712/ice1712.c~alsa-101 sound/pci/ice1712/ice1712.c --- 25/sound/pci/ice1712/ice1712.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ice1712/ice1712.c 2004-01-19 22:19:00.000000000 -0800 @@ -1040,16 +1040,21 @@ static void snd_ice1712_set_pro_rate(ice 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 @@ static int snd_ice1712_playback_pro_hw_p 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 @@ static int __devinit snd_ice1712_ac97_mi 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 @@ static int __devinit snd_ice1712_ac97_mi } 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 @@ static void __devinit snd_ice1712_proc_i 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); } /* @@ -2356,7 +2367,7 @@ static int __devinit snd_ice1712_create( snd_printk("architecture does not support 28bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x0fffffff); + pci_set_consistent_dma_mask(pci, 0x0fffffff); ice = snd_magic_kcalloc(ice1712_t, 0, GFP_KERNEL); if (ice == NULL) diff -puN sound/pci/ice1712/ice1712.h~alsa-101 sound/pci/ice1712/ice1712.h --- 25/sound/pci/ice1712/ice1712.h~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ice1712/ice1712.h 2004-01-19 22:19:00.000000000 -0800 @@ -353,6 +353,8 @@ struct _snd_ice1712 { 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 -puN sound/pci/ice1712/ice1724.c~alsa-101 sound/pci/ice1712/ice1724.c --- 25/sound/pci/ice1712/ice1724.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ice1712/ice1724.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 @@ MODULE_DEVICES("{" 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 @@ static int __devinit snd_vt1724_ac97_mix 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 @@ static void __devinit snd_vt1724_proc_in 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 @@ static struct snd_ice1712_card_info *car snd_vt1724_revo_cards, snd_vt1724_amp_cards, snd_vt1724_aureon_cards, + snd_vt1724_prodigy_cards, 0, }; @@ -1793,7 +1801,7 @@ static int __devinit snd_vt1724_create(s /* enable PCI device */ if ((err = pci_enable_device(pci)) < 0) return err; - pci_set_dma_mask(pci, 0xffffffff); + pci_set_consistent_dma_mask(pci, 0xffffffff); ice = snd_magic_kcalloc(ice1712_t, 0, GFP_KERNEL); if (ice == NULL) diff -puN sound/pci/ice1712/Makefile~alsa-101 sound/pci/ice1712/Makefile --- 25/sound/pci/ice1712/Makefile~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ice1712/Makefile 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN /dev/null sound/pci/ice1712/prodigy.c --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25-akpm/sound/pci/ice1712/prodigy.c 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN /dev/null sound/pci/ice1712/prodigy.h --- /dev/null 2002-08-30 16:31:37.000000000 -0700 +++ 25-akpm/sound/pci/ice1712/prodigy.h 2004-01-19 22:19:00.000000000 -0800 @@ -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 -puN sound/pci/intel8x0.c~alsa-101 sound/pci/intel8x0.c --- 25/sound/pci/intel8x0.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/intel8x0.c 2004-01-19 22:19:00.000000000 -0800 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -59,7 +60,9 @@ MODULE_DEVICES("{{Intel,82801AA-ICH}," "{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 +70,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEF 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 +89,9 @@ MODULE_PARM(ac97_clock, "1-" __MODULE_ST 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 +366,8 @@ typedef struct { 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; @@ -405,6 +402,7 @@ struct _snd_intel8x0 { int in_ac97_init: 1, in_sdin_init: 1; + ac97_bus_t *ac97_bus; ac97_t *ac97[3]; unsigned int ac97_sdin[3]; @@ -888,11 +886,37 @@ static int snd_intel8x0_ali_trigger(snd_ 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); + int err; + + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + if (err < 0) + return err; + 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) { + ichdev_t *ichdev = get_ichdev(substream); + + if (ichdev->pcm_open_flag) { + snd_ac97_pcm_close(ichdev->pcm); + ichdev->pcm_open_flag = 0; + } return snd_pcm_lib_free_pages(substream); } @@ -935,7 +959,6 @@ static int snd_intel8x0_pcm_prepare(snd_ 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 +968,6 @@ static int snd_intel8x0_pcm_prepare(snd_ 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 +1046,11 @@ static int snd_intel8x0_pcm_open(snd_pcm 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 +1526,7 @@ static int __devinit snd_intel8x0_pcm(in 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,77 +1544,95 @@ static int __devinit snd_intel8x0_pcm(in * 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 - }, { .vendor = 0x1043, .device = 0x80f3, @@ -1611,41 +1642,19 @@ static struct ac97_quirk ac97_quirks[] _ { .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", - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x11d4, - .device = 0x5375, - .name = "ADI AD1985 (discrete)", + .name = "Fujitsu-Siemens Scenic", /* AD1981? */ .type = AC97_TUNE_HP_ONLY }, { .vendor = 0x1734, .device = 0x0088, - .name = "Fujitsu-Siemens D1522", - .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)", + .name = "Fujitsu-Siemens D1522", /* AD1981 */ .type = AC97_TUNE_HP_ONLY }, { @@ -1658,7 +1667,7 @@ static struct ac97_quirk ac97_quirks[] _ { .vendor = 0x8086, .device = 0x4d44, - .name = "Intel D850EMV2", + .name = "Intel D850EMV2", /* AD1885 */ .type = AC97_TUNE_HP_ONLY }, { @@ -1675,14 +1684,7 @@ static struct ac97_quirk ac97_quirks[] _ .name = "Intel ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, - { - .vendor = 0x8086, - .device = 0xa000, - .mask = 0xfff0, - .name = "Intel ICH5/AD1985 (discrete)", - .type = AC97_TUNE_HP_ONLY - }, - { + { /* FIXME: which codec? */ .vendor = 0x103c, .device = 0x00c3, .name = "Hewlett-Packard onboard", @@ -1693,50 +1695,42 @@ static struct ac97_quirk ac97_quirks[] _ 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 +1750,10 @@ static int __devinit snd_intel8x0_mixer( } 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 +1765,82 @@ static int __devinit snd_intel8x0_mixer( 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; } @@ -2212,7 +2145,7 @@ static void __devinit intel8x0_measure_a 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 +2160,7 @@ static void __devinit intel8x0_measure_a /* 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 +2219,8 @@ static void __devinit intel8x0_measure_a 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 +2254,7 @@ static void __devinit snd_intel8x0_proc_ 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) @@ -2657,9 +2590,16 @@ static struct pci_driver driver = { * 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 +2608,24 @@ static int __devinit snd_intel8x0_joysti 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 +2634,27 @@ static int __devinit snd_intel8x0_joysti 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 +2673,7 @@ static struct pci_driver joystick_driver .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 +2716,7 @@ module_exit(alsa_card_intel8x0_exit) #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 +2727,14 @@ static int __init alsa_card_intel8x0_set (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 -puN sound/pci/korg1212/korg1212.c~alsa-101 sound/pci/korg1212/korg1212.c --- 25/sound/pci/korg1212/korg1212.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/korg1212/korg1212.c 2004-01-19 22:19:00.000000000 -0800 @@ -2093,7 +2093,7 @@ static void __devinit snd_korg1212_proc_ 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 diff -puN sound/pci/maestro3.c~alsa-101 sound/pci/maestro3.c --- 25/sound/pci/maestro3.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/maestro3.c 2004-01-19 22:19:00.000000000 -0800 @@ -1981,14 +1981,19 @@ static void snd_m3_ac97_reset(m3_t *chip 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 @@ snd_m3_enable_ints(m3_t *chip) { 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); } @@ -2545,7 +2551,7 @@ snd_m3_create(snd_card_t *card, struct p snd_printk("architecture does not support 28bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x0fffffff); + pci_set_consistent_dma_mask(pci, 0x0fffffff); chip = snd_magic_kcalloc(m3_t, 0, GFP_KERNEL); if (chip == NULL) diff -puN sound/pci/nm256/nm256.c~alsa-101 sound/pci/nm256/nm256.c --- 25/sound/pci/nm256/nm256.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/nm256/nm256.c 2004-01-19 22:19:00.000000000 -0800 @@ -335,7 +335,7 @@ snd_nm256_write_buffer(nm256_t *chip, vo return; } #endif - memcpy_toio(chip->buffer + offset, src, size); + memcpy_toio((void *)chip->buffer + offset, src, size); } /* @@ -1195,6 +1195,7 @@ snd_nm256_ac97_reset(ac97_t *ac97) 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 @@ snd_nm256_mixer(nm256_t *chip) -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))) { diff -puN sound/pci/rme32.c~alsa-101 sound/pci/rme32.c --- 25/sound/pci/rme32.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/rme32.c 2004-01-19 22:19:00.000000000 -0800 @@ -1191,18 +1191,18 @@ snd_rme32_playback_pointer(snd_pcm_subst } 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 @@ snd_rme32_capture_pointer(snd_pcm_substr 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 @@ static void __devinit snd_rme32_proc_ini 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); } /* diff -puN sound/pci/rme9652/hdsp.c~alsa-101 sound/pci/rme9652/hdsp.c --- 25/sound/pci/rme9652/hdsp.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/rme9652/hdsp.c 2004-01-19 22:19:00.000000000 -0800 @@ -69,15 +69,24 @@ MODULE_DESCRIPTION("RME Hammerfall DSP") 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 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," #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 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," #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 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," #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 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," #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 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," /* 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 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," /* 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 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," /* 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 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," #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 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," #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 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," #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 @@ MODULE_DEVICES("{{RME Hammerfall-DSP}," #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 @@ struct _hdsp { 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 @@ struct _hdsp { 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 @@ struct _hdsp { 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 @@ static char channel_map_mf_ss[HDSP_MAX_C 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 @@ static char channel_map_ds[HDSP_MAX_CHAN /* 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 int snd_hdsp_enable_io (hd 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 @@ static inline int hdsp_input_to_output_k 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 unsigned int hdsp_read(hds 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 @@ static int snd_hdsp_load_firmware_from_c 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 @@ static int snd_hdsp_load_firmware_from_c 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_get_iobox_version 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 @@ static inline int hdsp_write_gain(hdsp_t 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 @@ static inline int hdsp_write_gain(hdsp_t 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 @@ static inline int hdsp_write_gain(hdsp_t 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 @@ static inline int hdsp_spdif_sample_rate 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 @@ static int hdsp_set_rate(hdsp_t *hdsp, i 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 @@ static int hdsp_set_rate(hdsp_t *hdsp, i 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 @@ static int hdsp_set_rate(hdsp_t *hdsp, i 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 @@ static int hdsp_set_rate(hdsp_t *hdsp, i 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 @@ static int hdsp_set_rate(hdsp_t *hdsp, i 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 @@ static int hdsp_set_rate(hdsp_t *hdsp, i 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 @@ static int hdsp_set_rate(hdsp_t *hdsp, i } hdsp->system_sample_rate = rate; - - if (reject_if_open) { - hdsp_update_simple_mixer_controls (hdsp); - } return 0; } @@ -993,11 +1172,11 @@ static void hdsp_set_thru(hdsp_t *hdsp, /* 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 @@ static void hdsp_set_thru(hdsp_t *hdsp, } 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 hdsp_set_spdif_input(hdsp_t * 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 @@ static int snd_hdsp_put_spdif_in(snd_kco 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_put_spdif_nonaudio(s 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 @@ static int snd_hdsp_get_spdif_sample_rat 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_get_system_sample_ra 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 @@ static int snd_hdsp_get_autosync_sample_ 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 @@ static int hdsp_clock_source(hdsp_t *hds 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 @@ static int hdsp_set_clock_source(hdsp_t 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 @@ static int hdsp_set_clock_source(hdsp_t 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 hdsp_set_clock_source(hdsp_t 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 @@ static int snd_hdsp_put_clock_source(snd 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,264 +2197,362 @@ static int snd_hdsp_put_clock_source(snd return change; } -#define HDSP_PREF_SYNC_REF(xname, xindex) \ +#define HDSP_DA_GAIN(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ .name = xname, \ .index = xindex, \ - .info = snd_hdsp_info_pref_sync_ref, \ - .get = snd_hdsp_get_pref_sync_ref, \ - .put = snd_hdsp_put_pref_sync_ref \ + .info = snd_hdsp_info_da_gain, \ + .get = snd_hdsp_get_da_gain, \ + .put = snd_hdsp_put_da_gain \ } -static int hdsp_pref_sync_ref(hdsp_t *hdsp) +static int hdsp_da_gain(hdsp_t *hdsp) { - /* Notice that this looks at the requested sync source, - not the one actually in use. - */ - - switch (hdsp->control_register & HDSP_SyncRefMask) { - case HDSP_SyncRef_ADAT1: - return HDSP_SYNC_FROM_ADAT1; - case HDSP_SyncRef_ADAT2: - return HDSP_SYNC_FROM_ADAT2; - case HDSP_SyncRef_ADAT3: - return HDSP_SYNC_FROM_ADAT3; - case HDSP_SyncRef_SPDIF: - return HDSP_SYNC_FROM_SPDIF; - case HDSP_SyncRef_WORD: - return HDSP_SYNC_FROM_WORD; - case HDSP_SyncRef_ADAT_SYNC: - return HDSP_SYNC_FROM_ADAT_SYNC; + switch (hdsp->control_register & HDSP_DAGainMask) { + case HDSP_DAGainHighGain: + return 0; + case HDSP_DAGainPlus4dBu: + return 1; + case HDSP_DAGainMinus10dBV: + return 2; default: - return HDSP_SYNC_FROM_WORD; + return 1; } - return 0; } -static int hdsp_set_pref_sync_ref(hdsp_t *hdsp, int pref) +static int hdsp_set_da_gain(hdsp_t *hdsp, int mode) { - hdsp->control_register &= ~HDSP_SyncRefMask; - switch (pref) { - case HDSP_SYNC_FROM_ADAT1: - hdsp->control_register &= ~HDSP_SyncRefMask; /* clear SyncRef bits */ - break; - case HDSP_SYNC_FROM_ADAT2: - hdsp->control_register |= HDSP_SyncRef_ADAT2; - break; - case HDSP_SYNC_FROM_ADAT3: - hdsp->control_register |= HDSP_SyncRef_ADAT3; - break; - case HDSP_SYNC_FROM_SPDIF: - hdsp->control_register |= HDSP_SyncRef_SPDIF; - break; - case HDSP_SYNC_FROM_WORD: - hdsp->control_register |= HDSP_SyncRef_WORD; + hdsp->control_register &= ~HDSP_DAGainMask; + switch (mode) { + case 0: + hdsp->control_register |= HDSP_DAGainHighGain; break; - case HDSP_SYNC_FROM_ADAT_SYNC: - hdsp->control_register |= HDSP_SyncRef_ADAT_SYNC; + 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_pref_sync_ref(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +static int snd_hdsp_info_da_gain(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - static char *texts[] = {"Word", "ADAT Sync", "IEC958", "ADAT1", "ADAT2", "ADAT3" }; - hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + static char *texts[] = {"Hi Gain", "+4 dBu", "-10 dbV"}; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - - switch (hdsp->io_type) { - case Digiface: - case H9652: - uinfo->value.enumerated.items = 6; - break; - case Multiface: - uinfo->value.enumerated.items = 4; - default: - uinfo->value.enumerated.items = 0; - break; - } - + 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_pref_sync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +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_pref_sync_ref(hdsp); + ucontrol->value.enumerated.item[0] = hdsp_da_gain(hdsp); return 0; } -static int snd_hdsp_put_pref_sync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +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, max; - unsigned int val; + int change; + int val; if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; - - switch (hdsp->io_type) { - case Digiface: - case H9652: - max = 6; - break; - case Multiface: - max = 4; - break; - default: - return -EIO; - } - - val = ucontrol->value.enumerated.item[0] % max; + val = ucontrol->value.enumerated.item[0]; + if (val < 0) val = 0; + if (val > 2) val = 2; spin_lock_irqsave(&hdsp->lock, flags); - change = (int)val != hdsp_pref_sync_ref(hdsp); - hdsp_set_pref_sync_ref(hdsp, val); + 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_AUTOSYNC_REF(xname, xindex) \ +#define HDSP_AD_GAIN(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ .name = xname, \ .index = xindex, \ - .access = SNDRV_CTL_ELEM_ACCESS_READ, \ - .info = snd_hdsp_info_autosync_ref, \ - .get = snd_hdsp_get_autosync_ref, \ + .info = snd_hdsp_info_ad_gain, \ + .get = snd_hdsp_get_ad_gain, \ + .put = snd_hdsp_put_ad_gain \ } -static int hdsp_autosync_ref(hdsp_t *hdsp) +static int hdsp_ad_gain(hdsp_t *hdsp) { - /* This looks at the autosync selected sync reference */ - unsigned int status2 = hdsp_read(hdsp, HDSP_status2Register); + switch (hdsp->control_register & HDSP_ADGainMask) { + case HDSP_ADGainMinus10dBV: + return 0; + case HDSP_ADGainPlus4dBu: + return 1; + case HDSP_ADGainLowGain: + return 2; + default: + return 1; + } +} - switch (status2 & HDSP_SelSyncRefMask) { - case HDSP_SelSyncRef_WORD: - return HDSP_AUTOSYNC_FROM_WORD; - case HDSP_SelSyncRef_ADAT_SYNC: - return HDSP_AUTOSYNC_FROM_ADAT_SYNC; - case HDSP_SelSyncRef_SPDIF: - return HDSP_AUTOSYNC_FROM_SPDIF; - case HDSP_SelSyncRefMask: - return HDSP_AUTOSYNC_FROM_NONE; - case HDSP_SelSyncRef_ADAT1: - return HDSP_AUTOSYNC_FROM_ADAT1; - case HDSP_SelSyncRef_ADAT2: - return HDSP_AUTOSYNC_FROM_ADAT2; - case HDSP_SelSyncRef_ADAT3: - return HDSP_AUTOSYNC_FROM_ADAT3; +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 HDSP_AUTOSYNC_FROM_WORD; + return -1; + } + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); return 0; } -static int snd_hdsp_info_autosync_ref(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +static int snd_hdsp_info_ad_gain(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { - static char *texts[] = {"Word", "ADAT Sync", "IEC958", "None", "ADAT1", "ADAT2", "ADAT3" }; + static char *texts[] = {"-10 dBV", "+4 dBu", "Lo Gain"}; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = 7; + 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_autosync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +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_pref_sync_ref(hdsp); + ucontrol->value.enumerated.item[0] = hdsp_ad_gain(hdsp); return 0; } -#define HDSP_PASSTHRU(xname, xindex) \ +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_passthru, \ - .put = snd_hdsp_put_passthru, \ - .get = snd_hdsp_get_passthru \ + .info = snd_hdsp_info_phone_gain, \ + .get = snd_hdsp_get_phone_gain, \ + .put = snd_hdsp_put_phone_gain \ } -static int snd_hdsp_info_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) +static int hdsp_phone_gain(hdsp_t *hdsp) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 1; - return 0; + 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 snd_hdsp_get_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +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); - unsigned long flags; + + 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); - ucontrol->value.integer.value[0] = hdsp->passthru; + 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 snd_hdsp_put_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +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; - unsigned int val; - int err = 0; - + 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 = (ucontrol->value.integer.value[0] != hdsp->passthru); - if (change) - err = hdsp_set_passthru(hdsp, val); + change = (int)val != hdsp_xlr_breakout_cable(hdsp); + hdsp_set_xlr_breakout_cable(hdsp, val); spin_unlock_irqrestore(&hdsp->lock, flags); - return err ? err : change; + return change; } -#define HDSP_LINE_OUT(xname, xindex) \ +/* (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_line_out, \ - .get = snd_hdsp_get_line_out, \ - .put = snd_hdsp_put_line_out \ + .info = snd_hdsp_info_aeb, \ + .get = snd_hdsp_get_aeb, \ + .put = snd_hdsp_put_aeb \ } -static int hdsp_line_out(hdsp_t *hdsp) +static int hdsp_aeb(hdsp_t *hdsp) { - return (hdsp->control_register & HDSP_LineOut) ? 1 : 0; + if (hdsp->control_register & HDSP_AnalogExtensionBoard) { + return 1; + } + return 0; } -static int hdsp_set_line_output(hdsp_t *hdsp, int out) +static int hdsp_set_aeb(hdsp_t *hdsp, int mode) { - if (out) { - hdsp->control_register |= HDSP_LineOut; + if (mode) { + hdsp->control_register |= HDSP_AnalogExtensionBoard; } else { - hdsp->control_register &= ~HDSP_LineOut; + hdsp->control_register &= ~HDSP_AnalogExtensionBoard; } hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); return 0; } -static int snd_hdsp_info_line_out(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +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; @@ -2237,182 +2561,399 @@ static int snd_hdsp_info_line_out(snd_kc return 0; } -static int snd_hdsp_get_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int snd_hdsp_get_aeb(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); - unsigned long flags; - spin_lock_irqsave(&hdsp->lock, flags); - ucontrol->value.integer.value[0] = hdsp_line_out(hdsp); - spin_unlock_irqrestore(&hdsp->lock, flags); + ucontrol->value.enumerated.item[0] = hdsp_aeb(hdsp); return 0; } -static int snd_hdsp_put_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +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; - unsigned int val; + 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_line_out(hdsp); - hdsp_set_line_output(hdsp, val); + change = (int)val != hdsp_aeb(hdsp); + hdsp_set_aeb(hdsp, val); spin_unlock_irqrestore(&hdsp->lock, flags); return change; } -#define HDSP_MIXER(xname, xindex) \ +#define HDSP_PREF_SYNC_REF(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ .name = xname, \ .index = xindex, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ - .info = snd_hdsp_info_mixer, \ - .get = snd_hdsp_get_mixer, \ - .put = snd_hdsp_put_mixer \ + .info = snd_hdsp_info_pref_sync_ref, \ + .get = snd_hdsp_get_pref_sync_ref, \ + .put = snd_hdsp_put_pref_sync_ref \ } -static int snd_hdsp_info_mixer(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +static int hdsp_pref_sync_ref(hdsp_t *hdsp) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 3; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 65536; - uinfo->value.integer.step = 1; + /* Notice that this looks at the requested sync source, + not the one actually in use. + */ + + switch (hdsp->control_register & HDSP_SyncRefMask) { + case HDSP_SyncRef_ADAT1: + return HDSP_SYNC_FROM_ADAT1; + case HDSP_SyncRef_ADAT2: + return HDSP_SYNC_FROM_ADAT2; + case HDSP_SyncRef_ADAT3: + return HDSP_SYNC_FROM_ADAT3; + case HDSP_SyncRef_SPDIF: + return HDSP_SYNC_FROM_SPDIF; + case HDSP_SyncRef_WORD: + return HDSP_SYNC_FROM_WORD; + case HDSP_SyncRef_ADAT_SYNC: + return HDSP_SYNC_FROM_ADAT_SYNC; + default: + return HDSP_SYNC_FROM_WORD; + } return 0; } -static int snd_hdsp_get_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int hdsp_set_pref_sync_ref(hdsp_t *hdsp, int pref) +{ + hdsp->control_register &= ~HDSP_SyncRefMask; + switch (pref) { + case HDSP_SYNC_FROM_ADAT1: + hdsp->control_register &= ~HDSP_SyncRefMask; /* clear SyncRef bits */ + break; + case HDSP_SYNC_FROM_ADAT2: + hdsp->control_register |= HDSP_SyncRef_ADAT2; + break; + case HDSP_SYNC_FROM_ADAT3: + hdsp->control_register |= HDSP_SyncRef_ADAT3; + break; + case HDSP_SYNC_FROM_SPDIF: + hdsp->control_register |= HDSP_SyncRef_SPDIF; + break; + case HDSP_SYNC_FROM_WORD: + hdsp->control_register |= HDSP_SyncRef_WORD; + break; + case HDSP_SYNC_FROM_ADAT_SYNC: + hdsp->control_register |= HDSP_SyncRef_ADAT_SYNC; + break; + default: + return -1; + } + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + return 0; +} + +static int snd_hdsp_info_pref_sync_ref(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = {"Word", "IEC958", "ADAT1", "ADAT Sync", "ADAT2", "ADAT3" }; + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + + switch (hdsp->io_type) { + case Digiface: + case H9652: + uinfo->value.enumerated.items = 6; + break; + case Multiface: + uinfo->value.enumerated.items = 4; + break; + case H9632: + uinfo->value.enumerated.items = 3; + break; + default: + uinfo->value.enumerated.items = 0; + break; + } + + 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_pref_sync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdsp_pref_sync_ref(hdsp); + return 0; +} + +static int snd_hdsp_put_pref_sync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); unsigned long flags; - int source; - int destination; - int addr; + int change, max; + unsigned int val; + + if (!snd_hdsp_use_is_exclusive(hdsp)) + return -EBUSY; - source = ucontrol->value.integer.value[0]; - destination = ucontrol->value.integer.value[1]; + switch (hdsp->io_type) { + case Digiface: + case H9652: + max = 6; + break; + case Multiface: + max = 4; + break; + case H9632: + max = 3; + break; + default: + return -EIO; + } - if (source > 25) { - addr = hdsp_playback_to_output_key(hdsp,source-26,destination); - } else { - addr = hdsp_input_to_output_key(hdsp,source, destination); + val = ucontrol->value.enumerated.item[0] % max; + spin_lock_irqsave(&hdsp->lock, flags); + change = (int)val != hdsp_pref_sync_ref(hdsp); + hdsp_set_pref_sync_ref(hdsp, val); + spin_unlock_irqrestore(&hdsp->lock, flags); + return change; +} + +#define HDSP_AUTOSYNC_REF(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ, \ + .info = snd_hdsp_info_autosync_ref, \ + .get = snd_hdsp_get_autosync_ref, \ +} + +static int hdsp_autosync_ref(hdsp_t *hdsp) +{ + /* This looks at the autosync selected sync reference */ + unsigned int status2 = hdsp_read(hdsp, HDSP_status2Register); + + switch (status2 & HDSP_SelSyncRefMask) { + case HDSP_SelSyncRef_WORD: + return HDSP_AUTOSYNC_FROM_WORD; + case HDSP_SelSyncRef_ADAT_SYNC: + return HDSP_AUTOSYNC_FROM_ADAT_SYNC; + case HDSP_SelSyncRef_SPDIF: + return HDSP_AUTOSYNC_FROM_SPDIF; + case HDSP_SelSyncRefMask: + return HDSP_AUTOSYNC_FROM_NONE; + case HDSP_SelSyncRef_ADAT1: + return HDSP_AUTOSYNC_FROM_ADAT1; + case HDSP_SelSyncRef_ADAT2: + return HDSP_AUTOSYNC_FROM_ADAT2; + case HDSP_SelSyncRef_ADAT3: + return HDSP_AUTOSYNC_FROM_ADAT3; + default: + return HDSP_AUTOSYNC_FROM_WORD; } + return 0; +} + +static int snd_hdsp_info_autosync_ref(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = {"Word", "ADAT Sync", "IEC958", "None", "ADAT1", "ADAT2", "ADAT3" }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + 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]); + return 0; +} + +static int snd_hdsp_get_autosync_ref(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + + ucontrol->value.enumerated.item[0] = hdsp_pref_sync_ref(hdsp); + return 0; +} + +#define HDSP_PASSTHRU(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdsp_info_passthru, \ + .put = snd_hdsp_put_passthru, \ + .get = snd_hdsp_get_passthru \ +} + +static int snd_hdsp_info_passthru(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_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + unsigned long flags; + spin_lock_irqsave(&hdsp->lock, flags); - ucontrol->value.integer.value[2] = hdsp_read_gain (hdsp, addr); + ucontrol->value.integer.value[0] = hdsp->passthru; spin_unlock_irqrestore(&hdsp->lock, flags); return 0; } -static int snd_hdsp_put_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +static int snd_hdsp_put_passthru(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); unsigned long flags; int change; - int source; - int destination; - int gain; - int addr; + unsigned int val; + int err = 0; if (!snd_hdsp_use_is_exclusive(hdsp)) return -EBUSY; - source = ucontrol->value.integer.value[0]; - destination = ucontrol->value.integer.value[1]; + val = ucontrol->value.integer.value[0] & 1; + spin_lock_irqsave(&hdsp->lock, flags); + change = (ucontrol->value.integer.value[0] != hdsp->passthru); + if (change) + err = hdsp_set_passthru(hdsp, val); + spin_unlock_irqrestore(&hdsp->lock, flags); + return err ? err : change; +} + +#define HDSP_LINE_OUT(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdsp_info_line_out, \ + .get = snd_hdsp_get_line_out, \ + .put = snd_hdsp_put_line_out \ +} - if (source > 25) { - addr = hdsp_playback_to_output_key(hdsp,source-26, destination); +static int hdsp_line_out(hdsp_t *hdsp) +{ + return (hdsp->control_register & HDSP_LineOut) ? 1 : 0; +} + +static int hdsp_set_line_output(hdsp_t *hdsp, int out) +{ + if (out) { + hdsp->control_register |= HDSP_LineOut; } else { - addr = hdsp_input_to_output_key(hdsp,source, destination); + hdsp->control_register &= ~HDSP_LineOut; } + hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); + return 0; +} - gain = ucontrol->value.integer.value[2]; +static int snd_hdsp_info_line_out(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_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + unsigned long flags; + + spin_lock_irqsave(&hdsp->lock, flags); + ucontrol->value.integer.value[0] = hdsp_line_out(hdsp); + spin_unlock_irqrestore(&hdsp->lock, flags); + return 0; +} +static int snd_hdsp_put_line_out(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); + unsigned long flags; + int change; + unsigned 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 = gain != hdsp_read_gain(hdsp, addr); - if (change) - hdsp_write_gain(hdsp, addr, gain); + change = (int)val != hdsp_line_out(hdsp); + hdsp_set_line_output(hdsp, val); spin_unlock_irqrestore(&hdsp->lock, flags); 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 | \ +#define HDSP_MIXER(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ - .info = snd_hdsp_info_playback_mixer, \ - .get = snd_hdsp_get_playback_mixer, \ - .put = snd_hdsp_put_playback_mixer \ + .info = snd_hdsp_info_mixer, \ + .get = snd_hdsp_get_mixer, \ + .put = snd_hdsp_put_mixer \ } -static int snd_hdsp_info_playback_mixer(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +static int snd_hdsp_info_mixer(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; + uinfo->count = 3; 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) +static int snd_hdsp_get_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { hdsp_t *hdsp = _snd_kcontrol_chip(kcontrol); unsigned long flags; + int source; + int destination; 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; + source = ucontrol->value.integer.value[0]; + destination = ucontrol->value.integer.value[1]; + + 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); } - - 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); + ucontrol->value.integer.value[2] = 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) +static int snd_hdsp_put_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 source; + int destination; int gain; + int addr; 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; - } + source = ucontrol->value.integer.value[0]; + destination = ucontrol->value.integer.value[1]; - addr = hdsp_playback_to_output_key(hdsp,mapped_channel, mapped_channel); - gain = ucontrol->value.integer.value[0]; + 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); + } + gain = ucontrol->value.integer.value[2]; spin_lock_irqsave(&hdsp->lock, flags); change = gain != hdsp_read_gain(hdsp, addr); @@ -2566,6 +3107,7 @@ static int snd_hdsp_get_adat_sync_check( return -EINVAL; break; case Multiface: + case H9632: if (offset >= 1) return -EINVAL; break; @@ -2577,6 +3119,13 @@ static int snd_hdsp_get_adat_sync_check( 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 @@ HDSP_LINE_OUT("Line Out", 0), #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 @@ int snd_hdsp_create_controls(snd_card_t 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 @@ int snd_hdsp_create_controls(snd_card_t } } } + + /* 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 @@ snd_hdsp_proc_read(snd_info_entry_t *ent 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_hdsp_proc_read(snd_info_entry_t *ent 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_hdsp_proc_read(snd_info_entry_t *ent } 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); -#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); + 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); + + 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 @@ static void __devinit snd_hdsp_proc_init 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 @@ static int snd_hdsp_set_defaults(hdsp_t 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 @@ static int snd_hdsp_set_defaults(hdsp_t 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 @@ static int snd_hdsp_set_defaults(hdsp_t 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 @@ static int snd_hdsp_set_defaults(hdsp_t 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 @@ static char *hdsp_channel_buffer_locatio { 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 @@ static int snd_hdsp_channel_info(snd_pcm 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 @@ static snd_pcm_hardware_t snd_hdsp_captu .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->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_channels, - .max = hdsp->ds_channels, + .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 @@ static int snd_hdsp_hw_rule_channels_rat 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_out_channels) { + snd_interval_t t = { + .min = 32000, + .max = 48000, + .integer = 1, + }; + return snd_interval_refine(r, &t); + } 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_channels) { + 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->ds_channels) { + } 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 @@ static int snd_hdsp_playback_open(snd_pc 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 @@ static int snd_hdsp_capture_open(snd_pcm 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_capture_release(snd_ 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 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde 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 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde 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 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde 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 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde 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 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde return err; } - if (!(hdsp->state & HDSP_InitializationComplete)) { snd_hdsp_initialize_channels(hdsp); @@ -3914,8 +4742,8 @@ static int snd_hdsp_hwdep_ioctl(snd_hwde 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 @@ static inline int snd_hdsp_enable_io (hd 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 int snd_hdsp_enable_io (hd 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 @@ static int __devinit snd_hdsp_create_als 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 @@ static int __devinit snd_hdsp_create(snd { 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 @@ static int __devinit snd_hdsp_create(snd 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; @@ -4150,7 +4998,11 @@ static int __devinit snd_hdsp_create(snd 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 +5037,7 @@ static int __devinit snd_hdsp_create(snd 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 +5068,10 @@ static int __devinit snd_hdsp_create(snd 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) { diff -puN sound/pci/rme9652/rme9652.c~alsa-101 sound/pci/rme9652/rme9652.c --- 25/sound/pci/rme9652/rme9652.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/rme9652/rme9652.c 2004-01-19 22:19:00.000000000 -0800 @@ -1618,7 +1618,6 @@ RME9652_SYNC_PREF("Preferred Sync Source 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 @@ static void __devinit snd_rme9652_proc_i 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) diff -puN sound/pci/rme96.c~alsa-101 sound/pci/rme96.c --- 25/sound/pci/rme96.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/rme96.c 2004-01-19 22:19:00.000000000 -0800 @@ -1524,21 +1524,21 @@ snd_rme96_playback_pointer(snd_pcm_subst 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 @@ snd_rme96_capture_pointer(snd_pcm_substr 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_rme96_proc_init(rme96_t *rme96) 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); } /* diff -puN sound/pci/sonicvibes.c~alsa-101 sound/pci/sonicvibes.c --- 25/sound/pci/sonicvibes.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/sonicvibes.c 2004-01-19 22:19:00.000000000 -0800 @@ -1177,7 +1177,7 @@ static void __devinit snd_sonicvibes_pro 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); } /* @@ -1253,7 +1253,7 @@ static int __devinit snd_sonicvibes_crea snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x00ffffff); + pci_set_consistent_dma_mask(pci, 0x00ffffff); sonic = snd_magic_kcalloc(sonicvibes_t, 0, GFP_KERNEL); if (sonic == NULL) diff -puN sound/pci/trident/trident_main.c~alsa-101 sound/pci/trident/trident_main.c --- 25/sound/pci/trident/trident_main.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/trident/trident_main.c 2004-01-19 22:19:00.000000000 -0800 @@ -2955,6 +2955,7 @@ static int snd_trident_pcm_mixer_free(tr 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 @@ static int __devinit snd_trident_mixer(t 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 @@ static int __devinit snd_trident_mixer(t 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 @@ static void __devinit snd_trident_proc_i 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) @@ -3522,7 +3527,7 @@ int __devinit snd_trident_create(snd_car snd_printk("architecture does not support 30bit PCI busmaster DMA\n"); return -ENXIO; } - pci_set_dma_mask(pci, 0x3fffffff); + pci_set_consistent_dma_mask(pci, 0x3fffffff); trident = snd_magic_kcalloc(trident_t, 0, GFP_KERNEL); if (trident == NULL) @@ -3947,7 +3952,7 @@ void snd_trident_resume(trident_t *tride return; pci_enable_device(trident->pci); - pci_set_dma_mask(trident->pci, 0x3fffffff); /* to be sure */ + pci_set_consistent_dma_mask(trident->pci, 0x3fffffff); /* FIXME: correct? */ pci_set_master(trident->pci); /* to be sure */ switch (trident->device) { diff -puN sound/pci/via82xx.c~alsa-101 sound/pci/via82xx.c --- 25/sound/pci/via82xx.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/via82xx.c 2004-01-19 22:19:00.000000000 -0800 @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -69,10 +70,17 @@ MODULE_LICENSE("GPL"); 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(enable, "1-" __MODULE_STRING 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 */ @@ -290,6 +303,7 @@ DEFINE_VIA_REGSET(CAPTURE_8233, 0x60); #define VIA_DXS_ENABLE 1 #define VIA_DXS_DISABLE 2 #define VIA_DXS_48K 3 +#define VIA_DXS_NO_VRA 4 /* @@ -449,9 +463,11 @@ struct _snd_via82xx { 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 +475,11 @@ struct _snd_via82xx { 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 +530,6 @@ static int snd_via82xx_codec_valid(via82 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 +574,7 @@ static unsigned short snd_via82xx_codec_ 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 +886,12 @@ static int via_lock_rate(struct via_rate 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 +911,8 @@ static int snd_via8233_playback_prepare( 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 +1402,7 @@ static int snd_via8233_capture_source_in 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 +1410,7 @@ static int snd_via8233_capture_source_ge 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; @@ -1509,6 +1529,12 @@ static snd_kcontrol_new_t snd_via8233_dx /* */ +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 +1542,42 @@ static void snd_via82xx_mixer_free_ac97( } 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 +1591,6 @@ static int __devinit snd_via82xx_mixer_n } /* - * 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 +1645,7 @@ static int snd_via686_init_misc(via82xx_ "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 +1672,18 @@ static int snd_via686_init_misc(via82xx_ 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 +1697,13 @@ static int snd_via686_init_misc(via82xx_ } 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 +1717,7 @@ static void snd_via82xx_proc_read(snd_in 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 +1726,7 @@ static void __devinit snd_via82xx_proc_i 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 +1865,13 @@ static int snd_via82xx_free(via82xx_t *c 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); } @@ -1967,8 +1980,20 @@ struct dxs_whitelist { 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 = 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 +2019,8 @@ static int __devinit check_dxs_list(stru * 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 +2099,14 @@ static int __devinit snd_via82xx_probe(s 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 +2170,7 @@ module_exit(alsa_card_via82xx_exit) #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 +2181,10 @@ static int __init alsa_card_via82xx_setu (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 -puN sound/pci/ymfpci/ymfpci.c~alsa-101 sound/pci/ymfpci/ymfpci.c --- 25/sound/pci/ymfpci/ymfpci.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ymfpci/ymfpci.c 2004-01-19 22:19:00.000000000 -0800 @@ -44,8 +44,11 @@ MODULE_DEVICES("{{Yamaha,YMF724}," 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_SYNTAX(mpu_port, SNDRV_ENABL 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 @@ static int __devinit snd_card_ymfpci_pro 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 @@ static int __devinit snd_card_ymfpci_pro 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,19 @@ static int __devinit snd_card_ymfpci_pro 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 if ((err = snd_ymfpci_pcm(chip, 0, NULL)) < 0) { snd_card_free(card); return err; @@ -206,6 +267,10 @@ static int __devinit snd_card_ymfpci_pro 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,9 +294,10 @@ static int __devinit snd_card_ymfpci_pro 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); @@ -319,8 +385,8 @@ static int __init alsa_card_ymfpci_setup (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 -puN sound/pci/ymfpci/ymfpci_main.c~alsa-101 sound/pci/ymfpci/ymfpci_main.c --- 25/sound/pci/ymfpci/ymfpci_main.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pci/ymfpci/ymfpci_main.c 2004-01-19 22:19:00.000000000 -0800 @@ -779,7 +779,8 @@ static irqreturn_t snd_ymfpci_interrupt( 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 @@ int __devinit snd_ymfpci_pcm2(ymfpci_t * 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 @@ int __devinit snd_ymfpci_pcm2(ymfpci_t * /* 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 @@ static snd_kcontrol_new_t snd_ymfpci_spd .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 @@ static snd_kcontrol_new_t snd_ymfpci_rea * 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 @@ static void snd_ymfpci_mixer_free_ac97(a 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 @@ int __devinit snd_ymfpci_mixer(ymfpci_t 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 @@ int __devinit snd_ymfpci_mixer(ymfpci_t /* - * 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) +static int snd_ymfpci_timer_start(snd_timer_t *timer) { - 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) -{ - 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) +static int snd_ymfpci_timer_stop(snd_timer_t *timer) { - 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) -{ - 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 @@ static int __devinit snd_ymfpci_proc_ini 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 @@ static int snd_ymfpci_free(ymfpci_t *chi 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 @@ void snd_ymfpci_resume(ymfpci_t *chip) /* 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 @@ int __devinit snd_ymfpci_create(snd_card 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; diff -puN sound/pcmcia/Kconfig~alsa-101 sound/pcmcia/Kconfig --- 25/sound/pcmcia/Kconfig~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pcmcia/Kconfig 2004-01-19 22:19:00.000000000 -0800 @@ -5,13 +5,13 @@ menu "PCMCIA devices" 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 -puN sound/pcmcia/vx/vx_entry.c~alsa-101 sound/pcmcia/vx/vx_entry.c --- 25/sound/pcmcia/vx/vx_entry.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/pcmcia/vx/vx_entry.c 2004-01-19 22:19:00.000000000 -0800 @@ -27,6 +27,10 @@ #include +MODULE_AUTHOR("Takashi Iwai "); +MODULE_DESCRIPTION("Common routines for Digigram PCMCIA VX drivers"); +MODULE_LICENSE("GPL"); + /* * prototypes */ diff -puN sound/ppc/daca.c~alsa-101 sound/ppc/daca.c --- 25/sound/ppc/daca.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/ppc/daca.c 2004-01-19 22:19:00.000000000 -0800 @@ -249,7 +249,8 @@ int __init snd_pmac_daca_init(pmac_t *ch 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 -puN sound/ppc/tumbler.c~alsa-101 sound/ppc/tumbler.c --- 25/sound/ppc/tumbler.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/ppc/tumbler.c 2004-01-19 22:19:00.000000000 -0800 @@ -993,7 +993,8 @@ int __init snd_pmac_tumbler_init(pmac_t 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 -puN sound/usb/usbaudio.c~alsa-101 sound/usb/usbaudio.c --- 25/sound/usb/usbaudio.c~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/usb/usbaudio.c 2004-01-19 22:19:00.000000000 -0800 @@ -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). */ @@ -56,6 +68,7 @@ static int enable[SNDRV_CARDS] = SNDRV_D 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."); @@ -75,21 +88,9 @@ MODULE_PARM_SYNTAX(pid, SNDRV_ENABLED ", 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); /* @@ -571,20 +572,18 @@ static void snd_complete_urb(struct urb 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); } @@ -596,63 +595,66 @@ static void snd_complete_sync_urb(struct 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 } @@ -681,9 +683,11 @@ static int start_urbs(snd_usb_substream_ } } + 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; } @@ -691,7 +695,7 @@ static int start_urbs(snd_usb_substream_ } 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; } @@ -702,7 +706,7 @@ static int start_urbs(snd_usb_substream_ __error: // snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN); - deactivate_urbs(subs, 0); + deactivate_urbs(subs, 0, 0); return -EPIPE; } @@ -762,7 +766,7 @@ static int snd_usb_pcm_trigger(snd_pcm_s 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; @@ -795,8 +799,8 @@ static void release_substream_urbs(snd_u 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]); @@ -824,14 +828,6 @@ static int init_substream_urbs(snd_usb_s 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) { @@ -914,7 +910,7 @@ static int init_substream_urbs(snd_usb_s } 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); @@ -936,7 +932,7 @@ static int init_substream_urbs(snd_usb_s 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); @@ -954,6 +950,7 @@ static struct audioformat *find_format(s { struct list_head *p; struct audioformat *found = NULL; + int cur_attr = 0, attr; list_for_each(p, &subs->fmt_list) { struct audioformat *fp; @@ -970,9 +967,37 @@ static struct audioformat *find_format(s 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; } @@ -1240,6 +1265,17 @@ static int snd_usb_pcm_prepare(snd_pcm_s 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; } @@ -1429,7 +1465,7 @@ static int hw_rule_format(snd_pcm_hw_par 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]; @@ -1454,6 +1490,7 @@ static int check_hw_params_convention(sn 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)); @@ -1465,6 +1502,15 @@ static int check_hw_params_convention(sn /* 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]) @@ -1819,7 +1865,7 @@ static void proc_pcm_format_add(snd_usb_ 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); } @@ -1955,7 +2001,7 @@ static int add_audio_endpoint(snd_usb_au 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 @@ -2008,10 +2054,20 @@ static int parse_audio_format_i_type(str 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; @@ -2604,6 +2660,32 @@ static int snd_usb_create_quirk(snd_usb_ /* + * 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 @@ -2701,6 +2783,8 @@ static int snd_usb_audio_create(snd_card if (len < sizeof(card->longname)) usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); + snd_usb_audio_create_proc(chip); + *rchip = chip; return 0; } diff -puN sound/usb/usbquirks.h~alsa-101 sound/usb/usbquirks.h --- 25/sound/usb/usbquirks.h~alsa-101 2004-01-19 22:19:00.000000000 -0800 +++ 25-akpm/sound/usb/usbquirks.h 2004-01-19 22:19:00.000000000 -0800 @@ -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), @@ -768,6 +638,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 */ { _