2005-04-17 02:20:36 +04:00
/*
* drivers / usb / core / sysfs . c
*
* ( C ) Copyright 2002 David Brownell
* ( C ) Copyright 2002 , 2004 Greg Kroah - Hartman
* ( C ) Copyright 2002 , 2004 IBM Corp .
*
* All of the sysfs file attributes for usb devices and interfaces .
*
*/
# include <linux/kernel.h>
2007-03-20 21:59:39 +03:00
# include <linux/string.h>
2005-04-17 02:20:36 +04:00
# include <linux/usb.h>
2009-03-18 21:28:53 +03:00
# include <linux/usb/quirks.h>
2005-04-17 02:20:36 +04:00
# include "usb.h"
/* Active configuration fields */
2012-12-18 18:25:46 +04:00
# define usb_actconfig_show(field, format_string) \
2007-01-23 23:55:28 +03:00
static ssize_t show_ # # field ( struct device * dev , \
2005-10-24 23:36:00 +04:00
struct device_attribute * attr , char * buf ) \
2005-04-17 02:20:36 +04:00
{ \
struct usb_device * udev ; \
struct usb_host_config * actconfig ; \
\
2007-01-23 23:55:28 +03:00
udev = to_usb_device ( dev ) ; \
2005-04-17 02:20:36 +04:00
actconfig = udev - > actconfig ; \
if ( actconfig ) \
2007-01-23 23:55:28 +03:00
return sprintf ( buf , format_string , \
2012-12-18 18:25:46 +04:00
actconfig - > desc . field ) ; \
2005-04-17 02:20:36 +04:00
else \
return 0 ; \
} \
2012-12-18 18:25:46 +04:00
# define usb_actconfig_attr(field, format_string) \
usb_actconfig_show ( field , format_string ) \
static DEVICE_ATTR ( field , S_IRUGO , show_ # # field , NULL ) ;
2005-04-17 02:20:36 +04:00
2012-12-18 18:25:46 +04:00
usb_actconfig_attr ( bNumInterfaces , " %2d \n " )
usb_actconfig_attr ( bmAttributes , " %2x \n " )
static ssize_t show_bMaxPower ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct usb_device * udev ;
struct usb_host_config * actconfig ;
udev = to_usb_device ( dev ) ;
actconfig = udev - > actconfig ;
if ( ! actconfig )
return 0 ;
return sprintf ( buf , " %dmA \n " , usb_get_max_power ( udev , actconfig ) ) ;
}
static DEVICE_ATTR ( bMaxPower , S_IRUGO , show_bMaxPower , NULL ) ;
2005-04-17 02:20:36 +04:00
2005-10-24 23:36:00 +04:00
static ssize_t show_configuration_string ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct usb_device * udev ;
struct usb_host_config * actconfig ;
2007-01-23 23:55:28 +03:00
udev = to_usb_device ( dev ) ;
2005-04-17 02:20:36 +04:00
actconfig = udev - > actconfig ;
if ( ( ! actconfig ) | | ( ! actconfig - > string ) )
return 0 ;
2005-10-25 00:24:14 +04:00
return sprintf ( buf , " %s \n " , actconfig - > string ) ;
2005-04-17 02:20:36 +04:00
}
static DEVICE_ATTR ( configuration , S_IRUGO , show_configuration_string , NULL ) ;
/* configuration value is always present, and r/w */
2012-12-18 18:25:46 +04:00
usb_actconfig_show ( bConfigurationValue , " %u \n " ) ;
2005-04-17 02:20:36 +04:00
static ssize_t
2007-01-23 23:55:28 +03:00
set_bConfigurationValue ( struct device * dev , struct device_attribute * attr ,
2005-10-24 23:36:00 +04:00
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2007-01-23 23:55:28 +03:00
struct usb_device * udev = to_usb_device ( dev ) ;
2005-04-17 02:20:36 +04:00
int config , value ;
2007-02-09 00:40:43 +03:00
if ( sscanf ( buf , " %d " , & config ) ! = 1 | | config < - 1 | | config > 255 )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
usb_lock_device ( udev ) ;
2007-01-23 23:55:28 +03:00
value = usb_set_configuration ( udev , config ) ;
2005-04-17 02:20:36 +04:00
usb_unlock_device ( udev ) ;
return ( value < 0 ) ? value : count ;
}
2012-05-14 21:30:03 +04:00
static DEVICE_ATTR_IGNORE_LOCKDEP ( bConfigurationValue , S_IRUGO | S_IWUSR ,
2005-04-17 02:20:36 +04:00
show_bConfigurationValue , set_bConfigurationValue ) ;
/* String fields */
# define usb_string_attr(name) \
2005-10-24 23:36:00 +04:00
static ssize_t show_ # # name ( struct device * dev , \
struct device_attribute * attr , char * buf ) \
2005-04-17 02:20:36 +04:00
{ \
struct usb_device * udev ; \
2009-12-08 23:54:44 +03:00
int retval ; \
2005-04-17 02:20:36 +04:00
\
2007-01-23 23:55:28 +03:00
udev = to_usb_device ( dev ) ; \
2009-12-08 23:54:44 +03:00
usb_lock_device ( udev ) ; \
retval = sprintf ( buf , " %s \n " , udev - > name ) ; \
usb_unlock_device ( udev ) ; \
return retval ; \
2005-04-17 02:20:36 +04:00
} \
static DEVICE_ATTR ( name , S_IRUGO , show_ # # name , NULL ) ;
usb_string_attr ( product ) ;
usb_string_attr ( manufacturer ) ;
usb_string_attr ( serial ) ;
static ssize_t
2007-01-23 23:55:28 +03:00
show_speed ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct usb_device * udev ;
char * speed ;
2007-01-23 23:55:28 +03:00
udev = to_usb_device ( dev ) ;
2005-04-17 02:20:36 +04:00
switch ( udev - > speed ) {
case USB_SPEED_LOW :
speed = " 1.5 " ;
break ;
case USB_SPEED_UNKNOWN :
case USB_SPEED_FULL :
speed = " 12 " ;
break ;
case USB_SPEED_HIGH :
speed = " 480 " ;
break ;
2010-01-14 22:08:04 +03:00
case USB_SPEED_WIRELESS :
2010-01-14 21:33:19 +03:00
speed = " 480 " ;
break ;
case USB_SPEED_SUPER :
speed = " 5000 " ;
break ;
2005-04-17 02:20:36 +04:00
default :
speed = " unknown " ;
}
2007-01-23 23:55:28 +03:00
return sprintf ( buf , " %s \n " , speed ) ;
2005-04-17 02:20:36 +04:00
}
static DEVICE_ATTR ( speed , S_IRUGO , show_speed , NULL ) ;
2007-04-25 23:15:43 +04:00
static ssize_t
show_busnum ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct usb_device * udev ;
udev = to_usb_device ( dev ) ;
return sprintf ( buf , " %d \n " , udev - > bus - > busnum ) ;
}
static DEVICE_ATTR ( busnum , S_IRUGO , show_busnum , NULL ) ;
2005-04-17 02:20:36 +04:00
static ssize_t
2007-01-23 23:55:28 +03:00
show_devnum ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct usb_device * udev ;
2007-01-23 23:55:28 +03:00
udev = to_usb_device ( dev ) ;
return sprintf ( buf , " %d \n " , udev - > devnum ) ;
2005-04-17 02:20:36 +04:00
}
static DEVICE_ATTR ( devnum , S_IRUGO , show_devnum , NULL ) ;
2009-11-30 22:15:02 +03:00
static ssize_t
show_devpath ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct usb_device * udev ;
udev = to_usb_device ( dev ) ;
return sprintf ( buf , " %s \n " , udev - > devpath ) ;
}
static DEVICE_ATTR ( devpath , S_IRUGO , show_devpath , NULL ) ;
2005-04-17 02:20:36 +04:00
static ssize_t
2007-01-23 23:55:28 +03:00
show_version ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct usb_device * udev ;
u16 bcdUSB ;
udev = to_usb_device ( dev ) ;
bcdUSB = le16_to_cpu ( udev - > descriptor . bcdUSB ) ;
return sprintf ( buf , " %2x.%02x \n " , bcdUSB > > 8 , bcdUSB & 0xff ) ;
}
static DEVICE_ATTR ( version , S_IRUGO , show_version , NULL ) ;
static ssize_t
2007-01-23 23:55:28 +03:00
show_maxchild ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct usb_device * udev ;
2007-01-23 23:55:28 +03:00
udev = to_usb_device ( dev ) ;
return sprintf ( buf , " %d \n " , udev - > maxchild ) ;
2005-04-17 02:20:36 +04:00
}
static DEVICE_ATTR ( maxchild , S_IRUGO , show_maxchild , NULL ) ;
2007-01-26 16:26:21 +03:00
static ssize_t
show_quirks ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct usb_device * udev ;
udev = to_usb_device ( dev ) ;
return sprintf ( buf , " 0x%x \n " , udev - > quirks ) ;
}
static DEVICE_ATTR ( quirks , S_IRUGO , show_quirks , NULL ) ;
2010-01-16 03:33:03 +03:00
static ssize_t
show_avoid_reset_quirk ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct usb_device * udev ;
udev = to_usb_device ( dev ) ;
2012-08-17 12:44:56 +04:00
return sprintf ( buf , " %d \n " , ! ! ( udev - > quirks & USB_QUIRK_RESET ) ) ;
2010-01-16 03:33:03 +03:00
}
static ssize_t
set_avoid_reset_quirk ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct usb_device * udev = to_usb_device ( dev ) ;
2012-08-03 12:30:35 +04:00
int val ;
2010-01-16 03:33:03 +03:00
2012-08-03 12:30:35 +04:00
if ( sscanf ( buf , " %d " , & val ) ! = 1 | | val < 0 | | val > 1 )
2010-01-16 03:33:03 +03:00
return - EINVAL ;
usb_lock_device ( udev ) ;
2012-08-03 12:30:35 +04:00
if ( val )
2012-08-17 12:44:56 +04:00
udev - > quirks | = USB_QUIRK_RESET ;
2010-01-16 03:33:03 +03:00
else
2012-08-17 12:44:56 +04:00
udev - > quirks & = ~ USB_QUIRK_RESET ;
2010-01-16 03:33:03 +03:00
usb_unlock_device ( udev ) ;
return count ;
}
static DEVICE_ATTR ( avoid_reset_quirk , S_IRUGO | S_IWUSR ,
show_avoid_reset_quirk , set_avoid_reset_quirk ) ;
2007-10-04 01:56:03 +04:00
static ssize_t
show_urbnum ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct usb_device * udev ;
udev = to_usb_device ( dev ) ;
return sprintf ( buf , " %d \n " , atomic_read ( & udev - > urbnum ) ) ;
}
static DEVICE_ATTR ( urbnum , S_IRUGO , show_urbnum , NULL ) ;
2012-02-04 02:11:54 +04:00
static ssize_t
show_removable ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct usb_device * udev ;
char * state ;
udev = to_usb_device ( dev ) ;
switch ( udev - > removable ) {
case USB_DEVICE_REMOVABLE :
state = " removable " ;
break ;
case USB_DEVICE_FIXED :
state = " fixed " ;
break ;
default :
state = " unknown " ;
}
return sprintf ( buf , " %s \n " , state ) ;
}
static DEVICE_ATTR ( removable , S_IRUGO , show_removable , NULL ) ;
2007-05-30 23:39:33 +04:00
2012-07-06 04:17:24 +04:00
static ssize_t
show_ltm_capable ( struct device * dev , struct device_attribute * attr , char * buf )
{
if ( usb_device_supports_ltm ( to_usb_device ( dev ) ) )
return sprintf ( buf , " %s \n " , " yes " ) ;
return sprintf ( buf , " %s \n " , " no " ) ;
}
static DEVICE_ATTR ( ltm_capable , S_IRUGO , show_ltm_capable , NULL ) ;
2008-03-03 23:15:59 +03:00
# ifdef CONFIG_PM
2007-05-30 23:39:33 +04:00
static ssize_t
show_persist ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct usb_device * udev = to_usb_device ( dev ) ;
return sprintf ( buf , " %d \n " , udev - > persist_enabled ) ;
}
static ssize_t
set_persist ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct usb_device * udev = to_usb_device ( dev ) ;
int value ;
/* Hubs are always enabled for USB_PERSIST */
if ( udev - > descriptor . bDeviceClass = = USB_CLASS_HUB )
return - EPERM ;
if ( sscanf ( buf , " %d " , & value ) ! = 1 )
return - EINVAL ;
2010-01-08 20:56:42 +03:00
usb_lock_device ( udev ) ;
2007-05-30 23:39:33 +04:00
udev - > persist_enabled = ! ! value ;
2010-01-08 20:56:42 +03:00
usb_unlock_device ( udev ) ;
2007-05-30 23:39:33 +04:00
return count ;
}
static DEVICE_ATTR ( persist , S_IRUGO | S_IWUSR , show_persist , set_persist ) ;
static int add_persist_attributes ( struct device * dev )
{
int rc = 0 ;
if ( is_usb_device ( dev ) ) {
struct usb_device * udev = to_usb_device ( dev ) ;
2008-03-03 23:15:59 +03:00
/* Hubs are automatically enabled for USB_PERSIST,
* no point in creating the attribute file .
*/
if ( udev - > descriptor . bDeviceClass ! = USB_CLASS_HUB )
rc = sysfs_add_file_to_group ( & dev - > kobj ,
& dev_attr_persist . attr ,
2010-11-15 23:57:07 +03:00
power_group_name ) ;
2007-05-30 23:39:33 +04:00
}
return rc ;
}
static void remove_persist_attributes ( struct device * dev )
{
sysfs_remove_file_from_group ( & dev - > kobj ,
& dev_attr_persist . attr ,
2010-11-15 23:57:07 +03:00
power_group_name ) ;
2007-05-30 23:39:33 +04:00
}
# else
# define add_persist_attributes(dev) 0
# define remove_persist_attributes(dev) do {} while (0)
2008-03-03 23:15:59 +03:00
# endif /* CONFIG_PM */
2007-05-30 23:39:33 +04:00
2013-03-28 00:14:46 +04:00
# ifdef CONFIG_PM_RUNTIME
2007-02-20 23:03:32 +03:00
2007-12-22 03:54:15 +03:00
static ssize_t
show_connected_duration ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct usb_device * udev = to_usb_device ( dev ) ;
return sprintf ( buf , " %u \n " ,
jiffies_to_msecs ( jiffies - udev - > connect_time ) ) ;
}
static DEVICE_ATTR ( connected_duration , S_IRUGO , show_connected_duration , NULL ) ;
/*
* If the device is resumed , the last time the device was suspended has
* been pre - subtracted from active_duration . We add the current time to
* get the duration that the device was actually active .
*
* If the device is suspended , the active_duration is up - to - date .
*/
static ssize_t
show_active_duration ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct usb_device * udev = to_usb_device ( dev ) ;
int duration ;
if ( udev - > state ! = USB_STATE_SUSPENDED )
duration = jiffies_to_msecs ( jiffies + udev - > active_duration ) ;
else
duration = jiffies_to_msecs ( udev - > active_duration ) ;
return sprintf ( buf , " %u \n " , duration ) ;
}
static DEVICE_ATTR ( active_duration , S_IRUGO , show_active_duration , NULL ) ;
2007-02-20 23:03:32 +03:00
static ssize_t
show_autosuspend ( struct device * dev , struct device_attribute * attr , char * buf )
{
2010-11-15 23:57:51 +03:00
return sprintf ( buf , " %d \n " , dev - > power . autosuspend_delay / 1000 ) ;
2007-02-20 23:03:32 +03:00
}
static ssize_t
set_autosuspend ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
2010-11-15 23:57:51 +03:00
int value ;
2007-02-20 23:03:32 +03:00
2010-11-15 23:57:51 +03:00
if ( sscanf ( buf , " %d " , & value ) ! = 1 | | value > = INT_MAX / 1000 | |
value < = - INT_MAX / 1000 )
2007-02-20 23:03:32 +03:00
return - EINVAL ;
2010-11-15 23:57:51 +03:00
pm_runtime_set_autosuspend_delay ( dev , value * 1000 ) ;
2007-02-20 23:03:32 +03:00
return count ;
}
static DEVICE_ATTR ( autosuspend , S_IRUGO | S_IWUSR ,
show_autosuspend , set_autosuspend ) ;
2007-03-20 21:59:39 +03:00
static const char on_string [ ] = " on " ;
static const char auto_string [ ] = " auto " ;
2010-04-02 21:22:16 +04:00
static void warn_level ( void ) {
static int level_warned ;
if ( ! level_warned ) {
level_warned = 1 ;
printk ( KERN_WARNING " WARNING! power/level is deprecated; "
" use power/control instead \n " ) ;
}
}
2007-03-20 21:59:39 +03:00
static ssize_t
show_level ( struct device * dev , struct device_attribute * attr , char * buf )
{
struct usb_device * udev = to_usb_device ( dev ) ;
const char * p = auto_string ;
2010-04-02 21:22:16 +04:00
warn_level ( ) ;
2010-04-02 21:22:09 +04:00
if ( udev - > state ! = USB_STATE_SUSPENDED & & ! udev - > dev . power . runtime_auto )
2009-12-07 21:01:37 +03:00
p = on_string ;
2007-03-20 21:59:39 +03:00
return sprintf ( buf , " %s \n " , p ) ;
}
static ssize_t
set_level ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct usb_device * udev = to_usb_device ( dev ) ;
int len = count ;
char * cp ;
2010-04-02 21:22:09 +04:00
int rc = count ;
2007-03-20 21:59:39 +03:00
2010-04-02 21:22:16 +04:00
warn_level ( ) ;
2007-03-20 21:59:39 +03:00
cp = memchr ( buf , ' \n ' , count ) ;
if ( cp )
len = cp - buf ;
usb_lock_device ( udev ) ;
if ( len = = sizeof on_string - 1 & &
2010-01-08 20:56:54 +03:00
strncmp ( buf , on_string , len ) = = 0 )
2010-04-02 21:22:09 +04:00
usb_disable_autosuspend ( udev ) ;
2007-03-20 21:59:39 +03:00
2010-01-08 20:56:54 +03:00
else if ( len = = sizeof auto_string - 1 & &
strncmp ( buf , auto_string , len ) = = 0 )
2010-04-02 21:22:09 +04:00
usb_enable_autosuspend ( udev ) ;
2007-03-20 21:59:39 +03:00
2010-01-08 20:56:54 +03:00
else
2007-03-20 21:59:39 +03:00
rc = - EINVAL ;
usb_unlock_device ( udev ) ;
2010-04-02 21:22:09 +04:00
return rc ;
2007-03-20 21:59:39 +03:00
}
static DEVICE_ATTR ( level , S_IRUGO | S_IWUSR , show_level , set_level ) ;
2011-09-24 01:19:53 +04:00
static ssize_t
show_usb2_hardware_lpm ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct usb_device * udev = to_usb_device ( dev ) ;
const char * p ;
if ( udev - > usb2_hw_lpm_enabled = = 1 )
p = " enabled " ;
else
p = " disabled " ;
return sprintf ( buf , " %s \n " , p ) ;
}
static ssize_t
set_usb2_hardware_lpm ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct usb_device * udev = to_usb_device ( dev ) ;
bool value ;
int ret ;
usb_lock_device ( udev ) ;
ret = strtobool ( buf , & value ) ;
if ( ! ret )
ret = usb_set_usb2_hardware_lpm ( udev , value ) ;
usb_unlock_device ( udev ) ;
if ( ! ret )
return count ;
return ret ;
}
static DEVICE_ATTR ( usb2_hardware_lpm , S_IRUGO | S_IWUSR , show_usb2_hardware_lpm ,
set_usb2_hardware_lpm ) ;
static struct attribute * usb2_hardware_lpm_attr [ ] = {
& dev_attr_usb2_hardware_lpm . attr ,
NULL ,
} ;
static struct attribute_group usb2_hardware_lpm_attr_group = {
. name = power_group_name ,
. attrs = usb2_hardware_lpm_attr ,
} ;
2010-11-15 23:57:07 +03:00
static struct attribute * power_attrs [ ] = {
& dev_attr_autosuspend . attr ,
& dev_attr_level . attr ,
& dev_attr_connected_duration . attr ,
& dev_attr_active_duration . attr ,
NULL ,
} ;
static struct attribute_group power_attr_group = {
. name = power_group_name ,
. attrs = power_attrs ,
} ;
2007-02-20 23:03:32 +03:00
static int add_power_attributes ( struct device * dev )
{
int rc = 0 ;
2011-09-24 01:19:53 +04:00
if ( is_usb_device ( dev ) ) {
struct usb_device * udev = to_usb_device ( dev ) ;
2010-11-15 23:57:07 +03:00
rc = sysfs_merge_group ( & dev - > kobj , & power_attr_group ) ;
2011-09-24 01:19:53 +04:00
if ( udev - > usb2_hw_lpm_capable = = 1 )
rc = sysfs_merge_group ( & dev - > kobj ,
& usb2_hardware_lpm_attr_group ) ;
}
2007-02-20 23:03:32 +03:00
return rc ;
}
static void remove_power_attributes ( struct device * dev )
{
2011-09-24 01:19:53 +04:00
sysfs_unmerge_group ( & dev - > kobj , & usb2_hardware_lpm_attr_group ) ;
2010-11-15 23:57:07 +03:00
sysfs_unmerge_group ( & dev - > kobj , & power_attr_group ) ;
2007-02-20 23:03:32 +03:00
}
# else
# define add_power_attributes(dev) 0
# define remove_power_attributes(dev) do {} while (0)
2013-03-28 00:14:46 +04:00
# endif /* CONFIG_PM_RUNTIME */
2007-02-20 23:03:32 +03:00
2007-05-30 23:39:33 +04:00
2005-04-17 02:20:36 +04:00
/* Descriptor fields */
# define usb_descriptor_attr_le16(field, format_string) \
static ssize_t \
2007-01-23 23:55:28 +03:00
show_ # # field ( struct device * dev , struct device_attribute * attr , \
2005-10-24 23:36:00 +04:00
char * buf ) \
2005-04-17 02:20:36 +04:00
{ \
struct usb_device * udev ; \
\
2007-01-23 23:55:28 +03:00
udev = to_usb_device ( dev ) ; \
return sprintf ( buf , format_string , \
2005-04-17 02:20:36 +04:00
le16_to_cpu ( udev - > descriptor . field ) ) ; \
} \
static DEVICE_ATTR ( field , S_IRUGO , show_ # # field , NULL ) ;
usb_descriptor_attr_le16 ( idVendor , " %04x \n " )
usb_descriptor_attr_le16 ( idProduct , " %04x \n " )
usb_descriptor_attr_le16 ( bcdDevice , " %04x \n " )
# define usb_descriptor_attr(field, format_string) \
static ssize_t \
2007-01-23 23:55:28 +03:00
show_ # # field ( struct device * dev , struct device_attribute * attr , \
2005-10-24 23:36:00 +04:00
char * buf ) \
2005-04-17 02:20:36 +04:00
{ \
struct usb_device * udev ; \
\
2007-01-23 23:55:28 +03:00
udev = to_usb_device ( dev ) ; \
return sprintf ( buf , format_string , udev - > descriptor . field ) ; \
2005-04-17 02:20:36 +04:00
} \
static DEVICE_ATTR ( field , S_IRUGO , show_ # # field , NULL ) ;
2007-01-23 23:55:28 +03:00
usb_descriptor_attr ( bDeviceClass , " %02x \n " )
usb_descriptor_attr ( bDeviceSubClass , " %02x \n " )
usb_descriptor_attr ( bDeviceProtocol , " %02x \n " )
usb_descriptor_attr ( bNumConfigurations , " %d \n " )
usb_descriptor_attr ( bMaxPacketSize0 , " %d \n " )
2005-04-17 02:20:36 +04:00
2007-08-01 07:34:07 +04:00
/* show if the device is authorized (1) or not (0) */
static ssize_t usb_dev_authorized_show ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct usb_device * usb_dev = to_usb_device ( dev ) ;
return snprintf ( buf , PAGE_SIZE , " %u \n " , usb_dev - > authorized ) ;
}
/*
* Authorize a device to be used in the system
*
* Writing a 0 deauthorizes the device , writing a 1 authorizes it .
*/
static ssize_t usb_dev_authorized_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t size )
{
ssize_t result ;
struct usb_device * usb_dev = to_usb_device ( dev ) ;
unsigned val ;
result = sscanf ( buf , " %u \n " , & val ) ;
if ( result ! = 1 )
result = - EINVAL ;
else if ( val = = 0 )
result = usb_deauthorize_device ( usb_dev ) ;
else
result = usb_authorize_device ( usb_dev ) ;
return result < 0 ? result : size ;
}
2012-05-14 21:30:03 +04:00
static DEVICE_ATTR_IGNORE_LOCKDEP ( authorized , 0644 ,
2007-08-01 07:34:07 +04:00
usb_dev_authorized_show , usb_dev_authorized_store ) ;
2009-10-27 22:20:13 +03:00
/* "Safely remove a device" */
static ssize_t usb_remove_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
struct usb_device * udev = to_usb_device ( dev ) ;
int rc = 0 ;
usb_lock_device ( udev ) ;
if ( udev - > state ! = USB_STATE_NOTATTACHED ) {
/* To avoid races, first unconfigure and then remove */
usb_set_configuration ( udev , - 1 ) ;
rc = usb_remove_device ( udev ) ;
}
if ( rc = = 0 )
rc = count ;
usb_unlock_device ( udev ) ;
return rc ;
}
2012-05-14 21:30:03 +04:00
static DEVICE_ATTR_IGNORE_LOCKDEP ( remove , 0200 , NULL , usb_remove_store ) ;
2009-10-27 22:20:13 +03:00
2007-08-01 07:34:07 +04:00
2005-04-17 02:20:36 +04:00
static struct attribute * dev_attrs [ ] = {
/* current configuration's attributes */
2006-07-06 23:37:42 +04:00
& dev_attr_configuration . attr ,
2005-04-17 02:20:36 +04:00
& dev_attr_bNumInterfaces . attr ,
& dev_attr_bConfigurationValue . attr ,
& dev_attr_bmAttributes . attr ,
& dev_attr_bMaxPower . attr ,
/* device attributes */
2009-11-30 22:15:02 +03:00
& dev_attr_urbnum . attr ,
2005-04-17 02:20:36 +04:00
& dev_attr_idVendor . attr ,
& dev_attr_idProduct . attr ,
& dev_attr_bcdDevice . attr ,
& dev_attr_bDeviceClass . attr ,
& dev_attr_bDeviceSubClass . attr ,
& dev_attr_bDeviceProtocol . attr ,
& dev_attr_bNumConfigurations . attr ,
2005-06-30 03:53:29 +04:00
& dev_attr_bMaxPacketSize0 . attr ,
2005-04-17 02:20:36 +04:00
& dev_attr_speed . attr ,
2007-04-25 23:15:43 +04:00
& dev_attr_busnum . attr ,
2005-04-17 02:20:36 +04:00
& dev_attr_devnum . attr ,
2009-11-30 22:15:02 +03:00
& dev_attr_devpath . attr ,
2005-04-17 02:20:36 +04:00
& dev_attr_version . attr ,
& dev_attr_maxchild . attr ,
2007-01-26 16:26:21 +03:00
& dev_attr_quirks . attr ,
2010-01-16 03:33:03 +03:00
& dev_attr_avoid_reset_quirk . attr ,
2007-08-01 07:34:07 +04:00
& dev_attr_authorized . attr ,
2009-10-27 22:20:13 +03:00
& dev_attr_remove . attr ,
2012-02-04 02:11:54 +04:00
& dev_attr_removable . attr ,
2012-07-06 04:17:24 +04:00
& dev_attr_ltm_capable . attr ,
2005-04-17 02:20:36 +04:00
NULL ,
} ;
static struct attribute_group dev_attr_grp = {
. attrs = dev_attrs ,
} ;
2008-04-30 23:37:19 +04:00
/* When modifying this list, be sure to modify dev_string_attrs_are_visible()
* accordingly .
*/
static struct attribute * dev_string_attrs [ ] = {
& dev_attr_manufacturer . attr ,
& dev_attr_product . attr ,
& dev_attr_serial . attr ,
NULL
} ;
2011-07-24 07:11:19 +04:00
static umode_t dev_string_attrs_are_visible ( struct kobject * kobj ,
2008-04-30 23:37:19 +04:00
struct attribute * a , int n )
{
2009-04-16 05:34:40 +04:00
struct device * dev = container_of ( kobj , struct device , kobj ) ;
struct usb_device * udev = to_usb_device ( dev ) ;
2008-04-30 23:37:19 +04:00
if ( a = = & dev_attr_manufacturer . attr ) {
if ( udev - > manufacturer = = NULL )
return 0 ;
} else if ( a = = & dev_attr_product . attr ) {
if ( udev - > product = = NULL )
return 0 ;
} else if ( a = = & dev_attr_serial . attr ) {
if ( udev - > serial = = NULL )
return 0 ;
}
return a - > mode ;
}
static struct attribute_group dev_string_attr_grp = {
. attrs = dev_string_attrs ,
. is_visible = dev_string_attrs_are_visible ,
} ;
2009-06-24 21:06:31 +04:00
const struct attribute_group * usb_device_groups [ ] = {
2008-04-30 23:37:19 +04:00
& dev_attr_grp ,
& dev_string_attr_grp ,
NULL
} ;
2007-07-13 01:06:23 +04:00
/* Binary descriptors */
static ssize_t
2010-05-13 05:28:57 +04:00
read_descriptors ( struct file * filp , struct kobject * kobj ,
struct bin_attribute * attr ,
2007-07-13 01:06:23 +04:00
char * buf , loff_t off , size_t count )
{
2009-04-16 05:34:40 +04:00
struct device * dev = container_of ( kobj , struct device , kobj ) ;
struct usb_device * udev = to_usb_device ( dev ) ;
2007-07-13 01:06:23 +04:00
size_t nleft = count ;
size_t srclen , n ;
2008-05-21 00:40:42 +04:00
int cfgno ;
void * src ;
2007-07-13 01:06:23 +04:00
2008-05-21 00:40:42 +04:00
/* The binary attribute begins with the device descriptor.
* Following that are the raw descriptor entries for all the
* configurations ( config plus subsidiary descriptors ) .
2007-07-13 01:06:23 +04:00
*/
2008-05-21 00:40:42 +04:00
for ( cfgno = - 1 ; cfgno < udev - > descriptor . bNumConfigurations & &
nleft > 0 ; + + cfgno ) {
if ( cfgno < 0 ) {
src = & udev - > descriptor ;
srclen = sizeof ( struct usb_device_descriptor ) ;
} else {
src = udev - > rawdescriptors [ cfgno ] ;
srclen = __le16_to_cpu ( udev - > config [ cfgno ] . desc .
wTotalLength ) ;
}
2007-07-13 01:06:23 +04:00
if ( off < srclen ) {
2008-05-21 00:40:42 +04:00
n = min ( nleft , srclen - ( size_t ) off ) ;
memcpy ( buf , src + off , n ) ;
2007-07-13 01:06:23 +04:00
nleft - = n ;
2008-05-21 00:40:42 +04:00
buf + = n ;
off = 0 ;
} else {
off - = srclen ;
2007-07-13 01:06:23 +04:00
}
}
return count - nleft ;
}
static struct bin_attribute dev_bin_attr_descriptors = {
. attr = { . name = " descriptors " , . mode = 0444 } ,
. read = read_descriptors ,
. size = 18 + 65535 , /* dev descr + max-size raw descriptor */
} ;
2006-08-28 22:43:25 +04:00
int usb_create_sysfs_dev_files ( struct usb_device * udev )
2005-04-17 02:20:36 +04:00
{
struct device * dev = & udev - > dev ;
2006-08-28 22:43:25 +04:00
int retval ;
2005-04-17 02:20:36 +04:00
2007-07-13 01:06:23 +04:00
retval = device_create_bin_file ( dev , & dev_bin_attr_descriptors ) ;
if ( retval )
goto error ;
2007-05-30 23:39:33 +04:00
retval = add_persist_attributes ( dev ) ;
if ( retval )
goto error ;
2007-02-20 23:03:32 +03:00
retval = add_power_attributes ( dev ) ;
if ( retval )
goto error ;
2008-12-05 22:10:34 +03:00
return retval ;
2006-08-28 22:43:25 +04:00
error :
2007-02-20 22:59:59 +03:00
usb_remove_sysfs_dev_files ( udev ) ;
2006-08-28 22:43:25 +04:00
return retval ;
2005-04-17 02:20:36 +04:00
}
2007-01-23 23:55:28 +03:00
void usb_remove_sysfs_dev_files ( struct usb_device * udev )
2005-04-17 02:20:36 +04:00
{
struct device * dev = & udev - > dev ;
2007-02-20 23:03:32 +03:00
remove_power_attributes ( dev ) ;
2007-05-30 23:39:33 +04:00
remove_persist_attributes ( dev ) ;
2007-07-13 01:06:23 +04:00
device_remove_bin_file ( dev , & dev_bin_attr_descriptors ) ;
2005-04-17 02:20:36 +04:00
}
2007-06-16 07:14:35 +04:00
/* Interface Accociation Descriptor fields */
# define usb_intf_assoc_attr(field, format_string) \
static ssize_t \
2008-01-31 02:21:33 +03:00
show_iad_ # # field ( struct device * dev , struct device_attribute * attr , \
2007-06-16 07:14:35 +04:00
char * buf ) \
{ \
2008-01-31 02:21:33 +03:00
struct usb_interface * intf = to_usb_interface ( dev ) ; \
2007-06-16 07:14:35 +04:00
\
2008-01-31 02:21:33 +03:00
return sprintf ( buf , format_string , \
intf - > intf_assoc - > field ) ; \
2007-06-16 07:14:35 +04:00
} \
static DEVICE_ATTR ( iad_ # # field , S_IRUGO , show_iad_ # # field , NULL ) ;
2008-01-31 02:21:33 +03:00
usb_intf_assoc_attr ( bFirstInterface , " %02x \n " )
usb_intf_assoc_attr ( bInterfaceCount , " %02d \n " )
usb_intf_assoc_attr ( bFunctionClass , " %02x \n " )
usb_intf_assoc_attr ( bFunctionSubClass , " %02x \n " )
usb_intf_assoc_attr ( bFunctionProtocol , " %02x \n " )
2007-06-16 07:14:35 +04:00
2005-04-17 02:20:36 +04:00
/* Interface fields */
# define usb_intf_attr(field, format_string) \
static ssize_t \
2007-01-23 23:55:28 +03:00
show_ # # field ( struct device * dev , struct device_attribute * attr , \
2005-10-24 23:36:00 +04:00
char * buf ) \
2005-04-17 02:20:36 +04:00
{ \
2007-01-23 23:55:28 +03:00
struct usb_interface * intf = to_usb_interface ( dev ) ; \
2005-04-17 02:20:36 +04:00
\
2007-01-23 23:55:28 +03:00
return sprintf ( buf , format_string , \
2005-10-24 23:36:00 +04:00
intf - > cur_altsetting - > desc . field ) ; \
2005-04-17 02:20:36 +04:00
} \
static DEVICE_ATTR ( field , S_IRUGO , show_ # # field , NULL ) ;
2007-01-23 23:55:28 +03:00
usb_intf_attr ( bInterfaceNumber , " %02x \n " )
usb_intf_attr ( bAlternateSetting , " %2d \n " )
usb_intf_attr ( bNumEndpoints , " %02x \n " )
usb_intf_attr ( bInterfaceClass , " %02x \n " )
usb_intf_attr ( bInterfaceSubClass , " %02x \n " )
usb_intf_attr ( bInterfaceProtocol , " %02x \n " )
2005-04-17 02:20:36 +04:00
2005-10-24 23:36:00 +04:00
static ssize_t show_interface_string ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct usb_interface * intf ;
2008-04-30 23:37:19 +04:00
char * string ;
2005-04-17 02:20:36 +04:00
2007-01-23 23:55:28 +03:00
intf = to_usb_interface ( dev ) ;
2008-04-30 23:37:19 +04:00
string = intf - > cur_altsetting - > string ;
barrier ( ) ; /* The altsetting might change! */
if ( ! string )
2005-04-17 02:20:36 +04:00
return 0 ;
2008-04-30 23:37:19 +04:00
return sprintf ( buf , " %s \n " , string ) ;
2005-04-17 02:20:36 +04:00
}
static DEVICE_ATTR ( interface , S_IRUGO , show_interface_string , NULL ) ;
2005-10-24 23:36:00 +04:00
static ssize_t show_modalias ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-05-10 17:45:10 +04:00
{
struct usb_interface * intf ;
struct usb_device * udev ;
2005-06-21 08:15:16 +04:00
struct usb_host_interface * alt ;
2005-05-10 17:45:10 +04:00
intf = to_usb_interface ( dev ) ;
udev = interface_to_usbdev ( intf ) ;
2005-06-21 08:15:16 +04:00
alt = intf - > cur_altsetting ;
return sprintf ( buf , " usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X "
2012-05-18 23:27:43 +04:00
" ic%02Xisc%02Xip%02Xin%02X \n " ,
2005-06-21 08:15:16 +04:00
le16_to_cpu ( udev - > descriptor . idVendor ) ,
le16_to_cpu ( udev - > descriptor . idProduct ) ,
le16_to_cpu ( udev - > descriptor . bcdDevice ) ,
udev - > descriptor . bDeviceClass ,
udev - > descriptor . bDeviceSubClass ,
udev - > descriptor . bDeviceProtocol ,
alt - > desc . bInterfaceClass ,
alt - > desc . bInterfaceSubClass ,
2012-05-18 23:27:43 +04:00
alt - > desc . bInterfaceProtocol ,
alt - > desc . bInterfaceNumber ) ;
2005-05-10 17:45:10 +04:00
}
static DEVICE_ATTR ( modalias , S_IRUGO , show_modalias , NULL ) ;
2008-10-07 01:45:46 +04:00
static ssize_t show_supports_autosuspend ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct usb_interface * intf ;
struct usb_device * udev ;
int ret ;
intf = to_usb_interface ( dev ) ;
udev = interface_to_usbdev ( intf ) ;
usb_lock_device ( udev ) ;
/* Devices will be autosuspended even when an interface isn't claimed */
if ( ! intf - > dev . driver | |
to_usb_driver ( intf - > dev . driver ) - > supports_autosuspend )
ret = sprintf ( buf , " %u \n " , 1 ) ;
else
ret = sprintf ( buf , " %u \n " , 0 ) ;
usb_unlock_device ( udev ) ;
return ret ;
}
static DEVICE_ATTR ( supports_autosuspend , S_IRUGO , show_supports_autosuspend , NULL ) ;
2005-04-17 02:20:36 +04:00
static struct attribute * intf_attrs [ ] = {
& dev_attr_bInterfaceNumber . attr ,
& dev_attr_bAlternateSetting . attr ,
& dev_attr_bNumEndpoints . attr ,
& dev_attr_bInterfaceClass . attr ,
& dev_attr_bInterfaceSubClass . attr ,
& dev_attr_bInterfaceProtocol . attr ,
2005-05-10 17:45:10 +04:00
& dev_attr_modalias . attr ,
2008-10-07 01:45:46 +04:00
& dev_attr_supports_autosuspend . attr ,
2005-04-17 02:20:36 +04:00
NULL ,
} ;
static struct attribute_group intf_attr_grp = {
. attrs = intf_attrs ,
} ;
2008-04-30 23:37:19 +04:00
static struct attribute * intf_assoc_attrs [ ] = {
& dev_attr_iad_bFirstInterface . attr ,
& dev_attr_iad_bInterfaceCount . attr ,
& dev_attr_iad_bFunctionClass . attr ,
& dev_attr_iad_bFunctionSubClass . attr ,
& dev_attr_iad_bFunctionProtocol . attr ,
NULL ,
} ;
2011-07-24 07:11:19 +04:00
static umode_t intf_assoc_attrs_are_visible ( struct kobject * kobj ,
2008-04-30 23:37:19 +04:00
struct attribute * a , int n )
{
2009-04-16 05:34:40 +04:00
struct device * dev = container_of ( kobj , struct device , kobj ) ;
struct usb_interface * intf = to_usb_interface ( dev ) ;
2008-04-30 23:37:19 +04:00
if ( intf - > intf_assoc = = NULL )
return 0 ;
return a - > mode ;
}
static struct attribute_group intf_assoc_attr_grp = {
. attrs = intf_assoc_attrs ,
. is_visible = intf_assoc_attrs_are_visible ,
} ;
2009-06-24 21:06:31 +04:00
const struct attribute_group * usb_interface_groups [ ] = {
2008-04-30 23:37:19 +04:00
& intf_attr_grp ,
& intf_assoc_attr_grp ,
NULL
} ;
2011-04-14 19:47:09 +04:00
void usb_create_sysfs_intf_files ( struct usb_interface * intf )
2005-04-17 02:20:36 +04:00
{
2005-10-25 00:24:14 +04:00
struct usb_device * udev = interface_to_usbdev ( intf ) ;
struct usb_host_interface * alt = intf - > cur_altsetting ;
2008-10-29 22:16:58 +03:00
if ( intf - > sysfs_files_created | | intf - > unregistering )
2011-04-14 19:47:09 +04:00
return ;
2005-04-17 02:20:36 +04:00
2011-04-14 19:47:09 +04:00
if ( ! alt - > string & & ! ( udev - > quirks & USB_QUIRK_CONFIG_INTF_STRINGS ) )
2005-10-25 00:24:14 +04:00
alt - > string = usb_cache_string ( udev , alt - > desc . iInterface ) ;
2011-04-14 19:47:09 +04:00
if ( alt - > string & & device_create_file ( & intf - > dev , & dev_attr_interface ) )
; /* We don't actually care if the function fails. */
2007-11-06 19:43:42 +03:00
intf - > sysfs_files_created = 1 ;
2005-04-17 02:20:36 +04:00
}
2007-01-23 23:55:28 +03:00
void usb_remove_sysfs_intf_files ( struct usb_interface * intf )
2005-04-17 02:20:36 +04:00
{
2007-11-06 19:43:42 +03:00
if ( ! intf - > sysfs_files_created )
return ;
2008-10-29 22:18:50 +03:00
device_remove_file ( & intf - > dev , & dev_attr_interface ) ;
2007-11-06 19:43:42 +03:00
intf - > sysfs_files_created = 0 ;
2005-04-17 02:20:36 +04:00
}