2005-04-17 02:20:36 +04:00
/*
* Driver for generic MPU - 401 boards ( UART mode only )
2007-10-15 11:50:19 +04:00
* Copyright ( c ) by Jaroslav Kysela < perex @ perex . cz >
2005-04-17 02:20:36 +04:00
* Copyright ( c ) 2004 by Castet Matthieu < castet . matthieu @ free . fr >
*
*
* 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/pnp.h>
2005-11-17 18:03:39 +03:00
# include <linux/err.h>
# include <linux/platform_device.h>
2005-04-17 02:20:36 +04:00
# include <linux/moduleparam.h>
# include <sound/core.h>
# include <sound/mpu401.h>
# include <sound/initval.h>
2007-10-15 11:50:19 +04:00
MODULE_AUTHOR ( " Jaroslav Kysela <perex@perex.cz> " ) ;
2005-04-17 02:20:36 +04:00
MODULE_DESCRIPTION ( " MPU-401 UART " ) ;
MODULE_LICENSE ( " GPL " ) ;
static int index [ SNDRV_CARDS ] = { [ 0 . . . ( SNDRV_CARDS - 1 ) ] = - 2 } ; /* exclude the first card */
static char * id [ SNDRV_CARDS ] = SNDRV_DEFAULT_STR ; /* ID for this card */
static int enable [ SNDRV_CARDS ] = SNDRV_DEFAULT_ENABLE ; /* Enable this card */
# ifdef CONFIG_PNP
static int pnp [ SNDRV_CARDS ] = { [ 0 . . . ( SNDRV_CARDS - 1 ) ] = 1 } ;
# endif
static long port [ SNDRV_CARDS ] = SNDRV_DEFAULT_PORT ; /* MPU-401 port number */
static int irq [ SNDRV_CARDS ] = SNDRV_DEFAULT_IRQ ; /* MPU-401 IRQ */
2007-02-22 18:07:21 +03:00
static int uart_enter [ SNDRV_CARDS ] = { [ 0 . . . ( SNDRV_CARDS - 1 ) ] = 1 } ;
2005-04-17 02:20:36 +04:00
module_param_array ( index , int , NULL , 0444 ) ;
MODULE_PARM_DESC ( index , " Index value for MPU-401 device. " ) ;
module_param_array ( id , charp , NULL , 0444 ) ;
MODULE_PARM_DESC ( id , " ID string for MPU-401 device. " ) ;
module_param_array ( enable , bool , NULL , 0444 ) ;
MODULE_PARM_DESC ( enable , " Enable MPU-401 device. " ) ;
# ifdef CONFIG_PNP
module_param_array ( pnp , bool , NULL , 0444 ) ;
MODULE_PARM_DESC ( pnp , " PnP detection for MPU-401 device. " ) ;
# endif
module_param_array ( port , long , NULL , 0444 ) ;
MODULE_PARM_DESC ( port , " Port # for MPU-401 device. " ) ;
module_param_array ( irq , int , NULL , 0444 ) ;
MODULE_PARM_DESC ( irq , " IRQ # for MPU-401 device. " ) ;
2007-02-22 18:07:21 +03:00
module_param_array ( uart_enter , bool , NULL , 0444 ) ;
MODULE_PARM_DESC ( uart_enter , " Issue UART_ENTER command at open. " ) ;
2005-04-17 02:20:36 +04:00
2005-12-07 11:13:42 +03:00
static struct platform_device * platform_devices [ SNDRV_CARDS ] ;
2006-03-27 13:17:04 +04:00
static int pnp_registered ;
static unsigned int snd_mpu401_devices ;
2005-04-17 02:20:36 +04:00
2005-11-17 16:12:45 +03:00
static int snd_mpu401_create ( int dev , struct snd_card * * rcard )
2005-04-17 02:20:36 +04:00
{
2005-11-17 16:12:45 +03:00
struct snd_card * card ;
2005-04-17 02:20:36 +04:00
int err ;
2007-10-11 16:42:23 +04:00
if ( ! uart_enter [ dev ] )
snd_printk ( KERN_ERR " the uart_enter option is obsolete; remove it \n " ) ;
2005-04-17 02:20:36 +04:00
* rcard = NULL ;
card = snd_card_new ( index [ dev ] , id [ dev ] , THIS_MODULE , 0 ) ;
if ( card = = NULL )
return - ENOMEM ;
strcpy ( card - > driver , " MPU-401 UART " ) ;
strcpy ( card - > shortname , card - > driver ) ;
sprintf ( card - > longname , " %s at %#lx, " , card - > shortname , port [ dev ] ) ;
if ( irq [ dev ] > = 0 ) {
sprintf ( card - > longname + strlen ( card - > longname ) , " irq %d " , irq [ dev ] ) ;
} else {
strcat ( card - > longname , " polled " ) ;
}
2007-10-11 16:42:23 +04:00
err = snd_mpu401_uart_new ( card , 0 , MPU401_HW_MPU401 , port [ dev ] , 0 ,
2007-02-22 18:07:21 +03:00
irq [ dev ] , irq [ dev ] > = 0 ? IRQF_DISABLED : 0 ,
NULL ) ;
if ( err < 0 ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " MPU401 not detected at 0x%lx \n " , port [ dev ] ) ;
2005-09-05 19:17:58 +04:00
goto _err ;
2005-04-17 02:20:36 +04:00
}
2005-09-05 19:17:58 +04:00
2005-04-17 02:20:36 +04:00
* rcard = card ;
return 0 ;
2005-09-05 19:17:58 +04:00
_err :
snd_card_free ( card ) ;
return err ;
2005-04-17 02:20:36 +04:00
}
2005-11-17 18:03:39 +03:00
static int __devinit snd_mpu401_probe ( struct platform_device * devptr )
2005-04-17 02:20:36 +04:00
{
2005-11-17 18:03:39 +03:00
int dev = devptr - > id ;
int err ;
struct snd_card * card ;
2005-04-17 02:20:36 +04:00
if ( port [ dev ] = = SNDRV_AUTO_PORT ) {
snd_printk ( KERN_ERR " specify port \n " ) ;
return - EINVAL ;
}
if ( irq [ dev ] = = SNDRV_AUTO_IRQ ) {
snd_printk ( KERN_ERR " specify or disable IRQ \n " ) ;
return - EINVAL ;
}
2005-11-17 18:03:39 +03:00
err = snd_mpu401_create ( dev , & card ) ;
if ( err < 0 )
return err ;
snd_card_set_dev ( card , & devptr - > dev ) ;
if ( ( err = snd_card_register ( card ) ) < 0 ) {
snd_card_free ( card ) ;
return err ;
}
platform_set_drvdata ( devptr , card ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-11-17 18:03:39 +03:00
static int __devexit snd_mpu401_remove ( struct platform_device * devptr )
{
snd_card_free ( platform_get_drvdata ( devptr ) ) ;
platform_set_drvdata ( devptr , NULL ) ;
return 0 ;
}
# define SND_MPU401_DRIVER "snd_mpu401"
static struct platform_driver snd_mpu401_driver = {
. probe = snd_mpu401_probe ,
. remove = __devexit_p ( snd_mpu401_remove ) ,
. driver = {
. name = SND_MPU401_DRIVER
} ,
} ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_PNP
# define IO_EXTENT 2
static struct pnp_device_id snd_mpu401_pnpids [ ] = {
{ . id = " PNPb006 " } ,
{ . id = " " }
} ;
MODULE_DEVICE_TABLE ( pnp , snd_mpu401_pnpids ) ;
2006-05-21 02:00:34 +04:00
static int __devinit snd_mpu401_pnp ( int dev , struct pnp_dev * device ,
2005-04-17 02:20:36 +04:00
const struct pnp_device_id * id )
{
if ( ! pnp_port_valid ( device , 0 ) | |
pnp_port_flags ( device , 0 ) & IORESOURCE_DISABLED ) {
snd_printk ( KERN_ERR " no PnP port \n " ) ;
return - ENODEV ;
}
if ( pnp_port_len ( device , 0 ) < IO_EXTENT ) {
2006-06-13 01:50:27 +04:00
snd_printk ( KERN_ERR " PnP port length is %llu, expected %d \n " ,
( unsigned long long ) pnp_port_len ( device , 0 ) ,
IO_EXTENT ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
port [ dev ] = pnp_port_start ( device , 0 ) ;
if ( ! pnp_irq_valid ( device , 0 ) | |
pnp_irq_flags ( device , 0 ) & IORESOURCE_DISABLED ) {
snd_printk ( KERN_WARNING " no PnP irq, using polling \n " ) ;
irq [ dev ] = - 1 ;
} else {
irq [ dev ] = pnp_irq ( device , 0 ) ;
}
return 0 ;
}
static int __devinit snd_mpu401_pnp_probe ( struct pnp_dev * pnp_dev ,
const struct pnp_device_id * id )
{
static int dev ;
2005-11-17 16:12:45 +03:00
struct snd_card * card ;
2005-04-17 02:20:36 +04:00
int err ;
for ( ; dev < SNDRV_CARDS ; + + dev ) {
if ( ! enable [ dev ] | | ! pnp [ dev ] )
continue ;
err = snd_mpu401_pnp ( dev , pnp_dev , id ) ;
if ( err < 0 )
return err ;
err = snd_mpu401_create ( dev , & card ) ;
if ( err < 0 )
return err ;
2005-11-17 18:03:39 +03:00
if ( ( err = snd_card_register ( card ) ) < 0 ) {
snd_card_free ( card ) ;
return err ;
}
2005-04-17 02:20:36 +04:00
snd_card_set_dev ( card , & pnp_dev - > dev ) ;
pnp_set_drvdata ( pnp_dev , card ) ;
2006-03-27 13:17:04 +04:00
snd_mpu401_devices + + ;
2005-04-17 02:20:36 +04:00
+ + dev ;
return 0 ;
}
return - ENODEV ;
}
static void __devexit snd_mpu401_pnp_remove ( struct pnp_dev * dev )
{
2005-11-17 16:12:45 +03:00
struct snd_card * card = ( struct snd_card * ) pnp_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
snd_card_disconnect ( card ) ;
2006-06-23 16:38:26 +04:00
snd_card_free_when_closed ( card ) ;
2005-04-17 02:20:36 +04:00
}
static struct pnp_driver snd_mpu401_pnp_driver = {
. name = " mpu401 " ,
. id_table = snd_mpu401_pnpids ,
. probe = snd_mpu401_pnp_probe ,
. remove = __devexit_p ( snd_mpu401_pnp_remove ) ,
} ;
# else
static struct pnp_driver snd_mpu401_pnp_driver ;
# endif
2007-06-25 14:08:01 +04:00
static void snd_mpu401_unregister_all ( void )
2005-12-07 11:13:42 +03:00
{
int i ;
if ( pnp_registered )
pnp_unregister_driver ( & snd_mpu401_pnp_driver ) ;
for ( i = 0 ; i < ARRAY_SIZE ( platform_devices ) ; + + i )
platform_device_unregister ( platform_devices [ i ] ) ;
platform_driver_unregister ( & snd_mpu401_driver ) ;
}
2005-04-17 02:20:36 +04:00
static int __init alsa_card_mpu401_init ( void )
{
2006-03-27 13:17:04 +04:00
int i , err ;
2005-04-17 02:20:36 +04:00
2005-11-17 18:03:39 +03:00
if ( ( err = platform_driver_register ( & snd_mpu401_driver ) ) < 0 )
return err ;
2006-02-20 13:57:34 +03:00
for ( i = 0 ; i < SNDRV_CARDS ; i + + ) {
2005-11-17 18:03:39 +03:00
struct platform_device * device ;
2006-02-20 13:57:34 +03:00
if ( ! enable [ i ] )
continue ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_PNP
2005-11-17 18:03:39 +03:00
if ( pnp [ i ] )
2005-04-17 02:20:36 +04:00
continue ;
# endif
2005-11-17 18:03:39 +03:00
device = platform_device_register_simple ( SND_MPU401_DRIVER ,
i , NULL , 0 ) ;
2006-04-13 14:57:11 +04:00
if ( IS_ERR ( device ) )
continue ;
2006-04-13 14:58:06 +04:00
if ( ! platform_get_drvdata ( device ) ) {
platform_device_unregister ( device ) ;
continue ;
}
2005-12-07 11:13:42 +03:00
platform_devices [ i ] = device ;
2006-03-27 13:17:04 +04:00
snd_mpu401_devices + + ;
2005-04-17 02:20:36 +04:00
}
2006-03-27 13:17:04 +04:00
err = pnp_register_driver ( & snd_mpu401_pnp_driver ) ;
if ( ! err )
2005-04-17 02:20:36 +04:00
pnp_registered = 1 ;
2006-03-27 13:17:04 +04:00
if ( ! snd_mpu401_devices ) {
2005-04-17 02:20:36 +04:00
# ifdef MODULE
printk ( KERN_ERR " MPU-401 device not found or device busy \n " ) ;
# endif
2006-04-13 14:57:11 +04:00
snd_mpu401_unregister_all ( ) ;
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
static void __exit alsa_card_mpu401_exit ( void )
{
2005-12-07 11:13:42 +03:00
snd_mpu401_unregister_all ( ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( alsa_card_mpu401_init )
module_exit ( alsa_card_mpu401_exit )