blob: 09d06b082f8b8c8911548c300cd56898e45efbc5 [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/**
86 * pcmcia_store_new_id - add a new PCMCIA device ID to this driver and re-probe devices
87 * @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)
375 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
Dominik Brodowskif3990712005-11-14 21:25:23 +0100377 if (p_drv->remove)
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100378 p_drv->remove(p_dev);
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100379
Dominik Brodowskif3990712005-11-14 21:25:23 +0100380 /* check for proper unloading */
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100381 if (p_dev->_irq || p_dev->_io || p_dev->_locked)
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700382 dev_info(dev,
383 "pcmcia: driver %s did not release config properly\n",
384 p_drv->name);
Dominik Brodowskif3990712005-11-14 21:25:23 +0100385
386 for (i = 0; i < MAX_WIN; i++)
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100387 if (p_dev->_win & CLIENT_WIN_REQ(i))
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700388 dev_info(dev,
389 "pcmcia: driver %s did not release window properly\n",
390 p_drv->name);
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100391
Dominik Brodowskif3990712005-11-14 21:25:23 +0100392 /* references from pcmcia_probe_device */
393 pcmcia_put_dev(p_dev);
394 module_put(p_drv->owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
396 return 0;
397}
398
399
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100400/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 * pcmcia_device_query -- determine information about a pcmcia device
402 */
403static int pcmcia_device_query(struct pcmcia_device *p_dev)
404{
405 cistpl_manfid_t manf_id;
406 cistpl_funcid_t func_id;
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700407 cistpl_vers_1_t *vers1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 unsigned int i;
409
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700410 vers1 = kmalloc(sizeof(*vers1), GFP_KERNEL);
411 if (!vers1)
412 return -ENOMEM;
413
Dominik Brodowski84897fc2009-10-18 23:51:09 +0200414 if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 CISTPL_MANFID, &manf_id)) {
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100416 mutex_lock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 p_dev->manf_id = manf_id.manf;
418 p_dev->card_id = manf_id.card;
419 p_dev->has_manf_id = 1;
420 p_dev->has_card_id = 1;
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100421 mutex_unlock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 }
423
424 if (!pccard_read_tuple(p_dev->socket, p_dev->func,
425 CISTPL_FUNCID, &func_id)) {
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100426 mutex_lock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 p_dev->func_id = func_id.func;
428 p_dev->has_func_id = 1;
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100429 mutex_unlock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 } else {
431 /* rule of thumb: cards with no FUNCID, but with
432 * common memory device geometry information, are
433 * probably memory cards (from pcmcia-cs) */
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700434 cistpl_device_geo_t *devgeo;
435
436 devgeo = kmalloc(sizeof(*devgeo), GFP_KERNEL);
437 if (!devgeo) {
438 kfree(vers1);
439 return -ENOMEM;
440 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 if (!pccard_read_tuple(p_dev->socket, p_dev->func,
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700442 CISTPL_DEVICE_GEO, devgeo)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200443 dev_dbg(&p_dev->dev,
Dominik Brodowskiac449d62008-08-02 18:33:56 +0200444 "mem device geometry probably means "
445 "FUNCID_MEMORY\n");
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100446 mutex_lock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 p_dev->func_id = CISTPL_FUNCID_MEMORY;
448 p_dev->has_func_id = 1;
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100449 mutex_unlock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 }
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700451 kfree(devgeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 }
453
Dominik Brodowski84897fc2009-10-18 23:51:09 +0200454 if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL, CISTPL_VERS_1,
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700455 vers1)) {
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100456 mutex_lock(&p_dev->socket->ops_mutex);
Dominik Brodowskic5e09522009-10-19 00:04:25 +0200457 for (i = 0; i < min_t(unsigned int, 4, vers1->ns); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 char *tmp;
459 unsigned int length;
Dominik Brodowski44961a02010-01-24 12:11:02 +0100460 char *new;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700462 tmp = vers1->str + vers1->ofs[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464 length = strlen(tmp) + 1;
Janos Farkas6e3d4f22006-03-31 01:04:57 +0200465 if ((length < 2) || (length > 255))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 continue;
467
Geliang Tang7c22e642015-10-02 00:37:57 +0800468 new = kstrdup(tmp, GFP_KERNEL);
Dominik Brodowski44961a02010-01-24 12:11:02 +0100469 if (!new)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 continue;
471
Dominik Brodowski44961a02010-01-24 12:11:02 +0100472 tmp = p_dev->prod_id[i];
473 p_dev->prod_id[i] = new;
474 kfree(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 }
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100476 mutex_unlock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 }
478
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700479 kfree(vers1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 return 0;
481}
482
483
Dominik Brodowski5716d412010-07-11 09:51:14 +0200484static struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s,
485 unsigned int function)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486{
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100487 struct pcmcia_device *p_dev, *tmp_dev;
Dominik Brodowski44961a02010-01-24 12:11:02 +0100488 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
Dominik Brodowskidc109492005-06-27 16:28:50 -0700490 s = pcmcia_get_socket(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 if (!s)
492 return NULL;
493
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200494 pr_debug("adding device to %d, function %d\n", s->sock, function);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200495
Dominik Brodowski8084b372005-12-11 21:18:26 +0100496 p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 if (!p_dev)
498 goto err_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100500 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 p_dev->device_no = (s->device_count++);
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100502 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100503
Dominik Brodowski7d7ba8d2010-03-24 10:49:14 +0100504 /* max of 2 PFC devices */
505 if ((p_dev->device_no >= 2) && (function == 0))
506 goto err_free;
507
508 /* max of 4 devices overall */
509 if (p_dev->device_no >= 4)
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100510 goto err_free;
511
512 p_dev->socket = s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 p_dev->func = function;
514
515 p_dev->dev.bus = &pcmcia_bus_type;
Greg Kroah-Hartman87373312006-09-12 17:00:10 +0200516 p_dev->dev.parent = s->dev.parent;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 p_dev->dev.release = pcmcia_release_dev;
James Bottomley43d9f7f2007-10-16 01:23:58 -0700518 /* by default don't allow DMA */
519 p_dev->dma_mask = DMA_MASK_NONE;
520 p_dev->dev.dma_mask = &p_dev->dma_mask;
Kay Sievers25096982008-11-01 11:46:06 +0100521 dev_set_name(&p_dev->dev, "%d.%d", p_dev->socket->sock, p_dev->device_no);
522 if (!dev_name(&p_dev->dev))
523 goto err_free;
524 p_dev->devname = kasprintf(GFP_KERNEL, "pcmcia%s", dev_name(&p_dev->dev));
Brice Goglinbd65a682005-09-09 13:03:29 -0700525 if (!p_dev->devname)
526 goto err_free;
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200527 dev_dbg(&p_dev->dev, "devname is %s\n", p_dev->devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100529 mutex_lock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100530
531 /*
532 * p_dev->function_config must be the same for all card functions.
Dominik Brodowskia60f22c2010-03-07 09:22:51 +0100533 * Note that this is serialized by ops_mutex, so that only one
534 * such struct will be created.
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100535 */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100536 list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)
537 if (p_dev->func == tmp_dev->func) {
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100538 p_dev->function_config = tmp_dev->function_config;
Komuro3e879f62008-11-02 19:33:24 +0900539 p_dev->irq = tmp_dev->irq;
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100540 kref_get(&p_dev->function_config->ref);
541 }
542
543 /* Add to the list in pcmcia_bus_socket */
Komuro6171b882006-04-02 17:39:27 +0900544 list_add(&p_dev->socket_device_list, &s->devices_list);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100545
Dominik Brodowski6f0f38c2010-04-08 20:33:16 +0200546 if (pcmcia_setup_irq(p_dev))
547 dev_warn(&p_dev->dev,
548 "IRQ setup failed -- device might not work\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100550 if (!p_dev->function_config) {
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200551 config_t *c;
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200552 dev_dbg(&p_dev->dev, "creating config_t\n");
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200553 c = kzalloc(sizeof(struct config_t), GFP_KERNEL);
554 if (!c) {
Dominik Brodowski6f0f38c2010-04-08 20:33:16 +0200555 mutex_unlock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100556 goto err_unreg;
Dominik Brodowski6f0f38c2010-04-08 20:33:16 +0200557 }
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200558 p_dev->function_config = c;
559 kref_init(&c->ref);
560 for (i = 0; i < MAX_IO_WIN; i++) {
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200561 c->io[i].name = p_dev->devname;
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200562 c->io[i].flags = IORESOURCE_IO;
563 }
Laurent Navet46f533c2013-01-21 22:16:05 +0100564 for (i = 0; i < MAX_WIN; i++) {
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200565 c->mem[i].name = p_dev->devname;
Dominik Brodowski0ca724d32010-07-24 19:03:02 +0200566 c->mem[i].flags = IORESOURCE_MEM;
567 }
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100568 }
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200569 for (i = 0; i < MAX_IO_WIN; i++)
570 p_dev->resource[i] = &p_dev->function_config->io[i];
Dominik Brodowski0ca724d32010-07-24 19:03:02 +0200571 for (; i < (MAX_IO_WIN + MAX_WIN); i++)
572 p_dev->resource[i] = &p_dev->function_config->mem[i-MAX_IO_WIN];
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200573
Dominik Brodowski6f0f38c2010-04-08 20:33:16 +0200574 mutex_unlock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100575
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700576 dev_notice(&p_dev->dev, "pcmcia: registering new device %s (IRQ: %d)\n",
Dominik Brodowskieb141202010-03-07 12:21:16 +0100577 p_dev->devname, p_dev->irq);
Dominik Brodowski807277c2005-11-12 23:34:06 +0100578
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700579 pcmcia_device_query(p_dev);
580
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100581 if (device_register(&p_dev->dev))
582 goto err_unreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 return p_dev;
585
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100586 err_unreg:
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100587 mutex_lock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100588 list_del(&p_dev->socket_device_list);
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100589 mutex_unlock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100590
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 err_free:
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100592 mutex_lock(&s->ops_mutex);
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100593 s->device_count--;
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100594 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100595
Dominik Brodowski44961a02010-01-24 12:11:02 +0100596 for (i = 0; i < 4; i++)
597 kfree(p_dev->prod_id[i]);
Brice Goglinbd65a682005-09-09 13:03:29 -0700598 kfree(p_dev->devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 kfree(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 err_put:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700601 pcmcia_put_socket(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
603 return NULL;
604}
605
606
607static int pcmcia_card_add(struct pcmcia_socket *s)
608{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 cistpl_longlink_mfc_t mfc;
Dominik Brodowskic5081d52008-06-19 20:12:34 +0200610 unsigned int no_funcs, i, no_chains;
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100611 int ret = -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100613 mutex_lock(&s->ops_mutex);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200614 if (!(s->resource_setup_done)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200615 dev_dbg(&s->dev,
Dominik Brodowskiac449d62008-08-02 18:33:56 +0200616 "no resources available, delaying card_add\n");
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100617 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 return -EAGAIN; /* try again, but later... */
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200619 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200621 if (pcmcia_validate_mem(s)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200622 dev_dbg(&s->dev, "validating mem resources failed, "
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200623 "delaying card_add\n");
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100624 mutex_unlock(&s->ops_mutex);
Dominik Brodowskide759142005-09-28 19:41:56 +0200625 return -EAGAIN; /* try again, but later... */
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200626 }
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100627 mutex_unlock(&s->ops_mutex);
Dominik Brodowskide759142005-09-28 19:41:56 +0200628
Dominik Brodowski84897fc2009-10-18 23:51:09 +0200629 ret = pccard_validate_cis(s, &no_chains);
Dominik Brodowskic5081d52008-06-19 20:12:34 +0200630 if (ret || !no_chains) {
Dominik Brodowskie8e68fd2015-06-14 21:52:46 +0200631#if defined(CONFIG_MTD_PCMCIA_ANONYMOUS)
632 /* Set up as an anonymous card. If we don't have anonymous
633 memory support then just error the card as there is no
634 point trying to second guess.
635
636 Note: some cards have just a device entry, it may be
637 worth extending support to cover these in future */
638 if (ret == -EIO) {
639 dev_info(&s->dev, "no CIS, assuming an anonymous memory card.\n");
640 pcmcia_replace_cis(s, "\xFF", 1);
641 no_chains = 1;
642 ret = 0;
643 } else
644#endif
645 {
646 dev_dbg(&s->dev, "invalid CIS or invalid resources\n");
647 return -ENODEV;
648 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 }
650
651 if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc))
652 no_funcs = mfc.nfn;
653 else
654 no_funcs = 1;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500655 s->functions = no_funcs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100657 for (i = 0; i < no_funcs; i++)
Dominik Brodowskidc109492005-06-27 16:28:50 -0700658 pcmcia_device_add(s, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100660 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661}
662
663
Laurent Navet46f533c2013-01-21 22:16:05 +0100664static int pcmcia_requery_callback(struct device *dev, void *_data)
Dominik Brodowskiff1fa9e2005-06-27 16:28:09 -0700665{
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700666 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200667 if (!p_dev->dev.driver) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200668 dev_dbg(dev, "update device information\n");
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700669 pcmcia_device_query(p_dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200670 }
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700671
672 return 0;
673}
674
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100675
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100676static void pcmcia_requery(struct pcmcia_socket *s)
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700677{
Dominik Brodowski04de0812010-04-20 14:49:01 +0200678 int has_pfc;
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700679
Alan Cox84026412014-12-10 15:06:40 +0000680 if (!(s->state & SOCKET_PRESENT))
681 return;
682
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100683 if (s->functions == 0) {
684 pcmcia_card_add(s);
685 return;
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700686 }
687
688 /* some device information might have changed because of a CIS
689 * update or because we can finally read it correctly... so
690 * determine it again, overwriting old values if necessary. */
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100691 bus_for_each_dev(&pcmcia_bus_type, NULL, NULL, pcmcia_requery_callback);
692
693 /* if the CIS changed, we need to check whether the number of
694 * functions changed. */
695 if (s->fake_cis) {
696 int old_funcs, new_funcs;
697 cistpl_longlink_mfc_t mfc;
698
699 /* does this cis override add or remove functions? */
700 old_funcs = s->functions;
701
702 if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC,
703 &mfc))
704 new_funcs = mfc.nfn;
705 else
706 new_funcs = 1;
Dominik Brodowskib1095af2010-04-08 20:10:21 +0200707 if (old_funcs != new_funcs) {
708 /* we need to re-start */
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100709 pcmcia_card_remove(s, NULL);
Dominik Brodowskib83156b2010-06-07 18:31:17 +0200710 s->functions = 0;
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100711 pcmcia_card_add(s);
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100712 }
713 }
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700714
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100715 /* If the PCMCIA device consists of two pseudo devices,
716 * call pcmcia_device_add() -- which will fail if both
717 * devices are already registered. */
718 mutex_lock(&s->ops_mutex);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +0200719 has_pfc = s->pcmcia_pfc;
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100720 mutex_unlock(&s->ops_mutex);
721 if (has_pfc)
722 pcmcia_device_add(s, 0);
723
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700724 /* we re-scan all devices, not just the ones connected to this
725 * socket. This does not matter, though. */
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100726 if (bus_rescan_devices(&pcmcia_bus_type))
727 dev_warn(&s->dev, "rescanning the bus failed\n");
Dominik Brodowskiff1fa9e2005-06-27 16:28:09 -0700728}
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700729
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100730
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500731#ifdef CONFIG_PCMCIA_LOAD_CIS
732
733/**
734 * pcmcia_load_firmware - load CIS from userspace if device-provided is broken
Randy Dunlap78187862007-12-10 15:49:22 -0800735 * @dev: the pcmcia device which needs a CIS override
736 * @filename: requested filename in /lib/firmware/
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500737 *
738 * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if
739 * the one provided by the card is broken. The firmware files reside in
740 * /lib/firmware/ in userspace.
741 */
Laurent Navet46f533c2013-01-21 22:16:05 +0100742static int pcmcia_load_firmware(struct pcmcia_device *dev, char *filename)
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500743{
744 struct pcmcia_socket *s = dev->socket;
745 const struct firmware *fw;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500746 int ret = -ENOMEM;
Dominik Brodowskib1095af2010-04-08 20:10:21 +0200747 cistpl_longlink_mfc_t mfc;
748 int old_funcs, new_funcs = 1;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500749
750 if (!filename)
751 return -EINVAL;
752
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200753 dev_dbg(&dev->dev, "trying to load CIS file %s\n", filename);
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500754
Samuel Ortized62ace2009-05-27 00:49:35 +0200755 if (request_firmware(&fw, filename, &dev->dev) == 0) {
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200756 if (fw->size >= CISTPL_MAX_CIS_SIZE) {
757 ret = -EINVAL;
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700758 dev_err(&dev->dev, "pcmcia: CIS override is too big\n");
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500759 goto release;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200760 }
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500761
Dominik Brodowski53efec92008-07-28 19:44:05 +0200762 if (!pcmcia_replace_cis(s, fw->data, fw->size))
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500763 ret = 0;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200764 else {
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700765 dev_err(&dev->dev, "pcmcia: CIS override failed\n");
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200766 goto release;
767 }
768
Dominik Brodowskib1095af2010-04-08 20:10:21 +0200769 /* we need to re-start if the number of functions changed */
770 old_funcs = s->functions;
771 if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC,
772 &mfc))
773 new_funcs = mfc.nfn;
774
775 if (old_funcs != new_funcs)
776 ret = -EBUSY;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500777
778 /* update information */
779 pcmcia_device_query(dev);
780
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100781 /* requery (as number of functions might have changed) */
782 pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500783 }
784 release:
785 release_firmware(fw);
786
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100787 return ret;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500788}
789
790#else /* !CONFIG_PCMCIA_LOAD_CIS */
791
Laurent Navet46f533c2013-01-21 22:16:05 +0100792static inline int pcmcia_load_firmware(struct pcmcia_device *dev,
793 char *filename)
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500794{
795 return -ENODEV;
796}
797
798#endif
799
800
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700801static inline int pcmcia_devmatch(struct pcmcia_device *dev,
Joe Perchese9fb13b2011-05-03 19:29:00 -0700802 const struct pcmcia_device_id *did)
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700803{
804 if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) {
805 if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id))
806 return 0;
807 }
808
809 if (did->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID) {
810 if ((!dev->has_card_id) || (dev->card_id != did->card_id))
811 return 0;
812 }
813
814 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION) {
815 if (dev->func != did->function)
816 return 0;
817 }
818
819 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1) {
820 if (!dev->prod_id[0])
821 return 0;
822 if (strcmp(did->prod_id[0], dev->prod_id[0]))
823 return 0;
824 }
825
826 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2) {
827 if (!dev->prod_id[1])
828 return 0;
829 if (strcmp(did->prod_id[1], dev->prod_id[1]))
830 return 0;
831 }
832
833 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3) {
834 if (!dev->prod_id[2])
835 return 0;
836 if (strcmp(did->prod_id[2], dev->prod_id[2]))
837 return 0;
838 }
839
840 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4) {
841 if (!dev->prod_id[3])
842 return 0;
843 if (strcmp(did->prod_id[3], dev->prod_id[3]))
844 return 0;
845 }
846
847 if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {
Alexander Kurz83bf6f12010-04-25 13:44:35 +0400848 dev_dbg(&dev->dev, "this is a pseudo-multi-function device\n");
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100849 mutex_lock(&dev->socket->ops_mutex);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +0200850 dev->socket->pcmcia_pfc = 1;
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100851 mutex_unlock(&dev->socket->ops_mutex);
Alexander Kurz83bf6f12010-04-25 13:44:35 +0400852 if (dev->device_no != did->device_no)
853 return 0;
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700854 }
855
856 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) {
Dominik Brodowski94a819f2010-01-17 18:31:34 +0100857 int ret;
858
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700859 if ((!dev->has_func_id) || (dev->func_id != did->func_id))
860 return 0;
861
862 /* if this is a pseudo-multi-function device,
863 * we need explicit matches */
Dominik Brodowskice3f9d72010-07-21 14:43:05 +0200864 if (dev->socket->pcmcia_pfc)
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700865 return 0;
866 if (dev->device_no)
867 return 0;
868
869 /* also, FUNC_ID matching needs to be activated by userspace
870 * after it has re-checked that there is no possible module
871 * with a prod_id/manf_id/card_id match.
872 */
Dominik Brodowski94a819f2010-01-17 18:31:34 +0100873 mutex_lock(&dev->socket->ops_mutex);
874 ret = dev->allow_func_id_match;
875 mutex_unlock(&dev->socket->ops_mutex);
876
877 if (!ret) {
878 dev_dbg(&dev->dev,
879 "skipping FUNC_ID match until userspace ACK\n");
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700880 return 0;
Dominik Brodowski94a819f2010-01-17 18:31:34 +0100881 }
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700882 }
883
Dominik Brodowskiea7b3882005-06-27 16:28:07 -0700884 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200885 dev_dbg(&dev->dev, "device needs a fake CIS\n");
Dominik Brodowskidaa95172005-06-27 16:28:14 -0700886 if (!dev->socket->fake_cis)
Dominik Brodowskib1095af2010-04-08 20:10:21 +0200887 if (pcmcia_load_firmware(dev, did->cisfile))
888 return 0;
Dominik Brodowskiea7b3882005-06-27 16:28:07 -0700889 }
890
Dominik Brodowskif602ff72005-06-27 16:28:09 -0700891 if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {
892 int i;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100893 for (i = 0; i < 4; i++)
Dominik Brodowskif602ff72005-06-27 16:28:09 -0700894 if (dev->prod_id[i])
895 return 0;
896 if (dev->has_manf_id || dev->has_card_id || dev->has_func_id)
897 return 0;
898 }
899
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700900 return 1;
901}
902
903
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100904static int pcmcia_bus_match(struct device *dev, struct device_driver *drv)
905{
906 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
907 struct pcmcia_driver *p_drv = to_pcmcia_drv(drv);
Joe Perchese9fb13b2011-05-03 19:29:00 -0700908 const struct pcmcia_device_id *did = p_drv->id_table;
Bernhard Walle6179b552007-05-06 14:48:44 -0700909 struct pcmcia_dynid *dynid;
910
911 /* match dynamic devices first */
Dominik Brodowski3f565232010-01-16 13:06:40 +0100912 mutex_lock(&p_drv->dynids.lock);
Bernhard Walle6179b552007-05-06 14:48:44 -0700913 list_for_each_entry(dynid, &p_drv->dynids.list, node) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200914 dev_dbg(dev, "trying to match to %s\n", drv->name);
Bernhard Walle6179b552007-05-06 14:48:44 -0700915 if (pcmcia_devmatch(p_dev, &dynid->id)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200916 dev_dbg(dev, "matched to %s\n", drv->name);
Dominik Brodowski3f565232010-01-16 13:06:40 +0100917 mutex_unlock(&p_drv->dynids.lock);
Bernhard Walle6179b552007-05-06 14:48:44 -0700918 return 1;
919 }
920 }
Dominik Brodowski3f565232010-01-16 13:06:40 +0100921 mutex_unlock(&p_drv->dynids.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700923 while (did && did->match_flags) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200924 dev_dbg(dev, "trying to match to %s\n", drv->name);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200925 if (pcmcia_devmatch(p_dev, did)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200926 dev_dbg(dev, "matched to %s\n", drv->name);
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700927 return 1;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200928 }
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700929 did++;
930 }
931
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 return 0;
933}
934
Kay Sievers7eff2e72007-08-14 15:15:12 +0200935static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700936{
937 struct pcmcia_device *p_dev;
Kay Sievers7eff2e72007-08-14 15:15:12 +0200938 int i;
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700939 u32 hash[4] = { 0, 0, 0, 0};
940
941 if (!dev)
942 return -ENODEV;
943
944 p_dev = to_pcmcia_dev(dev);
945
946 /* calculate hashes */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100947 for (i = 0; i < 4; i++) {
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700948 if (!p_dev->prod_id[i])
949 continue;
950 hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i]));
951 }
952
Kay Sievers7eff2e72007-08-14 15:15:12 +0200953 if (add_uevent_var(env, "SOCKET_NO=%u", p_dev->socket->sock))
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700954 return -ENOMEM;
955
Kay Sievers7eff2e72007-08-14 15:15:12 +0200956 if (add_uevent_var(env, "DEVICE_NO=%02X", p_dev->device_no))
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700957 return -ENOMEM;
958
Kay Sievers7eff2e72007-08-14 15:15:12 +0200959 if (add_uevent_var(env, "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
Kay Sievers312c0042005-11-16 09:00:00 +0100960 "pa%08Xpb%08Xpc%08Xpd%08X",
961 p_dev->has_manf_id ? p_dev->manf_id : 0,
962 p_dev->has_card_id ? p_dev->card_id : 0,
963 p_dev->has_func_id ? p_dev->func_id : 0,
964 p_dev->func,
965 p_dev->device_no,
966 hash[0],
967 hash[1],
968 hash[2],
969 hash[3]))
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700970 return -ENOMEM;
971
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700972 return 0;
973}
974
Alan Stern3f8df782007-07-12 16:57:22 -0400975/************************ runtime PM support ***************************/
976
Russell Kingad8d52b2016-08-31 08:49:43 +0100977static int pcmcia_dev_suspend(struct device *dev);
Alan Stern3f8df782007-07-12 16:57:22 -0400978static int pcmcia_dev_resume(struct device *dev);
979
980static int runtime_suspend(struct device *dev)
981{
982 int rc;
983
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800984 device_lock(dev);
Russell Kingad8d52b2016-08-31 08:49:43 +0100985 rc = pcmcia_dev_suspend(dev);
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800986 device_unlock(dev);
Alan Stern3f8df782007-07-12 16:57:22 -0400987 return rc;
988}
989
Dominik Brodowski933a8382009-12-29 18:21:39 +0100990static int runtime_resume(struct device *dev)
Alan Stern3f8df782007-07-12 16:57:22 -0400991{
992 int rc;
993
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800994 device_lock(dev);
Alan Stern3f8df782007-07-12 16:57:22 -0400995 rc = pcmcia_dev_resume(dev);
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800996 device_unlock(dev);
Dominik Brodowski933a8382009-12-29 18:21:39 +0100997 return rc;
Alan Stern3f8df782007-07-12 16:57:22 -0400998}
999
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000/************************ per-device sysfs output ***************************/
1001
1002#define pcmcia_device_attr(field, test, format) \
Yani Ioannoue404e272005-05-17 06:42:58 -04001003static ssize_t field##_show (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004{ \
1005 struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001006 return p_dev->test ? sprintf(buf, format, p_dev->field) : -ENODEV; \
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001007} \
1008static DEVICE_ATTR_RO(field);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
1010#define pcmcia_device_stringattr(name, field) \
Yani Ioannoue404e272005-05-17 06:42:58 -04001011static ssize_t name##_show (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012{ \
1013 struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001014 return p_dev->field ? sprintf(buf, "%s\n", p_dev->field) : -ENODEV; \
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001015} \
1016static DEVICE_ATTR_RO(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018pcmcia_device_attr(func_id, has_func_id, "0x%02x\n");
1019pcmcia_device_attr(manf_id, has_manf_id, "0x%04x\n");
1020pcmcia_device_attr(card_id, has_card_id, "0x%04x\n");
1021pcmcia_device_stringattr(prod_id1, prod_id[0]);
1022pcmcia_device_stringattr(prod_id2, prod_id[1]);
1023pcmcia_device_stringattr(prod_id3, prod_id[2]);
1024pcmcia_device_stringattr(prod_id4, prod_id[3]);
1025
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001026static ssize_t function_show(struct device *dev, struct device_attribute *attr,
1027 char *buf)
1028{
1029 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1030 return p_dev->socket ? sprintf(buf, "0x%02x\n", p_dev->func) : -ENODEV;
1031}
1032static DEVICE_ATTR_RO(function);
1033
1034static ssize_t resources_show(struct device *dev,
1035 struct device_attribute *attr, char *buf)
Dominik Brodowski8f677ea2010-07-25 11:10:29 +02001036{
1037 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1038 char *str = buf;
1039 int i;
1040
1041 for (i = 0; i < PCMCIA_NUM_RESOURCES; i++)
1042 str += sprintf(str, "%pr\n", p_dev->resource[i]);
1043
1044 return str - buf;
1045}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001046static DEVICE_ATTR_RO(resources);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001047
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001048static ssize_t pm_state_show(struct device *dev, struct device_attribute *attr, char *buf)
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001049{
1050 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1051
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001052 if (p_dev->suspended)
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001053 return sprintf(buf, "off\n");
1054 else
1055 return sprintf(buf, "on\n");
1056}
1057
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001058static ssize_t pm_state_store(struct device *dev, struct device_attribute *attr,
1059 const char *buf, size_t count)
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001060{
1061 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1062 int ret = 0;
1063
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001064 if (!count)
1065 return -EINVAL;
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001066
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001067 if ((!p_dev->suspended) && !strncmp(buf, "off", 3))
Alan Stern3f8df782007-07-12 16:57:22 -04001068 ret = runtime_suspend(dev);
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001069 else if (p_dev->suspended && !strncmp(buf, "on", 2))
Dominik Brodowski933a8382009-12-29 18:21:39 +01001070 ret = runtime_resume(dev);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001071
1072 return ret ? ret : count;
1073}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001074static DEVICE_ATTR_RW(pm_state);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001075
Dominik Brodowski37045112005-06-30 02:58:47 -07001076static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001077{
1078 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1079 int i;
1080 u32 hash[4] = { 0, 0, 0, 0};
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001081
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001082 /* calculate hashes */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001083 for (i = 0; i < 4; i++) {
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001084 if (!p_dev->prod_id[i])
1085 continue;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001086 hash[i] = crc32(0, p_dev->prod_id[i],
1087 strlen(p_dev->prod_id[i]));
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001088 }
1089 return sprintf(buf, "pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
1090 "pa%08Xpb%08Xpc%08Xpd%08X\n",
1091 p_dev->has_manf_id ? p_dev->manf_id : 0,
1092 p_dev->has_card_id ? p_dev->card_id : 0,
1093 p_dev->has_func_id ? p_dev->func_id : 0,
1094 p_dev->func, p_dev->device_no,
1095 hash[0], hash[1], hash[2], hash[3]);
1096}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001097static DEVICE_ATTR_RO(modalias);
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001098
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001099static ssize_t allow_func_id_match_store(struct device *dev,
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001100 struct device_attribute *attr, const char *buf, size_t count)
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001101{
1102 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001103
1104 if (!count)
1105 return -EINVAL;
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001106
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001107 mutex_lock(&p_dev->socket->ops_mutex);
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001108 p_dev->allow_func_id_match = 1;
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001109 mutex_unlock(&p_dev->socket->ops_mutex);
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +01001110 pcmcia_parse_uevents(p_dev->socket, PCMCIA_UEVENT_REQUERY);
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001111
1112 return count;
1113}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001114static DEVICE_ATTR_WO(allow_func_id_match);
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001115
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001116static struct attribute *pcmcia_dev_attrs[] = {
1117 &dev_attr_resources.attr,
1118 &dev_attr_pm_state.attr,
1119 &dev_attr_function.attr,
1120 &dev_attr_func_id.attr,
1121 &dev_attr_manf_id.attr,
1122 &dev_attr_card_id.attr,
1123 &dev_attr_prod_id1.attr,
1124 &dev_attr_prod_id2.attr,
1125 &dev_attr_prod_id3.attr,
1126 &dev_attr_prod_id4.attr,
1127 &dev_attr_modalias.attr,
1128 &dev_attr_allow_func_id_match.attr,
1129 NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130};
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001131ATTRIBUTE_GROUPS(pcmcia_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001133/* PM support, also needed for reset */
1134
Russell Kingad8d52b2016-08-31 08:49:43 +01001135static int pcmcia_dev_suspend(struct device *dev)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001136{
1137 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1138 struct pcmcia_driver *p_drv = NULL;
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001139 int ret = 0;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001140
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001141 mutex_lock(&p_dev->socket->ops_mutex);
1142 if (p_dev->suspended) {
1143 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001144 return 0;
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001145 }
1146 p_dev->suspended = 1;
1147 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001148
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001149 dev_dbg(dev, "suspending\n");
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001150
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001151 if (dev->driver)
1152 p_drv = to_pcmcia_drv(dev->driver);
1153
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001154 if (!p_drv)
1155 goto out;
1156
1157 if (p_drv->suspend) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +01001158 ret = p_drv->suspend(p_dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001159 if (ret) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001160 dev_err(dev,
1161 "pcmcia: device %s (driver %s) did not want to go to sleep (%d)\n",
1162 p_dev->devname, p_drv->name, ret);
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001163 mutex_lock(&p_dev->socket->ops_mutex);
1164 p_dev->suspended = 0;
1165 mutex_unlock(&p_dev->socket->ops_mutex);
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001166 goto out;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001167 }
Dominik Brodowski8661bb52006-03-02 00:02:33 +01001168 }
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001169
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001170 if (p_dev->device_no == p_dev->func) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001171 dev_dbg(dev, "releasing configuration\n");
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001172 pcmcia_release_configuration(p_dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001173 }
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001174
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001175 out:
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001176 return ret;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001177}
1178
1179
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001180static int pcmcia_dev_resume(struct device *dev)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001181{
1182 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001183 struct pcmcia_driver *p_drv = NULL;
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001184 int ret = 0;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001185
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001186 mutex_lock(&p_dev->socket->ops_mutex);
1187 if (!p_dev->suspended) {
1188 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001189 return 0;
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001190 }
1191 p_dev->suspended = 0;
1192 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001193
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001194 dev_dbg(dev, "resuming\n");
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001195
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001196 if (dev->driver)
1197 p_drv = to_pcmcia_drv(dev->driver);
1198
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001199 if (!p_drv)
1200 goto out;
1201
1202 if (p_dev->device_no == p_dev->func) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001203 dev_dbg(dev, "requesting configuration\n");
Dominik Brodowski1ac71e52010-07-29 19:27:09 +02001204 ret = pcmcia_enable_device(p_dev);
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001205 if (ret)
1206 goto out;
Dominik Brodowski8661bb52006-03-02 00:02:33 +01001207 }
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001208
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001209 if (p_drv->resume)
1210 ret = p_drv->resume(p_dev);
1211
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001212 out:
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001213 return ret;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001214}
1215
1216
Laurent Navet46f533c2013-01-21 22:16:05 +01001217static int pcmcia_bus_suspend_callback(struct device *dev, void *_data)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001218{
1219 struct pcmcia_socket *skt = _data;
1220 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1221
Alan Stern3f8df782007-07-12 16:57:22 -04001222 if (p_dev->socket != skt || p_dev->suspended)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001223 return 0;
1224
Alan Stern3f8df782007-07-12 16:57:22 -04001225 return runtime_suspend(dev);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001226}
1227
Laurent Navet46f533c2013-01-21 22:16:05 +01001228static int pcmcia_bus_resume_callback(struct device *dev, void *_data)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001229{
1230 struct pcmcia_socket *skt = _data;
1231 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1232
Alan Stern3f8df782007-07-12 16:57:22 -04001233 if (p_dev->socket != skt || !p_dev->suspended)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001234 return 0;
1235
Alan Stern3f8df782007-07-12 16:57:22 -04001236 runtime_resume(dev);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001237
1238 return 0;
1239}
1240
1241static int pcmcia_bus_resume(struct pcmcia_socket *skt)
1242{
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001243 dev_dbg(&skt->dev, "resuming socket %d\n", skt->sock);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001244 bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback);
1245 return 0;
1246}
1247
1248static int pcmcia_bus_suspend(struct pcmcia_socket *skt)
1249{
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001250 dev_dbg(&skt->dev, "suspending socket %d\n", skt->sock);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001251 if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt,
1252 pcmcia_bus_suspend_callback)) {
1253 pcmcia_bus_resume(skt);
1254 return -EIO;
1255 }
1256 return 0;
1257}
1258
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001259static int pcmcia_bus_remove(struct pcmcia_socket *skt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260{
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001261 atomic_set(&skt->present, 0);
1262 pcmcia_card_remove(skt, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001264 mutex_lock(&skt->ops_mutex);
1265 destroy_cis_cache(skt);
1266 pcmcia_cleanup_irq(skt);
1267 mutex_unlock(&skt->ops_mutex);
1268
1269 return 0;
1270}
1271
1272static int pcmcia_bus_add(struct pcmcia_socket *skt)
1273{
1274 atomic_set(&skt->present, 1);
1275
1276 mutex_lock(&skt->ops_mutex);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +02001277 skt->pcmcia_pfc = 0;
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001278 destroy_cis_cache(skt); /* to be on the safe side... */
1279 mutex_unlock(&skt->ops_mutex);
1280
1281 pcmcia_card_add(skt);
1282
1283 return 0;
1284}
1285
1286static int pcmcia_bus_early_resume(struct pcmcia_socket *skt)
1287{
Russell King025e4ab2012-02-08 17:13:41 -08001288 if (!verify_cis_cache(skt))
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001289 return 0;
Florin Malita16174062006-05-24 21:21:31 -04001290
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001291 dev_dbg(&skt->dev, "cis mismatch - different card\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001293 /* first, remove the card */
1294 pcmcia_bus_remove(skt);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +01001295
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001296 mutex_lock(&skt->ops_mutex);
1297 destroy_cis_cache(skt);
1298 kfree(skt->fake_cis);
1299 skt->fake_cis = NULL;
1300 skt->functions = 0;
1301 mutex_unlock(&skt->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001303 /* now, add the new card */
1304 pcmcia_bus_add(skt);
1305 return 0;
1306}
Dominik Brodowski88b060d2010-01-02 14:14:23 +01001307
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
Dominik Brodowski04de0812010-04-20 14:49:01 +02001309/*
1310 * NOTE: This is racy. There's no guarantee the card will still be
1311 * physically present, even if the call to this function returns
1312 * non-NULL. Furthermore, the device driver most likely is unbound
1313 * almost immediately, so the timeframe where pcmcia_dev_present
1314 * returns NULL is probably really really small.
1315 */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001316struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev)
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001317{
1318 struct pcmcia_device *p_dev;
1319 struct pcmcia_device *ret = NULL;
1320
1321 p_dev = pcmcia_get_dev(_p_dev);
1322 if (!p_dev)
1323 return NULL;
1324
Dominik Brodowski04de0812010-04-20 14:49:01 +02001325 if (atomic_read(&p_dev->socket->present) != 0)
1326 ret = p_dev;
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001327
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001328 pcmcia_put_dev(p_dev);
1329 return ret;
1330}
1331EXPORT_SYMBOL(pcmcia_dev_present);
1332
1333
Dominik Brodowski90c6cdd2005-06-27 16:28:49 -07001334static struct pcmcia_callback pcmcia_bus_callback = {
1335 .owner = THIS_MODULE,
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001336 .add = pcmcia_bus_add,
1337 .remove = pcmcia_bus_remove,
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +01001338 .requery = pcmcia_requery,
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001339 .validate = pccard_validate_cis,
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001340 .suspend = pcmcia_bus_suspend,
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001341 .early_resume = pcmcia_bus_early_resume,
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001342 .resume = pcmcia_bus_resume,
Dominik Brodowski90c6cdd2005-06-27 16:28:49 -07001343};
1344
Bill Pemberton34cdf252012-11-19 13:23:12 -05001345static int pcmcia_bus_add_socket(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001346 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001348 struct pcmcia_socket *socket = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 int ret;
1350
Dominik Brodowskidc109492005-06-27 16:28:50 -07001351 socket = pcmcia_get_socket(socket);
1352 if (!socket) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001353 dev_err(dev, "PCMCIA obtaining reference to socket failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 return -ENODEV;
1355 }
1356
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001357 ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
1358 if (ret) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001359 dev_err(dev, "PCMCIA registration failed\n");
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001360 pcmcia_put_socket(socket);
1361 return ret;
1362 }
1363
Dominik Brodowskidc109492005-06-27 16:28:50 -07001364 INIT_LIST_HEAD(&socket->devices_list);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +02001365 socket->pcmcia_pfc = 0;
Dominik Brodowskidc109492005-06-27 16:28:50 -07001366 socket->device_count = 0;
Dominik Brodowskie4f1ac22010-06-19 14:33:56 +02001367 atomic_set(&socket->present, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368
Dominik Brodowski90c6cdd2005-06-27 16:28:49 -07001369 ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 if (ret) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001371 dev_err(dev, "PCMCIA registration failed\n");
Dominik Brodowskidc109492005-06-27 16:28:50 -07001372 pcmcia_put_socket(socket);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001373 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 }
1375
1376 return 0;
1377}
1378
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001379static void pcmcia_bus_remove_socket(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001380 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001382 struct pcmcia_socket *socket = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
Dominik Brodowskidc109492005-06-27 16:28:50 -07001384 if (!socket)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 return;
1386
1387 pccard_register_pcmcia(socket, NULL);
1388
Daniel Ritzdfbc9e92006-11-18 22:19:34 -08001389 /* unregister any unbound devices */
Daniel Ritz8e4d9dc2006-11-25 11:09:17 -08001390 mutex_lock(&socket->skt_mutex);
Daniel Ritzdfbc9e92006-11-18 22:19:34 -08001391 pcmcia_card_remove(socket, NULL);
Dominik Brodowski180c33e2010-01-02 17:34:09 +01001392 release_cis_mem(socket);
Daniel Ritz8e4d9dc2006-11-25 11:09:17 -08001393 mutex_unlock(&socket->skt_mutex);
Daniel Ritzdfbc9e92006-11-18 22:19:34 -08001394
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001395 sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr);
1396
Dominik Brodowskidc109492005-06-27 16:28:50 -07001397 pcmcia_put_socket(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
1399 return;
1400}
1401
1402
1403/* the pcmcia_bus_interface is used to handle pcmcia socket devices */
Sam Ravnborged49f5d2008-05-01 04:34:50 -07001404static struct class_interface pcmcia_bus_interface __refdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 .class = &pcmcia_socket_class,
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001406 .add_dev = &pcmcia_bus_add_socket,
1407 .remove_dev = &pcmcia_bus_remove_socket,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408};
1409
Russell Kingad8d52b2016-08-31 08:49:43 +01001410static const struct dev_pm_ops pcmcia_bus_pm_ops = {
1411 SET_SYSTEM_SLEEP_PM_OPS(pcmcia_dev_suspend, pcmcia_dev_resume)
1412};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001414struct bus_type pcmcia_bus_type = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 .name = "pcmcia",
Kay Sievers312c0042005-11-16 09:00:00 +01001416 .uevent = pcmcia_bus_uevent,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 .match = pcmcia_bus_match,
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001418 .dev_groups = pcmcia_dev_groups,
Russell King1d0baa32006-01-05 14:40:58 +00001419 .probe = pcmcia_device_probe,
1420 .remove = pcmcia_device_remove,
Russell Kingad8d52b2016-08-31 08:49:43 +01001421 .pm = &pcmcia_bus_pm_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
1424
1425static int __init init_pcmcia_bus(void)
1426{
Randy Dunlapace7d472006-10-20 14:44:12 -07001427 int ret;
1428
Randy Dunlapace7d472006-10-20 14:44:12 -07001429 ret = bus_register(&pcmcia_bus_type);
1430 if (ret < 0) {
1431 printk(KERN_WARNING "pcmcia: bus_register error: %d\n", ret);
1432 return ret;
1433 }
1434 ret = class_interface_register(&pcmcia_bus_interface);
1435 if (ret < 0) {
1436 printk(KERN_WARNING
1437 "pcmcia: class_interface_register error: %d\n", ret);
1438 bus_unregister(&pcmcia_bus_type);
1439 return ret;
1440 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 return 0;
1443}
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001444fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 * pcmcia_socket_class is already registered */
1446
1447
1448static void __exit exit_pcmcia_bus(void)
1449{
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001450 class_interface_unregister(&pcmcia_bus_interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451
1452 bus_unregister(&pcmcia_bus_type);
1453}
1454module_exit(exit_pcmcia_bus);
1455
1456
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457MODULE_ALIAS("ds");