2019-06-03 07:45:06 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2006-06-21 15:42:43 +02:00
/*
* Apple Onboard Audio driver core
*
* Copyright 2006 Johannes Berg < johannes @ sipsolutions . net >
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/list.h>
# include "../aoa.h"
2008-10-23 15:47:56 +02:00
# include "alsa.h"
2006-06-21 15:42:43 +02:00
MODULE_DESCRIPTION ( " Apple Onboard Audio Sound Driver " ) ;
MODULE_AUTHOR ( " Johannes Berg <johannes@sipsolutions.net> " ) ;
MODULE_LICENSE ( " GPL " ) ;
/* We allow only one fabric. This simplifies things,
* and more don ' t really make that much sense */
static struct aoa_fabric * fabric ;
static LIST_HEAD ( codec_list ) ;
static int attach_codec_to_fabric ( struct aoa_codec * c )
{
int err ;
if ( ! try_module_get ( c - > owner ) )
return - EBUSY ;
/* found_codec has to be assigned */
err = - ENOENT ;
if ( fabric - > found_codec )
err = fabric - > found_codec ( c ) ;
if ( err ) {
module_put ( c - > owner ) ;
printk ( KERN_ERR " snd-aoa: fabric didn't like codec %s \n " ,
c - > name ) ;
return err ;
}
c - > fabric = fabric ;
err = 0 ;
if ( c - > init )
err = c - > init ( c ) ;
if ( err ) {
printk ( KERN_ERR " snd-aoa: codec %s didn't init \n " , c - > name ) ;
c - > fabric = NULL ;
if ( fabric - > remove_codec )
fabric - > remove_codec ( c ) ;
module_put ( c - > owner ) ;
return err ;
}
if ( fabric - > attached_codec )
fabric - > attached_codec ( c ) ;
return 0 ;
}
int aoa_codec_register ( struct aoa_codec * codec )
{
int err = 0 ;
/* if there's a fabric already, we can tell if we
* will want to have this codec , so propagate error
* through . Otherwise , this will happen later . . . */
if ( fabric )
err = attach_codec_to_fabric ( codec ) ;
if ( ! err )
list_add ( & codec - > list , & codec_list ) ;
return err ;
}
EXPORT_SYMBOL_GPL ( aoa_codec_register ) ;
void aoa_codec_unregister ( struct aoa_codec * codec )
{
list_del ( & codec - > list ) ;
if ( codec - > fabric & & codec - > exit )
codec - > exit ( codec ) ;
if ( fabric & & fabric - > remove_codec )
fabric - > remove_codec ( codec ) ;
codec - > fabric = NULL ;
module_put ( codec - > owner ) ;
}
EXPORT_SYMBOL_GPL ( aoa_codec_unregister ) ;
2006-12-07 08:24:12 +01:00
int aoa_fabric_register ( struct aoa_fabric * new_fabric , struct device * dev )
2006-06-21 15:42:43 +02:00
{
struct aoa_codec * c ;
int err ;
/* allow querying for presence of fabric
* ( i . e . do this test first ! ) */
if ( new_fabric = = fabric ) {
err = - EALREADY ;
goto attach ;
}
if ( fabric )
return - EEXIST ;
if ( ! new_fabric )
return - EINVAL ;
2006-12-07 08:24:12 +01:00
err = aoa_alsa_init ( new_fabric - > name , new_fabric - > owner , dev ) ;
2006-06-21 15:42:43 +02:00
if ( err )
return err ;
fabric = new_fabric ;
attach :
list_for_each_entry ( c , & codec_list , list ) {
if ( c - > fabric ! = fabric )
attach_codec_to_fabric ( c ) ;
}
return err ;
}
EXPORT_SYMBOL_GPL ( aoa_fabric_register ) ;
void aoa_fabric_unregister ( struct aoa_fabric * old_fabric )
{
struct aoa_codec * c ;
if ( fabric ! = old_fabric )
return ;
list_for_each_entry ( c , & codec_list , list ) {
if ( c - > fabric )
aoa_fabric_unlink_codec ( c ) ;
}
aoa_alsa_cleanup ( ) ;
fabric = NULL ;
}
EXPORT_SYMBOL_GPL ( aoa_fabric_unregister ) ;
void aoa_fabric_unlink_codec ( struct aoa_codec * codec )
{
if ( ! codec - > fabric ) {
printk ( KERN_ERR " snd-aoa: fabric unassigned "
" in aoa_fabric_unlink_codec \n " ) ;
dump_stack ( ) ;
return ;
}
if ( codec - > exit )
codec - > exit ( codec ) ;
if ( codec - > fabric - > remove_codec )
codec - > fabric - > remove_codec ( codec ) ;
codec - > fabric = NULL ;
module_put ( codec - > owner ) ;
}
EXPORT_SYMBOL_GPL ( aoa_fabric_unlink_codec ) ;
static int __init aoa_init ( void )
{
return 0 ;
}
static void __exit aoa_exit ( void )
{
aoa_alsa_cleanup ( ) ;
}
module_init ( aoa_init ) ;
module_exit ( aoa_exit ) ;