2019-06-03 08:45:06 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2006-06-21 17:42:43 +04:00
/*
* soundbus
*
* Copyright 2006 Johannes Berg < johannes @ sipsolutions . net >
*/
# include <linux/module.h>
# include "soundbus.h"
MODULE_AUTHOR ( " Johannes Berg <johannes@sipsolutions.net> " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " Apple Soundbus " ) ;
struct soundbus_dev * soundbus_dev_get ( struct soundbus_dev * dev )
{
struct device * tmp ;
if ( ! dev )
return NULL ;
tmp = get_device ( & dev - > ofdev . dev ) ;
if ( tmp )
return to_soundbus_device ( tmp ) ;
else
return NULL ;
}
EXPORT_SYMBOL_GPL ( soundbus_dev_get ) ;
void soundbus_dev_put ( struct soundbus_dev * dev )
{
if ( dev )
put_device ( & dev - > ofdev . dev ) ;
}
EXPORT_SYMBOL_GPL ( soundbus_dev_put ) ;
static int soundbus_probe ( struct device * dev )
{
int error = - ENODEV ;
struct soundbus_driver * drv ;
struct soundbus_dev * soundbus_dev ;
drv = to_soundbus_driver ( dev - > driver ) ;
soundbus_dev = to_soundbus_device ( dev ) ;
if ( ! drv - > probe )
return error ;
soundbus_dev_get ( soundbus_dev ) ;
error = drv - > probe ( soundbus_dev ) ;
if ( error )
soundbus_dev_put ( soundbus_dev ) ;
return error ;
}
2007-08-14 17:15:12 +04:00
static int soundbus_uevent ( struct device * dev , struct kobj_uevent_env * env )
2006-06-21 17:42:43 +04:00
{
struct soundbus_dev * soundbus_dev ;
2010-08-06 19:25:50 +04:00
struct platform_device * of ;
2007-04-03 04:52:17 +04:00
const char * compat ;
2007-08-14 17:15:12 +04:00
int retval = 0 ;
2007-03-31 09:23:12 +04:00
int cplen , seen = 0 ;
2006-06-21 17:42:43 +04:00
if ( ! dev )
return - ENODEV ;
soundbus_dev = to_soundbus_device ( dev ) ;
if ( ! soundbus_dev )
return - ENODEV ;
of = & soundbus_dev - > ofdev ;
/* stuff we want to pass to /sbin/hotplug */
2018-12-05 22:50:48 +03:00
retval = add_uevent_var ( env , " OF_NAME=%pOFn " , of - > dev . of_node ) ;
2007-03-31 09:23:12 +04:00
if ( retval )
return retval ;
2018-11-17 01:11:04 +03:00
retval = add_uevent_var ( env , " OF_TYPE=%s " , of_node_get_device_type ( of - > dev . of_node ) ) ;
2007-03-31 09:23:12 +04:00
if ( retval )
return retval ;
2006-06-21 17:42:43 +04:00
/* Since the compatible field can contain pretty much anything
* it ' s not really legal to split it out with commas . We split it
* up using a number of environment variables instead . */
2010-04-14 03:12:29 +04:00
compat = of_get_property ( of - > dev . of_node , " compatible " , & cplen ) ;
2006-06-21 17:42:43 +04:00
while ( compat & & cplen > 0 ) {
2007-08-14 17:15:12 +04:00
int tmp = env - > buflen ;
retval = add_uevent_var ( env , " OF_COMPATIBLE_%d=%s " , seen , compat ) ;
2007-03-31 09:23:12 +04:00
if ( retval )
return retval ;
2007-08-14 17:15:12 +04:00
compat + = env - > buflen - tmp ;
cplen - = env - > buflen - tmp ;
2007-03-31 09:23:12 +04:00
seen + = 1 ;
2006-06-21 17:42:43 +04:00
}
2007-08-14 17:15:12 +04:00
retval = add_uevent_var ( env , " OF_COMPATIBLE_N=%d " , seen ) ;
2007-03-31 09:23:12 +04:00
if ( retval )
return retval ;
2007-08-14 17:15:12 +04:00
retval = add_uevent_var ( env , " MODALIAS=%s " , soundbus_dev - > modalias ) ;
2006-06-21 17:42:43 +04:00
2007-03-31 09:23:12 +04:00
return retval ;
2006-06-21 17:42:43 +04:00
}
static int soundbus_device_remove ( struct device * dev )
{
struct soundbus_dev * soundbus_dev = to_soundbus_device ( dev ) ;
struct soundbus_driver * drv = to_soundbus_driver ( dev - > driver ) ;
if ( dev - > driver & & drv - > remove )
drv - > remove ( soundbus_dev ) ;
soundbus_dev_put ( soundbus_dev ) ;
return 0 ;
}
static void soundbus_device_shutdown ( struct device * dev )
{
struct soundbus_dev * soundbus_dev = to_soundbus_device ( dev ) ;
struct soundbus_driver * drv = to_soundbus_driver ( dev - > driver ) ;
if ( dev - > driver & & drv - > shutdown )
drv - > shutdown ( soundbus_dev ) ;
}
2015-06-12 11:38:41 +03:00
/* soundbus_dev_attrs is declared in sysfs.c */
ATTRIBUTE_GROUPS ( soundbus_dev ) ;
2006-06-21 17:42:43 +04:00
static struct bus_type soundbus_bus_type = {
. name = " aoa-soundbus " ,
. probe = soundbus_probe ,
. uevent = soundbus_uevent ,
. remove = soundbus_device_remove ,
. shutdown = soundbus_device_shutdown ,
2015-06-12 11:38:41 +03:00
. dev_groups = soundbus_dev_groups ,
2006-06-21 17:42:43 +04:00
} ;
int soundbus_add_one ( struct soundbus_dev * dev )
{
static int devcount ;
/* sanity checks */
if ( ! dev - > attach_codec | |
2010-04-14 03:12:29 +04:00
! dev - > ofdev . dev . of_node | |
2006-06-21 17:42:43 +04:00
dev - > pcmname | |
dev - > pcmid ! = - 1 ) {
printk ( KERN_ERR " soundbus: adding device failed sanity check! \n " ) ;
return - EINVAL ;
}
2008-11-02 05:50:35 +03:00
dev_set_name ( & dev - > ofdev . dev , " soundbus:%x " , + + devcount ) ;
2006-06-21 17:42:43 +04:00
dev - > ofdev . dev . bus = & soundbus_bus_type ;
return of_device_register ( & dev - > ofdev ) ;
}
EXPORT_SYMBOL_GPL ( soundbus_add_one ) ;
void soundbus_remove_one ( struct soundbus_dev * dev )
{
of_device_unregister ( & dev - > ofdev ) ;
}
EXPORT_SYMBOL_GPL ( soundbus_remove_one ) ;
int soundbus_register_driver ( struct soundbus_driver * drv )
{
/* initialize common driver fields */
drv - > driver . name = drv - > name ;
drv - > driver . bus = & soundbus_bus_type ;
/* register with core */
return driver_register ( & drv - > driver ) ;
}
EXPORT_SYMBOL_GPL ( soundbus_register_driver ) ;
void soundbus_unregister_driver ( struct soundbus_driver * drv )
{
driver_unregister ( & drv - > driver ) ;
}
EXPORT_SYMBOL_GPL ( soundbus_unregister_driver ) ;
2006-07-10 15:44:35 +04:00
static int __init soundbus_init ( void )
{
return bus_register ( & soundbus_bus_type ) ;
}
static void __exit soundbus_exit ( void )
{
bus_unregister ( & soundbus_bus_type ) ;
}
subsys_initcall ( soundbus_init ) ;
2006-06-21 17:42:43 +04:00
module_exit ( soundbus_exit ) ;