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 Yamaha ' s DS1 / DS1E cards
2007-10-15 09:50:19 +02:00
* Copyright ( c ) by Jaroslav Kysela < perex @ perex . cz >
2005-04-16 15:20:36 -07:00
*/
# include <linux/init.h>
# include <linux/pci.h>
# include <linux/time.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 "ymfpci.h"
2005-04-16 15:20:36 -07:00
# include <sound/mpu401.h>
# include <sound/opl3.h>
# include <sound/initval.h>
2007-10-15 09:50:19 +02:00
MODULE_AUTHOR ( " Jaroslav Kysela <perex@perex.cz> " ) ;
2005-12-12 09:27:14 +01:00
MODULE_DESCRIPTION ( " Yamaha DS-1 PCI " ) ;
2005-04-16 15:20:36 -07:00
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 */
2005-04-16 15:20:36 -07:00
static long fm_port [ SNDRV_CARDS ] ;
static long mpu_port [ SNDRV_CARDS ] ;
# ifdef SUPPORT_JOYSTICK
static long joystick_port [ SNDRV_CARDS ] ;
# endif
2011-12-15 13:49:36 +10:30
static bool rear_switch [ SNDRV_CARDS ] ;
2005-04-16 15:20:36 -07:00
module_param_array ( index , int , NULL , 0444 ) ;
2005-12-12 09:27:14 +01:00
MODULE_PARM_DESC ( index , " Index value for the Yamaha DS-1 PCI soundcard. " ) ;
2005-04-16 15:20:36 -07:00
module_param_array ( id , charp , NULL , 0444 ) ;
2005-12-12 09:27:14 +01:00
MODULE_PARM_DESC ( id , " ID string for the Yamaha DS-1 PCI soundcard. " ) ;
2005-04-16 15:20:36 -07:00
module_param_array ( enable , bool , NULL , 0444 ) ;
2005-12-12 09:27:14 +01:00
MODULE_PARM_DESC ( enable , " Enable Yamaha DS-1 soundcard. " ) ;
2017-04-04 16:54:30 +01:00
module_param_hw_array ( mpu_port , long , ioport , NULL , 0444 ) ;
2005-04-16 15:20:36 -07:00
MODULE_PARM_DESC ( mpu_port , " MPU-401 Port. " ) ;
2017-04-04 16:54:30 +01:00
module_param_hw_array ( fm_port , long , ioport , NULL , 0444 ) ;
2005-04-16 15:20:36 -07:00
MODULE_PARM_DESC ( fm_port , " FM OPL-3 Port. " ) ;
# ifdef SUPPORT_JOYSTICK
2017-04-04 16:54:30 +01:00
module_param_hw_array ( joystick_port , long , ioport , NULL , 0444 ) ;
2005-04-16 15:20:36 -07:00
MODULE_PARM_DESC ( joystick_port , " Joystick port address " ) ;
# endif
module_param_array ( rear_switch , bool , NULL , 0444 ) ;
MODULE_PARM_DESC ( rear_switch , " Enable shared rear/line-in switch " ) ;
2014-08-08 15:56:03 +02:00
static const struct pci_device_id snd_ymfpci_ids [ ] = {
2009-06-24 22:13:35 -07:00
{ PCI_VDEVICE ( YAMAHA , 0x0004 ) , 0 , } , /* YMF724 */
{ PCI_VDEVICE ( YAMAHA , 0x000d ) , 0 , } , /* YMF724F */
{ PCI_VDEVICE ( YAMAHA , 0x000a ) , 0 , } , /* YMF740 */
{ PCI_VDEVICE ( YAMAHA , 0x000c ) , 0 , } , /* YMF740C */
{ PCI_VDEVICE ( YAMAHA , 0x0010 ) , 0 , } , /* YMF744 */
{ PCI_VDEVICE ( YAMAHA , 0x0012 ) , 0 , } , /* YMF754 */
2005-04-16 15:20:36 -07:00
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , snd_ymfpci_ids ) ;
# ifdef SUPPORT_JOYSTICK
2012-12-06 12:35:10 -05:00
static int snd_ymfpci_create_gameport ( struct snd_ymfpci * chip , int dev ,
int legacy_ctrl , int legacy_ctrl2 )
2005-04-16 15:20:36 -07:00
{
struct gameport * gp ;
struct resource * r = NULL ;
int io_port = joystick_port [ dev ] ;
if ( ! io_port )
return - ENODEV ;
if ( chip - > pci - > device > = 0x0010 ) { /* YMF 744/754 */
if ( io_port = = 1 ) {
/* auto-detect */
2021-06-08 16:05:26 +02:00
io_port = pci_resource_start ( chip - > pci , 2 ) ;
if ( ! io_port )
2005-04-16 15:20:36 -07:00
return - ENODEV ;
}
} else {
if ( io_port = = 1 ) {
/* auto-detect */
for ( io_port = 0x201 ; io_port < = 0x205 ; io_port + + ) {
if ( io_port = = 0x203 )
continue ;
2021-06-08 16:05:26 +02:00
r = request_region ( io_port , 1 , " YMFPCI gameport " ) ;
if ( r )
2005-04-16 15:20:36 -07:00
break ;
}
if ( ! r ) {
2014-02-26 12:18:27 +01:00
dev_err ( chip - > card - > dev ,
" no gameport ports available \n " ) ;
2005-04-16 15:20:36 -07:00
return - EBUSY ;
}
}
switch ( io_port ) {
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 :
2014-02-26 12:18:27 +01:00
dev_err ( chip - > card - > dev ,
" invalid joystick port %#x " , io_port ) ;
2005-04-16 15:20:36 -07:00
return - EINVAL ;
}
}
2021-06-08 16:05:26 +02:00
if ( ! r ) {
2021-07-15 09:59:13 +02:00
r = devm_request_region ( & chip - > pci - > dev , io_port , 1 ,
" YMFPCI gameport " ) ;
2021-06-08 16:05:26 +02:00
if ( ! r ) {
dev_err ( chip - > card - > dev ,
" joystick port %#x is in use. \n " , io_port ) ;
return - EBUSY ;
}
2005-04-16 15:20:36 -07:00
}
chip - > gameport = gp = gameport_allocate_port ( ) ;
if ( ! gp ) {
2014-02-26 12:18:27 +01:00
dev_err ( chip - > card - > dev ,
" cannot allocate memory for gameport \n " ) ;
2005-04-16 15:20:36 -07:00
return - ENOMEM ;
}
gameport_set_name ( gp , " Yamaha YMF Gameport " ) ;
gameport_set_phys ( gp , " pci%s/gameport0 " , pci_name ( chip - > pci ) ) ;
gameport_set_dev_parent ( gp , & chip - > pci - > dev ) ;
gp - > io = io_port ;
if ( chip - > pci - > device > = 0x0010 ) /* YMF 744/754 */
pci_write_config_word ( chip - > pci , PCIR_DSXG_JOYBASE , io_port ) ;
pci_write_config_word ( chip - > pci , PCIR_DSXG_LEGACY , legacy_ctrl | YMFPCI_LEGACY_JPEN ) ;
pci_write_config_word ( chip - > pci , PCIR_DSXG_ELEGACY , legacy_ctrl2 ) ;
gameport_register_port ( chip - > gameport ) ;
return 0 ;
}
2005-11-17 14:53:41 +01:00
void snd_ymfpci_free_gameport ( struct snd_ymfpci * chip )
2005-04-16 15:20:36 -07:00
{
if ( chip - > gameport ) {
gameport_unregister_port ( chip - > gameport ) ;
chip - > gameport = NULL ;
}
}
# else
2005-11-17 14:53:41 +01:00
static inline int snd_ymfpci_create_gameport ( struct snd_ymfpci * chip , int dev , int l , int l2 ) { return - ENOSYS ; }
void snd_ymfpci_free_gameport ( struct snd_ymfpci * chip ) { }
2005-04-16 15:20:36 -07:00
# endif /* SUPPORT_JOYSTICK */
2012-12-06 12:35:10 -05:00
static int snd_card_ymfpci_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:53:41 +01:00
struct snd_card * card ;
2005-04-16 15:20:36 -07:00
struct resource * fm_res = NULL ;
struct resource * mpu_res = NULL ;
2005-11-17 14:53:41 +01:00
struct snd_ymfpci * chip ;
struct snd_opl3 * opl3 ;
2005-12-12 09:27:14 +01:00
const char * str , * model ;
2005-04-16 15:20:36 -07:00
int err ;
u16 legacy_ctrl , legacy_ctrl2 , old_legacy_ctrl ;
if ( dev > = SNDRV_CARDS )
return - ENODEV ;
if ( ! enable [ dev ] ) {
dev + + ;
return - ENOENT ;
}
2014-01-29 14:20:19 +01:00
err = snd_card_new ( & pci - > dev , index [ dev ] , id [ dev ] , THIS_MODULE ,
2021-07-15 09:59:13 +02:00
sizeof ( * chip ) , & card ) ;
2008-12-28 16:44:30 +01:00
if ( err < 0 )
return err ;
2021-07-15 09:59:13 +02:00
chip = card - > private_data ;
2005-04-16 15:20:36 -07:00
switch ( pci_id - > device ) {
2005-12-12 09:27:14 +01:00
case 0x0004 : str = " YMF724 " ; model = " DS-1 " ; break ;
case 0x000d : str = " YMF724F " ; model = " DS-1 " ; break ;
case 0x000a : str = " YMF740 " ; model = " DS-1L " ; break ;
case 0x000c : str = " YMF740C " ; model = " DS-1L " ; break ;
case 0x0010 : str = " YMF744 " ; model = " DS-1S " ; break ;
case 0x0012 : str = " YMF754 " ; model = " DS-1E " ; break ;
default : model = str = " ??? " ; break ;
2005-04-16 15:20:36 -07:00
}
legacy_ctrl = 0 ;
legacy_ctrl2 = 0x0800 ; /* SBEN = 0, SMOD = 01, LAD = 0 */
if ( pci_id - > device > = 0x0010 ) { /* YMF 744/754 */
if ( fm_port [ dev ] = = 1 ) {
/* auto-detect */
fm_port [ dev ] = pci_resource_start ( pci , 1 ) ;
}
2021-06-08 16:05:26 +02:00
if ( fm_port [ dev ] > 0 )
2021-07-15 09:59:13 +02:00
fm_res = devm_request_region ( & pci - > dev , fm_port [ dev ] ,
4 , " YMFPCI OPL3 " ) ;
2021-06-08 16:05:26 +02:00
if ( fm_res ) {
2005-04-16 15:20:36 -07:00
legacy_ctrl | = YMFPCI_LEGACY_FMEN ;
pci_write_config_word ( pci , PCIR_DSXG_FMBASE , fm_port [ dev ] ) ;
}
if ( mpu_port [ dev ] = = 1 ) {
/* auto-detect */
mpu_port [ dev ] = pci_resource_start ( pci , 1 ) + 0x20 ;
}
2021-06-08 16:05:26 +02:00
if ( mpu_port [ dev ] > 0 )
2021-07-15 09:59:13 +02:00
mpu_res = devm_request_region ( & pci - > dev , mpu_port [ dev ] ,
2 , " YMFPCI MPU401 " ) ;
2021-06-08 16:05:26 +02:00
if ( mpu_res ) {
2005-04-16 15:20:36 -07:00
legacy_ctrl | = YMFPCI_LEGACY_MEN ;
pci_write_config_word ( pci , PCIR_DSXG_MPU401BASE , mpu_port [ dev ] ) ;
}
} 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 ] = 0 ; break ;
}
2021-06-08 16:05:26 +02:00
if ( fm_port [ dev ] > 0 )
2021-07-15 09:59:13 +02:00
fm_res = devm_request_region ( & pci - > dev , fm_port [ dev ] ,
4 , " YMFPCI OPL3 " ) ;
2021-06-08 16:05:26 +02:00
if ( fm_res ) {
2005-04-16 15:20:36 -07:00
legacy_ctrl | = YMFPCI_LEGACY_FMEN ;
} else {
legacy_ctrl2 & = ~ YMFPCI_LEGACY2_FMIO ;
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 ] = 0 ; break ;
}
2021-06-08 16:05:26 +02:00
if ( mpu_port [ dev ] > 0 )
2021-07-15 09:59:13 +02:00
mpu_res = devm_request_region ( & pci - > dev , mpu_port [ dev ] ,
2 , " YMFPCI MPU401 " ) ;
2021-06-08 16:05:26 +02:00
if ( mpu_res ) {
2005-04-16 15:20:36 -07:00
legacy_ctrl | = YMFPCI_LEGACY_MEN ;
} else {
legacy_ctrl2 & = ~ YMFPCI_LEGACY2_MPUIO ;
mpu_port [ dev ] = 0 ;
}
}
if ( mpu_res ) {
legacy_ctrl | = YMFPCI_LEGACY_MIEN ;
legacy_ctrl2 | = YMFPCI_LEGACY2_IMOD ;
}
pci_read_config_word ( pci , PCIR_DSXG_LEGACY , & old_legacy_ctrl ) ;
pci_write_config_word ( pci , PCIR_DSXG_LEGACY , legacy_ctrl ) ;
pci_write_config_word ( pci , PCIR_DSXG_ELEGACY , legacy_ctrl2 ) ;
2021-07-15 09:59:13 +02:00
err = snd_ymfpci_create ( card , pci , old_legacy_ctrl ) ;
if ( err < 0 )
return err ;
2005-11-17 16:09:43 +01:00
2005-04-16 15:20:36 -07:00
strcpy ( card - > driver , str ) ;
2005-12-12 09:27:14 +01:00
sprintf ( card - > shortname , " Yamaha %s (%s) " , model , str ) ;
2005-04-16 15:20:36 -07:00
sprintf ( card - > longname , " %s at 0x%lx, irq %i " ,
card - > shortname ,
chip - > reg_area_phys ,
chip - > irq ) ;
2017-09-06 20:45:11 +02:00
err = snd_ymfpci_pcm ( chip , 0 ) ;
if ( err < 0 )
2021-07-15 09:59:13 +02:00
return err ;
2017-09-06 20:45:11 +02:00
err = snd_ymfpci_pcm_spdif ( chip , 1 ) ;
if ( err < 0 )
2021-07-15 09:59:13 +02:00
return err ;
2017-09-06 20:45:11 +02:00
2012-01-17 11:41:47 +08:00
err = snd_ymfpci_mixer ( chip , rear_switch [ dev ] ) ;
2017-09-06 20:45:11 +02:00
if ( err < 0 )
2021-07-15 09:59:13 +02:00
return err ;
2017-09-06 20:45:11 +02:00
2012-01-17 11:41:47 +08:00
if ( chip - > ac97 - > ext_id & AC97_EI_SDAC ) {
2015-01-02 12:24:55 +01:00
err = snd_ymfpci_pcm_4ch ( chip , 2 ) ;
2017-09-06 20:45:11 +02:00
if ( err < 0 )
2021-07-15 09:59:13 +02:00
return err ;
2017-09-06 20:45:11 +02:00
2015-01-02 12:24:55 +01:00
err = snd_ymfpci_pcm2 ( chip , 3 ) ;
2017-09-06 20:45:11 +02:00
if ( err < 0 )
2021-07-15 09:59:13 +02:00
return err ;
2005-04-16 15:20:36 -07:00
}
2017-09-06 20:45:11 +02:00
err = snd_ymfpci_timer ( chip , 0 ) ;
if ( err < 0 )
2021-07-15 09:59:13 +02:00
return err ;
2017-09-06 20:45:11 +02:00
2021-07-15 09:59:13 +02:00
if ( mpu_res ) {
2021-06-08 16:05:26 +02:00
err = snd_mpu401_uart_new ( card , 0 , MPU401_HW_YMFPCI ,
mpu_port [ dev ] ,
MPU401_INFO_INTEGRATED |
MPU401_INFO_IRQ_HOOK ,
- 1 , & chip - > rawmidi ) ;
if ( err < 0 ) {
2014-02-26 12:18:27 +01:00
dev_warn ( card - > dev ,
" cannot initialize MPU401 at 0x%lx, skipping... \n " ,
mpu_port [ dev ] ) ;
2005-04-16 15:20:36 -07:00
legacy_ctrl & = ~ YMFPCI_LEGACY_MIEN ; /* disable MPU401 irq */
pci_write_config_word ( pci , PCIR_DSXG_LEGACY , legacy_ctrl ) ;
}
}
2021-07-15 09:59:13 +02:00
if ( fm_res ) {
2021-06-08 16:05:26 +02:00
err = snd_opl3_create ( card ,
fm_port [ dev ] ,
fm_port [ dev ] + 2 ,
OPL3_HW_OPL3 , 1 , & opl3 ) ;
if ( err < 0 ) {
2014-02-26 12:18:27 +01:00
dev_warn ( card - > dev ,
" cannot initialize FM OPL3 at 0x%lx, skipping... \n " ,
fm_port [ dev ] ) ;
2005-04-16 15:20:36 -07:00
legacy_ctrl & = ~ YMFPCI_LEGACY_FMEN ;
pci_write_config_word ( pci , PCIR_DSXG_LEGACY , legacy_ctrl ) ;
2021-06-08 16:05:26 +02:00
} else {
err = snd_opl3_hwdep_new ( opl3 , 0 , 1 , NULL ) ;
if ( err < 0 ) {
dev_err ( card - > dev , " cannot create opl3 hwdep \n " ) ;
2021-07-15 09:59:13 +02:00
return err ;
2021-06-08 16:05:26 +02:00
}
2005-04-16 15:20:36 -07:00
}
}
snd_ymfpci_create_gameport ( chip , dev , legacy_ctrl , legacy_ctrl2 ) ;
2017-09-06 20:45:11 +02:00
err = snd_card_register ( card ) ;
if ( err < 0 )
2021-07-15 09:59:13 +02:00
return err ;
2017-09-06 20:45:11 +02:00
2005-04-16 15:20:36 -07:00
pci_set_drvdata ( pci , card ) ;
dev + + ;
return 0 ;
}
2012-04-24 12:25:00 +02:00
static struct pci_driver ymfpci_driver = {
2011-06-10 16:20:20 +02:00
. name = KBUILD_MODNAME ,
2005-04-16 15:20:36 -07:00
. id_table = snd_ymfpci_ids ,
. probe = snd_card_ymfpci_probe ,
2012-08-14 18:12:04 +02:00
# ifdef CONFIG_PM_SLEEP
2012-07-02 15:20:37 +02:00
. driver = {
. pm = & snd_ymfpci_pm ,
} ,
2005-11-17 16:09:43 +01:00
# endif
2005-04-16 15:20:36 -07:00
} ;
2012-04-24 12:25:00 +02:00
module_pci_driver ( ymfpci_driver ) ;