in cs.c [592:692]
static int pccardd(void *__skt)
{
struct pcmcia_socket *skt = __skt;
int ret;
skt->thread = current;
skt->socket = dead_socket;
skt->ops->init(skt);
skt->ops->set_socket(skt, &skt->socket);
/* register with the device core */
ret = device_register(&skt->dev);
if (ret) {
dev_warn(&skt->dev, "PCMCIA: unable to register socket\n");
skt->thread = NULL;
complete(&skt->thread_done);
return 0;
}
ret = pccard_sysfs_add_socket(&skt->dev);
if (ret)
dev_warn(&skt->dev, "err %d adding socket attributes\n", ret);
complete(&skt->thread_done);
/* wait for userspace to catch up */
msleep(250);
set_freezable();
for (;;) {
unsigned long flags;
unsigned int events;
unsigned int sysfs_events;
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 & SS_DETECT)
socket_detect_change(skt);
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_SUSPEND) &&
!(skt->state & SOCKET_CARDBUS)) {
if (skt->callback)
ret = skt->callback->suspend(skt);
else
ret = 0;
if (!ret) {
socket_suspend(skt);
msleep(100);
}
}
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_REQUERY) &&
!(skt->state & SOCKET_CARDBUS)) {
if (!ret && skt->callback)
skt->callback->requery(skt);
}
}
mutex_unlock(&skt->skt_mutex);
if (events || sysfs_events)
continue;
set_current_state(TASK_INTERRUPTIBLE);
if (kthread_should_stop())
break;
schedule();
try_to_freeze();
}
/* make sure we are running before we exit */
__set_current_state(TASK_RUNNING);
/* shut down socket, if a device is still present */
if (skt->state & SOCKET_PRESENT) {
mutex_lock(&skt->skt_mutex);
socket_remove(skt);
mutex_unlock(&skt->skt_mutex);
}
/* remove from the device core */
pccard_sysfs_remove_socket(&skt->dev);
device_unregister(&skt->dev);
return 0;
}