2005-04-17 02:20:36 +04:00
/*
card - als100 . c - driver for Avance Logic ALS100 based soundcards .
Copyright ( C ) 1999 - 2000 by Massimo Piccioni < dafastidio @ libero . it >
2009-12-10 22:39:28 +03:00
Copyright ( C ) 1999 - 2002 by Massimo Piccioni < dafastidio @ libero . it >
2005-04-17 02:20:36 +04:00
Thanks to Pierfrancesco ' qM2 ' Passerini .
2009-12-10 22:39:28 +03:00
Generalised for soundcards based on DT - 01 96 and ALS - 007 chips
2012-03-27 06:31:01 +04:00
by Jonathan Woithe < jwoithe @ just42 . net > : June 2002.
2009-12-10 22:39:28 +03:00
2005-04-17 02:20:36 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/init.h>
# include <linux/wait.h>
# include <linux/time.h>
# include <linux/pnp.h>
2011-07-15 21:13:37 +04:00
# include <linux/module.h>
2005-04-17 02:20:36 +04:00
# include <sound/core.h>
# include <sound/initval.h>
# include <sound/mpu401.h>
# include <sound/opl3.h>
# include <sound/sb.h>
# define PFX "als100: "
2009-12-10 22:39:28 +03:00
MODULE_DESCRIPTION ( " Avance Logic ALS007/ALS1X0 " ) ;
MODULE_SUPPORTED_DEVICE ( " {{Diamond Technologies DT-019X}, "
" {Avance Logic ALS-007}} "
" {{Avance Logic,ALS100 - PRO16PNP}, "
2005-04-17 02:20:36 +04:00
" {Avance Logic,ALS110}, "
" {Avance Logic,ALS120}, "
" {Avance Logic,ALS200}, "
" {3D Melody,MF1000}, "
" {Digimate,3D Sound}, "
" {Avance Logic,ALS120}, "
" {RTL,RTL3000}} " ) ;
2009-12-10 22:39:28 +03:00
MODULE_AUTHOR ( " Massimo Piccioni <dafastidio@libero.it> " ) ;
MODULE_LICENSE ( " GPL " ) ;
2005-04-17 02:20:36 +04:00
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 07:19:36 +04:00
static bool enable [ SNDRV_CARDS ] = SNDRV_DEFAULT_ENABLE ; /* Enable this card */
2005-04-17 02:20:36 +04:00
static long port [ SNDRV_CARDS ] = SNDRV_DEFAULT_PORT ; /* PnP setup */
static long mpu_port [ SNDRV_CARDS ] = SNDRV_DEFAULT_PORT ; /* PnP setup */
static long fm_port [ SNDRV_CARDS ] = SNDRV_DEFAULT_PORT ; /* PnP setup */
static int irq [ SNDRV_CARDS ] = SNDRV_DEFAULT_IRQ ; /* PnP setup */
static int mpu_irq [ SNDRV_CARDS ] = SNDRV_DEFAULT_IRQ ; /* PnP setup */
static int dma8 [ SNDRV_CARDS ] = SNDRV_DEFAULT_DMA ; /* PnP setup */
static int dma16 [ SNDRV_CARDS ] = SNDRV_DEFAULT_DMA ; /* PnP setup */
module_param_array ( index , int , NULL , 0444 ) ;
2009-12-10 22:39:28 +03:00
MODULE_PARM_DESC ( index , " Index value for Avance Logic based soundcard. " ) ;
2005-04-17 02:20:36 +04:00
module_param_array ( id , charp , NULL , 0444 ) ;
2009-12-10 22:39:28 +03:00
MODULE_PARM_DESC ( id , " ID string for Avance Logic based soundcard. " ) ;
2005-04-17 02:20:36 +04:00
module_param_array ( enable , bool , NULL , 0444 ) ;
2009-12-10 22:39:28 +03:00
MODULE_PARM_DESC ( enable , " Enable Avance Logic based soundcard. " ) ;
MODULE_ALIAS ( " snd-dt019x " ) ;
2005-04-17 02:20:36 +04:00
struct snd_card_als100 {
struct pnp_dev * dev ;
struct pnp_dev * devmpu ;
struct pnp_dev * devopl ;
2005-11-17 19:03:53 +03:00
struct snd_sb * chip ;
2005-04-17 02:20:36 +04:00
} ;
static struct pnp_card_device_id snd_als100_pnpids [ ] = {
2009-12-10 22:39:28 +03:00
/* DT197A30 */
{ . id = " RWB1688 " ,
. devs = { { " @@@0001 " } , { " @X@0001 " } , { " @H@0001 " } } ,
. driver_data = SB_HW_DT019X } ,
/* DT0196 / ALS-007 */
{ . id = " ALS0007 " ,
. devs = { { " @@@0001 " } , { " @X@0001 " } , { " @H@0001 " } } ,
. driver_data = SB_HW_DT019X } ,
2005-04-17 02:20:36 +04:00
/* ALS100 - PRO16PNP */
2009-12-10 22:39:28 +03:00
{ . id = " ALS0001 " ,
. devs = { { " @@@0001 " } , { " @X@0001 " } , { " @H@0001 " } } ,
. driver_data = SB_HW_ALS100 } ,
2005-04-17 02:20:36 +04:00
/* ALS110 - MF1000 - Digimate 3D Sound */
2009-12-10 22:39:28 +03:00
{ . id = " ALS0110 " ,
. devs = { { " @@@1001 " } , { " @X@1001 " } , { " @H@1001 " } } ,
. driver_data = SB_HW_ALS100 } ,
2005-04-17 02:20:36 +04:00
/* ALS120 */
2009-12-10 22:39:28 +03:00
{ . id = " ALS0120 " ,
. devs = { { " @@@2001 " } , { " @X@2001 " } , { " @H@2001 " } } ,
. driver_data = SB_HW_ALS100 } ,
2005-04-17 02:20:36 +04:00
/* ALS200 */
2009-12-10 22:39:28 +03:00
{ . id = " ALS0200 " ,
. devs = { { " @@@0020 " } , { " @X@0020 " } , { " @H@0001 " } } ,
. driver_data = SB_HW_ALS100 } ,
2005-04-17 02:20:36 +04:00
/* ALS200 OEM */
2009-12-10 22:39:28 +03:00
{ . id = " ALS0200 " ,
. devs = { { " @@@0020 " } , { " @X@0020 " } , { " @H@0020 " } } ,
. driver_data = SB_HW_ALS100 } ,
2005-04-17 02:20:36 +04:00
/* RTL3000 */
2009-12-10 22:39:28 +03:00
{ . id = " RTL3000 " ,
. devs = { { " @@@2001 " } , { " @X@2001 " } , { " @H@2001 " } } ,
. driver_data = SB_HW_ALS100 } ,
{ . id = " " } /* end */
2005-04-17 02:20:36 +04:00
} ;
MODULE_DEVICE_TABLE ( pnp_card , snd_als100_pnpids ) ;
2012-12-06 21:35:21 +04:00
static int snd_card_als100_pnp ( int dev , struct snd_card_als100 * acard ,
struct pnp_card_link * card ,
const struct pnp_card_device_id * id )
2005-04-17 02:20:36 +04:00
{
struct pnp_dev * pdev ;
int err ;
acard - > dev = pnp_request_card_device ( card , id - > devs [ 0 ] . id , NULL ) ;
2007-11-30 19:59:25 +03:00
if ( acard - > dev = = NULL )
2005-04-17 02:20:36 +04:00
return - ENODEV ;
2007-11-30 19:59:25 +03:00
2005-04-17 02:20:36 +04:00
acard - > devmpu = pnp_request_card_device ( card , id - > devs [ 1 ] . id , acard - > dev ) ;
acard - > devopl = pnp_request_card_device ( card , id - > devs [ 2 ] . id , acard - > dev ) ;
pdev = acard - > dev ;
err = pnp_activate_dev ( pdev ) ;
if ( err < 0 ) {
snd_printk ( KERN_ERR PFX " AUDIO pnp configure failure \n " ) ;
return err ;
}
port [ dev ] = pnp_port_start ( pdev , 0 ) ;
2009-12-10 22:39:28 +03:00
if ( id - > driver_data = = SB_HW_DT019X )
dma8 [ dev ] = pnp_dma ( pdev , 0 ) ;
else {
dma8 [ dev ] = pnp_dma ( pdev , 1 ) ;
dma16 [ dev ] = pnp_dma ( pdev , 0 ) ;
}
2005-04-17 02:20:36 +04:00
irq [ dev ] = pnp_irq ( pdev , 0 ) ;
pdev = acard - > devmpu ;
if ( pdev ! = NULL ) {
err = pnp_activate_dev ( pdev ) ;
if ( err < 0 )
goto __mpu_error ;
mpu_port [ dev ] = pnp_port_start ( pdev , 0 ) ;
mpu_irq [ dev ] = pnp_irq ( pdev , 0 ) ;
} else {
__mpu_error :
if ( pdev ) {
pnp_release_card_device ( pdev ) ;
snd_printk ( KERN_ERR PFX " MPU401 pnp configure failure, skipping \n " ) ;
}
acard - > devmpu = NULL ;
mpu_port [ dev ] = - 1 ;
}
pdev = acard - > devopl ;
if ( pdev ! = NULL ) {
err = pnp_activate_dev ( pdev ) ;
if ( err < 0 )
goto __fm_error ;
fm_port [ dev ] = pnp_port_start ( pdev , 0 ) ;
} else {
__fm_error :
if ( pdev ) {
pnp_release_card_device ( pdev ) ;
snd_printk ( KERN_ERR PFX " OPL3 pnp configure failure, skipping \n " ) ;
}
acard - > devopl = NULL ;
fm_port [ dev ] = - 1 ;
}
return 0 ;
}
2012-12-06 21:35:21 +04:00
static int snd_card_als100_probe ( int dev ,
struct pnp_card_link * pcard ,
const struct pnp_card_device_id * pid )
2005-04-17 02:20:36 +04:00
{
int error ;
2005-11-17 16:42:36 +03:00
struct snd_sb * chip ;
struct snd_card * card ;
2005-04-17 02:20:36 +04:00
struct snd_card_als100 * acard ;
2005-11-17 16:42:36 +03:00
struct snd_opl3 * opl3 ;
2005-04-17 02:20:36 +04:00
2014-01-29 16:03:56 +04:00
error = snd_card_new ( & pcard - > card - > dev ,
index [ dev ] , id [ dev ] , THIS_MODULE ,
sizeof ( struct snd_card_als100 ) , & card ) ;
2008-12-28 18:43:35 +03:00
if ( error < 0 )
return error ;
2005-11-17 19:03:53 +03:00
acard = card - > private_data ;
2005-04-17 02:20:36 +04:00
if ( ( error = snd_card_als100_pnp ( dev , acard , pcard , pid ) ) ) {
snd_card_free ( card ) ;
return error ;
}
2009-12-10 22:39:28 +03:00
if ( pid - > driver_data = = SB_HW_DT019X )
dma16 [ dev ] = - 1 ;
error = snd_sbdsp_create ( card , port [ dev ] , irq [ dev ] ,
snd_sb16dsp_interrupt ,
dma8 [ dev ] , dma16 [ dev ] ,
pid - > driver_data ,
& chip ) ;
if ( error < 0 ) {
2005-04-17 02:20:36 +04:00
snd_card_free ( card ) ;
return error ;
}
2005-11-17 19:03:53 +03:00
acard - > chip = chip ;
2005-04-17 02:20:36 +04:00
2009-12-10 22:39:28 +03:00
if ( pid - > driver_data = = SB_HW_DT019X ) {
strcpy ( card - > driver , " DT-019X " ) ;
strcpy ( card - > shortname , " Diamond Tech. DT-019X " ) ;
sprintf ( card - > longname , " %s, %s at 0x%lx, irq %d, dma %d " ,
card - > shortname , chip - > name , chip - > port ,
irq [ dev ] , dma8 [ dev ] ) ;
} else {
strcpy ( card - > driver , " ALS100 " ) ;
strcpy ( card - > shortname , " Avance Logic ALS100 " ) ;
sprintf ( card - > longname , " %s, %s at 0x%lx, irq %d, dma %d&%d " ,
card - > shortname , chip - > name , chip - > port ,
irq [ dev ] , dma8 [ dev ] , dma16 [ dev ] ) ;
}
2005-04-17 02:20:36 +04:00
2015-01-02 14:24:42 +03:00
if ( ( error = snd_sb16dsp_pcm ( chip , 0 ) ) < 0 ) {
2005-04-17 02:20:36 +04:00
snd_card_free ( card ) ;
return error ;
}
if ( ( error = snd_sbmixer_new ( chip ) ) < 0 ) {
snd_card_free ( card ) ;
return error ;
}
if ( mpu_port [ dev ] > 0 & & mpu_port [ dev ] ! = SNDRV_AUTO_PORT ) {
2009-12-10 22:39:28 +03:00
int mpu_type = MPU401_HW_ALS100 ;
if ( mpu_irq [ dev ] = = SNDRV_AUTO_IRQ )
mpu_irq [ dev ] = - 1 ;
if ( pid - > driver_data = = SB_HW_DT019X )
mpu_type = MPU401_HW_MPU401 ;
if ( snd_mpu401_uart_new ( card , 0 ,
mpu_type ,
2005-04-17 02:20:36 +04:00
mpu_port [ dev ] , 0 ,
2009-12-10 22:39:28 +03:00
mpu_irq [ dev ] ,
2005-04-17 02:20:36 +04:00
NULL ) < 0 )
snd_printk ( KERN_ERR PFX " no MPU-401 device at 0x%lx \n " , mpu_port [ dev ] ) ;
}
if ( fm_port [ dev ] > 0 & & fm_port [ dev ] ! = SNDRV_AUTO_PORT ) {
if ( snd_opl3_create ( card ,
fm_port [ dev ] , fm_port [ dev ] + 2 ,
OPL3_HW_AUTO , 0 , & opl3 ) < 0 ) {
snd_printk ( KERN_ERR PFX " no OPL device at 0x%lx-0x%lx \n " ,
fm_port [ dev ] , fm_port [ dev ] + 2 ) ;
} else {
if ( ( error = snd_opl3_timer_new ( opl3 , 0 , 1 ) ) < 0 ) {
snd_card_free ( card ) ;
return error ;
}
if ( ( error = snd_opl3_hwdep_new ( opl3 , 0 , 1 , NULL ) ) < 0 ) {
snd_card_free ( card ) ;
return error ;
}
}
}
if ( ( error = snd_card_register ( card ) ) < 0 ) {
snd_card_free ( card ) ;
return error ;
}
pnp_set_card_drvdata ( pcard , card ) ;
return 0 ;
}
2012-12-06 21:35:21 +04:00
static unsigned int als100_devices ;
2006-03-27 13:17:09 +04:00
2012-12-06 21:35:21 +04:00
static int snd_als100_pnp_detect ( struct pnp_card_link * card ,
const struct pnp_card_device_id * id )
2005-04-17 02:20:36 +04:00
{
static int dev ;
int res ;
for ( ; dev < SNDRV_CARDS ; dev + + ) {
if ( ! enable [ dev ] )
continue ;
res = snd_card_als100_probe ( dev , card , id ) ;
if ( res < 0 )
return res ;
dev + + ;
2006-03-27 13:17:09 +04:00
als100_devices + + ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
return - ENODEV ;
}
2012-12-06 21:35:21 +04:00
static void snd_als100_pnp_remove ( struct pnp_card_link * pcard )
2005-04-17 02:20:36 +04:00
{
2005-11-17 19:03:53 +03:00
snd_card_free ( pnp_get_card_drvdata ( pcard ) ) ;
pnp_set_card_drvdata ( pcard , NULL ) ;
}
# ifdef CONFIG_PM
static int snd_als100_pnp_suspend ( struct pnp_card_link * pcard , pm_message_t state )
{
struct snd_card * card = pnp_get_card_drvdata ( pcard ) ;
struct snd_card_als100 * acard = card - > private_data ;
struct snd_sb * chip = acard - > chip ;
snd_power_change_state ( card , SNDRV_CTL_POWER_D3hot ) ;
snd_pcm_suspend_all ( chip - > pcm ) ;
snd_sbmixer_suspend ( chip ) ;
return 0 ;
}
static int snd_als100_pnp_resume ( struct pnp_card_link * pcard )
{
struct snd_card * card = pnp_get_card_drvdata ( pcard ) ;
struct snd_card_als100 * acard = card - > private_data ;
struct snd_sb * chip = acard - > chip ;
2005-04-17 02:20:36 +04:00
2005-11-17 19:03:53 +03:00
snd_sbdsp_reset ( chip ) ;
snd_sbmixer_resume ( chip ) ;
snd_power_change_state ( card , SNDRV_CTL_POWER_D0 ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-11-17 19:03:53 +03:00
# endif
2005-04-17 02:20:36 +04:00
static struct pnp_card_driver als100_pnpc_driver = {
. flags = PNP_DRIVER_RES_DISABLE ,
2009-12-10 22:39:28 +03:00
. name = " als100 " ,
2005-04-17 02:20:36 +04:00
. id_table = snd_als100_pnpids ,
. probe = snd_als100_pnp_detect ,
2012-12-06 21:35:21 +04:00
. remove = snd_als100_pnp_remove ,
2005-11-17 19:03:53 +03:00
# ifdef CONFIG_PM
. suspend = snd_als100_pnp_suspend ,
. resume = snd_als100_pnp_resume ,
# endif
2005-04-17 02:20:36 +04:00
} ;
static int __init alsa_card_als100_init ( void )
{
2006-03-27 13:17:09 +04:00
int err ;
err = pnp_register_card_driver ( & als100_pnpc_driver ) ;
if ( err )
return err ;
2005-04-17 02:20:36 +04:00
2006-03-27 13:17:09 +04:00
if ( ! als100_devices ) {
2005-04-17 02:20:36 +04:00
pnp_unregister_card_driver ( & als100_pnpc_driver ) ;
2005-11-17 19:03:53 +03:00
# ifdef MODULE
2009-12-10 22:39:28 +03:00
snd_printk ( KERN_ERR " no Avance Logic based soundcards found \n " ) ;
2005-04-17 02:20:36 +04:00
# endif
2005-11-17 19:03:53 +03:00
return - ENODEV ;
}
return 0 ;
2005-04-17 02:20:36 +04:00
}
static void __exit alsa_card_als100_exit ( void )
{
pnp_unregister_card_driver ( & als100_pnpc_driver ) ;
}
module_init ( alsa_card_als100_init )
module_exit ( alsa_card_als100_exit )