2005-04-16 15:20:36 -07:00
/* Bluetooth HCI driver model support. */
2011-05-27 09:12:25 -04:00
# include <linux/module.h>
2005-04-16 15:20:36 -07:00
# include <net/bluetooth/bluetooth.h>
# include <net/bluetooth/hci_core.h>
2010-03-21 05:27:45 +01:00
static struct class * bt_class ;
2008-08-18 13:23:53 +02:00
static inline char * link_typetostr ( int type )
{
switch ( type ) {
case ACL_LINK :
return " ACL " ;
case SCO_LINK :
return " SCO " ;
case ESCO_LINK :
return " eSCO " ;
2011-08-24 10:04:56 -04:00
case LE_LINK :
return " LE " ;
2008-08-18 13:23:53 +02:00
default :
return " UNKNOWN " ;
}
}
2012-05-17 00:36:23 -03:00
static ssize_t show_link_type ( struct device * dev ,
struct device_attribute * attr , char * buf )
2008-08-18 13:23:53 +02:00
{
2012-02-09 21:58:33 +01:00
struct hci_conn * conn = to_hci_conn ( dev ) ;
2008-08-18 13:23:53 +02:00
return sprintf ( buf , " %s \n " , link_typetostr ( conn - > type ) ) ;
}
2012-05-17 00:36:23 -03:00
static ssize_t show_link_address ( struct device * dev ,
struct device_attribute * attr , char * buf )
2008-08-18 13:23:53 +02:00
{
2012-02-09 21:58:33 +01:00
struct hci_conn * conn = to_hci_conn ( dev ) ;
2012-09-25 12:49:44 +03:00
return sprintf ( buf , " %pMR \n " , & conn - > dst ) ;
2008-08-18 13:23:53 +02:00
}
2011-02-17 19:22:19 -03:00
# define LINK_ATTR(_name, _mode, _show, _store) \
struct device_attribute link_attr_ # # _name = __ATTR ( _name , _mode , _show , _store )
2008-08-18 13:23:53 +02:00
static LINK_ATTR ( type , S_IRUGO , show_link_type , NULL ) ;
static LINK_ATTR ( address , S_IRUGO , show_link_address , NULL ) ;
static struct attribute * bt_link_attrs [ ] = {
& link_attr_type . attr ,
& link_attr_address . attr ,
NULL
} ;
2014-01-07 22:23:08 +08:00
ATTRIBUTE_GROUPS ( bt_link ) ;
2008-08-18 13:23:53 +02:00
static void bt_link_release ( struct device * dev )
{
2012-02-09 21:58:34 +01:00
struct hci_conn * conn = to_hci_conn ( dev ) ;
kfree ( conn ) ;
2008-08-18 13:23:53 +02:00
}
static struct device_type bt_link = {
. name = " link " ,
. groups = bt_link_groups ,
. release = bt_link_release ,
} ;
2011-12-17 18:53:02 -02:00
/*
* The rfcomm tty device will possibly retain even when conn
* is down , and sysfs doesn ' t support move zombie device ,
* so we should move the device before conn device is destroyed .
*/
static int __match_tty ( struct device * dev , void * data )
{
return ! strncmp ( dev_name ( dev ) , " rfcomm " , 6 ) ;
}
void hci_conn_init_sysfs ( struct hci_conn * conn )
{
struct hci_dev * hdev = conn - > hdev ;
BT_DBG ( " conn %p " , conn ) ;
conn - > dev . type = & bt_link ;
conn - > dev . class = bt_class ;
conn - > dev . parent = & hdev - > dev ;
device_initialize ( & conn - > dev ) ;
}
void hci_conn_add_sysfs ( struct hci_conn * conn )
2008-08-18 13:23:53 +02:00
{
2009-05-05 13:09:01 -07:00
struct hci_dev * hdev = conn - > hdev ;
2008-08-18 13:23:53 +02:00
2011-12-17 18:53:02 -02:00
BT_DBG ( " conn %p " , conn ) ;
2009-05-05 13:09:01 -07:00
dev_set_name ( & conn - > dev , " %s:%d " , hdev - > name , conn - > handle ) ;
2008-08-18 13:23:53 +02:00
if ( device_add ( & conn - > dev ) < 0 ) {
BT_ERR ( " Failed to register connection device " ) ;
return ;
}
2009-05-08 18:20:43 -07:00
hci_dev_hold ( hdev ) ;
2008-08-18 13:23:53 +02:00
}
2011-12-17 18:53:02 -02:00
void hci_conn_del_sysfs ( struct hci_conn * conn )
2008-08-18 13:23:53 +02:00
{
struct hci_dev * hdev = conn - > hdev ;
2009-05-02 18:24:06 -07:00
if ( ! device_is_registered ( & conn - > dev ) )
return ;
2009-04-23 14:50:54 +03:00
2008-08-18 13:23:53 +02:00
while ( 1 ) {
struct device * dev ;
dev = device_find_child ( & conn - > dev , NULL , __match_tty ) ;
if ( ! dev )
break ;
2009-03-04 12:44:00 +01:00
device_move ( dev , NULL , DPM_ORDER_DEV_LAST ) ;
2008-08-18 13:23:53 +02:00
put_device ( dev ) ;
}
device_del ( & conn - > dev ) ;
2009-05-08 18:20:43 -07:00
2008-08-18 13:23:53 +02:00
hci_dev_put ( hdev ) ;
}
2010-02-13 02:28:41 +01:00
static inline char * host_typetostr ( int type )
{
switch ( type ) {
case HCI_BREDR :
return " BR/EDR " ;
2010-08-09 17:38:10 -04:00
case HCI_AMP :
return " AMP " ;
2010-02-13 02:28:41 +01:00
default :
return " UNKNOWN " ;
}
}
2012-05-17 00:36:23 -03:00
static ssize_t show_type ( struct device * dev ,
struct device_attribute * attr , char * buf )
2010-02-13 02:28:41 +01:00
{
2012-02-09 21:58:30 +01:00
struct hci_dev * hdev = to_hci_dev ( dev ) ;
2010-02-13 02:28:41 +01:00
return sprintf ( buf , " %s \n " , host_typetostr ( hdev - > dev_type ) ) ;
}
2012-05-17 00:36:23 -03:00
static ssize_t show_name ( struct device * dev ,
struct device_attribute * attr , char * buf )
2007-10-20 13:33:56 +02:00
{
2012-02-09 21:58:30 +01:00
struct hci_dev * hdev = to_hci_dev ( dev ) ;
2011-03-16 14:29:35 +02:00
char name [ HCI_MAX_NAME_LENGTH + 1 ] ;
2007-10-20 13:33:56 +02:00
int i ;
2011-03-16 14:29:35 +02:00
for ( i = 0 ; i < HCI_MAX_NAME_LENGTH ; i + + )
2007-10-20 13:33:56 +02:00
name [ i ] = hdev - > dev_name [ i ] ;
2011-03-16 14:29:35 +02:00
name [ HCI_MAX_NAME_LENGTH ] = ' \0 ' ;
2007-10-20 13:33:56 +02:00
return sprintf ( buf , " %s \n " , name ) ;
}
2012-05-17 00:36:23 -03:00
static ssize_t show_address ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-16 15:20:36 -07:00
{
2012-02-09 21:58:30 +01:00
struct hci_dev * hdev = to_hci_dev ( dev ) ;
2012-09-25 12:49:44 +03:00
return sprintf ( buf , " %pMR \n " , & hdev - > bdaddr ) ;
2005-04-16 15:20:36 -07:00
}
2010-02-13 02:28:41 +01:00
static DEVICE_ATTR ( type , S_IRUGO , show_type , NULL ) ;
2007-10-20 13:33:56 +02:00
static DEVICE_ATTR ( name , S_IRUGO , show_name , NULL ) ;
2006-07-03 10:02:41 +02:00
static DEVICE_ATTR ( address , S_IRUGO , show_address , NULL ) ;
2005-04-16 15:20:36 -07:00
2008-08-18 13:23:53 +02:00
static struct attribute * bt_host_attrs [ ] = {
2010-02-13 02:28:41 +01:00
& dev_attr_type . attr ,
2008-08-18 13:23:53 +02:00
& dev_attr_name . attr ,
& dev_attr_address . attr ,
2005-04-16 15:20:36 -07:00
NULL
} ;
2014-01-07 22:23:08 +08:00
ATTRIBUTE_GROUPS ( bt_host ) ;
2006-07-03 10:02:37 +02:00
2008-08-18 13:23:53 +02:00
static void bt_host_release ( struct device * dev )
2006-07-03 10:02:41 +02:00
{
2012-02-09 21:58:34 +01:00
struct hci_dev * hdev = to_hci_dev ( dev ) ;
kfree ( hdev ) ;
2012-01-07 15:47:21 +01:00
module_put ( THIS_MODULE ) ;
2006-07-06 12:38:46 +02:00
}
2008-08-18 13:23:53 +02:00
static struct device_type bt_host = {
. name = " host " ,
. groups = bt_host_groups ,
. release = bt_host_release ,
} ;
2006-07-03 10:02:41 +02:00
2011-10-08 14:58:47 +02:00
void hci_init_sysfs ( struct hci_dev * hdev )
{
struct device * dev = & hdev - > dev ;
dev - > type = & bt_host ;
dev - > class = bt_class ;
2012-01-07 15:47:21 +01:00
__module_get ( THIS_MODULE ) ;
2011-10-08 14:58:47 +02:00
device_initialize ( dev ) ;
}
2005-04-16 15:20:36 -07:00
int __init bt_sysfs_init ( void )
{
2006-07-03 10:02:41 +02:00
bt_class = class_create ( THIS_MODULE , " bluetooth " ) ;
2006-07-03 10:02:37 +02:00
2013-07-15 11:20:32 +09:30
return PTR_ERR_OR_ZERO ( bt_class ) ;
2005-04-16 15:20:36 -07:00
}
2006-09-28 15:29:37 -07:00
void bt_sysfs_cleanup ( void )
2005-04-16 15:20:36 -07:00
{
2006-07-03 10:02:41 +02:00
class_destroy ( bt_class ) ;
2005-04-16 15:20:36 -07:00
}