2019-05-27 08:55:05 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-16 15:20:36 -07:00
/*
* The driver for the Cirrus Logic ' s Sound Fusion CS46XX based soundcards
2007-10-15 09:50:19 +02:00
* Copyright ( c ) by Jaroslav Kysela < perex @ perex . cz >
2005-04-16 15:20:36 -07:00
*/
/*
NOTES :
- sometimes the sound is metallic and sibilant , unloading and
reloading the module may solve this .
*/
# include <linux/pci.h>
# include <linux/time.h>
# include <linux/init.h>
2011-07-15 13:13:37 -04:00
# include <linux/module.h>
2005-04-16 15:20:36 -07:00
# include <sound/core.h>
2012-07-02 16:37:05 +02:00
# include "cs46xx.h"
2005-04-16 15:20:36 -07:00
# include <sound/initval.h>
2007-10-15 09:50:19 +02:00
MODULE_AUTHOR ( " Jaroslav Kysela <perex@perex.cz> " ) ;
2005-04-16 15:20:36 -07:00
MODULE_DESCRIPTION ( " Cirrus Logic Sound Fusion CS46XX " ) ;
MODULE_LICENSE ( " GPL " ) ;
static int index [ SNDRV_CARDS ] = SNDRV_DEFAULT_IDX ; /* Index 0-MAX */
static char * id [ SNDRV_CARDS ] = SNDRV_DEFAULT_STR ; /* ID for this card */
2011-12-15 13:49:36 +10:30
static bool enable [ SNDRV_CARDS ] = SNDRV_DEFAULT_ENABLE_PNP ; /* Enable this card */
static bool external_amp [ SNDRV_CARDS ] ;
static bool thinkpad [ SNDRV_CARDS ] ;
static bool mmap_valid [ SNDRV_CARDS ] = { [ 0 . . . ( SNDRV_CARDS - 1 ) ] = 1 } ;
2005-04-16 15:20:36 -07:00
module_param_array ( index , int , NULL , 0444 ) ;
MODULE_PARM_DESC ( index , " Index value for the CS46xx soundcard. " ) ;
module_param_array ( id , charp , NULL , 0444 ) ;
MODULE_PARM_DESC ( id , " ID string for the CS46xx soundcard. " ) ;
module_param_array ( enable , bool , NULL , 0444 ) ;
MODULE_PARM_DESC ( enable , " Enable CS46xx soundcard. " ) ;
module_param_array ( external_amp , bool , NULL , 0444 ) ;
2018-04-27 20:02:45 +01:00
MODULE_PARM_DESC ( external_amp , " Force to enable external amplifier. " ) ;
2005-04-16 15:20:36 -07:00
module_param_array ( thinkpad , bool , NULL , 0444 ) ;
MODULE_PARM_DESC ( thinkpad , " Force to enable Thinkpad's CLKRUN control. " ) ;
module_param_array ( mmap_valid , bool , NULL , 0444 ) ;
MODULE_PARM_DESC ( mmap_valid , " Support OSS mmap. " ) ;
2014-08-08 15:56:03 +02:00
static const struct pci_device_id snd_cs46xx_ids [ ] = {
2009-06-24 22:13:35 -07:00
{ PCI_VDEVICE ( CIRRUS , 0x6001 ) , 0 , } , /* CS4280 */
{ PCI_VDEVICE ( CIRRUS , 0x6003 ) , 0 , } , /* CS4612 */
{ PCI_VDEVICE ( CIRRUS , 0x6004 ) , 0 , } , /* CS4615 */
2005-04-16 15:20:36 -07:00
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , snd_cs46xx_ids ) ;
2012-12-06 12:35:10 -05:00
static int snd_card_cs46xx_probe ( struct pci_dev * pci ,
const struct pci_device_id * pci_id )
2005-04-16 15:20:36 -07:00
{
static int dev ;
2005-11-17 14:48:14 +01:00
struct snd_card * card ;
struct snd_cs46xx * chip ;
2005-04-16 15:20:36 -07:00
int err ;
if ( dev > = SNDRV_CARDS )
return - ENODEV ;
if ( ! enable [ dev ] ) {
dev + + ;
return - ENOENT ;
}
2021-07-15 09:58:52 +02:00
err = snd_devm_card_new ( & pci - > dev , index [ dev ] , id [ dev ] , THIS_MODULE ,
sizeof ( * chip ) , & card ) ;
2008-12-28 16:44:30 +01:00
if ( err < 0 )
return err ;
2021-07-15 09:58:52 +02:00
chip = card - > private_data ;
2021-06-08 16:05:11 +02:00
err = snd_cs46xx_create ( card , pci ,
2021-07-15 09:58:52 +02:00
external_amp [ dev ] , thinkpad [ dev ] ) ;
if ( err < 0 )
2022-07-05 17:23:36 +02:00
goto error ;
2005-11-17 16:09:04 +01:00
card - > private_data = chip ;
2005-04-16 15:20:36 -07:00
chip - > accept_valid = mmap_valid [ dev ] ;
2021-06-08 16:05:11 +02:00
err = snd_cs46xx_pcm ( chip , 0 ) ;
2021-07-15 09:58:52 +02:00
if ( err < 0 )
2022-07-05 17:23:36 +02:00
goto error ;
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_SND_CS46XX_NEW_DSP
2021-06-08 16:05:11 +02:00
err = snd_cs46xx_pcm_rear ( chip , 1 ) ;
2021-07-15 09:58:52 +02:00
if ( err < 0 )
2022-07-05 17:23:36 +02:00
goto error ;
2021-06-08 16:05:11 +02:00
err = snd_cs46xx_pcm_iec958 ( chip , 2 ) ;
2021-07-15 09:58:52 +02:00
if ( err < 0 )
2022-07-05 17:23:36 +02:00
goto error ;
2005-04-16 15:20:36 -07:00
# endif
2021-06-08 16:05:11 +02:00
err = snd_cs46xx_mixer ( chip , 2 ) ;
2021-07-15 09:58:52 +02:00
if ( err < 0 )
2022-07-05 17:23:36 +02:00
goto error ;
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_SND_CS46XX_NEW_DSP
if ( chip - > nr_ac97_codecs = = 2 ) {
2021-06-08 16:05:11 +02:00
err = snd_cs46xx_pcm_center_lfe ( chip , 3 ) ;
2021-07-15 09:58:52 +02:00
if ( err < 0 )
2022-07-05 17:23:36 +02:00
goto error ;
2005-04-16 15:20:36 -07:00
}
# endif
2021-06-08 16:05:11 +02:00
err = snd_cs46xx_midi ( chip , 0 ) ;
2021-07-15 09:58:52 +02:00
if ( err < 0 )
2022-07-05 17:23:36 +02:00
goto error ;
2021-06-08 16:05:11 +02:00
err = snd_cs46xx_start_dsp ( chip ) ;
2021-07-15 09:58:52 +02:00
if ( err < 0 )
2022-07-05 17:23:36 +02:00
goto error ;
2005-04-16 15:20:36 -07:00
snd_cs46xx_gameport ( chip ) ;
strcpy ( card - > driver , " CS46xx " ) ;
strcpy ( card - > shortname , " Sound Fusion CS46xx " ) ;
sprintf ( card - > longname , " %s at 0x%lx/0x%lx, irq %i " ,
card - > shortname ,
chip - > ba0_addr ,
chip - > ba1_addr ,
chip - > irq ) ;
2021-06-08 16:05:11 +02:00
err = snd_card_register ( card ) ;
2021-07-15 09:58:52 +02:00
if ( err < 0 )
2022-07-05 17:23:36 +02:00
goto error ;
2005-04-16 15:20:36 -07:00
pci_set_drvdata ( pci , card ) ;
dev + + ;
return 0 ;
2022-07-05 17:23:36 +02:00
error :
snd_card_free ( card ) ;
return err ;
2005-04-16 15:20:36 -07:00
}
2012-04-24 12:25:00 +02:00
static struct pci_driver cs46xx_driver = {
2011-06-10 16:20:20 +02:00
. name = KBUILD_MODNAME ,
2005-04-16 15:20:36 -07:00
. id_table = snd_cs46xx_ids ,
. probe = snd_card_cs46xx_probe ,
2012-08-14 18:12:04 +02:00
# ifdef CONFIG_PM_SLEEP
2012-07-02 15:20:37 +02:00
. driver = {
. pm = & snd_cs46xx_pm ,
} ,
2005-11-17 16:09:04 +01:00
# endif
2005-04-16 15:20:36 -07:00
} ;
2012-04-24 12:25:00 +02:00
module_pci_driver ( cs46xx_driver ) ;