/* try to obtain a socket number [yes, it gets ugly if we *registermorethan2^sizeof(unsignedint)pcmcia *sockets...butthesocketnumberisdeprecated
* anyways, so I don't care] */
down_write(&pcmcia_socket_list_rwsem); if (list_empty(&pcmcia_socket_list))
socket->sock = 0; else { unsignedint found, i = 1; struct pcmcia_socket *tmp; do {
found = 1;
list_for_each_entry(tmp, &pcmcia_socket_list, socket_list) { if (tmp->sock == i)
found = 0;
}
i++;
} while (!found);
socket->sock = i - 1;
}
list_add_tail(&socket->socket_list, &pcmcia_socket_list);
up_write(&pcmcia_socket_list_rwsem);
if (socket->resource_ops->init) {
mutex_lock(&socket->ops_mutex);
ret = socket->resource_ops->init(socket);
mutex_unlock(&socket->ops_mutex); if (ret) goto err;
}
tsk = kthread_run(pccardd, socket, "pccardd"); if (IS_ERR(tsk)) {
ret = PTR_ERR(tsk); goto err;
}
wait_for_completion(&socket->thread_done); if (!socket->thread) {
dev_warn(&socket->dev, "PCMCIA: warning: socket thread did not start\n"); return -EIO;
}
/* remove from our own list */
down_write(&pcmcia_socket_list_rwsem);
list_del(&socket->socket_list);
up_write(&pcmcia_socket_list_rwsem);
/* wait for sysfs to drop all references */ if (socket->resource_ops->exit) {
mutex_lock(&socket->ops_mutex);
socket->resource_ops->exit(socket);
mutex_unlock(&socket->ops_mutex);
}
wait_for_completion(&socket->socket_released);
} /* pcmcia_unregister_socket */
EXPORT_SYMBOL(pcmcia_unregister_socket);
staticint socket_reset(struct pcmcia_socket *skt)
{ int status, i;
/* Blank out the socket state */
s->socket = dead_socket;
s->ops->init(s);
s->ops->set_socket(s, &s->socket);
s->lock_count = 0;
kfree(s->fake_cis);
s->fake_cis = NULL;
s->functions = 0;
/* From here on we can be sure that only we (that is, the *pccarddthread)accessesthissocket,andall(16-bit) *PCMCIAinteractionsaregone.Therefore,release *ops_mutexsothatwedon'tgetasysfs-relatedlockdep *warning.
*/
mutex_unlock(&s->ops_mutex);
#ifdef CONFIG_CARDBUS
cb_free(s); #endif
/* give socket some time to power down */
msleep(100);
s->ops->get_status(s, &status); if (status & SS_POWERON) {
dev_err(&s->dev, "*** DANGER *** unable to remove socket power\n");
}
s->state &= ~SOCKET_INUSE;
}
staticint socket_setup(struct pcmcia_socket *skt, int initial_delay)
{ int status, i;
dev_dbg(&skt->dev, "setup\n");
skt->ops->get_status(skt, &status); if (!(status & SS_DETECT)) return -ENODEV;
msleep(initial_delay * 10);
for (i = 0; i < 100; i++) {
skt->ops->get_status(skt, &status); if (!(status & SS_DETECT)) return -ENODEV;
mutex_lock(&skt->ops_mutex); /* store state on first suspend, but not after spurious wakeups */ if (!(skt->state & SOCKET_IN_RESUME))
skt->suspended_state = skt->state;
if (!(skt->state & SOCKET_CARDBUS) && (skt->callback))
ret = skt->callback->early_resume(skt); return ret;
}
/* *Finalizetheresume.Incaseofacardbussocket,wehave *torebindthedevicesaswecan'tbecertainthatithasbeen *replaced,ornot.
*/ staticint socket_complete_resume(struct pcmcia_socket *skt)
{ int ret = 0; #ifdef CONFIG_CARDBUS if (skt->state & SOCKET_CARDBUS) { /* We can't be sure the CardBus card is the same *astheonepreviouslyinserted.Therefore,remove
* and re-add... */
cb_free(skt);
ret = cb_alloc(skt); if (ret)
cb_free(skt);
} #endif return ret;
}
/* *Resumeasocket.Ifacardispresent,verifyitsCISagainst *ourcachedcopy.Iftheyaredifferent,thecardhasbeen *replaced,andweneedtotellthedrivers.
*/ staticint socket_resume(struct pcmcia_socket *skt)
{ int err; if (!(skt->state & SOCKET_SUSPEND)) return -EBUSY;
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);
/* I'm not sure which "reset" function this is supposed to use, *butfornow,itusesthelow-levelinterface'sreset,notthe *CISregister.
*/
int pcmcia_reset_card(struct pcmcia_socket *skt)
{ int ret;
dev_dbg(&skt->dev, "resetting socket\n");
mutex_lock(&skt->skt_mutex); do { if (!(skt->state & SOCKET_PRESENT)) {
dev_dbg(&skt->dev, "can't reset, not present\n");
ret = -ENODEV; break;
} if (skt->state & SOCKET_SUSPEND) {
dev_dbg(&skt->dev, "can't reset, suspended\n");
ret = -EBUSY; break;
} if (skt->state & SOCKET_CARDBUS) {
dev_dbg(&skt->dev, "can't reset, is cardbus\n");
ret = -EPERM; break;
}
if (skt->callback)
skt->callback->suspend(skt);
mutex_lock(&skt->ops_mutex);
ret = socket_reset(skt);
mutex_unlock(&skt->ops_mutex); if ((ret == 0) && (skt->callback))
skt->callback->resume(skt);
ret = 0;
} while (0);
mutex_unlock(&skt->skt_mutex);
staticconststruct dev_pm_ops pcmcia_socket_pm_ops = { /* dev_resume may be called with IRQs enabled */
SET_SYSTEM_SLEEP_PM_OPS(NULL,
pcmcia_socket_dev_resume)
/* late suspend must be called with IRQs disabled */
.suspend_noirq = pcmcia_socket_dev_suspend_noirq,
.freeze_noirq = pcmcia_socket_dev_suspend_noirq,
.poweroff_noirq = pcmcia_socket_dev_suspend_noirq,
/* early resume must be called with IRQs disabled */
.resume_noirq = pcmcia_socket_dev_resume_noirq,
.thaw_noirq = pcmcia_socket_dev_resume_noirq,
.restore_noirq = pcmcia_socket_dev_resume_noirq,
.complete = pcmcia_socket_dev_complete,
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.