2008-07-28 22:05:35 +04:00
/*
* Jack abstraction layer
*
* Copyright 2008 Wolfson Microelectronics
*
* 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/input.h>
# include <sound/jack.h>
# include <sound/core.h>
2009-01-03 19:56:56 +03:00
static int jack_types [ ] = {
SW_HEADPHONE_INSERT ,
SW_MICROPHONE_INSERT ,
SW_LINEOUT_INSERT ,
SW_JACK_PHYSICAL_INSERT ,
2009-01-07 12:54:25 +03:00
SW_VIDEOOUT_INSERT ,
2009-01-03 19:56:56 +03:00
} ;
2008-07-28 22:05:35 +04:00
static int snd_jack_dev_free ( struct snd_device * device )
{
struct snd_jack * jack = device - > device_data ;
2009-04-14 18:13:58 +04:00
if ( jack - > private_free )
jack - > private_free ( jack ) ;
2008-07-28 22:05:35 +04:00
/* If the input device is registered with the input subsystem
* then we need to use a different deallocator . */
if ( jack - > registered )
input_unregister_device ( jack - > input_dev ) ;
else
input_free_device ( jack - > input_dev ) ;
2008-10-25 09:05:29 +04:00
kfree ( jack - > id ) ;
2008-07-28 22:05:35 +04:00
kfree ( jack ) ;
return 0 ;
}
static int snd_jack_dev_register ( struct snd_device * device )
{
struct snd_jack * jack = device - > device_data ;
struct snd_card * card = device - > card ;
int err ;
snprintf ( jack - > name , sizeof ( jack - > name ) , " %s %s " ,
2009-02-18 18:46:27 +03:00
card - > shortname , jack - > id ) ;
2008-07-28 22:05:35 +04:00
jack - > input_dev - > name = jack - > name ;
/* Default to the sound card device. */
if ( ! jack - > input_dev - > dev . parent )
2009-06-10 21:50:33 +04:00
jack - > input_dev - > dev . parent = snd_card_get_device_link ( card ) ;
2008-07-28 22:05:35 +04:00
err = input_register_device ( jack - > input_dev ) ;
if ( err = = 0 )
jack - > registered = 1 ;
return err ;
}
/**
* snd_jack_new - Create a new jack
* @ card : the card instance
* @ id : an identifying string for this jack
* @ type : a bitmask of enum snd_jack_type values that can be detected by
* this jack
* @ jjack : Used to provide the allocated jack object to the caller .
*
* Creates a new jack object .
*
* Returns zero if successful , or a negative error code on failure .
* On success jjack will be initialised .
*/
int snd_jack_new ( struct snd_card * card , const char * id , int type ,
struct snd_jack * * jjack )
{
struct snd_jack * jack ;
int err ;
2009-01-03 19:56:56 +03:00
int i ;
2008-07-28 22:05:35 +04:00
static struct snd_device_ops ops = {
. dev_free = snd_jack_dev_free ,
. dev_register = snd_jack_dev_register ,
} ;
jack = kzalloc ( sizeof ( struct snd_jack ) , GFP_KERNEL ) ;
if ( jack = = NULL )
return - ENOMEM ;
2008-10-25 09:05:29 +04:00
jack - > id = kstrdup ( id , GFP_KERNEL ) ;
2008-07-28 22:05:35 +04:00
jack - > input_dev = input_allocate_device ( ) ;
if ( jack - > input_dev = = NULL ) {
err = - ENOMEM ;
goto fail_input ;
}
jack - > input_dev - > phys = " ALSA " ;
jack - > type = type ;
2009-01-03 19:56:56 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( jack_types ) ; i + + )
if ( type & ( 1 < < i ) )
input_set_capability ( jack - > input_dev , EV_SW ,
jack_types [ i ] ) ;
2008-07-28 22:05:35 +04:00
err = snd_device_new ( card , SNDRV_DEV_JACK , jack , & ops ) ;
if ( err < 0 )
goto fail_input ;
* jjack = jack ;
return 0 ;
fail_input :
input_free_device ( jack - > input_dev ) ;
kfree ( jack ) ;
return err ;
}
EXPORT_SYMBOL ( snd_jack_new ) ;
/**
* snd_jack_set_parent - Set the parent device for a jack
*
* @ jack : The jack to configure
* @ parent : The device to set as parent for the jack .
*
* Set the parent for the jack input device in the device tree . This
* function is only valid prior to registration of the jack . If no
* parent is configured then the parent device will be the sound card .
*/
void snd_jack_set_parent ( struct snd_jack * jack , struct device * parent )
{
WARN_ON ( jack - > registered ) ;
jack - > input_dev - > dev . parent = parent ;
}
EXPORT_SYMBOL ( snd_jack_set_parent ) ;
/**
* snd_jack_report - Report the current status of a jack
*
* @ jack : The jack to report status for
* @ status : The current status of the jack
*/
void snd_jack_report ( struct snd_jack * jack , int status )
{
2009-01-03 19:56:56 +03:00
int i ;
2008-10-15 20:07:47 +04:00
if ( ! jack )
return ;
2009-01-03 19:56:56 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( jack_types ) ; i + + ) {
int testbit = 1 < < i ;
if ( jack - > type & testbit )
input_report_switch ( jack - > input_dev , jack_types [ i ] ,
status & testbit ) ;
}
2008-07-28 22:05:35 +04:00
input_sync ( jack - > input_dev ) ;
}
EXPORT_SYMBOL ( snd_jack_report ) ;
MODULE_AUTHOR ( " Mark Brown <broonie@opensource.wolfsonmicro.com> " ) ;
MODULE_DESCRIPTION ( " Jack detection support for ALSA " ) ;
MODULE_LICENSE ( " GPL " ) ;