2005-04-16 15:20:36 -07:00
/*
* Driver for Digigram VXpocket V2 / 440 soundcards
*
* Copyright ( c ) 2002 by Takashi Iwai < tiwai @ suse . de >
*
* 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 <sound/driver.h>
# include <linux/init.h>
# include <linux/moduleparam.h>
# include <sound/core.h>
# include "vxpocket.h"
2005-06-30 13:40:51 +02:00
# include <pcmcia/ciscode.h>
# include <pcmcia/cisreg.h>
2005-04-16 15:20:36 -07:00
# include <sound/initval.h>
/*
*/
MODULE_AUTHOR ( " Takashi Iwai <tiwai@suse.de> " ) ;
2005-06-30 13:40:51 +02:00
MODULE_DESCRIPTION ( " Digigram VXPocket " ) ;
2005-04-16 15:20:36 -07:00
MODULE_LICENSE ( " GPL " ) ;
2005-06-30 13:40:51 +02:00
MODULE_SUPPORTED_DEVICE ( " {{Digigram,VXPocket},{Digigram,VXPocket440}} " ) ;
2005-04-16 15:20:36 -07:00
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 int ibl [ SNDRV_CARDS ] ;
module_param_array ( index , int , NULL , 0444 ) ;
2005-06-30 13:40:51 +02:00
MODULE_PARM_DESC ( index , " Index value for VXPocket soundcard. " ) ;
2005-04-16 15:20:36 -07:00
module_param_array ( id , charp , NULL , 0444 ) ;
2005-06-30 13:40:51 +02:00
MODULE_PARM_DESC ( id , " ID string for VXPocket soundcard. " ) ;
2005-04-16 15:20:36 -07:00
module_param_array ( enable , bool , NULL , 0444 ) ;
2005-06-30 13:40:51 +02:00
MODULE_PARM_DESC ( enable , " Enable VXPocket soundcard. " ) ;
2005-04-16 15:20:36 -07:00
module_param_array ( ibl , int , NULL , 0444 ) ;
2005-06-30 13:40:51 +02:00
MODULE_PARM_DESC ( ibl , " Capture IBL size for VXPocket soundcard. " ) ;
2005-04-16 15:20:36 -07:00
/*
*/
2005-06-30 13:40:51 +02:00
static unsigned int card_alloc ;
2005-04-16 15:20:36 -07:00
2005-06-30 13:40:51 +02:00
/*
*/
static void vxpocket_release ( dev_link_t * link )
{
2006-01-15 09:32:39 +01:00
pcmcia_disable_device ( link - > handle ) ;
2005-06-30 13:40:51 +02:00
}
2005-04-16 15:20:36 -07:00
2005-06-30 13:40:51 +02:00
/*
* destructor , called from snd_card_free_in_thread ( )
*/
2005-11-17 14:46:59 +01:00
static int snd_vxpocket_dev_free ( struct snd_device * device )
2005-06-30 13:40:51 +02:00
{
2005-11-17 14:46:59 +01:00
struct vx_core * chip = device - > device_data ;
2005-04-16 15:20:36 -07:00
2005-06-30 13:40:51 +02:00
snd_vx_free_firmware ( chip ) ;
kfree ( chip ) ;
return 0 ;
}
2005-04-16 15:20:36 -07:00
2005-06-30 13:40:51 +02:00
/*
* Hardware information
*/
/* VX-pocket V2
*
* 1 DSP , 1 sync UER
* 1 programmable clock ( NIY )
* 1 stereo analog input ( line / micro )
* 1 stereo analog output
* Only output levels can be modified
*/
static struct snd_vx_hardware vxpocket_hw = {
. name = " VXPocket " ,
. type = VX_TYPE_VXPOCKET ,
2005-04-16 15:20:36 -07:00
/* hardware specs */
2005-06-30 13:40:51 +02:00
. num_codecs = 1 ,
. num_ins = 1 ,
. num_outs = 1 ,
2005-04-16 15:20:36 -07:00
. output_level_max = VX_ANALOG_OUT_LEVEL_MAX ,
} ;
2005-06-30 13:40:51 +02:00
/* VX-pocket 440
*
* 1 DSP , 1 sync UER , 1 sync World Clock ( NIY )
* SMPTE ( NIY )
* 2 stereo analog input ( line / micro )
* 2 stereo analog output
* Only output levels can be modified
* UER , but only for the first two inputs and outputs .
*/
2005-04-16 15:20:36 -07:00
2005-06-30 13:40:51 +02:00
static struct snd_vx_hardware vxp440_hw = {
. name = " VXPocket440 " ,
. type = VX_TYPE_VXP440 ,
/* hardware specs */
. num_codecs = 2 ,
. num_ins = 2 ,
. num_outs = 2 ,
. output_level_max = VX_ANALOG_OUT_LEVEL_MAX ,
} ;
/*
* create vxpocket instance
*/
2006-03-05 10:45:09 +01:00
static struct snd_vxpocket * snd_vxpocket_new ( struct snd_card * card , int ibl ,
struct pcmcia_device * p_dev )
2005-06-30 13:40:51 +02:00
{
dev_link_t * link ; /* Info for cardmgr */
2005-11-17 14:46:59 +01:00
struct vx_core * chip ;
2005-06-30 13:40:51 +02:00
struct snd_vxpocket * vxp ;
2005-11-17 14:46:59 +01:00
static struct snd_device_ops ops = {
2005-06-30 13:40:51 +02:00
. dev_free = snd_vxpocket_dev_free ,
} ;
2006-03-05 10:45:09 +01:00
link = dev_to_instance ( p_dev ) ;
2005-06-30 13:40:51 +02:00
chip = snd_vx_create ( card , & vxpocket_hw , & snd_vxpocket_ops ,
2005-11-17 14:46:59 +01:00
sizeof ( struct snd_vxpocket ) - sizeof ( struct vx_core ) ) ;
2005-06-30 13:40:51 +02:00
if ( ! chip )
return NULL ;
if ( snd_device_new ( card , SNDRV_DEV_LOWLEVEL , chip , & ops ) < 0 ) {
kfree ( chip ) ;
return NULL ;
}
chip - > ibl . size = ibl ;
vxp = ( struct snd_vxpocket * ) chip ;
2006-03-05 10:45:09 +01:00
vxp - > p_dev = p_dev ;
2005-06-30 13:40:51 +02:00
link - > priv = chip ;
link - > io . Attributes1 = IO_DATA_PATH_WIDTH_AUTO ;
link - > io . NumPorts1 = 16 ;
link - > irq . Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT ;
link - > irq . IRQInfo1 = IRQ_LEVEL_ID ;
link - > irq . Handler = & snd_vx_irq_handler ;
link - > irq . Instance = chip ;
link - > conf . Attributes = CONF_ENABLE_IRQ ;
link - > conf . IntType = INT_MEMORY_AND_IO ;
link - > conf . ConfigIndex = 1 ;
link - > conf . Present = PRESENT_OPTION ;
return vxp ;
}
/**
* snd_vxpocket_assign_resources - initialize the hardware and card instance .
* @ port : i / o port for the card
* @ irq : irq number for the card
*
* this function assigns the specified port and irq , boot the card ,
* create pcm and control instances , and initialize the rest hardware .
*
* returns 0 if successful , or a negative error code .
*/
2005-11-17 14:46:59 +01:00
static int snd_vxpocket_assign_resources ( struct vx_core * chip , int port , int irq )
2005-06-30 13:40:51 +02:00
{
int err ;
2005-11-17 14:46:59 +01:00
struct snd_card * card = chip - > card ;
2005-06-30 13:40:51 +02:00
struct snd_vxpocket * vxp = ( struct snd_vxpocket * ) chip ;
snd_printdd ( KERN_DEBUG " vxpocket assign resources: port = 0x%x, irq = %d \n " , port , irq ) ;
vxp - > port = port ;
sprintf ( card - > shortname , " Digigram %s " , card - > driver ) ;
sprintf ( card - > longname , " %s at 0x%x, irq %i " ,
card - > shortname , port , irq ) ;
chip - > irq = irq ;
if ( ( err = snd_vx_setup_firmware ( chip ) ) < 0 )
return err ;
return 0 ;
}
/*
* configuration callback
*/
# define CS_CHECK(fn, ret) \
do { last_fn = ( fn ) ; if ( ( last_ret = ( ret ) ) ! = 0 ) goto cs_failed ; } while ( 0 )
static void vxpocket_config ( dev_link_t * link )
{
client_handle_t handle = link - > handle ;
2005-11-17 14:46:59 +01:00
struct vx_core * chip = link - > priv ;
2005-06-30 13:40:51 +02:00
struct snd_vxpocket * vxp = ( struct snd_vxpocket * ) chip ;
tuple_t tuple ;
cisparse_t * parse ;
u_short buf [ 32 ] ;
int last_fn , last_ret ;
snd_printdd ( KERN_DEBUG " vxpocket_config called \n " ) ;
parse = kmalloc ( sizeof ( * parse ) , GFP_KERNEL ) ;
if ( ! parse ) {
snd_printk ( KERN_ERR " vx: cannot allocate \n " ) ;
return ;
}
tuple . Attributes = 0 ;
tuple . TupleData = ( cisdata_t * ) buf ;
tuple . TupleDataMax = sizeof ( buf ) ;
tuple . TupleOffset = 0 ;
tuple . DesiredTuple = CISTPL_CONFIG ;
CS_CHECK ( GetFirstTuple , pcmcia_get_first_tuple ( handle , & tuple ) ) ;
CS_CHECK ( GetTupleData , pcmcia_get_tuple_data ( handle , & tuple ) ) ;
CS_CHECK ( ParseTuple , pcmcia_parse_tuple ( handle , & tuple , parse ) ) ;
link - > conf . ConfigBase = parse - > config . base ;
link - > conf . Present = parse - > config . rmask [ 0 ] ;
/* redefine hardware record according to the VERSION1 string */
tuple . DesiredTuple = CISTPL_VERS_1 ;
CS_CHECK ( GetFirstTuple , pcmcia_get_first_tuple ( handle , & tuple ) ) ;
CS_CHECK ( GetTupleData , pcmcia_get_tuple_data ( handle , & tuple ) ) ;
CS_CHECK ( ParseTuple , pcmcia_parse_tuple ( handle , & tuple , parse ) ) ;
if ( ! strcmp ( parse - > version_1 . str + parse - > version_1 . ofs [ 1 ] , " VX-POCKET " ) ) {
snd_printdd ( " VX-pocket is detected \n " ) ;
} else {
snd_printdd ( " VX-pocket 440 is detected \n " ) ;
/* overwrite the hardware information */
chip - > hw = & vxp440_hw ;
chip - > type = vxp440_hw . type ;
strcpy ( chip - > card - > driver , vxp440_hw . name ) ;
}
/* Configure card */
link - > state | = DEV_CONFIG ;
CS_CHECK ( RequestIO , pcmcia_request_io ( handle , & link - > io ) ) ;
CS_CHECK ( RequestIRQ , pcmcia_request_irq ( link - > handle , & link - > irq ) ) ;
CS_CHECK ( RequestConfiguration , pcmcia_request_configuration ( link - > handle , & link - > conf ) ) ;
chip - > dev = & handle_to_dev ( link - > handle ) ;
2005-08-23 19:27:31 +02:00
snd_card_set_dev ( chip - > card , chip - > dev ) ;
2005-06-30 13:40:51 +02:00
if ( snd_vxpocket_assign_resources ( chip , link - > io . BasePort1 , link - > irq . AssignedIRQ ) < 0 )
goto failed ;
2006-03-05 10:45:09 +01:00
link - > dev_node = & vxp - > node ;
2005-06-30 13:40:51 +02:00
link - > state & = ~ DEV_CONFIG_PENDING ;
kfree ( parse ) ;
return ;
cs_failed :
cs_error ( link - > handle , last_fn , last_ret ) ;
failed :
2006-01-15 10:05:19 +01:00
pcmcia_disable_device ( link - > handle ) ;
2005-06-30 13:40:51 +02:00
kfree ( parse ) ;
}
2006-01-06 00:27:16 +01:00
# ifdef CONFIG_PM
2005-06-30 13:40:51 +02:00
2006-01-06 00:27:16 +01:00
static int vxp_suspend ( struct pcmcia_device * dev )
2005-06-30 13:40:51 +02:00
{
2006-01-06 00:27:16 +01:00
dev_link_t * link = dev_to_instance ( dev ) ;
2005-11-17 14:46:59 +01:00
struct vx_core * chip = link - > priv ;
2005-06-30 13:40:51 +02:00
2006-01-06 00:27:16 +01:00
snd_printdd ( KERN_DEBUG " SUSPEND \n " ) ;
if ( chip ) {
snd_printdd ( KERN_DEBUG " snd_vx_suspend calling \n " ) ;
snd_vx_suspend ( chip , PMSG_SUSPEND ) ;
}
return 0 ;
}
static int vxp_resume ( struct pcmcia_device * dev )
{
dev_link_t * link = dev_to_instance ( dev ) ;
struct vx_core * chip = link - > priv ;
snd_printdd ( KERN_DEBUG " RESUME \n " ) ;
if ( DEV_OK ( link ) ) {
//struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip;
2005-11-17 16:06:05 +01:00
if ( chip ) {
2006-01-06 00:27:16 +01:00
snd_printdd ( KERN_DEBUG " calling snd_vx_resume \n " ) ;
snd_vx_resume ( chip ) ;
2005-06-30 13:40:51 +02:00
}
}
2006-01-06 00:27:16 +01:00
snd_printdd ( KERN_DEBUG " resume done! \n " ) ;
2005-06-30 13:40:51 +02:00
return 0 ;
}
2005-04-16 15:20:36 -07:00
2006-01-06 00:27:16 +01:00
# endif
2005-04-16 15:20:36 -07:00
/*
*/
2006-01-06 00:27:16 +01:00
static int vxpocket_attach ( struct pcmcia_device * p_dev )
2005-04-16 15:20:36 -07:00
{
2005-11-17 14:46:59 +01:00
struct snd_card * card ;
2005-06-30 13:40:51 +02:00
struct snd_vxpocket * vxp ;
int i ;
/* find an empty slot from the card list */
for ( i = 0 ; i < SNDRV_CARDS ; i + + ) {
if ( ! card_alloc & ( 1 < < i ) )
break ;
}
if ( i > = SNDRV_CARDS ) {
snd_printk ( KERN_ERR " vxpocket: too many cards found \n " ) ;
2006-01-06 00:27:16 +01:00
return - EINVAL ;
2005-06-30 13:40:51 +02:00
}
if ( ! enable [ i ] )
2006-01-06 00:27:16 +01:00
return - ENODEV ; /* disabled explicitly */
2005-06-30 13:40:51 +02:00
/* ok, create a card instance */
card = snd_card_new ( index [ i ] , id [ i ] , THIS_MODULE , 0 ) ;
if ( card = = NULL ) {
snd_printk ( KERN_ERR " vxpocket: cannot create a card instance \n " ) ;
2006-01-06 00:27:16 +01:00
return - ENOMEM ;
2005-06-30 13:40:51 +02:00
}
2006-03-05 10:45:09 +01:00
vxp = snd_vxpocket_new ( card , ibl [ i ] , p_dev ) ;
2005-06-30 13:40:51 +02:00
if ( ! vxp ) {
snd_card_free ( card ) ;
2006-01-06 00:27:16 +01:00
return - ENODEV ;
2005-06-30 13:40:51 +02:00
}
2005-11-17 16:06:05 +01:00
card - > private_data = vxp ;
2005-06-30 13:40:51 +02:00
2005-08-23 19:01:38 +02:00
vxp - > index = i ;
2005-06-30 13:40:51 +02:00
card_alloc | = 1 < < i ;
2006-03-05 10:45:09 +01:00
vxp - > p_dev = p_dev ;
vxp - > p_dev - > state | = DEV_PRESENT | DEV_CONFIG_PENDING ;
2006-01-06 00:27:16 +01:00
2006-03-05 10:45:09 +01:00
vxpocket_config ( p_dev ) ;
2005-06-30 13:40:51 +02:00
2006-01-06 00:27:16 +01:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2006-01-06 00:27:16 +01:00
static void vxpocket_detach ( struct pcmcia_device * p_dev )
2005-04-16 15:20:36 -07:00
{
2006-01-06 00:27:16 +01:00
dev_link_t * link = dev_to_instance ( p_dev ) ;
2005-06-30 13:40:51 +02:00
struct snd_vxpocket * vxp ;
2005-11-17 14:46:59 +01:00
struct vx_core * chip ;
2005-06-30 13:40:51 +02:00
if ( ! link )
return ;
vxp = link - > priv ;
2005-11-17 14:46:59 +01:00
chip = ( struct vx_core * ) vxp ;
2005-06-30 13:40:51 +02:00
card_alloc & = ~ ( 1 < < vxp - > index ) ;
chip - > chip_status | = VX_STAT_IS_STALE ; /* to be sure */
snd_card_disconnect ( chip - > card ) ;
vxpocket_release ( link ) ;
snd_card_free_in_thread ( chip - > card ) ;
2005-04-16 15:20:36 -07:00
}
/*
* Module entry points
*/
2005-06-27 16:28:33 -07:00
static struct pcmcia_device_id vxp_ids [ ] = {
PCMCIA_DEVICE_MANF_CARD ( 0x01f1 , 0x0100 ) ,
PCMCIA_DEVICE_NULL
} ;
MODULE_DEVICE_TABLE ( pcmcia , vxp_ids ) ;
2005-04-16 15:20:36 -07:00
static struct pcmcia_driver vxp_cs_driver = {
. owner = THIS_MODULE ,
. drv = {
2005-06-30 13:40:51 +02:00
. name = " snd-vxpocket " ,
2005-04-16 15:20:36 -07:00
} ,
2006-01-06 00:27:16 +01:00
. probe = vxpocket_attach ,
. remove = vxpocket_detach ,
2005-06-27 16:28:33 -07:00
. id_table = vxp_ids ,
2006-01-06 00:27:16 +01:00
# ifdef CONFIG_PM
. suspend = vxp_suspend ,
. resume = vxp_resume ,
# endif
2005-04-16 15:20:36 -07:00
} ;
static int __init init_vxpocket ( void )
{
return pcmcia_register_driver ( & vxp_cs_driver ) ;
}
static void __exit exit_vxpocket ( void )
{
pcmcia_unregister_driver ( & vxp_cs_driver ) ;
}
module_init ( init_vxpocket ) ;
module_exit ( exit_vxpocket ) ;