@ -505,7 +505,10 @@ static int socket_insert(struct pcmcia_socket *skt)
dev_dbg ( & skt - > dev , " insert \n " ) ;
mutex_lock ( & skt - > ops_mutex ) ;
WARN_ON ( skt - > state & SOCKET_INUSE ) ;
if ( skt - > state & SOCKET_INUSE ) {
mutex_unlock ( & skt - > ops_mutex ) ;
return - EINVAL ;
}
skt - > state | = SOCKET_INUSE ;
ret = socket_setup ( skt , setup_delay ) ;
@ -682,16 +685,19 @@ static int pccardd(void *__skt)
for ( ; ; ) {
unsigned long flags ;
unsigned int events ;
unsigned int sysfs_events ;
set_current_state ( TASK_INTERRUPTIBLE ) ;
spin_lock_irqsave ( & skt - > thread_lock , flags ) ;
events = skt - > thread_events ;
skt - > thread_events = 0 ;
sysfs_events = skt - > sysfs_events ;
skt - > sysfs_events = 0 ;
spin_unlock_irqrestore ( & skt - > thread_lock , flags ) ;
mutex_lock ( & skt - > skt_mutex ) ;
if ( events ) {
mutex_lock ( & skt - > skt_mutex ) ;
if ( events & SS_DETECT )
socket_detect_change ( skt ) ;
if ( events & SS_BATDEAD )
@ -700,10 +706,34 @@ static int pccardd(void *__skt)
send_event ( skt , CS_EVENT_BATTERY_LOW , CS_EVENT_PRI_LOW ) ;
if ( events & SS_READY )
send_event ( skt , CS_EVENT_READY_CHANGE , CS_EVENT_PRI_LOW ) ;
mutex_unlock ( & skt - > skt_mutex ) ;
continue ;
}
if ( sysfs_events ) {
if ( sysfs_events & PCMCIA_UEVENT_EJECT )
socket_remove ( skt ) ;
if ( sysfs_events & PCMCIA_UEVENT_INSERT )
socket_insert ( skt ) ;
if ( ( sysfs_events & PCMCIA_UEVENT_RESUME ) & &
! ( skt - > state & SOCKET_CARDBUS ) ) {
ret = socket_resume ( skt ) ;
if ( ! ret & & skt - > callback )
skt - > callback - > resume ( skt ) ;
}
if ( ( sysfs_events & PCMCIA_UEVENT_SUSPEND ) & &
! ( skt - > state & SOCKET_CARDBUS ) ) {
if ( skt - > callback )
ret = skt - > callback - > suspend ( skt ) ;
else
ret = 0 ;
if ( ! ret )
socket_suspend ( skt ) ;
}
}
mutex_unlock ( & skt - > skt_mutex ) ;
if ( events | | sysfs_events )
continue ;
if ( kthread_should_stop ( ) )
break ;
@ -745,6 +775,30 @@ void pcmcia_parse_events(struct pcmcia_socket *s, u_int events)
} /* pcmcia_parse_events */
EXPORT_SYMBOL ( pcmcia_parse_events ) ;
/**
* pcmcia_parse_uevents ( ) - tell pccardd to issue manual commands
* @ s : the PCMCIA socket we wan ' t to command
* @ events : events to pass to pccardd
*
* userspace - issued insert , eject , suspend and resume commands must be
* handled by pccardd to avoid any sysfs - related deadlocks . Valid events
* are PCMCIA_UEVENT_EJECT ( for eject ) , PCMCIA_UEVENT__INSERT ( for insert ) ,
* PCMCIA_UEVENT_RESUME ( for resume ) and PCMCIA_UEVENT_SUSPEND ( for suspend ) .
*/
void pcmcia_parse_uevents ( struct pcmcia_socket * s , u_int events )
{
unsigned long flags ;
dev_dbg ( & s - > dev , " parse_uevents: events %08x \n " , events ) ;
if ( s - > thread ) {
spin_lock_irqsave ( & s - > thread_lock , flags ) ;
s - > sysfs_events | = events ;
spin_unlock_irqrestore ( & s - > thread_lock , flags ) ;
wake_up_process ( s - > thread ) ;
}
}
EXPORT_SYMBOL ( pcmcia_parse_uevents ) ;
/* register pcmcia_callback */
int pccard_register_pcmcia ( struct pcmcia_socket * s , struct pcmcia_callback * c )
@ -828,121 +882,6 @@ int pcmcia_reset_card(struct pcmcia_socket *skt)
EXPORT_SYMBOL ( pcmcia_reset_card ) ;
/* These shut down or wake up a socket. They are sort of user
* initiated versions of the APM suspend and resume actions .
*/
int pcmcia_suspend_card ( struct pcmcia_socket * skt )
{
int ret ;
dev_dbg ( & skt - > dev , " suspending socket \n " ) ;
mutex_lock ( & skt - > skt_mutex ) ;
do {
if ( ! ( skt - > state & SOCKET_PRESENT ) ) {
ret = - ENODEV ;
break ;
}
if ( skt - > state & SOCKET_CARDBUS ) {
ret = - EPERM ;
break ;
}
if ( skt - > callback ) {
ret = skt - > callback - > suspend ( skt ) ;
if ( ret )
break ;
}
ret = socket_suspend ( skt ) ;
} while ( 0 ) ;
mutex_unlock ( & skt - > skt_mutex ) ;
return ret ;
} /* suspend_card */
EXPORT_SYMBOL ( pcmcia_suspend_card ) ;
int pcmcia_resume_card ( struct pcmcia_socket * skt )
{
int ret ;
dev_dbg ( & skt - > dev , " waking up socket \n " ) ;
mutex_lock ( & skt - > skt_mutex ) ;
do {
if ( ! ( skt - > state & SOCKET_PRESENT ) ) {
ret = - ENODEV ;
break ;
}
if ( skt - > state & SOCKET_CARDBUS ) {
ret = - EPERM ;
break ;
}
ret = socket_resume ( skt ) ;
if ( ! ret & & skt - > callback )
skt - > callback - > resume ( skt ) ;
} while ( 0 ) ;
mutex_unlock ( & skt - > skt_mutex ) ;
return ret ;
} /* resume_card */
EXPORT_SYMBOL ( pcmcia_resume_card ) ;
/* These handle user requests to eject or insert a card. */
int pcmcia_eject_card ( struct pcmcia_socket * skt )
{
int ret ;
dev_dbg ( & skt - > dev , " user eject request \n " ) ;
mutex_lock ( & skt - > skt_mutex ) ;
do {
if ( ! ( skt - > state & SOCKET_PRESENT ) ) {
ret = - ENODEV ;
break ;
}
ret = send_event ( skt , CS_EVENT_EJECTION_REQUEST , CS_EVENT_PRI_LOW ) ;
if ( ret ! = 0 ) {
ret = - EINVAL ;
break ;
}
socket_remove ( skt ) ;
ret = 0 ;
} while ( 0 ) ;
mutex_unlock ( & skt - > skt_mutex ) ;
return ret ;
} /* eject_card */
EXPORT_SYMBOL ( pcmcia_eject_card ) ;
int pcmcia_insert_card ( struct pcmcia_socket * skt )
{
int ret ;
dev_dbg ( & skt - > dev , " user insert request \n " ) ;
mutex_lock ( & skt - > skt_mutex ) ;
do {
if ( skt - > state & SOCKET_PRESENT ) {
ret = - EBUSY ;
break ;
}
if ( socket_insert ( skt ) = = - ENODEV ) {
ret = - ENODEV ;
break ;
}
ret = 0 ;
} while ( 0 ) ;
mutex_unlock ( & skt - > skt_mutex ) ;
return ret ;
} /* insert_card */
EXPORT_SYMBOL ( pcmcia_insert_card ) ;
static int pcmcia_socket_uevent ( struct device * dev ,
struct kobj_uevent_env * env )
{