diff options
Diffstat (limited to 'drivers/pcmcia/ds.c')
| -rw-r--r-- | drivers/pcmcia/ds.c | 416 |
1 files changed, 197 insertions, 219 deletions
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index ad93ebd7b2a..757119b8714 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -10,7 +10,7 @@ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. * * (C) 1999 David A. Hinds - * (C) 2003 - 2006 Dominik Brodowski + * (C) 2003 - 2010 Dominik Brodowski */ #include <linux/kernel.h> @@ -24,9 +24,8 @@ #include <linux/firmware.h> #include <linux/kref.h> #include <linux/dma-mapping.h> +#include <linux/slab.h> -#include <pcmcia/cs_types.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> #include <pcmcia/ss.h> @@ -46,13 +45,13 @@ MODULE_LICENSE("GPL"); static void pcmcia_check_driver(struct pcmcia_driver *p_drv) { - struct pcmcia_device_id *did = p_drv->id_table; + const struct pcmcia_device_id *did = p_drv->id_table; unsigned int i; u32 hash; if (!p_drv->probe || !p_drv->remove) printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback " - "function\n", p_drv->drv.name); + "function\n", p_drv->name); while (did && did->match_flags) { for (i = 0; i < 4; i++) { @@ -65,7 +64,7 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv) printk(KERN_DEBUG "pcmcia: %s: invalid hash for " "product string \"%s\": is 0x%x, should " - "be 0x%x\n", p_drv->drv.name, did->prod_id[i], + "be 0x%x\n", p_drv->name, did->prod_id[i], did->prod_id_hash[i], hash); printk(KERN_DEBUG "pcmcia: see " "Documentation/pcmcia/devicetable.txt for " @@ -128,10 +127,7 @@ pcmcia_store_new_id(struct device_driver *driver, const char *buf, size_t count) list_add_tail(&dynid->node, &pdrv->dynids.list); mutex_unlock(&pdrv->dynids.lock); - if (get_driver(&pdrv->drv)) { - retval = driver_attach(&pdrv->drv); - put_driver(&pdrv->drv); - } + retval = driver_attach(&pdrv->drv); if (retval) return retval; @@ -161,6 +157,11 @@ pcmcia_create_newid_file(struct pcmcia_driver *drv) return error; } +static void +pcmcia_remove_newid_file(struct pcmcia_driver *drv) +{ + driver_remove_file(&drv->drv, &driver_attr_new_id); +} /** * pcmcia_register_driver - register a PCMCIA driver with the bus core @@ -180,10 +181,11 @@ int pcmcia_register_driver(struct pcmcia_driver *driver) /* initialize common fields */ driver->drv.bus = &pcmcia_bus_type; driver->drv.owner = driver->owner; + driver->drv.name = driver->name; mutex_init(&driver->dynids.lock); INIT_LIST_HEAD(&driver->dynids.list); - pr_debug("registering driver %s\n", driver->drv.name); + pr_debug("registering driver %s\n", driver->name); error = driver_register(&driver->drv); if (error < 0) @@ -203,7 +205,8 @@ EXPORT_SYMBOL(pcmcia_register_driver); */ void pcmcia_unregister_driver(struct pcmcia_driver *driver) { - pr_debug("unregistering driver %s\n", driver->drv.name); + pr_debug("unregistering driver %s\n", driver->name); + pcmcia_remove_newid_file(driver); driver_unregister(&driver->drv); pcmcia_free_dynids(driver); } @@ -212,7 +215,7 @@ EXPORT_SYMBOL(pcmcia_unregister_driver); /* pcmcia_device handling */ -struct pcmcia_device *pcmcia_get_dev(struct pcmcia_device *p_dev) +static struct pcmcia_device *pcmcia_get_dev(struct pcmcia_device *p_dev) { struct device *tmp_dev; tmp_dev = get_device(&p_dev->dev); @@ -221,7 +224,7 @@ struct pcmcia_device *pcmcia_get_dev(struct pcmcia_device *p_dev) return to_pcmcia_dev(tmp_dev); } -void pcmcia_put_dev(struct pcmcia_device *p_dev) +static void pcmcia_put_dev(struct pcmcia_device *p_dev) { if (p_dev) put_device(&p_dev->dev); @@ -264,7 +267,7 @@ static int pcmcia_device_probe(struct device *dev) p_drv = to_pcmcia_drv(dev->driver); s = p_dev->socket; - dev_dbg(dev, "trying to bind to %s\n", p_drv->drv.name); + dev_dbg(dev, "trying to bind to %s\n", p_drv->name); if ((!p_drv->probe) || (!p_dev->function_config) || (!try_module_get(p_drv->owner))) { @@ -276,24 +279,31 @@ static int pcmcia_device_probe(struct device *dev) ret = pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_CONFIG, &cis_config); if (!ret) { - p_dev->conf.ConfigBase = cis_config.base; - p_dev->conf.Present = cis_config.rmask[0]; + p_dev->config_base = cis_config.base; + p_dev->config_regs = cis_config.rmask[0]; + dev_dbg(dev, "base %x, regs %x", p_dev->config_base, + p_dev->config_regs); } else { dev_printk(KERN_INFO, dev, "pcmcia: could not parse base and rmask0 of CIS\n"); - p_dev->conf.ConfigBase = 0; - p_dev->conf.Present = 0; + p_dev->config_base = 0; + p_dev->config_regs = 0; } ret = p_drv->probe(p_dev); if (ret) { dev_dbg(dev, "binding to %s failed with %d\n", - p_drv->drv.name, ret); + p_drv->name, ret); goto put_module; } + dev_dbg(dev, "%s bound: Vpp %d.%d, idx %x, IRQ %d", p_drv->name, + p_dev->vpp/10, p_dev->vpp%10, p_dev->config_index, p_dev->irq); + dev_dbg(dev, "resources: ioport %pR %pR iomem %pR %pR %pR", + p_dev->resource[0], p_dev->resource[1], p_dev->resource[2], + p_dev->resource[3], p_dev->resource[4]); mutex_lock(&s->ops_mutex); - if ((s->pcmcia_state.has_pfc) && + if ((s->pcmcia_pfc) && (p_dev->socket->device_count == 1) && (p_dev->device_no == 0)) pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY); mutex_unlock(&s->ops_mutex); @@ -334,7 +344,6 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le mutex_lock(&s->ops_mutex); list_del(&p_dev->socket_device_list); - p_dev->_removed = 1; mutex_unlock(&s->ops_mutex); dev_dbg(&p_dev->dev, "unregistering device\n"); @@ -359,7 +368,7 @@ static int pcmcia_device_remove(struct device *dev) * pseudo multi-function card, we need to unbind * all devices */ - if ((p_dev->socket->pcmcia_state.has_pfc) && + if ((p_dev->socket->pcmcia_pfc) && (p_dev->socket->device_count > 0) && (p_dev->device_no == 0)) pcmcia_card_remove(p_dev->socket, p_dev); @@ -371,19 +380,17 @@ static int pcmcia_device_remove(struct device *dev) if (p_drv->remove) p_drv->remove(p_dev); - p_dev->dev_node = NULL; - /* check for proper unloading */ if (p_dev->_irq || p_dev->_io || p_dev->_locked) dev_printk(KERN_INFO, dev, "pcmcia: driver %s did not release config properly\n", - p_drv->drv.name); + p_drv->name); for (i = 0; i < MAX_WIN; i++) if (p_dev->_win & CLIENT_WIN_REQ(i)) dev_printk(KERN_INFO, dev, "pcmcia: driver %s did not release window properly\n", - p_drv->drv.name); + p_drv->name); /* references from pcmcia_probe_device */ pcmcia_put_dev(p_dev); @@ -479,16 +486,8 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev) } -/* device_add_lock is needed to avoid double registration by cardmgr and kernel. - * Serializes pcmcia_device_add; will most likely be removed in future. - * - * While it has the caveat that adding new PCMCIA devices inside(!) device_register() - * won't work, this doesn't matter much at the moment: the driver core doesn't - * support it either. - */ -static DEFINE_MUTEX(device_add_lock); - -struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int function) +static struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, + unsigned int function) { struct pcmcia_device *p_dev, *tmp_dev; int i; @@ -497,8 +496,6 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu if (!s) return NULL; - mutex_lock(&device_add_lock); - pr_debug("adding device to %d, function %d\n", s->sock, function); p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL); @@ -509,8 +506,12 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu p_dev->device_no = (s->device_count++); mutex_unlock(&s->ops_mutex); - /* max of 2 devices per card */ - if (p_dev->device_no >= 2) + /* max of 2 PFC devices */ + if ((p_dev->device_no >= 2) && (function == 0)) + goto err_free; + + /* max of 4 devices overall */ + if (p_dev->device_no >= 4) goto err_free; p_dev->socket = s; @@ -534,13 +535,12 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu /* * p_dev->function_config must be the same for all card functions. - * Note that this is serialized by the device_add_lock, so that - * only one such struct will be created. + * Note that this is serialized by ops_mutex, so that only one + * such struct will be created. */ list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list) if (p_dev->func == tmp_dev->func) { p_dev->function_config = tmp_dev->function_config; - p_dev->io = tmp_dev->io; p_dev->irq = tmp_dev->irq; kref_get(&p_dev->function_config->ref); } @@ -548,28 +548,45 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu /* Add to the list in pcmcia_bus_socket */ list_add(&p_dev->socket_device_list, &s->devices_list); - mutex_unlock(&s->ops_mutex); + if (pcmcia_setup_irq(p_dev)) + dev_warn(&p_dev->dev, + "IRQ setup failed -- device might not work\n"); if (!p_dev->function_config) { + config_t *c; dev_dbg(&p_dev->dev, "creating config_t\n"); - p_dev->function_config = kzalloc(sizeof(struct config_t), - GFP_KERNEL); - if (!p_dev->function_config) + c = kzalloc(sizeof(struct config_t), GFP_KERNEL); + if (!c) { + mutex_unlock(&s->ops_mutex); goto err_unreg; - kref_init(&p_dev->function_config->ref); + } + p_dev->function_config = c; + kref_init(&c->ref); + for (i = 0; i < MAX_IO_WIN; i++) { + c->io[i].name = p_dev->devname; + c->io[i].flags = IORESOURCE_IO; + } + for (i = 0; i< MAX_WIN; i++) { + c->mem[i].name = p_dev->devname; + c->mem[i].flags = IORESOURCE_MEM; + } } + for (i = 0; i < MAX_IO_WIN; i++) + p_dev->resource[i] = &p_dev->function_config->io[i]; + for (; i < (MAX_IO_WIN + MAX_WIN); i++) + p_dev->resource[i] = &p_dev->function_config->mem[i-MAX_IO_WIN]; + + mutex_unlock(&s->ops_mutex); dev_printk(KERN_NOTICE, &p_dev->dev, - "pcmcia: registering new device %s\n", - p_dev->devname); + "pcmcia: registering new device %s (IRQ: %d)\n", + p_dev->devname, p_dev->irq); pcmcia_device_query(p_dev); if (device_register(&p_dev->dev)) goto err_unreg; - mutex_unlock(&device_add_lock); - return p_dev; err_unreg: @@ -587,7 +604,6 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu kfree(p_dev->devname); kfree(p_dev); err_put: - mutex_unlock(&device_add_lock); pcmcia_put_socket(s); return NULL; @@ -649,14 +665,7 @@ static int pcmcia_requery_callback(struct device *dev, void * _data) static void pcmcia_requery(struct pcmcia_socket *s) { - int present, has_pfc; - - mutex_lock(&s->ops_mutex); - present = s->pcmcia_state.present; - mutex_unlock(&s->ops_mutex); - - if (!present) - return; + int has_pfc; if (s->functions == 0) { pcmcia_card_add(s); @@ -682,12 +691,11 @@ static void pcmcia_requery(struct pcmcia_socket *s) new_funcs = mfc.nfn; else new_funcs = 1; - if (old_funcs > new_funcs) { + if (old_funcs != new_funcs) { + /* we need to re-start */ pcmcia_card_remove(s, NULL); + s->functions = 0; pcmcia_card_add(s); - } else if (new_funcs > old_funcs) { - s->functions = new_funcs; - pcmcia_device_add(s, 1); } } @@ -695,7 +703,7 @@ static void pcmcia_requery(struct pcmcia_socket *s) * call pcmcia_device_add() -- which will fail if both * devices are already registered. */ mutex_lock(&s->ops_mutex); - has_pfc = s->pcmcia_state.has_pfc; + has_pfc = s->pcmcia_pfc; mutex_unlock(&s->ops_mutex); if (has_pfc) pcmcia_device_add(s, 0); @@ -723,6 +731,8 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) struct pcmcia_socket *s = dev->socket; const struct firmware *fw; int ret = -ENOMEM; + cistpl_longlink_mfc_t mfc; + int old_funcs, new_funcs = 1; if (!filename) return -EINVAL; @@ -745,6 +755,14 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) goto release; } + /* we need to re-start if the number of functions changed */ + old_funcs = s->functions; + if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, + &mfc)) + new_funcs = mfc.nfn; + + if (old_funcs != new_funcs) + ret = -EBUSY; /* update information */ pcmcia_device_query(dev); @@ -769,7 +787,7 @@ static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filenam static inline int pcmcia_devmatch(struct pcmcia_device *dev, - struct pcmcia_device_id *did) + const struct pcmcia_device_id *did) { if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) { if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id)) @@ -815,11 +833,12 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev, } if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) { - if (dev->device_no != did->device_no) - return 0; + dev_dbg(&dev->dev, "this is a pseudo-multi-function device\n"); mutex_lock(&dev->socket->ops_mutex); - dev->socket->pcmcia_state.has_pfc = 1; + dev->socket->pcmcia_pfc = 1; mutex_unlock(&dev->socket->ops_mutex); + if (dev->device_no != did->device_no) + return 0; } if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) { @@ -830,7 +849,7 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev, /* if this is a pseudo-multi-function device, * we need explicit matches */ - if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) + if (dev->socket->pcmcia_pfc) return 0; if (dev->device_no) return 0; @@ -853,10 +872,8 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev, if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) { dev_dbg(&dev->dev, "device needs a fake CIS\n"); if (!dev->socket->fake_cis) - pcmcia_load_firmware(dev, did->cisfile); - - if (!dev->socket->fake_cis) - return 0; + if (pcmcia_load_firmware(dev, did->cisfile)) + return 0; } if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) { @@ -876,7 +893,7 @@ static int pcmcia_bus_match(struct device *dev, struct device_driver *drv) { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); struct pcmcia_driver *p_drv = to_pcmcia_drv(drv); - struct pcmcia_device_id *did = p_drv->id_table; + const struct pcmcia_device_id *did = p_drv->id_table; struct pcmcia_dynid *dynid; /* match dynamic devices first */ @@ -891,14 +908,6 @@ static int pcmcia_bus_match(struct device *dev, struct device_driver *drv) } mutex_unlock(&p_drv->dynids.lock); -#ifdef CONFIG_PCMCIA_IOCTL - /* matching by cardmgr */ - if (p_dev->cardmgr == p_drv) { - dev_dbg(dev, "cardmgr matched to %s\n", drv->name); - return 1; - } -#endif - while (did && did->match_flags) { dev_dbg(dev, "trying to match to %s\n", drv->name); if (pcmcia_devmatch(p_dev, did)) { @@ -911,8 +920,6 @@ static int pcmcia_bus_match(struct device *dev, struct device_driver *drv) return 0; } -#ifdef CONFIG_HOTPLUG - static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct pcmcia_device *p_dev; @@ -953,15 +960,6 @@ static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env) return 0; } -#else - -static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - return -ENODEV; -} - -#endif - /************************ runtime PM support ***************************/ static int pcmcia_dev_suspend(struct device *dev, pm_message_t state); @@ -994,16 +992,17 @@ static ssize_t field##_show (struct device *dev, struct device_attribute *attr, { \ struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \ return p_dev->test ? sprintf(buf, format, p_dev->field) : -ENODEV; \ -} +} \ +static DEVICE_ATTR_RO(field); #define pcmcia_device_stringattr(name, field) \ static ssize_t name##_show (struct device *dev, struct device_attribute *attr, char *buf) \ { \ struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \ return p_dev->field ? sprintf(buf, "%s\n", p_dev->field) : -ENODEV; \ -} +} \ +static DEVICE_ATTR_RO(name); -pcmcia_device_attr(func, socket, "0x%02x\n"); pcmcia_device_attr(func_id, has_func_id, "0x%02x\n"); pcmcia_device_attr(manf_id, has_manf_id, "0x%04x\n"); pcmcia_device_attr(card_id, has_card_id, "0x%04x\n"); @@ -1012,8 +1011,29 @@ pcmcia_device_stringattr(prod_id2, prod_id[1]); pcmcia_device_stringattr(prod_id3, prod_id[2]); pcmcia_device_stringattr(prod_id4, prod_id[3]); +static ssize_t function_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct pcmcia_device *p_dev = to_pcmcia_dev(dev); + return p_dev->socket ? sprintf(buf, "0x%02x\n", p_dev->func) : -ENODEV; +} +static DEVICE_ATTR_RO(function); -static ssize_t pcmcia_show_pm_state(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t resources_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pcmcia_device *p_dev = to_pcmcia_dev(dev); + char *str = buf; + int i; + + for (i = 0; i < PCMCIA_NUM_RESOURCES; i++) + str += sprintf(str, "%pr\n", p_dev->resource[i]); + + return str - buf; +} +static DEVICE_ATTR_RO(resources); + +static ssize_t pm_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); @@ -1023,8 +1043,8 @@ static ssize_t pcmcia_show_pm_state(struct device *dev, struct device_attribute return sprintf(buf, "on\n"); } -static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t pm_state_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); int ret = 0; @@ -1039,7 +1059,7 @@ static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute return ret ? ret : count; } - +static DEVICE_ATTR_RW(pm_state); static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1062,8 +1082,9 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, p_dev->func, p_dev->device_no, hash[0], hash[1], hash[2], hash[3]); } +static DEVICE_ATTR_RO(modalias); -static ssize_t pcmcia_store_allow_func_id_match(struct device *dev, +static ssize_t allow_func_id_match_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct pcmcia_device *p_dev = to_pcmcia_dev(dev); @@ -1078,21 +1099,24 @@ static ssize_t pcmcia_store_allow_func_id_match(struct device *dev, return count; } - -static struct device_attribute pcmcia_dev_attrs[] = { - __ATTR(function, 0444, func_show, NULL), - __ATTR(pm_state, 0644, pcmcia_show_pm_state, pcmcia_store_pm_state), - __ATTR_RO(func_id), - __ATTR_RO(manf_id), - __ATTR_RO(card_id), - __ATTR_RO(prod_id1), - __ATTR_RO(prod_id2), - __ATTR_RO(prod_id3), - __ATTR_RO(prod_id4), - __ATTR_RO(modalias), - __ATTR(allow_func_id_match, 0200, NULL, pcmcia_store_allow_func_id_match), - __ATTR_NULL, +static DEVICE_ATTR_WO(allow_func_id_match); + +static struct attribute *pcmcia_dev_attrs[] = { + &dev_attr_resources.attr, + &dev_attr_pm_state.attr, + &dev_attr_function.attr, + &dev_attr_func_id.attr, + &dev_attr_manf_id.attr, + &dev_attr_card_id.attr, + &dev_attr_prod_id1.attr, + &dev_attr_prod_id2.attr, + &dev_attr_prod_id3.attr, + &dev_attr_prod_id4.attr, + &dev_attr_modalias.attr, + &dev_attr_allow_func_id_match.attr, + NULL, }; +ATTRIBUTE_GROUPS(pcmcia_dev); /* PM support, also needed for reset */ @@ -1124,7 +1148,7 @@ static int pcmcia_dev_suspend(struct device *dev, pm_message_t state) dev_printk(KERN_ERR, dev, "pcmcia: device %s (driver %s) did " "not want to go to sleep (%d)\n", - p_dev->devname, p_drv->drv.name, ret); + p_dev->devname, p_drv->name, ret); mutex_lock(&p_dev->socket->ops_mutex); p_dev->suspended = 0; mutex_unlock(&p_dev->socket->ops_mutex); @@ -1166,7 +1190,7 @@ static int pcmcia_dev_resume(struct device *dev) if (p_dev->device_no == p_dev->func) { dev_dbg(dev, "requesting configuration\n"); - ret = pcmcia_request_configuration(p_dev, &p_dev->conf); + ret = pcmcia_enable_device(p_dev); if (ret) goto out; } @@ -1221,88 +1245,63 @@ static int pcmcia_bus_suspend(struct pcmcia_socket *skt) return 0; } +static int pcmcia_bus_remove(struct pcmcia_socket *skt) +{ + atomic_set(&skt->present, 0); + pcmcia_card_remove(skt, NULL); -/*====================================================================== - - The card status event handler. - -======================================================================*/ + mutex_lock(&skt->ops_mutex); + destroy_cis_cache(skt); + pcmcia_cleanup_irq(skt); + mutex_unlock(&skt->ops_mutex); -/* Normally, the event is passed to individual drivers after - * informing userspace. Only for CS_EVENT_CARD_REMOVAL this - * is inversed to maintain historic compatibility. - */ + return 0; +} -static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) +static int pcmcia_bus_add(struct pcmcia_socket *skt) { - struct pcmcia_socket *s = pcmcia_get_socket(skt); + atomic_set(&skt->present, 1); - if (!s) { - dev_printk(KERN_ERR, &skt->dev, - "PCMCIA obtaining reference to socket " \ - "failed, event 0x%x lost!\n", event); - return -ENODEV; - } + mutex_lock(&skt->ops_mutex); + skt->pcmcia_pfc = 0; + destroy_cis_cache(skt); /* to be on the safe side... */ + mutex_unlock(&skt->ops_mutex); - dev_dbg(&skt->dev, "ds_event(0x%06x, %d, 0x%p)\n", - event, priority, skt); + pcmcia_card_add(skt); - switch (event) { - case CS_EVENT_CARD_REMOVAL: - mutex_lock(&s->ops_mutex); - s->pcmcia_state.present = 0; - mutex_unlock(&s->ops_mutex); - pcmcia_card_remove(skt, NULL); - handle_event(skt, event); - mutex_lock(&s->ops_mutex); - destroy_cis_cache(s); - mutex_unlock(&s->ops_mutex); - break; + return 0; +} - case CS_EVENT_CARD_INSERTION: - mutex_lock(&s->ops_mutex); - s->pcmcia_state.has_pfc = 0; - s->pcmcia_state.present = 1; - destroy_cis_cache(s); /* to be on the safe side... */ - mutex_unlock(&s->ops_mutex); - pcmcia_card_add(skt); - handle_event(skt, event); - break; - - case CS_EVENT_EJECTION_REQUEST: - break; - - case CS_EVENT_PM_RESUME: - if (verify_cis_cache(skt) != 0) { - dev_dbg(&skt->dev, "cis mismatch - different card\n"); - /* first, remove the card */ - ds_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH); - mutex_lock(&s->ops_mutex); - destroy_cis_cache(skt); - kfree(skt->fake_cis); - skt->fake_cis = NULL; - mutex_unlock(&s->ops_mutex); - /* now, add the new card */ - ds_event(skt, CS_EVENT_CARD_INSERTION, - CS_EVENT_PRI_LOW); - } - handle_event(skt, event); - break; +static int pcmcia_bus_early_resume(struct pcmcia_socket *skt) +{ + if (!verify_cis_cache(skt)) + return 0; - case CS_EVENT_PM_SUSPEND: - case CS_EVENT_RESET_PHYSICAL: - case CS_EVENT_CARD_RESET: - default: - handle_event(skt, event); - break; - } + dev_dbg(&skt->dev, "cis mismatch - different card\n"); - pcmcia_put_socket(s); + /* first, remove the card */ + pcmcia_bus_remove(skt); - return 0; -} /* ds_event */ + mutex_lock(&skt->ops_mutex); + destroy_cis_cache(skt); + kfree(skt->fake_cis); + skt->fake_cis = NULL; + skt->functions = 0; + mutex_unlock(&skt->ops_mutex); + + /* now, add the new card */ + pcmcia_bus_add(skt); + return 0; +} +/* + * NOTE: This is racy. There's no guarantee the card will still be + * physically present, even if the call to this function returns + * non-NULL. Furthermore, the device driver most likely is unbound + * almost immediately, so the timeframe where pcmcia_dev_present + * returns NULL is probably really really small. + */ struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev) { struct pcmcia_device *p_dev; @@ -1312,22 +1311,9 @@ struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev) if (!p_dev) return NULL; - mutex_lock(&p_dev->socket->ops_mutex); - if (!p_dev->socket->pcmcia_state.present) - goto out; - - if (p_dev->socket->pcmcia_state.dead) - goto out; - - if (p_dev->_removed) - goto out; - - if (p_dev->suspended) - goto out; + if (atomic_read(&p_dev->socket->present) != 0) + ret = p_dev; - ret = p_dev; - out: - mutex_unlock(&p_dev->socket->ops_mutex); pcmcia_put_dev(p_dev); return ret; } @@ -1336,14 +1322,16 @@ EXPORT_SYMBOL(pcmcia_dev_present); static struct pcmcia_callback pcmcia_bus_callback = { .owner = THIS_MODULE, - .event = ds_event, + .add = pcmcia_bus_add, + .remove = pcmcia_bus_remove, .requery = pcmcia_requery, .validate = pccard_validate_cis, .suspend = pcmcia_bus_suspend, + .early_resume = pcmcia_bus_early_resume, .resume = pcmcia_bus_resume, }; -static int __devinit pcmcia_bus_add_socket(struct device *dev, +static int pcmcia_bus_add_socket(struct device *dev, struct class_interface *class_intf) { struct pcmcia_socket *socket = dev_get_drvdata(dev); @@ -1363,12 +1351,10 @@ static int __devinit pcmcia_bus_add_socket(struct device *dev, return ret; } -#ifdef CONFIG_PCMCIA_IOCTL - init_waitqueue_head(&socket->queue); -#endif INIT_LIST_HEAD(&socket->devices_list); - memset(&socket->pcmcia_state, 0, sizeof(u8)); + socket->pcmcia_pfc = 0; socket->device_count = 0; + atomic_set(&socket->present, 0); ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback); if (ret) { @@ -1388,10 +1374,6 @@ static void pcmcia_bus_remove_socket(struct device *dev, if (!socket) return; - mutex_lock(&socket->ops_mutex); - socket->pcmcia_state.dead = 1; - mutex_unlock(&socket->ops_mutex); - pccard_register_pcmcia(socket, NULL); /* unregister any unbound devices */ @@ -1420,7 +1402,7 @@ struct bus_type pcmcia_bus_type = { .name = "pcmcia", .uevent = pcmcia_bus_uevent, .match = pcmcia_bus_match, - .dev_attrs = pcmcia_dev_attrs, + .dev_groups = pcmcia_dev_groups, .probe = pcmcia_device_probe, .remove = pcmcia_device_remove, .suspend = pcmcia_dev_suspend, @@ -1445,8 +1427,6 @@ static int __init init_pcmcia_bus(void) return ret; } - pcmcia_setup_ioctl(); - return 0; } fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that @@ -1455,8 +1435,6 @@ fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that static void __exit exit_pcmcia_bus(void) { - pcmcia_cleanup_ioctl(); - class_interface_unregister(&pcmcia_bus_interface); bus_unregister(&pcmcia_bus_type); |
