blob: 5bd1b80424e7234388134836db6aff58f0108871 [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
Uwe Kleine-Königfc7a6202021-07-13 21:35:22 +0200353static void 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
394
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100395/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 * pcmcia_device_query -- determine information about a pcmcia device
397 */
398static int pcmcia_device_query(struct pcmcia_device *p_dev)
399{
400 cistpl_manfid_t manf_id;
401 cistpl_funcid_t func_id;
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700402 cistpl_vers_1_t *vers1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 unsigned int i;
404
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700405 vers1 = kmalloc(sizeof(*vers1), GFP_KERNEL);
406 if (!vers1)
407 return -ENOMEM;
408
Dominik Brodowski84897fc2009-10-18 23:51:09 +0200409 if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 CISTPL_MANFID, &manf_id)) {
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100411 mutex_lock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 p_dev->manf_id = manf_id.manf;
413 p_dev->card_id = manf_id.card;
414 p_dev->has_manf_id = 1;
415 p_dev->has_card_id = 1;
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100416 mutex_unlock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 }
418
419 if (!pccard_read_tuple(p_dev->socket, p_dev->func,
420 CISTPL_FUNCID, &func_id)) {
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100421 mutex_lock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 p_dev->func_id = func_id.func;
423 p_dev->has_func_id = 1;
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100424 mutex_unlock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 } else {
426 /* rule of thumb: cards with no FUNCID, but with
427 * common memory device geometry information, are
428 * probably memory cards (from pcmcia-cs) */
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700429 cistpl_device_geo_t *devgeo;
430
431 devgeo = kmalloc(sizeof(*devgeo), GFP_KERNEL);
432 if (!devgeo) {
433 kfree(vers1);
434 return -ENOMEM;
435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 if (!pccard_read_tuple(p_dev->socket, p_dev->func,
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700437 CISTPL_DEVICE_GEO, devgeo)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200438 dev_dbg(&p_dev->dev,
Dominik Brodowskiac449d62008-08-02 18:33:56 +0200439 "mem device geometry probably means "
440 "FUNCID_MEMORY\n");
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100441 mutex_lock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 p_dev->func_id = CISTPL_FUNCID_MEMORY;
443 p_dev->has_func_id = 1;
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100444 mutex_unlock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 }
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700446 kfree(devgeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 }
448
Dominik Brodowski84897fc2009-10-18 23:51:09 +0200449 if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL, CISTPL_VERS_1,
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700450 vers1)) {
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100451 mutex_lock(&p_dev->socket->ops_mutex);
Dominik Brodowskic5e09522009-10-19 00:04:25 +0200452 for (i = 0; i < min_t(unsigned int, 4, vers1->ns); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 char *tmp;
454 unsigned int length;
Dominik Brodowski44961a02010-01-24 12:11:02 +0100455 char *new;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700457 tmp = vers1->str + vers1->ofs[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
459 length = strlen(tmp) + 1;
Janos Farkas6e3d4f22006-03-31 01:04:57 +0200460 if ((length < 2) || (length > 255))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 continue;
462
Geliang Tang7c22e642015-10-02 00:37:57 +0800463 new = kstrdup(tmp, GFP_KERNEL);
Dominik Brodowski44961a02010-01-24 12:11:02 +0100464 if (!new)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 continue;
466
Dominik Brodowski44961a02010-01-24 12:11:02 +0100467 tmp = p_dev->prod_id[i];
468 p_dev->prod_id[i] = new;
469 kfree(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 }
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100471 mutex_unlock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 }
473
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700474 kfree(vers1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 return 0;
476}
477
478
Dominik Brodowski5716d412010-07-11 09:51:14 +0200479static struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s,
480 unsigned int function)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481{
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100482 struct pcmcia_device *p_dev, *tmp_dev;
Dominik Brodowski44961a02010-01-24 12:11:02 +0100483 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
Dominik Brodowskidc109492005-06-27 16:28:50 -0700485 s = pcmcia_get_socket(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 if (!s)
487 return NULL;
488
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200489 pr_debug("adding device to %d, function %d\n", s->sock, function);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200490
Dominik Brodowski8084b372005-12-11 21:18:26 +0100491 p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 if (!p_dev)
493 goto err_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100495 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 p_dev->device_no = (s->device_count++);
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100497 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100498
Dominik Brodowski7d7ba8d2010-03-24 10:49:14 +0100499 /* max of 2 PFC devices */
500 if ((p_dev->device_no >= 2) && (function == 0))
501 goto err_free;
502
503 /* max of 4 devices overall */
504 if (p_dev->device_no >= 4)
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100505 goto err_free;
506
507 p_dev->socket = s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 p_dev->func = function;
509
510 p_dev->dev.bus = &pcmcia_bus_type;
Greg Kroah-Hartman87373312006-09-12 17:00:10 +0200511 p_dev->dev.parent = s->dev.parent;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 p_dev->dev.release = pcmcia_release_dev;
James Bottomley43d9f7f2007-10-16 01:23:58 -0700513 /* by default don't allow DMA */
Christoph Hellwig7ae10eb2020-09-11 09:29:50 +0200514 p_dev->dma_mask = 0;
James Bottomley43d9f7f2007-10-16 01:23:58 -0700515 p_dev->dev.dma_mask = &p_dev->dma_mask;
Kay Sievers25096982008-11-01 11:46:06 +0100516 dev_set_name(&p_dev->dev, "%d.%d", p_dev->socket->sock, p_dev->device_no);
517 if (!dev_name(&p_dev->dev))
518 goto err_free;
519 p_dev->devname = kasprintf(GFP_KERNEL, "pcmcia%s", dev_name(&p_dev->dev));
Brice Goglinbd65a682005-09-09 13:03:29 -0700520 if (!p_dev->devname)
521 goto err_free;
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200522 dev_dbg(&p_dev->dev, "devname is %s\n", p_dev->devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100524 mutex_lock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100525
526 /*
527 * p_dev->function_config must be the same for all card functions.
Dominik Brodowskia60f22c2010-03-07 09:22:51 +0100528 * Note that this is serialized by ops_mutex, so that only one
529 * such struct will be created.
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100530 */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100531 list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)
532 if (p_dev->func == tmp_dev->func) {
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100533 p_dev->function_config = tmp_dev->function_config;
Komuro3e879f62008-11-02 19:33:24 +0900534 p_dev->irq = tmp_dev->irq;
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100535 kref_get(&p_dev->function_config->ref);
536 }
537
538 /* Add to the list in pcmcia_bus_socket */
Komuro6171b882006-04-02 17:39:27 +0900539 list_add(&p_dev->socket_device_list, &s->devices_list);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100540
Dominik Brodowski6f0f38c2010-04-08 20:33:16 +0200541 if (pcmcia_setup_irq(p_dev))
542 dev_warn(&p_dev->dev,
543 "IRQ setup failed -- device might not work\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100545 if (!p_dev->function_config) {
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200546 config_t *c;
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200547 dev_dbg(&p_dev->dev, "creating config_t\n");
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200548 c = kzalloc(sizeof(struct config_t), GFP_KERNEL);
549 if (!c) {
Dominik Brodowski6f0f38c2010-04-08 20:33:16 +0200550 mutex_unlock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100551 goto err_unreg;
Dominik Brodowski6f0f38c2010-04-08 20:33:16 +0200552 }
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200553 p_dev->function_config = c;
554 kref_init(&c->ref);
555 for (i = 0; i < MAX_IO_WIN; i++) {
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200556 c->io[i].name = p_dev->devname;
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200557 c->io[i].flags = IORESOURCE_IO;
558 }
Laurent Navet46f533c2013-01-21 22:16:05 +0100559 for (i = 0; i < MAX_WIN; i++) {
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200560 c->mem[i].name = p_dev->devname;
Dominik Brodowski0ca724d32010-07-24 19:03:02 +0200561 c->mem[i].flags = IORESOURCE_MEM;
562 }
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100563 }
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200564 for (i = 0; i < MAX_IO_WIN; i++)
565 p_dev->resource[i] = &p_dev->function_config->io[i];
Dominik Brodowski0ca724d32010-07-24 19:03:02 +0200566 for (; i < (MAX_IO_WIN + MAX_WIN); i++)
567 p_dev->resource[i] = &p_dev->function_config->mem[i-MAX_IO_WIN];
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200568
Dominik Brodowski6f0f38c2010-04-08 20:33:16 +0200569 mutex_unlock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100570
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700571 dev_notice(&p_dev->dev, "pcmcia: registering new device %s (IRQ: %d)\n",
Dominik Brodowskieb141202010-03-07 12:21:16 +0100572 p_dev->devname, p_dev->irq);
Dominik Brodowski807277c2005-11-12 23:34:06 +0100573
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700574 pcmcia_device_query(p_dev);
575
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100576 if (device_register(&p_dev->dev))
577 goto err_unreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 return p_dev;
580
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100581 err_unreg:
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100582 mutex_lock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100583 list_del(&p_dev->socket_device_list);
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100584 mutex_unlock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 err_free:
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100587 mutex_lock(&s->ops_mutex);
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100588 s->device_count--;
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100589 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100590
Dominik Brodowski44961a02010-01-24 12:11:02 +0100591 for (i = 0; i < 4; i++)
592 kfree(p_dev->prod_id[i]);
Brice Goglinbd65a682005-09-09 13:03:29 -0700593 kfree(p_dev->devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 kfree(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 err_put:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700596 pcmcia_put_socket(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597
598 return NULL;
599}
600
601
602static int pcmcia_card_add(struct pcmcia_socket *s)
603{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 cistpl_longlink_mfc_t mfc;
Dominik Brodowskic5081d52008-06-19 20:12:34 +0200605 unsigned int no_funcs, i, no_chains;
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100606 int ret = -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100608 mutex_lock(&s->ops_mutex);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200609 if (!(s->resource_setup_done)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200610 dev_dbg(&s->dev,
Dominik Brodowskiac449d62008-08-02 18:33:56 +0200611 "no resources available, delaying card_add\n");
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100612 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 return -EAGAIN; /* try again, but later... */
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200614 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200616 if (pcmcia_validate_mem(s)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200617 dev_dbg(&s->dev, "validating mem resources failed, "
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200618 "delaying card_add\n");
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100619 mutex_unlock(&s->ops_mutex);
Dominik Brodowskide759142005-09-28 19:41:56 +0200620 return -EAGAIN; /* try again, but later... */
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200621 }
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100622 mutex_unlock(&s->ops_mutex);
Dominik Brodowskide759142005-09-28 19:41:56 +0200623
Dominik Brodowski84897fc2009-10-18 23:51:09 +0200624 ret = pccard_validate_cis(s, &no_chains);
Dominik Brodowskic5081d52008-06-19 20:12:34 +0200625 if (ret || !no_chains) {
Dominik Brodowskie8e68fd2015-06-14 21:52:46 +0200626#if defined(CONFIG_MTD_PCMCIA_ANONYMOUS)
627 /* Set up as an anonymous card. If we don't have anonymous
628 memory support then just error the card as there is no
629 point trying to second guess.
630
631 Note: some cards have just a device entry, it may be
632 worth extending support to cover these in future */
633 if (ret == -EIO) {
634 dev_info(&s->dev, "no CIS, assuming an anonymous memory card.\n");
635 pcmcia_replace_cis(s, "\xFF", 1);
636 no_chains = 1;
637 ret = 0;
638 } else
639#endif
640 {
641 dev_dbg(&s->dev, "invalid CIS or invalid resources\n");
642 return -ENODEV;
643 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 }
645
646 if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc))
647 no_funcs = mfc.nfn;
648 else
649 no_funcs = 1;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500650 s->functions = no_funcs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100652 for (i = 0; i < no_funcs; i++)
Dominik Brodowskidc109492005-06-27 16:28:50 -0700653 pcmcia_device_add(s, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100655 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656}
657
658
Laurent Navet46f533c2013-01-21 22:16:05 +0100659static int pcmcia_requery_callback(struct device *dev, void *_data)
Dominik Brodowskiff1fa9e2005-06-27 16:28:09 -0700660{
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700661 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200662 if (!p_dev->dev.driver) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200663 dev_dbg(dev, "update device information\n");
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700664 pcmcia_device_query(p_dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200665 }
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700666
667 return 0;
668}
669
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100670
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100671static void pcmcia_requery(struct pcmcia_socket *s)
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700672{
Dominik Brodowski04de0812010-04-20 14:49:01 +0200673 int has_pfc;
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700674
Alan Cox84026412014-12-10 15:06:40 +0000675 if (!(s->state & SOCKET_PRESENT))
676 return;
677
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100678 if (s->functions == 0) {
679 pcmcia_card_add(s);
680 return;
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700681 }
682
683 /* some device information might have changed because of a CIS
684 * update or because we can finally read it correctly... so
685 * determine it again, overwriting old values if necessary. */
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100686 bus_for_each_dev(&pcmcia_bus_type, NULL, NULL, pcmcia_requery_callback);
687
688 /* if the CIS changed, we need to check whether the number of
689 * functions changed. */
690 if (s->fake_cis) {
691 int old_funcs, new_funcs;
692 cistpl_longlink_mfc_t mfc;
693
694 /* does this cis override add or remove functions? */
695 old_funcs = s->functions;
696
697 if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC,
698 &mfc))
699 new_funcs = mfc.nfn;
700 else
701 new_funcs = 1;
Dominik Brodowskib1095af2010-04-08 20:10:21 +0200702 if (old_funcs != new_funcs) {
703 /* we need to re-start */
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100704 pcmcia_card_remove(s, NULL);
Dominik Brodowskib83156b2010-06-07 18:31:17 +0200705 s->functions = 0;
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100706 pcmcia_card_add(s);
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100707 }
708 }
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700709
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100710 /* If the PCMCIA device consists of two pseudo devices,
711 * call pcmcia_device_add() -- which will fail if both
712 * devices are already registered. */
713 mutex_lock(&s->ops_mutex);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +0200714 has_pfc = s->pcmcia_pfc;
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100715 mutex_unlock(&s->ops_mutex);
716 if (has_pfc)
717 pcmcia_device_add(s, 0);
718
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700719 /* we re-scan all devices, not just the ones connected to this
720 * socket. This does not matter, though. */
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100721 if (bus_rescan_devices(&pcmcia_bus_type))
722 dev_warn(&s->dev, "rescanning the bus failed\n");
Dominik Brodowskiff1fa9e2005-06-27 16:28:09 -0700723}
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700724
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100725
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500726#ifdef CONFIG_PCMCIA_LOAD_CIS
727
728/**
729 * pcmcia_load_firmware - load CIS from userspace if device-provided is broken
Randy Dunlap78187862007-12-10 15:49:22 -0800730 * @dev: the pcmcia device which needs a CIS override
731 * @filename: requested filename in /lib/firmware/
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500732 *
733 * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if
734 * the one provided by the card is broken. The firmware files reside in
735 * /lib/firmware/ in userspace.
736 */
Laurent Navet46f533c2013-01-21 22:16:05 +0100737static int pcmcia_load_firmware(struct pcmcia_device *dev, char *filename)
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500738{
739 struct pcmcia_socket *s = dev->socket;
740 const struct firmware *fw;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500741 int ret = -ENOMEM;
Dominik Brodowskib1095af2010-04-08 20:10:21 +0200742 cistpl_longlink_mfc_t mfc;
743 int old_funcs, new_funcs = 1;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500744
745 if (!filename)
746 return -EINVAL;
747
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200748 dev_dbg(&dev->dev, "trying to load CIS file %s\n", filename);
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500749
Samuel Ortized62ace2009-05-27 00:49:35 +0200750 if (request_firmware(&fw, filename, &dev->dev) == 0) {
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200751 if (fw->size >= CISTPL_MAX_CIS_SIZE) {
752 ret = -EINVAL;
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700753 dev_err(&dev->dev, "pcmcia: CIS override is too big\n");
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500754 goto release;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200755 }
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500756
Dominik Brodowski53efec92008-07-28 19:44:05 +0200757 if (!pcmcia_replace_cis(s, fw->data, fw->size))
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500758 ret = 0;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200759 else {
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700760 dev_err(&dev->dev, "pcmcia: CIS override failed\n");
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200761 goto release;
762 }
763
Dominik Brodowskib1095af2010-04-08 20:10:21 +0200764 /* we need to re-start if the number of functions changed */
765 old_funcs = s->functions;
766 if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC,
767 &mfc))
768 new_funcs = mfc.nfn;
769
770 if (old_funcs != new_funcs)
771 ret = -EBUSY;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500772
773 /* update information */
774 pcmcia_device_query(dev);
775
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100776 /* requery (as number of functions might have changed) */
777 pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500778 }
779 release:
780 release_firmware(fw);
781
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100782 return ret;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500783}
784
785#else /* !CONFIG_PCMCIA_LOAD_CIS */
786
Laurent Navet46f533c2013-01-21 22:16:05 +0100787static inline int pcmcia_load_firmware(struct pcmcia_device *dev,
788 char *filename)
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500789{
790 return -ENODEV;
791}
792
793#endif
794
795
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700796static inline int pcmcia_devmatch(struct pcmcia_device *dev,
Joe Perchese9fb13b2011-05-03 19:29:00 -0700797 const struct pcmcia_device_id *did)
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700798{
799 if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) {
800 if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id))
801 return 0;
802 }
803
804 if (did->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID) {
805 if ((!dev->has_card_id) || (dev->card_id != did->card_id))
806 return 0;
807 }
808
809 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION) {
810 if (dev->func != did->function)
811 return 0;
812 }
813
814 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1) {
815 if (!dev->prod_id[0])
816 return 0;
817 if (strcmp(did->prod_id[0], dev->prod_id[0]))
818 return 0;
819 }
820
821 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2) {
822 if (!dev->prod_id[1])
823 return 0;
824 if (strcmp(did->prod_id[1], dev->prod_id[1]))
825 return 0;
826 }
827
828 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3) {
829 if (!dev->prod_id[2])
830 return 0;
831 if (strcmp(did->prod_id[2], dev->prod_id[2]))
832 return 0;
833 }
834
835 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4) {
836 if (!dev->prod_id[3])
837 return 0;
838 if (strcmp(did->prod_id[3], dev->prod_id[3]))
839 return 0;
840 }
841
842 if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {
Alexander Kurz83bf6f12010-04-25 13:44:35 +0400843 dev_dbg(&dev->dev, "this is a pseudo-multi-function device\n");
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100844 mutex_lock(&dev->socket->ops_mutex);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +0200845 dev->socket->pcmcia_pfc = 1;
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100846 mutex_unlock(&dev->socket->ops_mutex);
Alexander Kurz83bf6f12010-04-25 13:44:35 +0400847 if (dev->device_no != did->device_no)
848 return 0;
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700849 }
850
851 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) {
Dominik Brodowski94a819f2010-01-17 18:31:34 +0100852 int ret;
853
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700854 if ((!dev->has_func_id) || (dev->func_id != did->func_id))
855 return 0;
856
857 /* if this is a pseudo-multi-function device,
858 * we need explicit matches */
Dominik Brodowskice3f9d72010-07-21 14:43:05 +0200859 if (dev->socket->pcmcia_pfc)
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700860 return 0;
861 if (dev->device_no)
862 return 0;
863
864 /* also, FUNC_ID matching needs to be activated by userspace
865 * after it has re-checked that there is no possible module
866 * with a prod_id/manf_id/card_id match.
867 */
Dominik Brodowski94a819f2010-01-17 18:31:34 +0100868 mutex_lock(&dev->socket->ops_mutex);
869 ret = dev->allow_func_id_match;
870 mutex_unlock(&dev->socket->ops_mutex);
871
872 if (!ret) {
873 dev_dbg(&dev->dev,
874 "skipping FUNC_ID match until userspace ACK\n");
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700875 return 0;
Dominik Brodowski94a819f2010-01-17 18:31:34 +0100876 }
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700877 }
878
Dominik Brodowskiea7b3882005-06-27 16:28:07 -0700879 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200880 dev_dbg(&dev->dev, "device needs a fake CIS\n");
Dominik Brodowskidaa95172005-06-27 16:28:14 -0700881 if (!dev->socket->fake_cis)
Dominik Brodowskib1095af2010-04-08 20:10:21 +0200882 if (pcmcia_load_firmware(dev, did->cisfile))
883 return 0;
Dominik Brodowskiea7b3882005-06-27 16:28:07 -0700884 }
885
Dominik Brodowskif602ff72005-06-27 16:28:09 -0700886 if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {
887 int i;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100888 for (i = 0; i < 4; i++)
Dominik Brodowskif602ff72005-06-27 16:28:09 -0700889 if (dev->prod_id[i])
890 return 0;
891 if (dev->has_manf_id || dev->has_card_id || dev->has_func_id)
892 return 0;
893 }
894
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700895 return 1;
896}
897
898
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100899static int pcmcia_bus_match(struct device *dev, struct device_driver *drv)
900{
901 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
902 struct pcmcia_driver *p_drv = to_pcmcia_drv(drv);
Joe Perchese9fb13b2011-05-03 19:29:00 -0700903 const struct pcmcia_device_id *did = p_drv->id_table;
Bernhard Walle6179b552007-05-06 14:48:44 -0700904 struct pcmcia_dynid *dynid;
905
906 /* match dynamic devices first */
Dominik Brodowski3f565232010-01-16 13:06:40 +0100907 mutex_lock(&p_drv->dynids.lock);
Bernhard Walle6179b552007-05-06 14:48:44 -0700908 list_for_each_entry(dynid, &p_drv->dynids.list, node) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200909 dev_dbg(dev, "trying to match to %s\n", drv->name);
Bernhard Walle6179b552007-05-06 14:48:44 -0700910 if (pcmcia_devmatch(p_dev, &dynid->id)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200911 dev_dbg(dev, "matched to %s\n", drv->name);
Dominik Brodowski3f565232010-01-16 13:06:40 +0100912 mutex_unlock(&p_drv->dynids.lock);
Bernhard Walle6179b552007-05-06 14:48:44 -0700913 return 1;
914 }
915 }
Dominik Brodowski3f565232010-01-16 13:06:40 +0100916 mutex_unlock(&p_drv->dynids.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700918 while (did && did->match_flags) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200919 dev_dbg(dev, "trying to match to %s\n", drv->name);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200920 if (pcmcia_devmatch(p_dev, did)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200921 dev_dbg(dev, "matched to %s\n", drv->name);
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700922 return 1;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200923 }
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700924 did++;
925 }
926
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 return 0;
928}
929
Kay Sievers7eff2e72007-08-14 15:15:12 +0200930static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700931{
932 struct pcmcia_device *p_dev;
Kay Sievers7eff2e72007-08-14 15:15:12 +0200933 int i;
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700934 u32 hash[4] = { 0, 0, 0, 0};
935
936 if (!dev)
937 return -ENODEV;
938
939 p_dev = to_pcmcia_dev(dev);
940
941 /* calculate hashes */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100942 for (i = 0; i < 4; i++) {
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700943 if (!p_dev->prod_id[i])
944 continue;
945 hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i]));
946 }
947
Kay Sievers7eff2e72007-08-14 15:15:12 +0200948 if (add_uevent_var(env, "SOCKET_NO=%u", p_dev->socket->sock))
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700949 return -ENOMEM;
950
Kay Sievers7eff2e72007-08-14 15:15:12 +0200951 if (add_uevent_var(env, "DEVICE_NO=%02X", p_dev->device_no))
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700952 return -ENOMEM;
953
Kay Sievers7eff2e72007-08-14 15:15:12 +0200954 if (add_uevent_var(env, "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
Kay Sievers312c0042005-11-16 09:00:00 +0100955 "pa%08Xpb%08Xpc%08Xpd%08X",
956 p_dev->has_manf_id ? p_dev->manf_id : 0,
957 p_dev->has_card_id ? p_dev->card_id : 0,
958 p_dev->has_func_id ? p_dev->func_id : 0,
959 p_dev->func,
960 p_dev->device_no,
961 hash[0],
962 hash[1],
963 hash[2],
964 hash[3]))
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700965 return -ENOMEM;
966
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700967 return 0;
968}
969
Alan Stern3f8df782007-07-12 16:57:22 -0400970/************************ runtime PM support ***************************/
971
Russell Kingad8d52b2016-08-31 08:49:43 +0100972static int pcmcia_dev_suspend(struct device *dev);
Alan Stern3f8df782007-07-12 16:57:22 -0400973static int pcmcia_dev_resume(struct device *dev);
974
975static int runtime_suspend(struct device *dev)
976{
977 int rc;
978
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800979 device_lock(dev);
Russell Kingad8d52b2016-08-31 08:49:43 +0100980 rc = pcmcia_dev_suspend(dev);
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800981 device_unlock(dev);
Alan Stern3f8df782007-07-12 16:57:22 -0400982 return rc;
983}
984
Dominik Brodowski933a8382009-12-29 18:21:39 +0100985static int runtime_resume(struct device *dev)
Alan Stern3f8df782007-07-12 16:57:22 -0400986{
987 int rc;
988
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800989 device_lock(dev);
Alan Stern3f8df782007-07-12 16:57:22 -0400990 rc = pcmcia_dev_resume(dev);
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800991 device_unlock(dev);
Dominik Brodowski933a8382009-12-29 18:21:39 +0100992 return rc;
Alan Stern3f8df782007-07-12 16:57:22 -0400993}
994
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995/************************ per-device sysfs output ***************************/
996
997#define pcmcia_device_attr(field, test, format) \
Yani Ioannoue404e272005-05-17 06:42:58 -0400998static ssize_t field##_show (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999{ \
1000 struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001001 return p_dev->test ? sprintf(buf, format, p_dev->field) : -ENODEV; \
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001002} \
1003static DEVICE_ATTR_RO(field);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
1005#define pcmcia_device_stringattr(name, field) \
Yani Ioannoue404e272005-05-17 06:42:58 -04001006static ssize_t name##_show (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007{ \
1008 struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001009 return p_dev->field ? sprintf(buf, "%s\n", p_dev->field) : -ENODEV; \
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001010} \
1011static DEVICE_ATTR_RO(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013pcmcia_device_attr(func_id, has_func_id, "0x%02x\n");
1014pcmcia_device_attr(manf_id, has_manf_id, "0x%04x\n");
1015pcmcia_device_attr(card_id, has_card_id, "0x%04x\n");
1016pcmcia_device_stringattr(prod_id1, prod_id[0]);
1017pcmcia_device_stringattr(prod_id2, prod_id[1]);
1018pcmcia_device_stringattr(prod_id3, prod_id[2]);
1019pcmcia_device_stringattr(prod_id4, prod_id[3]);
1020
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001021static ssize_t function_show(struct device *dev, struct device_attribute *attr,
1022 char *buf)
1023{
1024 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1025 return p_dev->socket ? sprintf(buf, "0x%02x\n", p_dev->func) : -ENODEV;
1026}
1027static DEVICE_ATTR_RO(function);
1028
1029static ssize_t resources_show(struct device *dev,
1030 struct device_attribute *attr, char *buf)
Dominik Brodowski8f677ea2010-07-25 11:10:29 +02001031{
1032 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1033 char *str = buf;
1034 int i;
1035
1036 for (i = 0; i < PCMCIA_NUM_RESOURCES; i++)
1037 str += sprintf(str, "%pr\n", p_dev->resource[i]);
1038
1039 return str - buf;
1040}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001041static DEVICE_ATTR_RO(resources);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001042
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001043static ssize_t pm_state_show(struct device *dev, struct device_attribute *attr, char *buf)
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001044{
1045 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1046
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001047 if (p_dev->suspended)
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001048 return sprintf(buf, "off\n");
1049 else
1050 return sprintf(buf, "on\n");
1051}
1052
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001053static ssize_t pm_state_store(struct device *dev, struct device_attribute *attr,
1054 const char *buf, size_t count)
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001055{
1056 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1057 int ret = 0;
1058
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001059 if (!count)
1060 return -EINVAL;
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001061
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001062 if ((!p_dev->suspended) && !strncmp(buf, "off", 3))
Alan Stern3f8df782007-07-12 16:57:22 -04001063 ret = runtime_suspend(dev);
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001064 else if (p_dev->suspended && !strncmp(buf, "on", 2))
Dominik Brodowski933a8382009-12-29 18:21:39 +01001065 ret = runtime_resume(dev);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001066
1067 return ret ? ret : count;
1068}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001069static DEVICE_ATTR_RW(pm_state);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001070
Dominik Brodowski37045112005-06-30 02:58:47 -07001071static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001072{
1073 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1074 int i;
1075 u32 hash[4] = { 0, 0, 0, 0};
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001076
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001077 /* calculate hashes */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001078 for (i = 0; i < 4; i++) {
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001079 if (!p_dev->prod_id[i])
1080 continue;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001081 hash[i] = crc32(0, p_dev->prod_id[i],
1082 strlen(p_dev->prod_id[i]));
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001083 }
1084 return sprintf(buf, "pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
1085 "pa%08Xpb%08Xpc%08Xpd%08X\n",
1086 p_dev->has_manf_id ? p_dev->manf_id : 0,
1087 p_dev->has_card_id ? p_dev->card_id : 0,
1088 p_dev->has_func_id ? p_dev->func_id : 0,
1089 p_dev->func, p_dev->device_no,
1090 hash[0], hash[1], hash[2], hash[3]);
1091}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001092static DEVICE_ATTR_RO(modalias);
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001093
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001094static ssize_t allow_func_id_match_store(struct device *dev,
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001095 struct device_attribute *attr, const char *buf, size_t count)
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001096{
1097 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001098
1099 if (!count)
1100 return -EINVAL;
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001101
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001102 mutex_lock(&p_dev->socket->ops_mutex);
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001103 p_dev->allow_func_id_match = 1;
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001104 mutex_unlock(&p_dev->socket->ops_mutex);
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +01001105 pcmcia_parse_uevents(p_dev->socket, PCMCIA_UEVENT_REQUERY);
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001106
1107 return count;
1108}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001109static DEVICE_ATTR_WO(allow_func_id_match);
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001110
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001111static struct attribute *pcmcia_dev_attrs[] = {
1112 &dev_attr_resources.attr,
1113 &dev_attr_pm_state.attr,
1114 &dev_attr_function.attr,
1115 &dev_attr_func_id.attr,
1116 &dev_attr_manf_id.attr,
1117 &dev_attr_card_id.attr,
1118 &dev_attr_prod_id1.attr,
1119 &dev_attr_prod_id2.attr,
1120 &dev_attr_prod_id3.attr,
1121 &dev_attr_prod_id4.attr,
1122 &dev_attr_modalias.attr,
1123 &dev_attr_allow_func_id_match.attr,
1124 NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125};
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001126ATTRIBUTE_GROUPS(pcmcia_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001128/* PM support, also needed for reset */
1129
Russell Kingad8d52b2016-08-31 08:49:43 +01001130static int pcmcia_dev_suspend(struct device *dev)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001131{
1132 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1133 struct pcmcia_driver *p_drv = NULL;
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001134 int ret = 0;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001135
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001136 mutex_lock(&p_dev->socket->ops_mutex);
1137 if (p_dev->suspended) {
1138 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001139 return 0;
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001140 }
1141 p_dev->suspended = 1;
1142 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001143
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001144 dev_dbg(dev, "suspending\n");
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001145
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001146 if (dev->driver)
1147 p_drv = to_pcmcia_drv(dev->driver);
1148
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001149 if (!p_drv)
1150 goto out;
1151
1152 if (p_drv->suspend) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +01001153 ret = p_drv->suspend(p_dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001154 if (ret) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001155 dev_err(dev,
1156 "pcmcia: device %s (driver %s) did not want to go to sleep (%d)\n",
1157 p_dev->devname, p_drv->name, ret);
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001158 mutex_lock(&p_dev->socket->ops_mutex);
1159 p_dev->suspended = 0;
1160 mutex_unlock(&p_dev->socket->ops_mutex);
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001161 goto out;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001162 }
Dominik Brodowski8661bb52006-03-02 00:02:33 +01001163 }
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001164
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001165 if (p_dev->device_no == p_dev->func) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001166 dev_dbg(dev, "releasing configuration\n");
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001167 pcmcia_release_configuration(p_dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001168 }
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001169
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001170 out:
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001171 return ret;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001172}
1173
1174
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001175static int pcmcia_dev_resume(struct device *dev)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001176{
1177 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001178 struct pcmcia_driver *p_drv = NULL;
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001179 int ret = 0;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001180
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001181 mutex_lock(&p_dev->socket->ops_mutex);
1182 if (!p_dev->suspended) {
1183 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001184 return 0;
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001185 }
1186 p_dev->suspended = 0;
1187 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001188
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001189 dev_dbg(dev, "resuming\n");
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001190
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001191 if (dev->driver)
1192 p_drv = to_pcmcia_drv(dev->driver);
1193
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001194 if (!p_drv)
1195 goto out;
1196
1197 if (p_dev->device_no == p_dev->func) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001198 dev_dbg(dev, "requesting configuration\n");
Dominik Brodowski1ac71e52010-07-29 19:27:09 +02001199 ret = pcmcia_enable_device(p_dev);
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001200 if (ret)
1201 goto out;
Dominik Brodowski8661bb52006-03-02 00:02:33 +01001202 }
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001203
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001204 if (p_drv->resume)
1205 ret = p_drv->resume(p_dev);
1206
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001207 out:
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001208 return ret;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001209}
1210
1211
Laurent Navet46f533c2013-01-21 22:16:05 +01001212static int pcmcia_bus_suspend_callback(struct device *dev, void *_data)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001213{
1214 struct pcmcia_socket *skt = _data;
1215 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1216
Alan Stern3f8df782007-07-12 16:57:22 -04001217 if (p_dev->socket != skt || p_dev->suspended)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001218 return 0;
1219
Alan Stern3f8df782007-07-12 16:57:22 -04001220 return runtime_suspend(dev);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001221}
1222
Laurent Navet46f533c2013-01-21 22:16:05 +01001223static int pcmcia_bus_resume_callback(struct device *dev, void *_data)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001224{
1225 struct pcmcia_socket *skt = _data;
1226 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1227
Alan Stern3f8df782007-07-12 16:57:22 -04001228 if (p_dev->socket != skt || !p_dev->suspended)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001229 return 0;
1230
Alan Stern3f8df782007-07-12 16:57:22 -04001231 runtime_resume(dev);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001232
1233 return 0;
1234}
1235
1236static int pcmcia_bus_resume(struct pcmcia_socket *skt)
1237{
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001238 dev_dbg(&skt->dev, "resuming socket %d\n", skt->sock);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001239 bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback);
1240 return 0;
1241}
1242
1243static int pcmcia_bus_suspend(struct pcmcia_socket *skt)
1244{
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001245 dev_dbg(&skt->dev, "suspending socket %d\n", skt->sock);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001246 if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt,
1247 pcmcia_bus_suspend_callback)) {
1248 pcmcia_bus_resume(skt);
1249 return -EIO;
1250 }
1251 return 0;
1252}
1253
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001254static int pcmcia_bus_remove(struct pcmcia_socket *skt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255{
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001256 atomic_set(&skt->present, 0);
1257 pcmcia_card_remove(skt, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001259 mutex_lock(&skt->ops_mutex);
1260 destroy_cis_cache(skt);
1261 pcmcia_cleanup_irq(skt);
1262 mutex_unlock(&skt->ops_mutex);
1263
1264 return 0;
1265}
1266
1267static int pcmcia_bus_add(struct pcmcia_socket *skt)
1268{
1269 atomic_set(&skt->present, 1);
1270
1271 mutex_lock(&skt->ops_mutex);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +02001272 skt->pcmcia_pfc = 0;
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001273 destroy_cis_cache(skt); /* to be on the safe side... */
1274 mutex_unlock(&skt->ops_mutex);
1275
1276 pcmcia_card_add(skt);
1277
1278 return 0;
1279}
1280
1281static int pcmcia_bus_early_resume(struct pcmcia_socket *skt)
1282{
Russell King025e4ab2012-02-08 17:13:41 -08001283 if (!verify_cis_cache(skt))
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001284 return 0;
Florin Malita16174062006-05-24 21:21:31 -04001285
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001286 dev_dbg(&skt->dev, "cis mismatch - different card\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001288 /* first, remove the card */
1289 pcmcia_bus_remove(skt);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +01001290
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001291 mutex_lock(&skt->ops_mutex);
1292 destroy_cis_cache(skt);
1293 kfree(skt->fake_cis);
1294 skt->fake_cis = NULL;
1295 skt->functions = 0;
1296 mutex_unlock(&skt->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001298 /* now, add the new card */
1299 pcmcia_bus_add(skt);
1300 return 0;
1301}
Dominik Brodowski88b060d2010-01-02 14:14:23 +01001302
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303
Dominik Brodowski04de0812010-04-20 14:49:01 +02001304/*
1305 * NOTE: This is racy. There's no guarantee the card will still be
1306 * physically present, even if the call to this function returns
1307 * non-NULL. Furthermore, the device driver most likely is unbound
1308 * almost immediately, so the timeframe where pcmcia_dev_present
1309 * returns NULL is probably really really small.
1310 */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001311struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev)
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001312{
1313 struct pcmcia_device *p_dev;
1314 struct pcmcia_device *ret = NULL;
1315
1316 p_dev = pcmcia_get_dev(_p_dev);
1317 if (!p_dev)
1318 return NULL;
1319
Dominik Brodowski04de0812010-04-20 14:49:01 +02001320 if (atomic_read(&p_dev->socket->present) != 0)
1321 ret = p_dev;
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001322
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001323 pcmcia_put_dev(p_dev);
1324 return ret;
1325}
1326EXPORT_SYMBOL(pcmcia_dev_present);
1327
1328
Dominik Brodowski90c6cdd2005-06-27 16:28:49 -07001329static struct pcmcia_callback pcmcia_bus_callback = {
1330 .owner = THIS_MODULE,
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001331 .add = pcmcia_bus_add,
1332 .remove = pcmcia_bus_remove,
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +01001333 .requery = pcmcia_requery,
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001334 .validate = pccard_validate_cis,
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001335 .suspend = pcmcia_bus_suspend,
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001336 .early_resume = pcmcia_bus_early_resume,
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001337 .resume = pcmcia_bus_resume,
Dominik Brodowski90c6cdd2005-06-27 16:28:49 -07001338};
1339
Bill Pemberton34cdf252012-11-19 13:23:12 -05001340static int pcmcia_bus_add_socket(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001341 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001343 struct pcmcia_socket *socket = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 int ret;
1345
Dominik Brodowskidc109492005-06-27 16:28:50 -07001346 socket = pcmcia_get_socket(socket);
1347 if (!socket) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001348 dev_err(dev, "PCMCIA obtaining reference to socket failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 return -ENODEV;
1350 }
1351
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001352 ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
1353 if (ret) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001354 dev_err(dev, "PCMCIA registration failed\n");
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001355 pcmcia_put_socket(socket);
1356 return ret;
1357 }
1358
Dominik Brodowskidc109492005-06-27 16:28:50 -07001359 INIT_LIST_HEAD(&socket->devices_list);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +02001360 socket->pcmcia_pfc = 0;
Dominik Brodowskidc109492005-06-27 16:28:50 -07001361 socket->device_count = 0;
Dominik Brodowskie4f1ac22010-06-19 14:33:56 +02001362 atomic_set(&socket->present, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
Dominik Brodowski90c6cdd2005-06-27 16:28:49 -07001364 ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 if (ret) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001366 dev_err(dev, "PCMCIA registration failed\n");
Dominik Brodowskidc109492005-06-27 16:28:50 -07001367 pcmcia_put_socket(socket);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001368 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 }
1370
1371 return 0;
1372}
1373
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001374static void pcmcia_bus_remove_socket(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001375 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001377 struct pcmcia_socket *socket = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
Dominik Brodowskidc109492005-06-27 16:28:50 -07001379 if (!socket)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 return;
1381
1382 pccard_register_pcmcia(socket, NULL);
1383
Daniel Ritzdfbc9e92006-11-18 22:19:34 -08001384 /* unregister any unbound devices */
Daniel Ritz8e4d9dc2006-11-25 11:09:17 -08001385 mutex_lock(&socket->skt_mutex);
Daniel Ritzdfbc9e92006-11-18 22:19:34 -08001386 pcmcia_card_remove(socket, NULL);
Dominik Brodowski180c33e2010-01-02 17:34:09 +01001387 release_cis_mem(socket);
Daniel Ritz8e4d9dc2006-11-25 11:09:17 -08001388 mutex_unlock(&socket->skt_mutex);
Daniel Ritzdfbc9e92006-11-18 22:19:34 -08001389
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001390 sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr);
1391
Dominik Brodowskidc109492005-06-27 16:28:50 -07001392 pcmcia_put_socket(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
1394 return;
1395}
1396
1397
1398/* the pcmcia_bus_interface is used to handle pcmcia socket devices */
Sam Ravnborged49f5d2008-05-01 04:34:50 -07001399static struct class_interface pcmcia_bus_interface __refdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 .class = &pcmcia_socket_class,
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001401 .add_dev = &pcmcia_bus_add_socket,
1402 .remove_dev = &pcmcia_bus_remove_socket,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403};
1404
Russell Kingad8d52b2016-08-31 08:49:43 +01001405static const struct dev_pm_ops pcmcia_bus_pm_ops = {
1406 SET_SYSTEM_SLEEP_PM_OPS(pcmcia_dev_suspend, pcmcia_dev_resume)
1407};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001409struct bus_type pcmcia_bus_type = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 .name = "pcmcia",
Kay Sievers312c0042005-11-16 09:00:00 +01001411 .uevent = pcmcia_bus_uevent,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 .match = pcmcia_bus_match,
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001413 .dev_groups = pcmcia_dev_groups,
Russell King1d0baa32006-01-05 14:40:58 +00001414 .probe = pcmcia_device_probe,
1415 .remove = pcmcia_device_remove,
Russell Kingad8d52b2016-08-31 08:49:43 +01001416 .pm = &pcmcia_bus_pm_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418
1419
1420static int __init init_pcmcia_bus(void)
1421{
Randy Dunlapace7d472006-10-20 14:44:12 -07001422 int ret;
1423
Randy Dunlapace7d472006-10-20 14:44:12 -07001424 ret = bus_register(&pcmcia_bus_type);
1425 if (ret < 0) {
1426 printk(KERN_WARNING "pcmcia: bus_register error: %d\n", ret);
1427 return ret;
1428 }
1429 ret = class_interface_register(&pcmcia_bus_interface);
1430 if (ret < 0) {
1431 printk(KERN_WARNING
1432 "pcmcia: class_interface_register error: %d\n", ret);
1433 bus_unregister(&pcmcia_bus_type);
1434 return ret;
1435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 return 0;
1438}
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001439fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 * pcmcia_socket_class is already registered */
1441
1442
1443static void __exit exit_pcmcia_bus(void)
1444{
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001445 class_interface_unregister(&pcmcia_bus_interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446
1447 bus_unregister(&pcmcia_bus_type);
1448}
1449module_exit(exit_pcmcia_bus);
1450
1451
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452MODULE_ALIAS("ds");