blob: bd81aa64d011b8839950e61f7c1e2a04563022be [file] [log] [blame]
Thomas Gleixnerd2912cb2019-06-04 10:11:33 +02001// SPDX-License-Identifier: GPL-2.0-only
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * ds.c -- 16-bit PCMCIA core support
4 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * The initial developer of the original code is David A. Hinds
6 * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
7 * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
8 *
9 * (C) 1999 David A. Hinds
Dominik Brodowski7b24e792010-07-11 10:26:53 +020010 * (C) 2003 - 2010 Dominik Brodowski
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/kernel.h>
Dominik Brodowski3b659fb2005-06-27 16:28:51 -070014#include <linux/module.h>
15#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/errno.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/list.h>
18#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/workqueue.h>
Dominik Brodowski840c2ac2005-06-27 16:28:04 -070020#include <linux/crc32.h>
Dominik Brodowskidaa95172005-06-27 16:28:14 -070021#include <linux/firmware.h>
Dominik Brodowski360b65b2006-01-10 20:50:39 +010022#include <linux/kref.h>
James Bottomley43d9f7f2007-10-16 01:23:58 -070023#include <linux/dma-mapping.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090024#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <pcmcia/cistpl.h>
27#include <pcmcia/ds.h>
28#include <pcmcia/ss.h>
29
30#include "cs_internal.h"
31
32/*====================================================================*/
33
34/* Module parameters */
35
36MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
37MODULE_DESCRIPTION("PCMCIA Driver Services");
38MODULE_LICENSE("GPL");
39
Linus Torvalds1da177e2005-04-16 15:20:36 -070040
Linus Torvalds1da177e2005-04-16 15:20:36 -070041/*====================================================================*/
42
Dominik Brodowski23a83bf2005-06-27 16:28:07 -070043static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
44{
Joe Perchese9fb13b2011-05-03 19:29:00 -070045 const struct pcmcia_device_id *did = p_drv->id_table;
Dominik Brodowski23a83bf2005-06-27 16:28:07 -070046 unsigned int i;
47 u32 hash;
48
Dominik Brodowskif8cfa612005-11-14 21:25:51 +010049 if (!p_drv->probe || !p_drv->remove)
Pavel Roskinba5bb6b2005-07-28 01:07:20 -070050 printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback "
Dominik Brodowski2e9b9812010-08-08 11:36:26 +020051 "function\n", p_drv->name);
Dominik Brodowski1e212f32005-07-07 17:59:00 -070052
Dominik Brodowski23a83bf2005-06-27 16:28:07 -070053 while (did && did->match_flags) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +010054 for (i = 0; i < 4; i++) {
Dominik Brodowski23a83bf2005-06-27 16:28:07 -070055 if (!did->prod_id[i])
56 continue;
57
58 hash = crc32(0, did->prod_id[i], strlen(did->prod_id[i]));
59 if (hash == did->prod_id_hash[i])
60 continue;
61
62 printk(KERN_DEBUG "pcmcia: %s: invalid hash for "
63 "product string \"%s\": is 0x%x, should "
Dominik Brodowski2e9b9812010-08-08 11:36:26 +020064 "be 0x%x\n", p_drv->name, did->prod_id[i],
Dominik Brodowski23a83bf2005-06-27 16:28:07 -070065 did->prod_id_hash[i], hash);
Dominik Brodowski5085cb22005-06-27 16:28:45 -070066 printk(KERN_DEBUG "pcmcia: see "
Mauro Carvalho Chehab3bdab162019-06-12 14:52:53 -030067 "Documentation/pcmcia/devicetable.rst for "
Dominik Brodowski5085cb22005-06-27 16:28:45 -070068 "details\n");
Dominik Brodowski23a83bf2005-06-27 16:28:07 -070069 }
70 did++;
71 }
72
73 return;
74}
75
Dominik Brodowskidaa95172005-06-27 16:28:14 -070076
Linus Torvalds1da177e2005-04-16 15:20:36 -070077/*======================================================================*/
78
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Bernhard Walle6179b552007-05-06 14:48:44 -070080struct pcmcia_dynid {
Laurent Navet46f533c2013-01-21 22:16:05 +010081 struct list_head node;
82 struct pcmcia_device_id id;
Bernhard Walle6179b552007-05-06 14:48:44 -070083};
84
85/**
Lee Jones6562e2c2021-03-12 11:02:37 +000086 * new_id_store() - add a new PCMCIA device ID to this driver and re-probe devices
Bernhard Walle6179b552007-05-06 14:48:44 -070087 * @driver: target device driver
88 * @buf: buffer for scanning device ID data
89 * @count: input size
90 *
91 * Adds a new dynamic PCMCIA device ID to this driver,
92 * and causes the driver to probe for all devices again.
93 */
94static ssize_t
Greg Kroah-Hartmanad8f20a2017-06-09 11:03:11 +020095new_id_store(struct device_driver *driver, const char *buf, size_t count)
Bernhard Walle6179b552007-05-06 14:48:44 -070096{
97 struct pcmcia_dynid *dynid;
98 struct pcmcia_driver *pdrv = to_pcmcia_drv(driver);
99 __u16 match_flags, manf_id, card_id;
100 __u8 func_id, function, device_no;
101 __u32 prod_id_hash[4] = {0, 0, 0, 0};
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100102 int fields = 0;
Bernhard Walle6179b552007-05-06 14:48:44 -0700103 int retval = 0;
104
105 fields = sscanf(buf, "%hx %hx %hx %hhx %hhx %hhx %x %x %x %x",
106 &match_flags, &manf_id, &card_id, &func_id, &function, &device_no,
107 &prod_id_hash[0], &prod_id_hash[1], &prod_id_hash[2], &prod_id_hash[3]);
108 if (fields < 6)
109 return -EINVAL;
110
111 dynid = kzalloc(sizeof(struct pcmcia_dynid), GFP_KERNEL);
112 if (!dynid)
113 return -ENOMEM;
114
Bernhard Walle6179b552007-05-06 14:48:44 -0700115 dynid->id.match_flags = match_flags;
116 dynid->id.manf_id = manf_id;
117 dynid->id.card_id = card_id;
118 dynid->id.func_id = func_id;
119 dynid->id.function = function;
120 dynid->id.device_no = device_no;
121 memcpy(dynid->id.prod_id_hash, prod_id_hash, sizeof(__u32) * 4);
122
Dominik Brodowski3f565232010-01-16 13:06:40 +0100123 mutex_lock(&pdrv->dynids.lock);
Wolfram Sangb4b3d7b2009-07-20 10:58:59 +0200124 list_add_tail(&dynid->node, &pdrv->dynids.list);
Dominik Brodowski3f565232010-01-16 13:06:40 +0100125 mutex_unlock(&pdrv->dynids.lock);
Bernhard Walle6179b552007-05-06 14:48:44 -0700126
Alan Sterncef9bc52012-01-24 13:34:41 -0500127 retval = driver_attach(&pdrv->drv);
Bernhard Walle6179b552007-05-06 14:48:44 -0700128
129 if (retval)
130 return retval;
131 return count;
132}
Greg Kroah-Hartmanad8f20a2017-06-09 11:03:11 +0200133static DRIVER_ATTR_WO(new_id);
Bernhard Walle6179b552007-05-06 14:48:44 -0700134
135static void
136pcmcia_free_dynids(struct pcmcia_driver *drv)
137{
138 struct pcmcia_dynid *dynid, *n;
139
Dominik Brodowski3f565232010-01-16 13:06:40 +0100140 mutex_lock(&drv->dynids.lock);
Bernhard Walle6179b552007-05-06 14:48:44 -0700141 list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
142 list_del(&dynid->node);
143 kfree(dynid);
144 }
Dominik Brodowski3f565232010-01-16 13:06:40 +0100145 mutex_unlock(&drv->dynids.lock);
Bernhard Walle6179b552007-05-06 14:48:44 -0700146}
147
148static int
149pcmcia_create_newid_file(struct pcmcia_driver *drv)
150{
151 int error = 0;
152 if (drv->probe != NULL)
Greg Kroah-Hartman2344c6d2007-11-28 12:23:18 -0800153 error = driver_create_file(&drv->drv, &driver_attr_new_id);
Bernhard Walle6179b552007-05-06 14:48:44 -0700154 return error;
155}
156
Alan Sterned283e92012-01-24 14:35:13 -0500157static void
158pcmcia_remove_newid_file(struct pcmcia_driver *drv)
159{
160 driver_remove_file(&drv->drv, &driver_attr_new_id);
161}
Bernhard Walle6179b552007-05-06 14:48:44 -0700162
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163/**
164 * pcmcia_register_driver - register a PCMCIA driver with the bus core
Randy Dunlap78187862007-12-10 15:49:22 -0800165 * @driver: the &driver being registered
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 *
167 * Registers a PCMCIA driver with the PCMCIA bus core.
168 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169int pcmcia_register_driver(struct pcmcia_driver *driver)
170{
Bernhard Walle6179b552007-05-06 14:48:44 -0700171 int error;
172
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 if (!driver)
174 return -EINVAL;
175
Dominik Brodowski23a83bf2005-06-27 16:28:07 -0700176 pcmcia_check_driver(driver);
177
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 /* initialize common fields */
179 driver->drv.bus = &pcmcia_bus_type;
180 driver->drv.owner = driver->owner;
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200181 driver->drv.name = driver->name;
Dominik Brodowski3f565232010-01-16 13:06:40 +0100182 mutex_init(&driver->dynids.lock);
Bernhard Walle6179b552007-05-06 14:48:44 -0700183 INIT_LIST_HEAD(&driver->dynids.list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200185 pr_debug("registering driver %s\n", driver->name);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200186
Bernhard Walle6179b552007-05-06 14:48:44 -0700187 error = driver_register(&driver->drv);
188 if (error < 0)
189 return error;
190
191 error = pcmcia_create_newid_file(driver);
192 if (error)
193 driver_unregister(&driver->drv);
194
195 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196}
197EXPORT_SYMBOL(pcmcia_register_driver);
198
199/**
200 * pcmcia_unregister_driver - unregister a PCMCIA driver with the bus core
Randy Dunlap78187862007-12-10 15:49:22 -0800201 * @driver: the &driver being unregistered
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 */
203void pcmcia_unregister_driver(struct pcmcia_driver *driver)
204{
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200205 pr_debug("unregistering driver %s\n", driver->name);
Alan Sterned283e92012-01-24 14:35:13 -0500206 pcmcia_remove_newid_file(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 driver_unregister(&driver->drv);
Bernhard Walle6179b552007-05-06 14:48:44 -0700208 pcmcia_free_dynids(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209}
210EXPORT_SYMBOL(pcmcia_unregister_driver);
211
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
213/* pcmcia_device handling */
214
Dominik Brodowski5716d412010-07-11 09:51:14 +0200215static struct pcmcia_device *pcmcia_get_dev(struct pcmcia_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216{
217 struct device *tmp_dev;
218 tmp_dev = get_device(&p_dev->dev);
219 if (!tmp_dev)
220 return NULL;
221 return to_pcmcia_dev(tmp_dev);
222}
223
Dominik Brodowski5716d412010-07-11 09:51:14 +0200224static void pcmcia_put_dev(struct pcmcia_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225{
226 if (p_dev)
227 put_device(&p_dev->dev);
228}
229
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100230static void pcmcia_release_function(struct kref *ref)
231{
232 struct config_t *c = container_of(ref, struct config_t, ref);
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200233 pr_debug("releasing config_t\n");
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100234 kfree(c);
235}
236
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237static void pcmcia_release_dev(struct device *dev)
238{
239 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
Dominik Brodowski44961a02010-01-24 12:11:02 +0100240 int i;
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200241 dev_dbg(dev, "releasing device\n");
Dominik Brodowskidc109492005-06-27 16:28:50 -0700242 pcmcia_put_socket(p_dev->socket);
Dominik Brodowski44961a02010-01-24 12:11:02 +0100243 for (i = 0; i < 4; i++)
244 kfree(p_dev->prod_id[i]);
Brice Goglinbd65a682005-09-09 13:03:29 -0700245 kfree(p_dev->devname);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100246 kref_put(&p_dev->function_config->ref, pcmcia_release_function);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 kfree(p_dev);
248}
249
250
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100251static int pcmcia_device_probe(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252{
253 struct pcmcia_device *p_dev;
254 struct pcmcia_driver *p_drv;
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100255 struct pcmcia_socket *s;
Dominik Brodowskiaf2b3b52006-10-25 21:49:27 -0400256 cistpl_config_t cis_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 int ret = 0;
258
259 dev = get_device(dev);
260 if (!dev)
261 return -ENODEV;
262
263 p_dev = to_pcmcia_dev(dev);
264 p_drv = to_pcmcia_drv(dev->driver);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100265 s = p_dev->socket;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200267 dev_dbg(dev, "trying to bind to %s\n", p_drv->name);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200268
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100269 if ((!p_drv->probe) || (!p_dev->function_config) ||
270 (!try_module_get(p_drv->owner))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 ret = -EINVAL;
272 goto put_dev;
273 }
274
Dominik Brodowskiaf2b3b52006-10-25 21:49:27 -0400275 /* set up some more device information */
276 ret = pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_CONFIG,
277 &cis_config);
278 if (!ret) {
Dominik Brodowski7feabb62010-07-29 18:35:47 +0200279 p_dev->config_base = cis_config.base;
280 p_dev->config_regs = cis_config.rmask[0];
Dominik Brodowski1cc745d2010-08-01 11:21:14 +0200281 dev_dbg(dev, "base %x, regs %x", p_dev->config_base,
282 p_dev->config_regs);
Dominik Brodowskiaf2b3b52006-10-25 21:49:27 -0400283 } else {
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700284 dev_info(dev,
285 "pcmcia: could not parse base and rmask0 of CIS\n");
Dominik Brodowski7feabb62010-07-29 18:35:47 +0200286 p_dev->config_base = 0;
287 p_dev->config_regs = 0;
Dominik Brodowskiaf2b3b52006-10-25 21:49:27 -0400288 }
289
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100290 ret = p_drv->probe(p_dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200291 if (ret) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200292 dev_dbg(dev, "binding to %s failed with %d\n",
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200293 p_drv->name, ret);
Dominik Brodowski82d56e62006-01-27 19:15:02 +0100294 goto put_module;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200295 }
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200296 dev_dbg(dev, "%s bound: Vpp %d.%d, idx %x, IRQ %d", p_drv->name,
Dominik Brodowski1cc745d2010-08-01 11:21:14 +0200297 p_dev->vpp/10, p_dev->vpp%10, p_dev->config_index, p_dev->irq);
298 dev_dbg(dev, "resources: ioport %pR %pR iomem %pR %pR %pR",
299 p_dev->resource[0], p_dev->resource[1], p_dev->resource[2],
300 p_dev->resource[3], p_dev->resource[4]);
Dominik Brodowski82d56e62006-01-27 19:15:02 +0100301
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100302 mutex_lock(&s->ops_mutex);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +0200303 if ((s->pcmcia_pfc) &&
Dominik Brodowski82d56e62006-01-27 19:15:02 +0100304 (p_dev->socket->device_count == 1) && (p_dev->device_no == 0))
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100305 pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100306 mutex_unlock(&s->ops_mutex);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100307
Alan Coxcec5eb72008-09-22 15:58:14 +0100308put_module:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 if (ret)
310 module_put(p_drv->owner);
Alan Coxcec5eb72008-09-22 15:58:14 +0100311put_dev:
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100312 if (ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 put_device(dev);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100314 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315}
316
317
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100318/*
319 * Removes a PCMCIA card from the device tree and socket list.
320 */
321static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *leftover)
322{
323 struct pcmcia_device *p_dev;
324 struct pcmcia_device *tmp;
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100325
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200326 dev_dbg(leftover ? &leftover->dev : &s->dev,
Dominik Brodowskiac449d62008-08-02 18:33:56 +0200327 "pcmcia_card_remove(%d) %s\n", s->sock,
328 leftover ? leftover->devname : "");
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100329
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100330 mutex_lock(&s->ops_mutex);
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100331 if (!leftover)
332 s->device_count = 0;
333 else
334 s->device_count = 1;
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100335 mutex_unlock(&s->ops_mutex);
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100336
337 /* unregister all pcmcia_devices registered with this socket, except leftover */
338 list_for_each_entry_safe(p_dev, tmp, &s->devices_list, socket_device_list) {
339 if (p_dev == leftover)
340 continue;
341
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100342 mutex_lock(&s->ops_mutex);
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100343 list_del(&p_dev->socket_device_list);
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100344 mutex_unlock(&s->ops_mutex);
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100345
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200346 dev_dbg(&p_dev->dev, "unregistering device\n");
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100347 device_unregister(&p_dev->dev);
348 }
349
350 return;
351}
352
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100353static int pcmcia_device_remove(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
355 struct pcmcia_device *p_dev;
356 struct pcmcia_driver *p_drv;
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100357 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 p_dev = to_pcmcia_dev(dev);
360 p_drv = to_pcmcia_drv(dev->driver);
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100361
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200362 dev_dbg(dev, "removing device\n");
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200363
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100364 /* If we're removing the primary module driving a
365 * pseudo multi-function card, we need to unbind
366 * all devices
367 */
Dominik Brodowskice3f9d72010-07-21 14:43:05 +0200368 if ((p_dev->socket->pcmcia_pfc) &&
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100369 (p_dev->socket->device_count > 0) &&
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100370 (p_dev->device_no == 0))
371 pcmcia_card_remove(p_dev->socket, p_dev);
372
373 /* detach the "instance" */
Dominik Brodowskif3990712005-11-14 21:25:23 +0100374 if (p_drv->remove)
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100375 p_drv->remove(p_dev);
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100376
Dominik Brodowskif3990712005-11-14 21:25:23 +0100377 /* check for proper unloading */
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100378 if (p_dev->_irq || p_dev->_io || p_dev->_locked)
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700379 dev_info(dev,
380 "pcmcia: driver %s did not release config properly\n",
381 p_drv->name);
Dominik Brodowskif3990712005-11-14 21:25:23 +0100382
383 for (i = 0; i < MAX_WIN; i++)
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100384 if (p_dev->_win & CLIENT_WIN_REQ(i))
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700385 dev_info(dev,
386 "pcmcia: driver %s did not release window properly\n",
387 p_drv->name);
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100388
Uwe Kleine-Königcd2b4f12021-03-01 18:38:47 +0100389 /* references from pcmcia_device_probe */
Dominik Brodowskif3990712005-11-14 21:25:23 +0100390 pcmcia_put_dev(p_dev);
391 module_put(p_drv->owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
393 return 0;
394}
395
396
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100397/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 * pcmcia_device_query -- determine information about a pcmcia device
399 */
400static int pcmcia_device_query(struct pcmcia_device *p_dev)
401{
402 cistpl_manfid_t manf_id;
403 cistpl_funcid_t func_id;
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700404 cistpl_vers_1_t *vers1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 unsigned int i;
406
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700407 vers1 = kmalloc(sizeof(*vers1), GFP_KERNEL);
408 if (!vers1)
409 return -ENOMEM;
410
Dominik Brodowski84897fc2009-10-18 23:51:09 +0200411 if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 CISTPL_MANFID, &manf_id)) {
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100413 mutex_lock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 p_dev->manf_id = manf_id.manf;
415 p_dev->card_id = manf_id.card;
416 p_dev->has_manf_id = 1;
417 p_dev->has_card_id = 1;
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100418 mutex_unlock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 }
420
421 if (!pccard_read_tuple(p_dev->socket, p_dev->func,
422 CISTPL_FUNCID, &func_id)) {
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100423 mutex_lock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 p_dev->func_id = func_id.func;
425 p_dev->has_func_id = 1;
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100426 mutex_unlock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 } else {
428 /* rule of thumb: cards with no FUNCID, but with
429 * common memory device geometry information, are
430 * probably memory cards (from pcmcia-cs) */
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700431 cistpl_device_geo_t *devgeo;
432
433 devgeo = kmalloc(sizeof(*devgeo), GFP_KERNEL);
434 if (!devgeo) {
435 kfree(vers1);
436 return -ENOMEM;
437 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 if (!pccard_read_tuple(p_dev->socket, p_dev->func,
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700439 CISTPL_DEVICE_GEO, devgeo)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200440 dev_dbg(&p_dev->dev,
Dominik Brodowskiac449d62008-08-02 18:33:56 +0200441 "mem device geometry probably means "
442 "FUNCID_MEMORY\n");
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100443 mutex_lock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 p_dev->func_id = CISTPL_FUNCID_MEMORY;
445 p_dev->has_func_id = 1;
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100446 mutex_unlock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 }
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700448 kfree(devgeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 }
450
Dominik Brodowski84897fc2009-10-18 23:51:09 +0200451 if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL, CISTPL_VERS_1,
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700452 vers1)) {
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100453 mutex_lock(&p_dev->socket->ops_mutex);
Dominik Brodowskic5e09522009-10-19 00:04:25 +0200454 for (i = 0; i < min_t(unsigned int, 4, vers1->ns); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 char *tmp;
456 unsigned int length;
Dominik Brodowski44961a02010-01-24 12:11:02 +0100457 char *new;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700459 tmp = vers1->str + vers1->ofs[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
461 length = strlen(tmp) + 1;
Janos Farkas6e3d4f22006-03-31 01:04:57 +0200462 if ((length < 2) || (length > 255))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 continue;
464
Geliang Tang7c22e642015-10-02 00:37:57 +0800465 new = kstrdup(tmp, GFP_KERNEL);
Dominik Brodowski44961a02010-01-24 12:11:02 +0100466 if (!new)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 continue;
468
Dominik Brodowski44961a02010-01-24 12:11:02 +0100469 tmp = p_dev->prod_id[i];
470 p_dev->prod_id[i] = new;
471 kfree(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 }
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100473 mutex_unlock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 }
475
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700476 kfree(vers1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 return 0;
478}
479
480
Dominik Brodowski5716d412010-07-11 09:51:14 +0200481static struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s,
482 unsigned int function)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483{
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100484 struct pcmcia_device *p_dev, *tmp_dev;
Dominik Brodowski44961a02010-01-24 12:11:02 +0100485 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486
Dominik Brodowskidc109492005-06-27 16:28:50 -0700487 s = pcmcia_get_socket(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 if (!s)
489 return NULL;
490
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200491 pr_debug("adding device to %d, function %d\n", s->sock, function);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200492
Dominik Brodowski8084b372005-12-11 21:18:26 +0100493 p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 if (!p_dev)
495 goto err_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100497 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 p_dev->device_no = (s->device_count++);
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100499 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100500
Dominik Brodowski7d7ba8d2010-03-24 10:49:14 +0100501 /* max of 2 PFC devices */
502 if ((p_dev->device_no >= 2) && (function == 0))
503 goto err_free;
504
505 /* max of 4 devices overall */
506 if (p_dev->device_no >= 4)
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100507 goto err_free;
508
509 p_dev->socket = s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 p_dev->func = function;
511
512 p_dev->dev.bus = &pcmcia_bus_type;
Greg Kroah-Hartman87373312006-09-12 17:00:10 +0200513 p_dev->dev.parent = s->dev.parent;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 p_dev->dev.release = pcmcia_release_dev;
James Bottomley43d9f7f2007-10-16 01:23:58 -0700515 /* by default don't allow DMA */
Christoph Hellwig7ae10eb2020-09-11 09:29:50 +0200516 p_dev->dma_mask = 0;
James Bottomley43d9f7f2007-10-16 01:23:58 -0700517 p_dev->dev.dma_mask = &p_dev->dma_mask;
Kay Sievers25096982008-11-01 11:46:06 +0100518 dev_set_name(&p_dev->dev, "%d.%d", p_dev->socket->sock, p_dev->device_no);
519 if (!dev_name(&p_dev->dev))
520 goto err_free;
521 p_dev->devname = kasprintf(GFP_KERNEL, "pcmcia%s", dev_name(&p_dev->dev));
Brice Goglinbd65a682005-09-09 13:03:29 -0700522 if (!p_dev->devname)
523 goto err_free;
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200524 dev_dbg(&p_dev->dev, "devname is %s\n", p_dev->devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100526 mutex_lock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100527
528 /*
529 * p_dev->function_config must be the same for all card functions.
Dominik Brodowskia60f22c2010-03-07 09:22:51 +0100530 * Note that this is serialized by ops_mutex, so that only one
531 * such struct will be created.
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100532 */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100533 list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)
534 if (p_dev->func == tmp_dev->func) {
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100535 p_dev->function_config = tmp_dev->function_config;
Komuro3e879f62008-11-02 19:33:24 +0900536 p_dev->irq = tmp_dev->irq;
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100537 kref_get(&p_dev->function_config->ref);
538 }
539
540 /* Add to the list in pcmcia_bus_socket */
Komuro6171b882006-04-02 17:39:27 +0900541 list_add(&p_dev->socket_device_list, &s->devices_list);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100542
Dominik Brodowski6f0f38c2010-04-08 20:33:16 +0200543 if (pcmcia_setup_irq(p_dev))
544 dev_warn(&p_dev->dev,
545 "IRQ setup failed -- device might not work\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100547 if (!p_dev->function_config) {
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200548 config_t *c;
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200549 dev_dbg(&p_dev->dev, "creating config_t\n");
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200550 c = kzalloc(sizeof(struct config_t), GFP_KERNEL);
551 if (!c) {
Dominik Brodowski6f0f38c2010-04-08 20:33:16 +0200552 mutex_unlock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100553 goto err_unreg;
Dominik Brodowski6f0f38c2010-04-08 20:33:16 +0200554 }
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200555 p_dev->function_config = c;
556 kref_init(&c->ref);
557 for (i = 0; i < MAX_IO_WIN; i++) {
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200558 c->io[i].name = p_dev->devname;
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200559 c->io[i].flags = IORESOURCE_IO;
560 }
Laurent Navet46f533c2013-01-21 22:16:05 +0100561 for (i = 0; i < MAX_WIN; i++) {
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200562 c->mem[i].name = p_dev->devname;
Dominik Brodowski0ca724d32010-07-24 19:03:02 +0200563 c->mem[i].flags = IORESOURCE_MEM;
564 }
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100565 }
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200566 for (i = 0; i < MAX_IO_WIN; i++)
567 p_dev->resource[i] = &p_dev->function_config->io[i];
Dominik Brodowski0ca724d32010-07-24 19:03:02 +0200568 for (; i < (MAX_IO_WIN + MAX_WIN); i++)
569 p_dev->resource[i] = &p_dev->function_config->mem[i-MAX_IO_WIN];
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200570
Dominik Brodowski6f0f38c2010-04-08 20:33:16 +0200571 mutex_unlock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100572
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700573 dev_notice(&p_dev->dev, "pcmcia: registering new device %s (IRQ: %d)\n",
Dominik Brodowskieb141202010-03-07 12:21:16 +0100574 p_dev->devname, p_dev->irq);
Dominik Brodowski807277c2005-11-12 23:34:06 +0100575
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700576 pcmcia_device_query(p_dev);
577
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100578 if (device_register(&p_dev->dev))
579 goto err_unreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 return p_dev;
582
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100583 err_unreg:
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100584 mutex_lock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100585 list_del(&p_dev->socket_device_list);
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100586 mutex_unlock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100587
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 err_free:
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100589 mutex_lock(&s->ops_mutex);
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100590 s->device_count--;
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100591 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100592
Dominik Brodowski44961a02010-01-24 12:11:02 +0100593 for (i = 0; i < 4; i++)
594 kfree(p_dev->prod_id[i]);
Brice Goglinbd65a682005-09-09 13:03:29 -0700595 kfree(p_dev->devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 kfree(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 err_put:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700598 pcmcia_put_socket(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
600 return NULL;
601}
602
603
604static int pcmcia_card_add(struct pcmcia_socket *s)
605{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 cistpl_longlink_mfc_t mfc;
Dominik Brodowskic5081d52008-06-19 20:12:34 +0200607 unsigned int no_funcs, i, no_chains;
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100608 int ret = -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100610 mutex_lock(&s->ops_mutex);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200611 if (!(s->resource_setup_done)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200612 dev_dbg(&s->dev,
Dominik Brodowskiac449d62008-08-02 18:33:56 +0200613 "no resources available, delaying card_add\n");
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100614 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 return -EAGAIN; /* try again, but later... */
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200616 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200618 if (pcmcia_validate_mem(s)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200619 dev_dbg(&s->dev, "validating mem resources failed, "
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200620 "delaying card_add\n");
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100621 mutex_unlock(&s->ops_mutex);
Dominik Brodowskide759142005-09-28 19:41:56 +0200622 return -EAGAIN; /* try again, but later... */
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200623 }
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100624 mutex_unlock(&s->ops_mutex);
Dominik Brodowskide759142005-09-28 19:41:56 +0200625
Dominik Brodowski84897fc2009-10-18 23:51:09 +0200626 ret = pccard_validate_cis(s, &no_chains);
Dominik Brodowskic5081d52008-06-19 20:12:34 +0200627 if (ret || !no_chains) {
Dominik Brodowskie8e68fd2015-06-14 21:52:46 +0200628#if defined(CONFIG_MTD_PCMCIA_ANONYMOUS)
629 /* Set up as an anonymous card. If we don't have anonymous
630 memory support then just error the card as there is no
631 point trying to second guess.
632
633 Note: some cards have just a device entry, it may be
634 worth extending support to cover these in future */
635 if (ret == -EIO) {
636 dev_info(&s->dev, "no CIS, assuming an anonymous memory card.\n");
637 pcmcia_replace_cis(s, "\xFF", 1);
638 no_chains = 1;
639 ret = 0;
640 } else
641#endif
642 {
643 dev_dbg(&s->dev, "invalid CIS or invalid resources\n");
644 return -ENODEV;
645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 }
647
648 if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc))
649 no_funcs = mfc.nfn;
650 else
651 no_funcs = 1;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500652 s->functions = no_funcs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100654 for (i = 0; i < no_funcs; i++)
Dominik Brodowskidc109492005-06-27 16:28:50 -0700655 pcmcia_device_add(s, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100657 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658}
659
660
Laurent Navet46f533c2013-01-21 22:16:05 +0100661static int pcmcia_requery_callback(struct device *dev, void *_data)
Dominik Brodowskiff1fa9e2005-06-27 16:28:09 -0700662{
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700663 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200664 if (!p_dev->dev.driver) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200665 dev_dbg(dev, "update device information\n");
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700666 pcmcia_device_query(p_dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200667 }
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700668
669 return 0;
670}
671
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100672
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100673static void pcmcia_requery(struct pcmcia_socket *s)
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700674{
Dominik Brodowski04de0812010-04-20 14:49:01 +0200675 int has_pfc;
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700676
Alan Cox84026412014-12-10 15:06:40 +0000677 if (!(s->state & SOCKET_PRESENT))
678 return;
679
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100680 if (s->functions == 0) {
681 pcmcia_card_add(s);
682 return;
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700683 }
684
685 /* some device information might have changed because of a CIS
686 * update or because we can finally read it correctly... so
687 * determine it again, overwriting old values if necessary. */
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100688 bus_for_each_dev(&pcmcia_bus_type, NULL, NULL, pcmcia_requery_callback);
689
690 /* if the CIS changed, we need to check whether the number of
691 * functions changed. */
692 if (s->fake_cis) {
693 int old_funcs, new_funcs;
694 cistpl_longlink_mfc_t mfc;
695
696 /* does this cis override add or remove functions? */
697 old_funcs = s->functions;
698
699 if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC,
700 &mfc))
701 new_funcs = mfc.nfn;
702 else
703 new_funcs = 1;
Dominik Brodowskib1095af2010-04-08 20:10:21 +0200704 if (old_funcs != new_funcs) {
705 /* we need to re-start */
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100706 pcmcia_card_remove(s, NULL);
Dominik Brodowskib83156b2010-06-07 18:31:17 +0200707 s->functions = 0;
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100708 pcmcia_card_add(s);
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100709 }
710 }
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700711
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100712 /* If the PCMCIA device consists of two pseudo devices,
713 * call pcmcia_device_add() -- which will fail if both
714 * devices are already registered. */
715 mutex_lock(&s->ops_mutex);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +0200716 has_pfc = s->pcmcia_pfc;
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100717 mutex_unlock(&s->ops_mutex);
718 if (has_pfc)
719 pcmcia_device_add(s, 0);
720
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700721 /* we re-scan all devices, not just the ones connected to this
722 * socket. This does not matter, though. */
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100723 if (bus_rescan_devices(&pcmcia_bus_type))
724 dev_warn(&s->dev, "rescanning the bus failed\n");
Dominik Brodowskiff1fa9e2005-06-27 16:28:09 -0700725}
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700726
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100727
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500728#ifdef CONFIG_PCMCIA_LOAD_CIS
729
730/**
731 * pcmcia_load_firmware - load CIS from userspace if device-provided is broken
Randy Dunlap78187862007-12-10 15:49:22 -0800732 * @dev: the pcmcia device which needs a CIS override
733 * @filename: requested filename in /lib/firmware/
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500734 *
735 * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if
736 * the one provided by the card is broken. The firmware files reside in
737 * /lib/firmware/ in userspace.
738 */
Laurent Navet46f533c2013-01-21 22:16:05 +0100739static int pcmcia_load_firmware(struct pcmcia_device *dev, char *filename)
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500740{
741 struct pcmcia_socket *s = dev->socket;
742 const struct firmware *fw;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500743 int ret = -ENOMEM;
Dominik Brodowskib1095af2010-04-08 20:10:21 +0200744 cistpl_longlink_mfc_t mfc;
745 int old_funcs, new_funcs = 1;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500746
747 if (!filename)
748 return -EINVAL;
749
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200750 dev_dbg(&dev->dev, "trying to load CIS file %s\n", filename);
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500751
Samuel Ortized62ace2009-05-27 00:49:35 +0200752 if (request_firmware(&fw, filename, &dev->dev) == 0) {
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200753 if (fw->size >= CISTPL_MAX_CIS_SIZE) {
754 ret = -EINVAL;
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700755 dev_err(&dev->dev, "pcmcia: CIS override is too big\n");
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500756 goto release;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200757 }
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500758
Dominik Brodowski53efec92008-07-28 19:44:05 +0200759 if (!pcmcia_replace_cis(s, fw->data, fw->size))
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500760 ret = 0;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200761 else {
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700762 dev_err(&dev->dev, "pcmcia: CIS override failed\n");
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200763 goto release;
764 }
765
Dominik Brodowskib1095af2010-04-08 20:10:21 +0200766 /* we need to re-start if the number of functions changed */
767 old_funcs = s->functions;
768 if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC,
769 &mfc))
770 new_funcs = mfc.nfn;
771
772 if (old_funcs != new_funcs)
773 ret = -EBUSY;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500774
775 /* update information */
776 pcmcia_device_query(dev);
777
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100778 /* requery (as number of functions might have changed) */
779 pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500780 }
781 release:
782 release_firmware(fw);
783
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100784 return ret;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500785}
786
787#else /* !CONFIG_PCMCIA_LOAD_CIS */
788
Laurent Navet46f533c2013-01-21 22:16:05 +0100789static inline int pcmcia_load_firmware(struct pcmcia_device *dev,
790 char *filename)
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500791{
792 return -ENODEV;
793}
794
795#endif
796
797
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700798static inline int pcmcia_devmatch(struct pcmcia_device *dev,
Joe Perchese9fb13b2011-05-03 19:29:00 -0700799 const struct pcmcia_device_id *did)
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700800{
801 if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) {
802 if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id))
803 return 0;
804 }
805
806 if (did->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID) {
807 if ((!dev->has_card_id) || (dev->card_id != did->card_id))
808 return 0;
809 }
810
811 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION) {
812 if (dev->func != did->function)
813 return 0;
814 }
815
816 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1) {
817 if (!dev->prod_id[0])
818 return 0;
819 if (strcmp(did->prod_id[0], dev->prod_id[0]))
820 return 0;
821 }
822
823 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2) {
824 if (!dev->prod_id[1])
825 return 0;
826 if (strcmp(did->prod_id[1], dev->prod_id[1]))
827 return 0;
828 }
829
830 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3) {
831 if (!dev->prod_id[2])
832 return 0;
833 if (strcmp(did->prod_id[2], dev->prod_id[2]))
834 return 0;
835 }
836
837 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4) {
838 if (!dev->prod_id[3])
839 return 0;
840 if (strcmp(did->prod_id[3], dev->prod_id[3]))
841 return 0;
842 }
843
844 if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {
Alexander Kurz83bf6f12010-04-25 13:44:35 +0400845 dev_dbg(&dev->dev, "this is a pseudo-multi-function device\n");
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100846 mutex_lock(&dev->socket->ops_mutex);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +0200847 dev->socket->pcmcia_pfc = 1;
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100848 mutex_unlock(&dev->socket->ops_mutex);
Alexander Kurz83bf6f12010-04-25 13:44:35 +0400849 if (dev->device_no != did->device_no)
850 return 0;
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700851 }
852
853 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) {
Dominik Brodowski94a819f2010-01-17 18:31:34 +0100854 int ret;
855
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700856 if ((!dev->has_func_id) || (dev->func_id != did->func_id))
857 return 0;
858
859 /* if this is a pseudo-multi-function device,
860 * we need explicit matches */
Dominik Brodowskice3f9d72010-07-21 14:43:05 +0200861 if (dev->socket->pcmcia_pfc)
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700862 return 0;
863 if (dev->device_no)
864 return 0;
865
866 /* also, FUNC_ID matching needs to be activated by userspace
867 * after it has re-checked that there is no possible module
868 * with a prod_id/manf_id/card_id match.
869 */
Dominik Brodowski94a819f2010-01-17 18:31:34 +0100870 mutex_lock(&dev->socket->ops_mutex);
871 ret = dev->allow_func_id_match;
872 mutex_unlock(&dev->socket->ops_mutex);
873
874 if (!ret) {
875 dev_dbg(&dev->dev,
876 "skipping FUNC_ID match until userspace ACK\n");
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700877 return 0;
Dominik Brodowski94a819f2010-01-17 18:31:34 +0100878 }
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700879 }
880
Dominik Brodowskiea7b3882005-06-27 16:28:07 -0700881 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200882 dev_dbg(&dev->dev, "device needs a fake CIS\n");
Dominik Brodowskidaa95172005-06-27 16:28:14 -0700883 if (!dev->socket->fake_cis)
Dominik Brodowskib1095af2010-04-08 20:10:21 +0200884 if (pcmcia_load_firmware(dev, did->cisfile))
885 return 0;
Dominik Brodowskiea7b3882005-06-27 16:28:07 -0700886 }
887
Dominik Brodowskif602ff72005-06-27 16:28:09 -0700888 if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {
889 int i;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100890 for (i = 0; i < 4; i++)
Dominik Brodowskif602ff72005-06-27 16:28:09 -0700891 if (dev->prod_id[i])
892 return 0;
893 if (dev->has_manf_id || dev->has_card_id || dev->has_func_id)
894 return 0;
895 }
896
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700897 return 1;
898}
899
900
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100901static int pcmcia_bus_match(struct device *dev, struct device_driver *drv)
902{
903 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
904 struct pcmcia_driver *p_drv = to_pcmcia_drv(drv);
Joe Perchese9fb13b2011-05-03 19:29:00 -0700905 const struct pcmcia_device_id *did = p_drv->id_table;
Bernhard Walle6179b552007-05-06 14:48:44 -0700906 struct pcmcia_dynid *dynid;
907
908 /* match dynamic devices first */
Dominik Brodowski3f565232010-01-16 13:06:40 +0100909 mutex_lock(&p_drv->dynids.lock);
Bernhard Walle6179b552007-05-06 14:48:44 -0700910 list_for_each_entry(dynid, &p_drv->dynids.list, node) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200911 dev_dbg(dev, "trying to match to %s\n", drv->name);
Bernhard Walle6179b552007-05-06 14:48:44 -0700912 if (pcmcia_devmatch(p_dev, &dynid->id)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200913 dev_dbg(dev, "matched to %s\n", drv->name);
Dominik Brodowski3f565232010-01-16 13:06:40 +0100914 mutex_unlock(&p_drv->dynids.lock);
Bernhard Walle6179b552007-05-06 14:48:44 -0700915 return 1;
916 }
917 }
Dominik Brodowski3f565232010-01-16 13:06:40 +0100918 mutex_unlock(&p_drv->dynids.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700920 while (did && did->match_flags) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200921 dev_dbg(dev, "trying to match to %s\n", drv->name);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200922 if (pcmcia_devmatch(p_dev, did)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200923 dev_dbg(dev, "matched to %s\n", drv->name);
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700924 return 1;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200925 }
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700926 did++;
927 }
928
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 return 0;
930}
931
Kay Sievers7eff2e72007-08-14 15:15:12 +0200932static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700933{
934 struct pcmcia_device *p_dev;
Kay Sievers7eff2e72007-08-14 15:15:12 +0200935 int i;
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700936 u32 hash[4] = { 0, 0, 0, 0};
937
938 if (!dev)
939 return -ENODEV;
940
941 p_dev = to_pcmcia_dev(dev);
942
943 /* calculate hashes */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100944 for (i = 0; i < 4; i++) {
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700945 if (!p_dev->prod_id[i])
946 continue;
947 hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i]));
948 }
949
Kay Sievers7eff2e72007-08-14 15:15:12 +0200950 if (add_uevent_var(env, "SOCKET_NO=%u", p_dev->socket->sock))
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700951 return -ENOMEM;
952
Kay Sievers7eff2e72007-08-14 15:15:12 +0200953 if (add_uevent_var(env, "DEVICE_NO=%02X", p_dev->device_no))
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700954 return -ENOMEM;
955
Kay Sievers7eff2e72007-08-14 15:15:12 +0200956 if (add_uevent_var(env, "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
Kay Sievers312c0042005-11-16 09:00:00 +0100957 "pa%08Xpb%08Xpc%08Xpd%08X",
958 p_dev->has_manf_id ? p_dev->manf_id : 0,
959 p_dev->has_card_id ? p_dev->card_id : 0,
960 p_dev->has_func_id ? p_dev->func_id : 0,
961 p_dev->func,
962 p_dev->device_no,
963 hash[0],
964 hash[1],
965 hash[2],
966 hash[3]))
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700967 return -ENOMEM;
968
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700969 return 0;
970}
971
Alan Stern3f8df782007-07-12 16:57:22 -0400972/************************ runtime PM support ***************************/
973
Russell Kingad8d52b2016-08-31 08:49:43 +0100974static int pcmcia_dev_suspend(struct device *dev);
Alan Stern3f8df782007-07-12 16:57:22 -0400975static int pcmcia_dev_resume(struct device *dev);
976
977static int runtime_suspend(struct device *dev)
978{
979 int rc;
980
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800981 device_lock(dev);
Russell Kingad8d52b2016-08-31 08:49:43 +0100982 rc = pcmcia_dev_suspend(dev);
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800983 device_unlock(dev);
Alan Stern3f8df782007-07-12 16:57:22 -0400984 return rc;
985}
986
Dominik Brodowski933a8382009-12-29 18:21:39 +0100987static int runtime_resume(struct device *dev)
Alan Stern3f8df782007-07-12 16:57:22 -0400988{
989 int rc;
990
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800991 device_lock(dev);
Alan Stern3f8df782007-07-12 16:57:22 -0400992 rc = pcmcia_dev_resume(dev);
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800993 device_unlock(dev);
Dominik Brodowski933a8382009-12-29 18:21:39 +0100994 return rc;
Alan Stern3f8df782007-07-12 16:57:22 -0400995}
996
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997/************************ per-device sysfs output ***************************/
998
999#define pcmcia_device_attr(field, test, format) \
Yani Ioannoue404e272005-05-17 06:42:58 -04001000static ssize_t field##_show (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001{ \
1002 struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001003 return p_dev->test ? sprintf(buf, format, p_dev->field) : -ENODEV; \
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001004} \
1005static DEVICE_ATTR_RO(field);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
1007#define pcmcia_device_stringattr(name, field) \
Yani Ioannoue404e272005-05-17 06:42:58 -04001008static ssize_t name##_show (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009{ \
1010 struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001011 return p_dev->field ? sprintf(buf, "%s\n", p_dev->field) : -ENODEV; \
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001012} \
1013static DEVICE_ATTR_RO(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015pcmcia_device_attr(func_id, has_func_id, "0x%02x\n");
1016pcmcia_device_attr(manf_id, has_manf_id, "0x%04x\n");
1017pcmcia_device_attr(card_id, has_card_id, "0x%04x\n");
1018pcmcia_device_stringattr(prod_id1, prod_id[0]);
1019pcmcia_device_stringattr(prod_id2, prod_id[1]);
1020pcmcia_device_stringattr(prod_id3, prod_id[2]);
1021pcmcia_device_stringattr(prod_id4, prod_id[3]);
1022
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001023static ssize_t function_show(struct device *dev, struct device_attribute *attr,
1024 char *buf)
1025{
1026 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1027 return p_dev->socket ? sprintf(buf, "0x%02x\n", p_dev->func) : -ENODEV;
1028}
1029static DEVICE_ATTR_RO(function);
1030
1031static ssize_t resources_show(struct device *dev,
1032 struct device_attribute *attr, char *buf)
Dominik Brodowski8f677ea2010-07-25 11:10:29 +02001033{
1034 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1035 char *str = buf;
1036 int i;
1037
1038 for (i = 0; i < PCMCIA_NUM_RESOURCES; i++)
1039 str += sprintf(str, "%pr\n", p_dev->resource[i]);
1040
1041 return str - buf;
1042}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001043static DEVICE_ATTR_RO(resources);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001044
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001045static ssize_t pm_state_show(struct device *dev, struct device_attribute *attr, char *buf)
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001046{
1047 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1048
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001049 if (p_dev->suspended)
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001050 return sprintf(buf, "off\n");
1051 else
1052 return sprintf(buf, "on\n");
1053}
1054
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001055static ssize_t pm_state_store(struct device *dev, struct device_attribute *attr,
1056 const char *buf, size_t count)
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001057{
1058 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1059 int ret = 0;
1060
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001061 if (!count)
1062 return -EINVAL;
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001063
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001064 if ((!p_dev->suspended) && !strncmp(buf, "off", 3))
Alan Stern3f8df782007-07-12 16:57:22 -04001065 ret = runtime_suspend(dev);
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001066 else if (p_dev->suspended && !strncmp(buf, "on", 2))
Dominik Brodowski933a8382009-12-29 18:21:39 +01001067 ret = runtime_resume(dev);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001068
1069 return ret ? ret : count;
1070}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001071static DEVICE_ATTR_RW(pm_state);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001072
Dominik Brodowski37045112005-06-30 02:58:47 -07001073static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001074{
1075 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1076 int i;
1077 u32 hash[4] = { 0, 0, 0, 0};
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001078
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001079 /* calculate hashes */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001080 for (i = 0; i < 4; i++) {
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001081 if (!p_dev->prod_id[i])
1082 continue;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001083 hash[i] = crc32(0, p_dev->prod_id[i],
1084 strlen(p_dev->prod_id[i]));
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001085 }
1086 return sprintf(buf, "pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
1087 "pa%08Xpb%08Xpc%08Xpd%08X\n",
1088 p_dev->has_manf_id ? p_dev->manf_id : 0,
1089 p_dev->has_card_id ? p_dev->card_id : 0,
1090 p_dev->has_func_id ? p_dev->func_id : 0,
1091 p_dev->func, p_dev->device_no,
1092 hash[0], hash[1], hash[2], hash[3]);
1093}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001094static DEVICE_ATTR_RO(modalias);
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001095
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001096static ssize_t allow_func_id_match_store(struct device *dev,
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001097 struct device_attribute *attr, const char *buf, size_t count)
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001098{
1099 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001100
1101 if (!count)
1102 return -EINVAL;
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001103
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001104 mutex_lock(&p_dev->socket->ops_mutex);
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001105 p_dev->allow_func_id_match = 1;
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001106 mutex_unlock(&p_dev->socket->ops_mutex);
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +01001107 pcmcia_parse_uevents(p_dev->socket, PCMCIA_UEVENT_REQUERY);
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001108
1109 return count;
1110}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001111static DEVICE_ATTR_WO(allow_func_id_match);
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001112
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001113static struct attribute *pcmcia_dev_attrs[] = {
1114 &dev_attr_resources.attr,
1115 &dev_attr_pm_state.attr,
1116 &dev_attr_function.attr,
1117 &dev_attr_func_id.attr,
1118 &dev_attr_manf_id.attr,
1119 &dev_attr_card_id.attr,
1120 &dev_attr_prod_id1.attr,
1121 &dev_attr_prod_id2.attr,
1122 &dev_attr_prod_id3.attr,
1123 &dev_attr_prod_id4.attr,
1124 &dev_attr_modalias.attr,
1125 &dev_attr_allow_func_id_match.attr,
1126 NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127};
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001128ATTRIBUTE_GROUPS(pcmcia_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001130/* PM support, also needed for reset */
1131
Russell Kingad8d52b2016-08-31 08:49:43 +01001132static int pcmcia_dev_suspend(struct device *dev)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001133{
1134 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1135 struct pcmcia_driver *p_drv = NULL;
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001136 int ret = 0;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001137
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001138 mutex_lock(&p_dev->socket->ops_mutex);
1139 if (p_dev->suspended) {
1140 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001141 return 0;
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001142 }
1143 p_dev->suspended = 1;
1144 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001145
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001146 dev_dbg(dev, "suspending\n");
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001147
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001148 if (dev->driver)
1149 p_drv = to_pcmcia_drv(dev->driver);
1150
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001151 if (!p_drv)
1152 goto out;
1153
1154 if (p_drv->suspend) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +01001155 ret = p_drv->suspend(p_dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001156 if (ret) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001157 dev_err(dev,
1158 "pcmcia: device %s (driver %s) did not want to go to sleep (%d)\n",
1159 p_dev->devname, p_drv->name, ret);
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001160 mutex_lock(&p_dev->socket->ops_mutex);
1161 p_dev->suspended = 0;
1162 mutex_unlock(&p_dev->socket->ops_mutex);
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001163 goto out;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001164 }
Dominik Brodowski8661bb52006-03-02 00:02:33 +01001165 }
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001166
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001167 if (p_dev->device_no == p_dev->func) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001168 dev_dbg(dev, "releasing configuration\n");
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001169 pcmcia_release_configuration(p_dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001170 }
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001171
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001172 out:
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001173 return ret;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001174}
1175
1176
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001177static int pcmcia_dev_resume(struct device *dev)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001178{
1179 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001180 struct pcmcia_driver *p_drv = NULL;
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001181 int ret = 0;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001182
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001183 mutex_lock(&p_dev->socket->ops_mutex);
1184 if (!p_dev->suspended) {
1185 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001186 return 0;
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001187 }
1188 p_dev->suspended = 0;
1189 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001190
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001191 dev_dbg(dev, "resuming\n");
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001192
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001193 if (dev->driver)
1194 p_drv = to_pcmcia_drv(dev->driver);
1195
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001196 if (!p_drv)
1197 goto out;
1198
1199 if (p_dev->device_no == p_dev->func) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001200 dev_dbg(dev, "requesting configuration\n");
Dominik Brodowski1ac71e52010-07-29 19:27:09 +02001201 ret = pcmcia_enable_device(p_dev);
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001202 if (ret)
1203 goto out;
Dominik Brodowski8661bb52006-03-02 00:02:33 +01001204 }
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001205
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001206 if (p_drv->resume)
1207 ret = p_drv->resume(p_dev);
1208
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001209 out:
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001210 return ret;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001211}
1212
1213
Laurent Navet46f533c2013-01-21 22:16:05 +01001214static int pcmcia_bus_suspend_callback(struct device *dev, void *_data)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001215{
1216 struct pcmcia_socket *skt = _data;
1217 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1218
Alan Stern3f8df782007-07-12 16:57:22 -04001219 if (p_dev->socket != skt || p_dev->suspended)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001220 return 0;
1221
Alan Stern3f8df782007-07-12 16:57:22 -04001222 return runtime_suspend(dev);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001223}
1224
Laurent Navet46f533c2013-01-21 22:16:05 +01001225static int pcmcia_bus_resume_callback(struct device *dev, void *_data)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001226{
1227 struct pcmcia_socket *skt = _data;
1228 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1229
Alan Stern3f8df782007-07-12 16:57:22 -04001230 if (p_dev->socket != skt || !p_dev->suspended)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001231 return 0;
1232
Alan Stern3f8df782007-07-12 16:57:22 -04001233 runtime_resume(dev);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001234
1235 return 0;
1236}
1237
1238static int pcmcia_bus_resume(struct pcmcia_socket *skt)
1239{
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001240 dev_dbg(&skt->dev, "resuming socket %d\n", skt->sock);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001241 bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback);
1242 return 0;
1243}
1244
1245static int pcmcia_bus_suspend(struct pcmcia_socket *skt)
1246{
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001247 dev_dbg(&skt->dev, "suspending socket %d\n", skt->sock);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001248 if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt,
1249 pcmcia_bus_suspend_callback)) {
1250 pcmcia_bus_resume(skt);
1251 return -EIO;
1252 }
1253 return 0;
1254}
1255
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001256static int pcmcia_bus_remove(struct pcmcia_socket *skt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257{
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001258 atomic_set(&skt->present, 0);
1259 pcmcia_card_remove(skt, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001261 mutex_lock(&skt->ops_mutex);
1262 destroy_cis_cache(skt);
1263 pcmcia_cleanup_irq(skt);
1264 mutex_unlock(&skt->ops_mutex);
1265
1266 return 0;
1267}
1268
1269static int pcmcia_bus_add(struct pcmcia_socket *skt)
1270{
1271 atomic_set(&skt->present, 1);
1272
1273 mutex_lock(&skt->ops_mutex);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +02001274 skt->pcmcia_pfc = 0;
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001275 destroy_cis_cache(skt); /* to be on the safe side... */
1276 mutex_unlock(&skt->ops_mutex);
1277
1278 pcmcia_card_add(skt);
1279
1280 return 0;
1281}
1282
1283static int pcmcia_bus_early_resume(struct pcmcia_socket *skt)
1284{
Russell King025e4ab2012-02-08 17:13:41 -08001285 if (!verify_cis_cache(skt))
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001286 return 0;
Florin Malita16174062006-05-24 21:21:31 -04001287
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001288 dev_dbg(&skt->dev, "cis mismatch - different card\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001290 /* first, remove the card */
1291 pcmcia_bus_remove(skt);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +01001292
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001293 mutex_lock(&skt->ops_mutex);
1294 destroy_cis_cache(skt);
1295 kfree(skt->fake_cis);
1296 skt->fake_cis = NULL;
1297 skt->functions = 0;
1298 mutex_unlock(&skt->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001300 /* now, add the new card */
1301 pcmcia_bus_add(skt);
1302 return 0;
1303}
Dominik Brodowski88b060d2010-01-02 14:14:23 +01001304
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305
Dominik Brodowski04de0812010-04-20 14:49:01 +02001306/*
1307 * NOTE: This is racy. There's no guarantee the card will still be
1308 * physically present, even if the call to this function returns
1309 * non-NULL. Furthermore, the device driver most likely is unbound
1310 * almost immediately, so the timeframe where pcmcia_dev_present
1311 * returns NULL is probably really really small.
1312 */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001313struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev)
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001314{
1315 struct pcmcia_device *p_dev;
1316 struct pcmcia_device *ret = NULL;
1317
1318 p_dev = pcmcia_get_dev(_p_dev);
1319 if (!p_dev)
1320 return NULL;
1321
Dominik Brodowski04de0812010-04-20 14:49:01 +02001322 if (atomic_read(&p_dev->socket->present) != 0)
1323 ret = p_dev;
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001324
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001325 pcmcia_put_dev(p_dev);
1326 return ret;
1327}
1328EXPORT_SYMBOL(pcmcia_dev_present);
1329
1330
Dominik Brodowski90c6cdd2005-06-27 16:28:49 -07001331static struct pcmcia_callback pcmcia_bus_callback = {
1332 .owner = THIS_MODULE,
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001333 .add = pcmcia_bus_add,
1334 .remove = pcmcia_bus_remove,
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +01001335 .requery = pcmcia_requery,
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001336 .validate = pccard_validate_cis,
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001337 .suspend = pcmcia_bus_suspend,
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001338 .early_resume = pcmcia_bus_early_resume,
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001339 .resume = pcmcia_bus_resume,
Dominik Brodowski90c6cdd2005-06-27 16:28:49 -07001340};
1341
Bill Pemberton34cdf252012-11-19 13:23:12 -05001342static int pcmcia_bus_add_socket(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001343 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001345 struct pcmcia_socket *socket = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 int ret;
1347
Dominik Brodowskidc109492005-06-27 16:28:50 -07001348 socket = pcmcia_get_socket(socket);
1349 if (!socket) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001350 dev_err(dev, "PCMCIA obtaining reference to socket failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 return -ENODEV;
1352 }
1353
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001354 ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
1355 if (ret) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001356 dev_err(dev, "PCMCIA registration failed\n");
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001357 pcmcia_put_socket(socket);
1358 return ret;
1359 }
1360
Dominik Brodowskidc109492005-06-27 16:28:50 -07001361 INIT_LIST_HEAD(&socket->devices_list);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +02001362 socket->pcmcia_pfc = 0;
Dominik Brodowskidc109492005-06-27 16:28:50 -07001363 socket->device_count = 0;
Dominik Brodowskie4f1ac22010-06-19 14:33:56 +02001364 atomic_set(&socket->present, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
Dominik Brodowski90c6cdd2005-06-27 16:28:49 -07001366 ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 if (ret) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001368 dev_err(dev, "PCMCIA registration failed\n");
Dominik Brodowskidc109492005-06-27 16:28:50 -07001369 pcmcia_put_socket(socket);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001370 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 }
1372
1373 return 0;
1374}
1375
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001376static void pcmcia_bus_remove_socket(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001377 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001379 struct pcmcia_socket *socket = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380
Dominik Brodowskidc109492005-06-27 16:28:50 -07001381 if (!socket)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 return;
1383
1384 pccard_register_pcmcia(socket, NULL);
1385
Daniel Ritzdfbc9e92006-11-18 22:19:34 -08001386 /* unregister any unbound devices */
Daniel Ritz8e4d9dc2006-11-25 11:09:17 -08001387 mutex_lock(&socket->skt_mutex);
Daniel Ritzdfbc9e92006-11-18 22:19:34 -08001388 pcmcia_card_remove(socket, NULL);
Dominik Brodowski180c33e2010-01-02 17:34:09 +01001389 release_cis_mem(socket);
Daniel Ritz8e4d9dc2006-11-25 11:09:17 -08001390 mutex_unlock(&socket->skt_mutex);
Daniel Ritzdfbc9e92006-11-18 22:19:34 -08001391
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001392 sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr);
1393
Dominik Brodowskidc109492005-06-27 16:28:50 -07001394 pcmcia_put_socket(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
1396 return;
1397}
1398
1399
1400/* the pcmcia_bus_interface is used to handle pcmcia socket devices */
Sam Ravnborged49f5d2008-05-01 04:34:50 -07001401static struct class_interface pcmcia_bus_interface __refdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 .class = &pcmcia_socket_class,
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001403 .add_dev = &pcmcia_bus_add_socket,
1404 .remove_dev = &pcmcia_bus_remove_socket,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405};
1406
Russell Kingad8d52b2016-08-31 08:49:43 +01001407static const struct dev_pm_ops pcmcia_bus_pm_ops = {
1408 SET_SYSTEM_SLEEP_PM_OPS(pcmcia_dev_suspend, pcmcia_dev_resume)
1409};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001411struct bus_type pcmcia_bus_type = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 .name = "pcmcia",
Kay Sievers312c0042005-11-16 09:00:00 +01001413 .uevent = pcmcia_bus_uevent,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 .match = pcmcia_bus_match,
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001415 .dev_groups = pcmcia_dev_groups,
Russell King1d0baa32006-01-05 14:40:58 +00001416 .probe = pcmcia_device_probe,
1417 .remove = pcmcia_device_remove,
Russell Kingad8d52b2016-08-31 08:49:43 +01001418 .pm = &pcmcia_bus_pm_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420
1421
1422static int __init init_pcmcia_bus(void)
1423{
Randy Dunlapace7d472006-10-20 14:44:12 -07001424 int ret;
1425
Randy Dunlapace7d472006-10-20 14:44:12 -07001426 ret = bus_register(&pcmcia_bus_type);
1427 if (ret < 0) {
1428 printk(KERN_WARNING "pcmcia: bus_register error: %d\n", ret);
1429 return ret;
1430 }
1431 ret = class_interface_register(&pcmcia_bus_interface);
1432 if (ret < 0) {
1433 printk(KERN_WARNING
1434 "pcmcia: class_interface_register error: %d\n", ret);
1435 bus_unregister(&pcmcia_bus_type);
1436 return ret;
1437 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 return 0;
1440}
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001441fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 * pcmcia_socket_class is already registered */
1443
1444
1445static void __exit exit_pcmcia_bus(void)
1446{
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001447 class_interface_unregister(&pcmcia_bus_interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
1449 bus_unregister(&pcmcia_bus_type);
1450}
1451module_exit(exit_pcmcia_bus);
1452
1453
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454MODULE_ALIAS("ds");