@ -40,6 +40,7 @@
# endif
struct usb_port {
struct usb_device * child ;
struct device dev ;
struct dev_state * port_owner ;
} ;
@ -181,7 +182,7 @@ static inline char *portspeed(struct usb_hub *hub, int portstatus)
/* Note that hdev or one of its children must be locked! */
static struct usb_hub * hdev_to_hub ( struct usb_device * hdev )
{
if ( ! hdev | | ! hdev - > actconfig )
if ( ! hdev | | ! hdev - > actconfig | | ! hdev - > maxchild )
return NULL ;
return usb_get_intfdata ( hdev - > actconfig - > interface [ 0 ] ) ;
}
@ -876,8 +877,8 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
struct usb_device * hdev = hub - > hdev ;
int ret = 0 ;
if ( hdev - > children [ port1 - 1 ] & & set_state )
usb_set_device_state ( hdev - > children [ port1 - 1 ] ,
if ( hub - > ports [ port1 - 1 ] - > child & & set_state )
usb_set_device_state ( hub - > ports [ port1 - 1 ] - > child ,
USB_STATE_NOTATTACHED ) ;
if ( ! hub - > error & & ! hub_is_superspeed ( hub - > hdev ) )
ret = clear_port_feature ( hdev , port1 , USB_PORT_FEAT_ENABLE ) ;
@ -1033,7 +1034,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
* which ports need attention .
*/
for ( port1 = 1 ; port1 < = hdev - > maxchild ; + + port1 ) {
struct usb_device * udev = hdev - > children [ port1 - 1 ] ;
struct usb_device * udev = hub - > ports [ port1 - 1 ] - > child ;
u16 portstatus , portchange ;
portstatus = portchange = 0 ;
@ -1198,8 +1199,8 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
if ( type ! = HUB_SUSPEND ) {
/* Disconnect all the children */
for ( i = 0 ; i < hdev - > maxchild ; + + i ) {
if ( hdev - > children [ i ] )
usb_disconnect ( & hdev - > children [ i ] ) ;
if ( hub - > ports [ i ] - > child )
usb_disconnect ( & hub - > ports [ i ] - > child ) ;
}
}
@ -1324,11 +1325,9 @@ static int hub_configure(struct usb_hub *hub,
dev_info ( hub_dev , " %d port%s detected \n " , hdev - > maxchild ,
( hdev - > maxchild = = 1 ) ? " " : " s " ) ;
hdev - > children = kzalloc ( hdev - > maxchild *
sizeof ( struct usb_device * ) , GFP_KERNEL ) ;
hub - > ports = kzalloc ( hdev - > maxchild * sizeof ( struct usb_port * ) ,
GFP_KERNEL ) ;
if ( ! hdev - > children | | ! h ub - > ports ) {
if ( ! hub - > ports ) {
ret = - ENOMEM ;
goto fail ;
}
@ -1591,7 +1590,6 @@ static void hub_disconnect(struct usb_interface *intf)
highspeed_hubs - - ;
usb_free_urb ( hub - > urb ) ;
kfree ( hdev - > children ) ;
kfree ( hub - > ports ) ;
kfree ( hub - > descriptor ) ;
kfree ( hub - > status ) ;
@ -1679,6 +1677,7 @@ static int
hub_ioctl ( struct usb_interface * intf , unsigned int code , void * user_data )
{
struct usb_device * hdev = interface_to_usbdev ( intf ) ;
struct usb_hub * hub = hdev_to_hub ( hdev ) ;
/* assert ifno == 0 (part of hub spec) */
switch ( code ) {
@ -1692,11 +1691,11 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
else {
info - > nports = hdev - > maxchild ;
for ( i = 0 ; i < info - > nports ; i + + ) {
if ( hdev - > children [ i ] = = NULL )
if ( hub - > ports [ i ] - > child = = NULL )
info - > port [ i ] = 0 ;
else
info - > port [ i ] =
hdev - > children [ i ] - > devnum ;
hub - > ports [ i ] - > child - > devnum ;
}
}
spin_unlock_irq ( & device_state_lock ) ;
@ -1784,11 +1783,12 @@ bool usb_device_is_owned(struct usb_device *udev)
static void recursively_mark_NOTATTACHED ( struct usb_device * udev )
{
struct usb_hub * hub = hdev_to_hub ( udev ) ;
int i ;
for ( i = 0 ; i < udev - > maxchild ; + + i ) {
if ( udev - > children [ i ] )
recursively_mark_NOTATTACHED ( udev - > children [ i ] ) ;
if ( hub - > ports [ i ] - > child )
recursively_mark_NOTATTACHED ( hub - > ports [ i ] - > child ) ;
}
if ( udev - > state = = USB_STATE_SUSPENDED )
udev - > active_duration - = jiffies ;
@ -1952,6 +1952,7 @@ static void hub_free_dev(struct usb_device *udev)
void usb_disconnect ( struct usb_device * * pdev )
{
struct usb_device * udev = * pdev ;
struct usb_hub * hub = hdev_to_hub ( udev ) ;
int i ;
/* mark the device as inactive, so any further urb submissions for
@ -1966,8 +1967,8 @@ void usb_disconnect(struct usb_device **pdev)
/* Free up all the children before we remove this device */
for ( i = 0 ; i < udev - > maxchild ; i + + ) {
if ( udev - > children [ i ] )
usb_disconnect ( & udev - > children [ i ] ) ;
if ( hub - > ports [ i ] - > child )
usb_disconnect ( & hub - > ports [ i ] - > child ) ;
}
/* deallocate hcd/hardware state ... nuking all pending urbs and
@ -3131,7 +3132,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
for ( port1 = 1 ; port1 < = hdev - > maxchild ; port1 + + ) {
struct usb_device * udev ;
udev = hdev - > children [ port1 - 1 ] ;
udev = hub - > ports [ port1 - 1 ] - > child ;
if ( udev & & udev - > can_submit ) {
dev_warn ( & intf - > dev , " port %d nyet suspended \n " , port1 ) ;
if ( PMSG_IS_AUTO ( msg ) )
@ -4058,7 +4059,7 @@ hub_power_remaining (struct usb_hub *hub)
remaining = hdev - > bus_mA - hub - > descriptor - > bHubContrCurrent ;
for ( port1 = 1 ; port1 < = hdev - > maxchild ; + + port1 ) {
struct usb_device * udev = hdev - > children [ port1 - 1 ] ;
struct usb_device * udev = hub - > ports [ port1 - 1 ] - > child ;
int delta ;
if ( ! udev )
@ -4122,7 +4123,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
# endif
/* Try to resuscitate an existing device */
udev = hdev - > children [ port1 - 1 ] ;
udev = hub - > ports [ port1 - 1 ] - > child ;
if ( ( portstatus & USB_PORT_STAT_CONNECTION ) & & udev & &
udev - > state ! = USB_STATE_NOTATTACHED ) {
usb_lock_device ( udev ) ;
@ -4151,7 +4152,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
/* Disconnect any existing devices under this port */
if ( udev )
usb_disconnect ( & hdev - > children [ port1 - 1 ] ) ;
usb_disconnect ( & hub - > ports [ port1 - 1 ] - > child ) ;
clear_bit ( port1 , hub - > change_bits ) ;
/* We can forget about a "removed" device when there's a physical
@ -4287,7 +4288,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
if ( hdev - > state = = USB_STATE_NOTATTACHED )
status = - ENOTCONN ;
else
hdev - > children [ port1 - 1 ] = udev ;
hub - > ports [ port1 - 1 ] - > child = udev ;
spin_unlock_irq ( & device_state_lock ) ;
/* Run it through the hoops (find a driver, etc) */
@ -4295,7 +4296,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
status = usb_new_device ( udev ) ;
if ( status ) {
spin_lock_irq ( & device_state_lock ) ;
hdev - > children [ port1 - 1 ] = NULL ;
hub - > ports [ port1 - 1 ] - > child = NULL ;
spin_unlock_irq ( & device_state_lock ) ;
}
}
@ -4341,7 +4342,7 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
int ret ;
hdev = hub - > hdev ;
udev = hdev - > children [ port - 1 ] ;
udev = hub - > ports [ port - 1 ] - > child ;
if ( ! hub_is_superspeed ( hdev ) ) {
if ( ! ( portchange & USB_PORT_STAT_C_SUSPEND ) )
return 0 ;
@ -4495,7 +4496,7 @@ static void hub_events(void)
*/
if ( ! ( portstatus & USB_PORT_STAT_ENABLE )
& & ! connect_change
& & hdev - > children [ i - 1 ] ) {
& & hub - > ports [ i - 1 ] - > child ) {
dev_err ( hub_dev ,
" port %i "
" disabled by hub (EMI?), "
@ -5052,3 +5053,27 @@ void usb_queue_reset_device(struct usb_interface *iface)
schedule_work ( & iface - > reset_ws ) ;
}
EXPORT_SYMBOL_GPL ( usb_queue_reset_device ) ;
/**
* usb_hub_find_child - Get the pointer of child device
* attached to the port which is specified by @ port1 .
* @ hdev : USB device belonging to the usb hub
* @ port1 : port num to indicate which port the child device
* is attached to .
*
* USB drivers call this function to get hub ' s child device
* pointer .
*
* Return NULL if input param is invalid and
* child ' s usb_device pointer if non - NULL .
*/
struct usb_device * usb_hub_find_child ( struct usb_device * hdev ,
int port1 )
{
struct usb_hub * hub = hdev_to_hub ( hdev ) ;
if ( port1 < 1 | | port1 > hdev - > maxchild )
return NULL ;
return hub - > ports [ port1 - 1 ] - > child ;
}
EXPORT_SYMBOL_GPL ( usb_hub_find_child ) ;