cregit-Linux how code gets into the kernel

Release 4.14 drivers/pcmcia/cs.c

Directory: drivers/pcmcia
/*
 * cs.c -- Kernel Card Services - core services
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * The initial developer of the original code is David A. Hinds
 * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
 * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 *
 * (C) 1999             David A. Hinds
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/device.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <asm/irq.h>

#include <pcmcia/ss.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>
#include "cs_internal.h"


/* Module parameters */

MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
MODULE_DESCRIPTION("Linux Kernel Card Services");
MODULE_LICENSE("GPL");


#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)

INT_MODULE_PARM(setup_delay,	10);		/* centiseconds */
INT_MODULE_PARM(resume_delay,	20);		/* centiseconds */
INT_MODULE_PARM(shutdown_delay,	3);		/* centiseconds */
INT_MODULE_PARM(vcc_settle,	40);		/* centiseconds */
INT_MODULE_PARM(reset_time,	10);		/* usecs */
INT_MODULE_PARM(unreset_delay,	10);		/* centiseconds */
INT_MODULE_PARM(unreset_check,	10);		/* centiseconds */
INT_MODULE_PARM(unreset_limit,	30);		/* unreset_check's */

/* Access speed for attribute memory windows */
INT_MODULE_PARM(cis_speed,	300);		/* ns */



socket_state_t dead_socket = {
	.csc_mask	= SS_DETECT,
};

EXPORT_SYMBOL(dead_socket);


/* List of all sockets, protected by a rwsem */

LIST_HEAD(pcmcia_socket_list);

EXPORT_SYMBOL(pcmcia_socket_list);


DECLARE_RWSEM(pcmcia_socket_list_rwsem);

EXPORT_SYMBOL(pcmcia_socket_list_rwsem);



struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt) { struct device *dev = get_device(&skt->dev); if (!dev) return NULL; return dev_get_drvdata(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski3384.62%266.67%
Greg Kroah-Hartman615.38%133.33%
Total39100.00%3100.00%

EXPORT_SYMBOL(pcmcia_get_socket);
void pcmcia_put_socket(struct pcmcia_socket *skt) { put_device(&skt->dev); }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski1794.44%150.00%
Greg Kroah-Hartman15.56%150.00%
Total18100.00%2100.00%

EXPORT_SYMBOL(pcmcia_put_socket);
static void pcmcia_release_socket(struct device *dev) { struct pcmcia_socket *socket = dev_get_drvdata(dev); complete(&socket->socket_released); }

Contributors

PersonTokensPropCommitsCommitProp
Russell King1034.48%225.00%
Dominik Brodowski1034.48%337.50%
Linus Torvalds (pre-git)517.24%225.00%
Greg Kroah-Hartman413.79%112.50%
Total29100.00%8100.00%

static int pccardd(void *__skt); /** * pcmcia_register_socket - add a new pcmcia socket device * @socket: the &socket to register */
int pcmcia_register_socket(struct pcmcia_socket *socket) { struct task_struct *tsk; int ret; if (!socket || !socket->ops || !socket->dev.parent || !socket->resource_ops) return -EINVAL; dev_dbg(&socket->dev, "pcmcia_register_socket(0x%p)\n", socket->ops); /* try to obtain a socket number [yes, it gets ugly if we * register more than 2^sizeof(unsigned int) pcmcia * sockets... but the socket number is deprecated * anyways, so I don't care] */ down_write(&pcmcia_socket_list_rwsem); if (list_empty(&pcmcia_socket_list)) socket->sock = 0; else { unsigned int 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); #ifndef CONFIG_CARDBUS /* * If we do not support Cardbus, ensure that * the Cardbus socket capability is disabled. */ socket->features &= ~SS_CAP_CARDBUS; #endif /* set proper values in socket->dev */ dev_set_drvdata(&socket->dev, socket); socket->dev.class = &pcmcia_socket_class; dev_set_name(&socket->dev, "pcmcia_socket%u", socket->sock); /* base address = 0, map = 0 */ socket->cis_mem.flags = 0; socket->cis_mem.speed = cis_speed; INIT_LIST_HEAD(&socket->cis_cache); init_completion(&socket->socket_released); init_completion(&socket->thread_done); mutex_init(&socket->skt_mutex); mutex_init(&socket->ops_mutex); spin_lock_init(&socket->thread_lock); 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; } pcmcia_parse_events(socket, SS_DETECT); /* * Let's try to get the PCMCIA module for 16-bit PCMCIA support. * If it fails, it doesn't matter -- we still have 32-bit CardBus * support to offer, so this is not a failure mode. */ request_module_nowait("pcmcia"); return 0; err: down_write(&pcmcia_socket_list_rwsem); list_del(&socket->socket_list); up_write(&pcmcia_socket_list_rwsem); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski23857.21%1466.67%
Russell King14835.58%314.29%
Serge E. Hallyn215.05%14.76%
Greg Kroah-Hartman61.44%14.76%
Kay Sievers20.48%14.76%
Joe Perches10.24%14.76%
Total416100.00%21100.00%

/* pcmcia_register_socket */ EXPORT_SYMBOL(pcmcia_register_socket); /** * pcmcia_unregister_socket - remove a pcmcia socket device * @socket: the &socket to unregister */
void pcmcia_unregister_socket(struct pcmcia_socket *socket) { if (!socket) return; dev_dbg(&socket->dev, "pcmcia_unregister_socket(0x%p)\n", socket->ops); if (socket->thread) kthread_stop(socket->thread); /* 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); }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski8275.93%753.85%
Russell King2220.37%323.08%
Linus Torvalds (pre-git)21.85%215.38%
Serge E. Hallyn21.85%17.69%
Total108100.00%13100.00%

/* pcmcia_unregister_socket */ EXPORT_SYMBOL(pcmcia_unregister_socket);
struct pcmcia_socket *pcmcia_get_socket_by_nr(unsigned int nr) { struct pcmcia_socket *s; down_read(&pcmcia_socket_list_rwsem); list_for_each_entry(s, &pcmcia_socket_list, socket_list) if (s->sock == nr) { up_read(&pcmcia_socket_list_rwsem); return s; } up_read(&pcmcia_socket_list_rwsem); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski58100.00%1100.00%
Total58100.00%1100.00%

EXPORT_SYMBOL(pcmcia_get_socket_by_nr);
static int socket_reset(struct pcmcia_socket *skt) { int status, i; dev_dbg(&skt->dev, "reset\n"); skt->socket.flags |= SS_OUTPUT_ENA | SS_RESET; skt->ops->set_socket(skt, &skt->socket); udelay((long)reset_time); skt->socket.flags &= ~SS_RESET; skt->ops->set_socket(skt, &skt->socket); msleep(unreset_delay * 10); for (i = 0; i < unreset_limit; i++) { skt->ops->get_status(skt, &status); if (!(status & SS_DETECT)) return -ENODEV; if (status & SS_READY) return 0; msleep(unreset_check * 10); } dev_err(&skt->dev, "time out after reset\n"); return -ETIMEDOUT; }

Contributors

PersonTokensPropCommitsCommitProp
Russell King7648.10%321.43%
Linus Torvalds (pre-git)5333.54%321.43%
Dominik Brodowski2717.09%750.00%
Joe Perches21.27%17.14%
Total158100.00%14100.00%

/* * socket_setup() and socket_shutdown() are called by the main event handler * when card insertion and removal events are received. * socket_setup() turns on socket power and resets the socket, in two stages. * socket_shutdown() unconfigures a socket and turns off socket power. */
static void socket_shutdown(struct pcmcia_socket *s) { int status; dev_dbg(&s->dev, "shutdown\n"); if (s->callback) s->callback->remove(s); mutex_lock(&s->ops_mutex); s->state &= SOCKET_INUSE | SOCKET_PRESENT; msleep(shutdown_delay * 10); s->state &= SOCKET_INUSE; /* 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 * pccardd thread) accesses this socket, and all (16-bit) * PCMCIA interactions are gone. Therefore, release * ops_mutex so that we don't get a sysfs-related lockdep * 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; }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Ritz12366.49%220.00%
Dominik Brodowski6132.97%770.00%
Joe Perches10.54%110.00%
Total185100.00%10100.00%


static int 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; if (!(status & SS_PENDING)) break; msleep(100); } if (status & SS_PENDING) { dev_err(&skt->dev, "voltage interrogation timed out\n"); return -ETIMEDOUT; } if (status & SS_CARDBUS) { if (!(skt->features & SS_CAP_CARDBUS)) { dev_err(&skt->dev, "cardbus cards are not supported\n"); return -EINVAL; } skt->state |= SOCKET_CARDBUS; } else skt->state &= ~SOCKET_CARDBUS; /* * Decode the card voltage requirements, and apply power to the card. */ if (status & SS_3VCARD) skt->socket.Vcc = skt->socket.Vpp = 33; else if (!(status & SS_XVCARD)) skt->socket.Vcc = skt->socket.Vpp = 50; else { dev_err(&skt->dev, "unsupported voltage key\n"); return -EIO; } if (skt->power_hook) skt->power_hook(skt, HOOK_POWER_PRE); skt->socket.flags = 0; skt->ops->set_socket(skt, &skt->socket); /* * Wait "vcc_settle" for the supply to stabilise. */ msleep(vcc_settle * 10); skt->ops->get_status(skt, &status); if (!(status & SS_POWERON)) { dev_err(&skt->dev, "unable to apply power\n"); return -EIO; } status = socket_reset(skt); if (skt->power_hook) skt->power_hook(skt, HOOK_POWER_POST); return status; }

Contributors

PersonTokensPropCommitsCommitProp
Russell King21460.11%631.58%
Dominik Brodowski5214.61%842.11%
Linus Torvalds (pre-git)4713.20%315.79%
Daniel Ritz359.83%15.26%
Joe Perches82.25%15.26%
Total356100.00%19100.00%

/* * Handle card insertion. Setup the socket, reset the card, * and then tell the rest of PCMCIA that a card is present. */
static int socket_insert(struct pcmcia_socket *skt) { int ret; dev_dbg(&skt->dev, "insert\n"); mutex_lock(&skt->ops_mutex); if (skt->state & SOCKET_INUSE) { mutex_unlock(&skt->ops_mutex); return -EINVAL; } skt->state |= SOCKET_INUSE; ret = socket_setup(skt, setup_delay); if (ret == 0) { skt->state |= SOCKET_PRESENT; dev_notice(&skt->dev, "pccard: %s card inserted into slot %d\n", (skt->state & SOCKET_CARDBUS) ? "CardBus" : "PCMCIA", skt->sock); #ifdef CONFIG_CARDBUS if (skt->state & SOCKET_CARDBUS) { cb_alloc(skt); skt->state |= SOCKET_CARDBUS_CONFIG; } #endif dev_dbg(&skt->dev, "insert done\n"); mutex_unlock(&skt->ops_mutex); if (!(skt->state & SOCKET_CARDBUS) && (skt->callback)) skt->callback->add(skt); } else { mutex_unlock(&skt->ops_mutex); socket_shutdown(skt); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski10854.55%952.94%
Russell King5728.79%529.41%
Linus Torvalds (pre-git)3216.16%211.76%
Joe Perches10.51%15.88%
Total198100.00%17100.00%


static int socket_suspend(struct pcmcia_socket *skt) { if (skt->state & SOCKET_SUSPEND) return -EBUSY; mutex_lock(&skt->ops_mutex); skt->suspended_state = skt->state; skt->socket = dead_socket; skt->ops->set_socket(skt, &skt->socket); if (skt->ops->suspend) skt->ops->suspend(skt); skt->state |= SOCKET_SUSPEND; mutex_unlock(&skt->ops_mutex); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski4851.61%872.73%
Russell King3638.71%218.18%
Linus Torvalds (pre-git)99.68%19.09%
Total93100.00%11100.00%


static int socket_early_resume(struct pcmcia_socket *skt) { mutex_lock(&skt->ops_mutex); skt->socket = dead_socket; skt->ops->init(skt); skt->ops->set_socket(skt, &skt->socket); if (skt->state & SOCKET_PRESENT) skt->resume_status = socket_setup(skt, resume_delay); mutex_unlock(&skt->ops_mutex); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski2937.18%444.44%
Rafael J. Wysocki2228.21%111.11%
Russell King2126.92%333.33%
Linus Torvalds (pre-git)67.69%111.11%
Total78100.00%9100.00%


static int socket_late_resume(struct pcmcia_socket *skt) { int ret = 0; mutex_lock(&skt->ops_mutex); skt->state &= ~SOCKET_SUSPEND; mutex_unlock(&skt->ops_mutex); if (!(skt->state & SOCKET_PRESENT)) { ret = socket_insert(skt); if (ret == -ENODEV) ret = 0; return ret; } if (skt->resume_status) { socket_shutdown(skt); return 0; } if (skt->suspended_state != skt->state) { dev_dbg(&skt->dev, "suspend state 0x%x != resume state 0x%x\n", skt->suspended_state, skt->state); socket_shutdown(skt); return socket_insert(skt); } if (!(skt->state & SOCKET_CARDBUS) && (skt->callback)) ret = skt->callback->early_resume(skt); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski7848.45%545.45%
Christian Lamparter3421.12%19.09%
Russell King2918.01%327.27%
Rafael J. Wysocki159.32%19.09%
Linus Torvalds (pre-git)53.11%19.09%
Total161100.00%11100.00%

/* * Finalize the resume. In case of a cardbus socket, we have * to rebind the devices as we can't be certain that it has been * replaced, or not. */
static int 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 * as the one previously inserted. Therefore, remove * and re-add... */ cb_free(skt); ret = cb_alloc(skt); if (ret) cb_free(skt); } #endif return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Christian Lamparter2341.07%114.29%
Dominik Brodowski1832.14%342.86%
Russell King1221.43%228.57%
Linus Torvalds (pre-git)35.36%114.29%
Total56100.00%7100.00%

/* * Resume a socket. If a card is present, verify its CIS against * our cached copy. If they are different, the card has been * replaced, and we need to tell the drivers. */
static int socket_resume(struct pcmcia_socket *skt) { int err; if (!(skt->state & SOCKET_SUSPEND)) return -EBUSY; socket_early_resume(skt); err = socket_late_resume(skt); if (!err) err = socket_complete_resume(skt); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Rafael J. Wysocki3664.29%150.00%
Christian Lamparter2035.71%150.00%
Total56100.00%2100.00%


static void socket_remove(struct pcmcia_socket *skt) { dev_notice(&skt->dev, "pccard: card ejected from slot %d\n", skt->sock); socket_shutdown(skt); }

Contributors

PersonTokensPropCommitsCommitProp
Russell King1653.33%125.00%
Dominik Brodowski1343.33%250.00%
Joe Perches13.33%125.00%
Total30100.00%4100.00%

/* * Process a socket card detect status change. * * If we don't have a card already present, delay the detect event for * about 20ms (to be on the safe side) before reading the socket status. * * Some i82365-based systems send multiple SS_DETECT events during card * insertion, and the "card present" status bit seems to bounce. This * will probably be true with GPIO-based card detection systems after * the product has aged. */
static void socket_detect_change(struct pcmcia_socket *skt) { if (!(skt->state & SOCKET_SUSPEND)) { int status; if (!(skt->state & SOCKET_PRESENT)) msleep(20); skt->ops->get_status(skt, &status); if ((skt->state & SOCKET_PRESENT) && !(status & SS_DETECT)) socket_remove(skt); if (!(skt->state & SOCKET_PRESENT) && (status & SS_DETECT)) socket_insert(skt); } }

Contributors

PersonTokensPropCommitsCommitProp
Russell King9494.95%250.00%
Dominik Brodowski55.05%250.00%
Total99100.00%4100.00%


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; if (kthread_should_stop()) break; set_current_state(TASK_INTERRUPTIBLE); schedule(); /* make sure we are running */ __set_current_state(TASK_RUNNING); try_to_freeze(); } /* 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; }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski25653.22%1144.00%
Russell King12525.99%416.00%
David Brownell347.07%14.00%
Linus Torvalds (pre-git)326.65%28.00%
Dmitry Baryshkov112.29%14.00%
Serge E. Hallyn81.66%14.00%
Daniel Ritz51.04%14.00%
Steven Rostedt40.83%14.00%
Rafael J. Wysocki30.62%14.00%
Greg Kroah-Hartman20.42%14.00%
Joe Perches10.21%14.00%
Total481100.00%25100.00%

/* * Yenta (at least) probes interrupts before registering the socket and * starting the handler thread. */
void pcmcia_parse_events(struct pcmcia_socket *s, u_int events) { unsigned long flags; dev_dbg(&s->dev, "parse_events: events %08x\n", events); if (s->thread) { spin_lock_irqsave(&s->thread_lock, flags); s->thread_events |= events; spin_unlock_irqrestore(&s->thread_lock, flags); wake_up_process(s->thread); } }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski2434.29%330.00%
Linus Torvalds (pre-git)1420.00%220.00%
Russell King1217.14%220.00%
Arjan van de Ven1014.29%110.00%
Andrew Morton811.43%110.00%
Christoph Hellwig22.86%110.00%
Total70100.00%10100.00%

/* 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), PCMCIA_UEVENT_SUSPEND (for suspend) * and PCMCIA_UEVENT_REQUERY (for re-querying the PCMCIA card). */
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); } }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski70100.00%1100.00%
Total70100.00%1100.00%

EXPORT_SYMBOL(pcmcia_parse_uevents); /* register pcmcia_callback */
int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c) { int ret = 0; /* s->skt_mutex also protects s->callback */ mutex_lock(&s->skt_mutex); if (c) { /* registration */ if (s->callback) { ret = -EBUSY; goto err; } s->callback = c; if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) s->callback->add(s); } else s->callback = NULL; err: mutex_unlock(&s->skt_mutex); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski6058.25%444.44%
Linus Torvalds (pre-git)3332.04%333.33%
Linus Torvalds98.74%111.11%
Russell King10.97%111.11%
Total103100.00%9100.00%

EXPORT_SYMBOL(pccard_register_pcmcia); /* I'm not sure which "reset" function this is supposed to use, * but for now, it uses the low-level interface's reset, not the * CIS register. */
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); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski10453.06%1381.25%
Russell King6030.61%212.50%
Linus Torvalds (pre-git)3216.33%16.25%
Total196100.00%16100.00%

/* reset_card */ EXPORT_SYMBOL(pcmcia_reset_card);
static int pcmcia_socket_uevent(struct device *dev, struct kobj_uevent_env *env) { struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev); if (add_uevent_var(env, "SOCKET_NO=%u", s->sock)) return -ENOMEM; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski4486.27%125.00%
Kay Sievers611.76%250.00%
Greg Kroah-Hartman11.96%125.00%
Total51100.00%4100.00%

static struct completion pcmcia_unload;
static void pcmcia_release_socket_class(struct class *data) { complete(&pcmcia_unload); }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski17100.00%1100.00%
Total17100.00%1100.00%

#ifdef CONFIG_PM
static int __pcmcia_pm_op(struct device *dev, int (*callback) (struct pcmcia_socket *skt)) { struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev); int ret; mutex_lock(&s->skt_mutex); ret = callback(s); mutex_unlock(&s->skt_mutex); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski67100.00%1100.00%
Total67100.00%1100.00%


static int pcmcia_socket_dev_suspend_noirq(struct device *dev) { return __pcmcia_pm_op(dev, socket_suspend); }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski19100.00%1100.00%
Total19100.00%1100.00%


static int pcmcia_socket_dev_resume_noirq(struct device *dev) { return __pcmcia_pm_op(dev, socket_early_resume); }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski19100.00%1100.00%
Total19100.00%1100.00%


static int __used pcmcia_socket_dev_resume(struct device *dev) { return __pcmcia_pm_op(dev, socket_late_resume); }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski1995.00%150.00%
Maciej Żenczykowski15.00%150.00%
Total20100.00%2100.00%


static void __used pcmcia_socket_dev_complete(struct device *dev) { WARN(__pcmcia_pm_op(dev, socket_complete_resume), "failed to complete resume"); }

Contributors

PersonTokensPropCommitsCommitProp
Christian Lamparter24100.00%1100.00%
Total24100.00%1100.00%

static const struct 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, }; #define PCMCIA_SOCKET_CLASS_PM_OPS (&pcmcia_socket_pm_ops) #else /* CONFIG_PM */ #define PCMCIA_SOCKET_CLASS_PM_OPS NULL #endif /* CONFIG_PM */ struct class pcmcia_socket_class = { .name = "pcmcia_socket", .dev_uevent = pcmcia_socket_uevent, .dev_release = pcmcia_release_socket, .class_release = pcmcia_release_socket_class, .pm = PCMCIA_SOCKET_CLASS_PM_OPS, }; EXPORT_SYMBOL(pcmcia_socket_class);
static int __init init_pcmcia_cs(void) { init_completion(&pcmcia_unload); return class_register(&pcmcia_socket_class); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1045.45%233.33%
Dominik Brodowski1045.45%233.33%
Greg Kroah-Hartman14.55%116.67%
David Brownell14.55%116.67%
Total22100.00%6100.00%


static void __exit exit_pcmcia_cs(void) { class_unregister(&pcmcia_socket_class); wait_for_completion(&pcmcia_unload); }

Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski1152.38%240.00%
Linus Torvalds (pre-git)942.86%240.00%
Greg Kroah-Hartman14.76%120.00%
Total21100.00%5100.00%

subsys_initcall(init_pcmcia_cs); module_exit(exit_pcmcia_cs);

Overall Contributors

PersonTokensPropCommitsCommitProp
Dominik Brodowski177047.70%5447.79%
Russell King95625.76%1715.04%
Linus Torvalds (pre-git)45312.21%1311.50%
Daniel Ritz1634.39%43.54%
Christian Lamparter1072.88%10.88%
Rafael J. Wysocki772.07%21.77%
David Brownell350.94%10.88%
Serge E. Hallyn340.92%10.88%
Greg Kroah-Hartman320.86%21.77%
Joe Perches150.40%10.88%
Linus Torvalds150.40%43.54%
Dmitry Baryshkov110.30%10.88%
Arjan van de Ven100.27%10.88%
Andrew Morton90.24%10.88%
Kay Sievers90.24%32.65%
Steven Rostedt40.11%10.88%
Randy Dunlap30.08%10.88%
Nigel Cunningham30.08%10.88%
Christoph Hellwig20.05%10.88%
Matthew Wilcox10.03%10.88%
Maciej Żenczykowski10.03%10.88%
Pavel Roskin10.03%10.88%
Total3711100.00%113100.00%
Directory: drivers/pcmcia
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.