blob: ace133b9f7d45d7f695d9f727c74d639d6723392 [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 Brodowski78e01852021-10-15 09:13:23 +02001001 return p_dev->test ? sysfs_emit(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 Brodowski78e01852021-10-15 09:13:23 +02001009 return p_dev->field ? sysfs_emit(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);
Dominik Brodowski78e01852021-10-15 09:13:23 +02001025 return p_dev->socket ? sysfs_emit(buf, "0x%02x\n", p_dev->func) : -ENODEV;
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001026}
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);
Dominik Brodowski78e01852021-10-15 09:13:23 +02001033 int i, at = 0;
Dominik Brodowski8f677ea2010-07-25 11:10:29 +02001034
1035 for (i = 0; i < PCMCIA_NUM_RESOURCES; i++)
Dominik Brodowski78e01852021-10-15 09:13:23 +02001036 at += sysfs_emit_at(buf, at, "%pr\n", p_dev->resource[i]);
Dominik Brodowski8f677ea2010-07-25 11:10:29 +02001037
Dominik Brodowski78e01852021-10-15 09:13:23 +02001038 return at;
Dominik Brodowski8f677ea2010-07-25 11:10:29 +02001039}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001040static DEVICE_ATTR_RO(resources);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001041
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001042static ssize_t pm_state_show(struct device *dev, struct device_attribute *attr, char *buf)
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001043{
1044 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1045
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001046 if (p_dev->suspended)
Dominik Brodowski78e01852021-10-15 09:13:23 +02001047 return sysfs_emit(buf, "off\n");
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001048 else
Dominik Brodowski78e01852021-10-15 09:13:23 +02001049 return sysfs_emit(buf, "on\n");
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001050}
1051
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001052static ssize_t pm_state_store(struct device *dev, struct device_attribute *attr,
1053 const char *buf, size_t count)
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001054{
1055 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1056 int ret = 0;
1057
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001058 if (!count)
1059 return -EINVAL;
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001060
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001061 if ((!p_dev->suspended) && !strncmp(buf, "off", 3))
Alan Stern3f8df782007-07-12 16:57:22 -04001062 ret = runtime_suspend(dev);
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001063 else if (p_dev->suspended && !strncmp(buf, "on", 2))
Dominik Brodowski933a8382009-12-29 18:21:39 +01001064 ret = runtime_resume(dev);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001065
1066 return ret ? ret : count;
1067}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001068static DEVICE_ATTR_RW(pm_state);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001069
Dominik Brodowski37045112005-06-30 02:58:47 -07001070static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001071{
1072 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1073 int i;
1074 u32 hash[4] = { 0, 0, 0, 0};
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001075
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001076 /* calculate hashes */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001077 for (i = 0; i < 4; i++) {
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001078 if (!p_dev->prod_id[i])
1079 continue;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001080 hash[i] = crc32(0, p_dev->prod_id[i],
1081 strlen(p_dev->prod_id[i]));
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001082 }
Dominik Brodowski78e01852021-10-15 09:13:23 +02001083 return sysfs_emit(buf, "pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02Xpa%08Xpb%08Xpc%08Xpd%08X\n",
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001084 p_dev->has_manf_id ? p_dev->manf_id : 0,
1085 p_dev->has_card_id ? p_dev->card_id : 0,
1086 p_dev->has_func_id ? p_dev->func_id : 0,
1087 p_dev->func, p_dev->device_no,
1088 hash[0], hash[1], hash[2], hash[3]);
1089}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001090static DEVICE_ATTR_RO(modalias);
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001091
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001092static ssize_t allow_func_id_match_store(struct device *dev,
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001093 struct device_attribute *attr, const char *buf, size_t count)
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001094{
1095 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001096
1097 if (!count)
1098 return -EINVAL;
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001099
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001100 mutex_lock(&p_dev->socket->ops_mutex);
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001101 p_dev->allow_func_id_match = 1;
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001102 mutex_unlock(&p_dev->socket->ops_mutex);
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +01001103 pcmcia_parse_uevents(p_dev->socket, PCMCIA_UEVENT_REQUERY);
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001104
1105 return count;
1106}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001107static DEVICE_ATTR_WO(allow_func_id_match);
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001108
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001109static struct attribute *pcmcia_dev_attrs[] = {
1110 &dev_attr_resources.attr,
1111 &dev_attr_pm_state.attr,
1112 &dev_attr_function.attr,
1113 &dev_attr_func_id.attr,
1114 &dev_attr_manf_id.attr,
1115 &dev_attr_card_id.attr,
1116 &dev_attr_prod_id1.attr,
1117 &dev_attr_prod_id2.attr,
1118 &dev_attr_prod_id3.attr,
1119 &dev_attr_prod_id4.attr,
1120 &dev_attr_modalias.attr,
1121 &dev_attr_allow_func_id_match.attr,
1122 NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123};
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001124ATTRIBUTE_GROUPS(pcmcia_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001126/* PM support, also needed for reset */
1127
Russell Kingad8d52b2016-08-31 08:49:43 +01001128static int pcmcia_dev_suspend(struct device *dev)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001129{
1130 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1131 struct pcmcia_driver *p_drv = NULL;
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001132 int ret = 0;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001133
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001134 mutex_lock(&p_dev->socket->ops_mutex);
1135 if (p_dev->suspended) {
1136 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001137 return 0;
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001138 }
1139 p_dev->suspended = 1;
1140 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001141
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001142 dev_dbg(dev, "suspending\n");
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001143
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001144 if (dev->driver)
1145 p_drv = to_pcmcia_drv(dev->driver);
1146
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001147 if (!p_drv)
1148 goto out;
1149
1150 if (p_drv->suspend) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +01001151 ret = p_drv->suspend(p_dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001152 if (ret) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001153 dev_err(dev,
1154 "pcmcia: device %s (driver %s) did not want to go to sleep (%d)\n",
1155 p_dev->devname, p_drv->name, ret);
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001156 mutex_lock(&p_dev->socket->ops_mutex);
1157 p_dev->suspended = 0;
1158 mutex_unlock(&p_dev->socket->ops_mutex);
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001159 goto out;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001160 }
Dominik Brodowski8661bb52006-03-02 00:02:33 +01001161 }
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001162
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001163 if (p_dev->device_no == p_dev->func) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001164 dev_dbg(dev, "releasing configuration\n");
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001165 pcmcia_release_configuration(p_dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001166 }
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001167
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001168 out:
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001169 return ret;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001170}
1171
1172
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001173static int pcmcia_dev_resume(struct device *dev)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001174{
1175 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001176 struct pcmcia_driver *p_drv = NULL;
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001177 int ret = 0;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001178
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001179 mutex_lock(&p_dev->socket->ops_mutex);
1180 if (!p_dev->suspended) {
1181 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001182 return 0;
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001183 }
1184 p_dev->suspended = 0;
1185 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001186
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001187 dev_dbg(dev, "resuming\n");
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001188
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001189 if (dev->driver)
1190 p_drv = to_pcmcia_drv(dev->driver);
1191
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001192 if (!p_drv)
1193 goto out;
1194
1195 if (p_dev->device_no == p_dev->func) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001196 dev_dbg(dev, "requesting configuration\n");
Dominik Brodowski1ac71e52010-07-29 19:27:09 +02001197 ret = pcmcia_enable_device(p_dev);
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001198 if (ret)
1199 goto out;
Dominik Brodowski8661bb52006-03-02 00:02:33 +01001200 }
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001201
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001202 if (p_drv->resume)
1203 ret = p_drv->resume(p_dev);
1204
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001205 out:
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001206 return ret;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001207}
1208
1209
Laurent Navet46f533c2013-01-21 22:16:05 +01001210static int pcmcia_bus_suspend_callback(struct device *dev, void *_data)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001211{
1212 struct pcmcia_socket *skt = _data;
1213 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1214
Alan Stern3f8df782007-07-12 16:57:22 -04001215 if (p_dev->socket != skt || p_dev->suspended)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001216 return 0;
1217
Alan Stern3f8df782007-07-12 16:57:22 -04001218 return runtime_suspend(dev);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001219}
1220
Laurent Navet46f533c2013-01-21 22:16:05 +01001221static int pcmcia_bus_resume_callback(struct device *dev, void *_data)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001222{
1223 struct pcmcia_socket *skt = _data;
1224 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1225
Alan Stern3f8df782007-07-12 16:57:22 -04001226 if (p_dev->socket != skt || !p_dev->suspended)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001227 return 0;
1228
Alan Stern3f8df782007-07-12 16:57:22 -04001229 runtime_resume(dev);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001230
1231 return 0;
1232}
1233
1234static int pcmcia_bus_resume(struct pcmcia_socket *skt)
1235{
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001236 dev_dbg(&skt->dev, "resuming socket %d\n", skt->sock);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001237 bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback);
1238 return 0;
1239}
1240
1241static int pcmcia_bus_suspend(struct pcmcia_socket *skt)
1242{
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001243 dev_dbg(&skt->dev, "suspending socket %d\n", skt->sock);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001244 if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt,
1245 pcmcia_bus_suspend_callback)) {
1246 pcmcia_bus_resume(skt);
1247 return -EIO;
1248 }
1249 return 0;
1250}
1251
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001252static int pcmcia_bus_remove(struct pcmcia_socket *skt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253{
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001254 atomic_set(&skt->present, 0);
1255 pcmcia_card_remove(skt, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001257 mutex_lock(&skt->ops_mutex);
1258 destroy_cis_cache(skt);
1259 pcmcia_cleanup_irq(skt);
1260 mutex_unlock(&skt->ops_mutex);
1261
1262 return 0;
1263}
1264
1265static int pcmcia_bus_add(struct pcmcia_socket *skt)
1266{
1267 atomic_set(&skt->present, 1);
1268
1269 mutex_lock(&skt->ops_mutex);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +02001270 skt->pcmcia_pfc = 0;
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001271 destroy_cis_cache(skt); /* to be on the safe side... */
1272 mutex_unlock(&skt->ops_mutex);
1273
1274 pcmcia_card_add(skt);
1275
1276 return 0;
1277}
1278
1279static int pcmcia_bus_early_resume(struct pcmcia_socket *skt)
1280{
Russell King025e4ab2012-02-08 17:13:41 -08001281 if (!verify_cis_cache(skt))
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001282 return 0;
Florin Malita16174062006-05-24 21:21:31 -04001283
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001284 dev_dbg(&skt->dev, "cis mismatch - different card\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001286 /* first, remove the card */
1287 pcmcia_bus_remove(skt);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +01001288
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001289 mutex_lock(&skt->ops_mutex);
1290 destroy_cis_cache(skt);
1291 kfree(skt->fake_cis);
1292 skt->fake_cis = NULL;
1293 skt->functions = 0;
1294 mutex_unlock(&skt->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001296 /* now, add the new card */
1297 pcmcia_bus_add(skt);
1298 return 0;
1299}
Dominik Brodowski88b060d2010-01-02 14:14:23 +01001300
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
Dominik Brodowski04de0812010-04-20 14:49:01 +02001302/*
1303 * NOTE: This is racy. There's no guarantee the card will still be
1304 * physically present, even if the call to this function returns
1305 * non-NULL. Furthermore, the device driver most likely is unbound
1306 * almost immediately, so the timeframe where pcmcia_dev_present
1307 * returns NULL is probably really really small.
1308 */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001309struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev)
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001310{
1311 struct pcmcia_device *p_dev;
1312 struct pcmcia_device *ret = NULL;
1313
1314 p_dev = pcmcia_get_dev(_p_dev);
1315 if (!p_dev)
1316 return NULL;
1317
Dominik Brodowski04de0812010-04-20 14:49:01 +02001318 if (atomic_read(&p_dev->socket->present) != 0)
1319 ret = p_dev;
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001320
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001321 pcmcia_put_dev(p_dev);
1322 return ret;
1323}
1324EXPORT_SYMBOL(pcmcia_dev_present);
1325
1326
Dominik Brodowski90c6cdd2005-06-27 16:28:49 -07001327static struct pcmcia_callback pcmcia_bus_callback = {
1328 .owner = THIS_MODULE,
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001329 .add = pcmcia_bus_add,
1330 .remove = pcmcia_bus_remove,
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +01001331 .requery = pcmcia_requery,
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001332 .validate = pccard_validate_cis,
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001333 .suspend = pcmcia_bus_suspend,
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001334 .early_resume = pcmcia_bus_early_resume,
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001335 .resume = pcmcia_bus_resume,
Dominik Brodowski90c6cdd2005-06-27 16:28:49 -07001336};
1337
Bill Pemberton34cdf252012-11-19 13:23:12 -05001338static int pcmcia_bus_add_socket(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001339 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001341 struct pcmcia_socket *socket = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 int ret;
1343
Dominik Brodowskidc109492005-06-27 16:28:50 -07001344 socket = pcmcia_get_socket(socket);
1345 if (!socket) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001346 dev_err(dev, "PCMCIA obtaining reference to socket failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 return -ENODEV;
1348 }
1349
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001350 ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
1351 if (ret) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001352 dev_err(dev, "PCMCIA registration failed\n");
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001353 pcmcia_put_socket(socket);
1354 return ret;
1355 }
1356
Dominik Brodowskidc109492005-06-27 16:28:50 -07001357 INIT_LIST_HEAD(&socket->devices_list);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +02001358 socket->pcmcia_pfc = 0;
Dominik Brodowskidc109492005-06-27 16:28:50 -07001359 socket->device_count = 0;
Dominik Brodowskie4f1ac22010-06-19 14:33:56 +02001360 atomic_set(&socket->present, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361
Dominik Brodowski90c6cdd2005-06-27 16:28:49 -07001362 ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 if (ret) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001364 dev_err(dev, "PCMCIA registration failed\n");
Dominik Brodowskidc109492005-06-27 16:28:50 -07001365 pcmcia_put_socket(socket);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001366 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 }
1368
1369 return 0;
1370}
1371
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001372static void pcmcia_bus_remove_socket(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001373 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001375 struct pcmcia_socket *socket = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376
Dominik Brodowskidc109492005-06-27 16:28:50 -07001377 if (!socket)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 return;
1379
1380 pccard_register_pcmcia(socket, NULL);
1381
Daniel Ritzdfbc9e92006-11-18 22:19:34 -08001382 /* unregister any unbound devices */
Daniel Ritz8e4d9dc2006-11-25 11:09:17 -08001383 mutex_lock(&socket->skt_mutex);
Daniel Ritzdfbc9e92006-11-18 22:19:34 -08001384 pcmcia_card_remove(socket, NULL);
Dominik Brodowski180c33e2010-01-02 17:34:09 +01001385 release_cis_mem(socket);
Daniel Ritz8e4d9dc2006-11-25 11:09:17 -08001386 mutex_unlock(&socket->skt_mutex);
Daniel Ritzdfbc9e92006-11-18 22:19:34 -08001387
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001388 sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr);
1389
Dominik Brodowskidc109492005-06-27 16:28:50 -07001390 pcmcia_put_socket(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391
1392 return;
1393}
1394
1395
1396/* the pcmcia_bus_interface is used to handle pcmcia socket devices */
Sam Ravnborged49f5d2008-05-01 04:34:50 -07001397static struct class_interface pcmcia_bus_interface __refdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 .class = &pcmcia_socket_class,
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001399 .add_dev = &pcmcia_bus_add_socket,
1400 .remove_dev = &pcmcia_bus_remove_socket,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401};
1402
Russell Kingad8d52b2016-08-31 08:49:43 +01001403static const struct dev_pm_ops pcmcia_bus_pm_ops = {
1404 SET_SYSTEM_SLEEP_PM_OPS(pcmcia_dev_suspend, pcmcia_dev_resume)
1405};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001407struct bus_type pcmcia_bus_type = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 .name = "pcmcia",
Kay Sievers312c0042005-11-16 09:00:00 +01001409 .uevent = pcmcia_bus_uevent,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 .match = pcmcia_bus_match,
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001411 .dev_groups = pcmcia_dev_groups,
Russell King1d0baa32006-01-05 14:40:58 +00001412 .probe = pcmcia_device_probe,
1413 .remove = pcmcia_device_remove,
Russell Kingad8d52b2016-08-31 08:49:43 +01001414 .pm = &pcmcia_bus_pm_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
1417
1418static int __init init_pcmcia_bus(void)
1419{
Randy Dunlapace7d472006-10-20 14:44:12 -07001420 int ret;
1421
Randy Dunlapace7d472006-10-20 14:44:12 -07001422 ret = bus_register(&pcmcia_bus_type);
1423 if (ret < 0) {
1424 printk(KERN_WARNING "pcmcia: bus_register error: %d\n", ret);
1425 return ret;
1426 }
1427 ret = class_interface_register(&pcmcia_bus_interface);
1428 if (ret < 0) {
1429 printk(KERN_WARNING
1430 "pcmcia: class_interface_register error: %d\n", ret);
1431 bus_unregister(&pcmcia_bus_type);
1432 return ret;
1433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 return 0;
1436}
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001437fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 * pcmcia_socket_class is already registered */
1439
1440
1441static void __exit exit_pcmcia_bus(void)
1442{
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001443 class_interface_unregister(&pcmcia_bus_interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
1445 bus_unregister(&pcmcia_bus_type);
1446}
1447module_exit(exit_pcmcia_bus);
1448
1449
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450MODULE_ALIAS("ds");