blob: 69b5e811ea2b2c2c02a902434063196f31425892 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ds.c -- 16-bit PCMCIA core support
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * The initial developer of the original code is David A. Hinds
9 * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
10 * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
11 *
12 * (C) 1999 David A. Hinds
Dominik Brodowski7b24e792010-07-11 10:26:53 +020013 * (C) 2003 - 2010 Dominik Brodowski
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 */
15
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/kernel.h>
Dominik Brodowski3b659fb2005-06-27 16:28:51 -070017#include <linux/module.h>
18#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/errno.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <linux/list.h>
21#include <linux/delay.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/workqueue.h>
Dominik Brodowski840c2ac2005-06-27 16:28:04 -070023#include <linux/crc32.h>
Dominik Brodowskidaa95172005-06-27 16:28:14 -070024#include <linux/firmware.h>
Dominik Brodowski360b65b2006-01-10 20:50:39 +010025#include <linux/kref.h>
James Bottomley43d9f7f2007-10-16 01:23:58 -070026#include <linux/dma-mapping.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090027#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <pcmcia/cistpl.h>
30#include <pcmcia/ds.h>
31#include <pcmcia/ss.h>
32
33#include "cs_internal.h"
34
35/*====================================================================*/
36
37/* Module parameters */
38
39MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
40MODULE_DESCRIPTION("PCMCIA Driver Services");
41MODULE_LICENSE("GPL");
42
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
Linus Torvalds1da177e2005-04-16 15:20:36 -070044/*====================================================================*/
45
Dominik Brodowski23a83bf2005-06-27 16:28:07 -070046static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
47{
Joe Perchese9fb13b2011-05-03 19:29:00 -070048 const struct pcmcia_device_id *did = p_drv->id_table;
Dominik Brodowski23a83bf2005-06-27 16:28:07 -070049 unsigned int i;
50 u32 hash;
51
Dominik Brodowskif8cfa612005-11-14 21:25:51 +010052 if (!p_drv->probe || !p_drv->remove)
Pavel Roskinba5bb6b2005-07-28 01:07:20 -070053 printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback "
Dominik Brodowski2e9b9812010-08-08 11:36:26 +020054 "function\n", p_drv->name);
Dominik Brodowski1e212f32005-07-07 17:59:00 -070055
Dominik Brodowski23a83bf2005-06-27 16:28:07 -070056 while (did && did->match_flags) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +010057 for (i = 0; i < 4; i++) {
Dominik Brodowski23a83bf2005-06-27 16:28:07 -070058 if (!did->prod_id[i])
59 continue;
60
61 hash = crc32(0, did->prod_id[i], strlen(did->prod_id[i]));
62 if (hash == did->prod_id_hash[i])
63 continue;
64
65 printk(KERN_DEBUG "pcmcia: %s: invalid hash for "
66 "product string \"%s\": is 0x%x, should "
Dominik Brodowski2e9b9812010-08-08 11:36:26 +020067 "be 0x%x\n", p_drv->name, did->prod_id[i],
Dominik Brodowski23a83bf2005-06-27 16:28:07 -070068 did->prod_id_hash[i], hash);
Dominik Brodowski5085cb22005-06-27 16:28:45 -070069 printk(KERN_DEBUG "pcmcia: see "
70 "Documentation/pcmcia/devicetable.txt for "
71 "details\n");
Dominik Brodowski23a83bf2005-06-27 16:28:07 -070072 }
73 did++;
74 }
75
76 return;
77}
78
Dominik Brodowskidaa95172005-06-27 16:28:14 -070079
Linus Torvalds1da177e2005-04-16 15:20:36 -070080/*======================================================================*/
81
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
Bernhard Walle6179b552007-05-06 14:48:44 -070083struct pcmcia_dynid {
Laurent Navet46f533c2013-01-21 22:16:05 +010084 struct list_head node;
85 struct pcmcia_device_id id;
Bernhard Walle6179b552007-05-06 14:48:44 -070086};
87
88/**
89 * pcmcia_store_new_id - add a new PCMCIA device ID to this driver and re-probe devices
90 * @driver: target device driver
91 * @buf: buffer for scanning device ID data
92 * @count: input size
93 *
94 * Adds a new dynamic PCMCIA device ID to this driver,
95 * and causes the driver to probe for all devices again.
96 */
97static ssize_t
98pcmcia_store_new_id(struct device_driver *driver, const char *buf, size_t count)
99{
100 struct pcmcia_dynid *dynid;
101 struct pcmcia_driver *pdrv = to_pcmcia_drv(driver);
102 __u16 match_flags, manf_id, card_id;
103 __u8 func_id, function, device_no;
104 __u32 prod_id_hash[4] = {0, 0, 0, 0};
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100105 int fields = 0;
Bernhard Walle6179b552007-05-06 14:48:44 -0700106 int retval = 0;
107
108 fields = sscanf(buf, "%hx %hx %hx %hhx %hhx %hhx %x %x %x %x",
109 &match_flags, &manf_id, &card_id, &func_id, &function, &device_no,
110 &prod_id_hash[0], &prod_id_hash[1], &prod_id_hash[2], &prod_id_hash[3]);
111 if (fields < 6)
112 return -EINVAL;
113
114 dynid = kzalloc(sizeof(struct pcmcia_dynid), GFP_KERNEL);
115 if (!dynid)
116 return -ENOMEM;
117
Bernhard Walle6179b552007-05-06 14:48:44 -0700118 dynid->id.match_flags = match_flags;
119 dynid->id.manf_id = manf_id;
120 dynid->id.card_id = card_id;
121 dynid->id.func_id = func_id;
122 dynid->id.function = function;
123 dynid->id.device_no = device_no;
124 memcpy(dynid->id.prod_id_hash, prod_id_hash, sizeof(__u32) * 4);
125
Dominik Brodowski3f565232010-01-16 13:06:40 +0100126 mutex_lock(&pdrv->dynids.lock);
Wolfram Sangb4b3d7b2009-07-20 10:58:59 +0200127 list_add_tail(&dynid->node, &pdrv->dynids.list);
Dominik Brodowski3f565232010-01-16 13:06:40 +0100128 mutex_unlock(&pdrv->dynids.lock);
Bernhard Walle6179b552007-05-06 14:48:44 -0700129
Alan Sterncef9bc52012-01-24 13:34:41 -0500130 retval = driver_attach(&pdrv->drv);
Bernhard Walle6179b552007-05-06 14:48:44 -0700131
132 if (retval)
133 return retval;
134 return count;
135}
136static DRIVER_ATTR(new_id, S_IWUSR, NULL, pcmcia_store_new_id);
137
138static void
139pcmcia_free_dynids(struct pcmcia_driver *drv)
140{
141 struct pcmcia_dynid *dynid, *n;
142
Dominik Brodowski3f565232010-01-16 13:06:40 +0100143 mutex_lock(&drv->dynids.lock);
Bernhard Walle6179b552007-05-06 14:48:44 -0700144 list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
145 list_del(&dynid->node);
146 kfree(dynid);
147 }
Dominik Brodowski3f565232010-01-16 13:06:40 +0100148 mutex_unlock(&drv->dynids.lock);
Bernhard Walle6179b552007-05-06 14:48:44 -0700149}
150
151static int
152pcmcia_create_newid_file(struct pcmcia_driver *drv)
153{
154 int error = 0;
155 if (drv->probe != NULL)
Greg Kroah-Hartman2344c6d2007-11-28 12:23:18 -0800156 error = driver_create_file(&drv->drv, &driver_attr_new_id);
Bernhard Walle6179b552007-05-06 14:48:44 -0700157 return error;
158}
159
Alan Sterned283e92012-01-24 14:35:13 -0500160static void
161pcmcia_remove_newid_file(struct pcmcia_driver *drv)
162{
163 driver_remove_file(&drv->drv, &driver_attr_new_id);
164}
Bernhard Walle6179b552007-05-06 14:48:44 -0700165
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166/**
167 * pcmcia_register_driver - register a PCMCIA driver with the bus core
Randy Dunlap78187862007-12-10 15:49:22 -0800168 * @driver: the &driver being registered
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 *
170 * Registers a PCMCIA driver with the PCMCIA bus core.
171 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172int pcmcia_register_driver(struct pcmcia_driver *driver)
173{
Bernhard Walle6179b552007-05-06 14:48:44 -0700174 int error;
175
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 if (!driver)
177 return -EINVAL;
178
Dominik Brodowski23a83bf2005-06-27 16:28:07 -0700179 pcmcia_check_driver(driver);
180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 /* initialize common fields */
182 driver->drv.bus = &pcmcia_bus_type;
183 driver->drv.owner = driver->owner;
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200184 driver->drv.name = driver->name;
Dominik Brodowski3f565232010-01-16 13:06:40 +0100185 mutex_init(&driver->dynids.lock);
Bernhard Walle6179b552007-05-06 14:48:44 -0700186 INIT_LIST_HEAD(&driver->dynids.list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200188 pr_debug("registering driver %s\n", driver->name);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200189
Bernhard Walle6179b552007-05-06 14:48:44 -0700190 error = driver_register(&driver->drv);
191 if (error < 0)
192 return error;
193
194 error = pcmcia_create_newid_file(driver);
195 if (error)
196 driver_unregister(&driver->drv);
197
198 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199}
200EXPORT_SYMBOL(pcmcia_register_driver);
201
202/**
203 * pcmcia_unregister_driver - unregister a PCMCIA driver with the bus core
Randy Dunlap78187862007-12-10 15:49:22 -0800204 * @driver: the &driver being unregistered
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 */
206void pcmcia_unregister_driver(struct pcmcia_driver *driver)
207{
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200208 pr_debug("unregistering driver %s\n", driver->name);
Alan Sterned283e92012-01-24 14:35:13 -0500209 pcmcia_remove_newid_file(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 driver_unregister(&driver->drv);
Bernhard Walle6179b552007-05-06 14:48:44 -0700211 pcmcia_free_dynids(driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212}
213EXPORT_SYMBOL(pcmcia_unregister_driver);
214
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216/* pcmcia_device handling */
217
Dominik Brodowski5716d412010-07-11 09:51:14 +0200218static struct pcmcia_device *pcmcia_get_dev(struct pcmcia_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219{
220 struct device *tmp_dev;
221 tmp_dev = get_device(&p_dev->dev);
222 if (!tmp_dev)
223 return NULL;
224 return to_pcmcia_dev(tmp_dev);
225}
226
Dominik Brodowski5716d412010-07-11 09:51:14 +0200227static void pcmcia_put_dev(struct pcmcia_device *p_dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228{
229 if (p_dev)
230 put_device(&p_dev->dev);
231}
232
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100233static void pcmcia_release_function(struct kref *ref)
234{
235 struct config_t *c = container_of(ref, struct config_t, ref);
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200236 pr_debug("releasing config_t\n");
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100237 kfree(c);
238}
239
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240static void pcmcia_release_dev(struct device *dev)
241{
242 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
Dominik Brodowski44961a02010-01-24 12:11:02 +0100243 int i;
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200244 dev_dbg(dev, "releasing device\n");
Dominik Brodowskidc109492005-06-27 16:28:50 -0700245 pcmcia_put_socket(p_dev->socket);
Dominik Brodowski44961a02010-01-24 12:11:02 +0100246 for (i = 0; i < 4; i++)
247 kfree(p_dev->prod_id[i]);
Brice Goglinbd65a682005-09-09 13:03:29 -0700248 kfree(p_dev->devname);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100249 kref_put(&p_dev->function_config->ref, pcmcia_release_function);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 kfree(p_dev);
251}
252
253
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100254static int pcmcia_device_probe(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255{
256 struct pcmcia_device *p_dev;
257 struct pcmcia_driver *p_drv;
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100258 struct pcmcia_socket *s;
Dominik Brodowskiaf2b3b52006-10-25 21:49:27 -0400259 cistpl_config_t cis_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 int ret = 0;
261
262 dev = get_device(dev);
263 if (!dev)
264 return -ENODEV;
265
266 p_dev = to_pcmcia_dev(dev);
267 p_drv = to_pcmcia_drv(dev->driver);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100268 s = p_dev->socket;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200270 dev_dbg(dev, "trying to bind to %s\n", p_drv->name);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200271
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100272 if ((!p_drv->probe) || (!p_dev->function_config) ||
273 (!try_module_get(p_drv->owner))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 ret = -EINVAL;
275 goto put_dev;
276 }
277
Dominik Brodowskiaf2b3b52006-10-25 21:49:27 -0400278 /* set up some more device information */
279 ret = pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_CONFIG,
280 &cis_config);
281 if (!ret) {
Dominik Brodowski7feabb62010-07-29 18:35:47 +0200282 p_dev->config_base = cis_config.base;
283 p_dev->config_regs = cis_config.rmask[0];
Dominik Brodowski1cc745d2010-08-01 11:21:14 +0200284 dev_dbg(dev, "base %x, regs %x", p_dev->config_base,
285 p_dev->config_regs);
Dominik Brodowskiaf2b3b52006-10-25 21:49:27 -0400286 } else {
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700287 dev_info(dev,
288 "pcmcia: could not parse base and rmask0 of CIS\n");
Dominik Brodowski7feabb62010-07-29 18:35:47 +0200289 p_dev->config_base = 0;
290 p_dev->config_regs = 0;
Dominik Brodowskiaf2b3b52006-10-25 21:49:27 -0400291 }
292
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100293 ret = p_drv->probe(p_dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200294 if (ret) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200295 dev_dbg(dev, "binding to %s failed with %d\n",
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200296 p_drv->name, ret);
Dominik Brodowski82d56e62006-01-27 19:15:02 +0100297 goto put_module;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200298 }
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200299 dev_dbg(dev, "%s bound: Vpp %d.%d, idx %x, IRQ %d", p_drv->name,
Dominik Brodowski1cc745d2010-08-01 11:21:14 +0200300 p_dev->vpp/10, p_dev->vpp%10, p_dev->config_index, p_dev->irq);
301 dev_dbg(dev, "resources: ioport %pR %pR iomem %pR %pR %pR",
302 p_dev->resource[0], p_dev->resource[1], p_dev->resource[2],
303 p_dev->resource[3], p_dev->resource[4]);
Dominik Brodowski82d56e62006-01-27 19:15:02 +0100304
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100305 mutex_lock(&s->ops_mutex);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +0200306 if ((s->pcmcia_pfc) &&
Dominik Brodowski82d56e62006-01-27 19:15:02 +0100307 (p_dev->socket->device_count == 1) && (p_dev->device_no == 0))
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100308 pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100309 mutex_unlock(&s->ops_mutex);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100310
Alan Coxcec5eb72008-09-22 15:58:14 +0100311put_module:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 if (ret)
313 module_put(p_drv->owner);
Alan Coxcec5eb72008-09-22 15:58:14 +0100314put_dev:
Dominik Brodowskif8cfa612005-11-14 21:25:51 +0100315 if (ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 put_device(dev);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100317 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318}
319
320
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100321/*
322 * Removes a PCMCIA card from the device tree and socket list.
323 */
324static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *leftover)
325{
326 struct pcmcia_device *p_dev;
327 struct pcmcia_device *tmp;
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100328
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200329 dev_dbg(leftover ? &leftover->dev : &s->dev,
Dominik Brodowskiac449d62008-08-02 18:33:56 +0200330 "pcmcia_card_remove(%d) %s\n", s->sock,
331 leftover ? leftover->devname : "");
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100332
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100333 mutex_lock(&s->ops_mutex);
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100334 if (!leftover)
335 s->device_count = 0;
336 else
337 s->device_count = 1;
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100338 mutex_unlock(&s->ops_mutex);
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100339
340 /* unregister all pcmcia_devices registered with this socket, except leftover */
341 list_for_each_entry_safe(p_dev, tmp, &s->devices_list, socket_device_list) {
342 if (p_dev == leftover)
343 continue;
344
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100345 mutex_lock(&s->ops_mutex);
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100346 list_del(&p_dev->socket_device_list);
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100347 mutex_unlock(&s->ops_mutex);
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100348
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200349 dev_dbg(&p_dev->dev, "unregistering device\n");
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100350 device_unregister(&p_dev->dev);
351 }
352
353 return;
354}
355
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100356static int pcmcia_device_remove(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357{
358 struct pcmcia_device *p_dev;
359 struct pcmcia_driver *p_drv;
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100360 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 p_dev = to_pcmcia_dev(dev);
363 p_drv = to_pcmcia_drv(dev->driver);
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100364
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200365 dev_dbg(dev, "removing device\n");
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200366
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100367 /* If we're removing the primary module driving a
368 * pseudo multi-function card, we need to unbind
369 * all devices
370 */
Dominik Brodowskice3f9d72010-07-21 14:43:05 +0200371 if ((p_dev->socket->pcmcia_pfc) &&
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100372 (p_dev->socket->device_count > 0) &&
Dominik Brodowskid6ff5a82006-02-05 09:51:34 +0100373 (p_dev->device_no == 0))
374 pcmcia_card_remove(p_dev->socket, p_dev);
375
376 /* detach the "instance" */
Dominik Brodowskif3990712005-11-14 21:25:23 +0100377 if (!p_drv)
378 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
Dominik Brodowskif3990712005-11-14 21:25:23 +0100380 if (p_drv->remove)
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100381 p_drv->remove(p_dev);
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100382
Dominik Brodowskif3990712005-11-14 21:25:23 +0100383 /* check for proper unloading */
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100384 if (p_dev->_irq || p_dev->_io || p_dev->_locked)
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700385 dev_info(dev,
386 "pcmcia: driver %s did not release config properly\n",
387 p_drv->name);
Dominik Brodowskif3990712005-11-14 21:25:23 +0100388
389 for (i = 0; i < MAX_WIN; i++)
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100390 if (p_dev->_win & CLIENT_WIN_REQ(i))
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700391 dev_info(dev,
392 "pcmcia: driver %s did not release window properly\n",
393 p_drv->name);
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100394
Dominik Brodowskif3990712005-11-14 21:25:23 +0100395 /* references from pcmcia_probe_device */
396 pcmcia_put_dev(p_dev);
397 module_put(p_drv->owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
399 return 0;
400}
401
402
Dominik Brodowskicc3b4862005-11-14 21:23:14 +0100403/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 * pcmcia_device_query -- determine information about a pcmcia device
405 */
406static int pcmcia_device_query(struct pcmcia_device *p_dev)
407{
408 cistpl_manfid_t manf_id;
409 cistpl_funcid_t func_id;
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700410 cistpl_vers_1_t *vers1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 unsigned int i;
412
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700413 vers1 = kmalloc(sizeof(*vers1), GFP_KERNEL);
414 if (!vers1)
415 return -ENOMEM;
416
Dominik Brodowski84897fc2009-10-18 23:51:09 +0200417 if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 CISTPL_MANFID, &manf_id)) {
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100419 mutex_lock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 p_dev->manf_id = manf_id.manf;
421 p_dev->card_id = manf_id.card;
422 p_dev->has_manf_id = 1;
423 p_dev->has_card_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 }
426
427 if (!pccard_read_tuple(p_dev->socket, p_dev->func,
428 CISTPL_FUNCID, &func_id)) {
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100429 mutex_lock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 p_dev->func_id = func_id.func;
431 p_dev->has_func_id = 1;
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100432 mutex_unlock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 } else {
434 /* rule of thumb: cards with no FUNCID, but with
435 * common memory device geometry information, are
436 * probably memory cards (from pcmcia-cs) */
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700437 cistpl_device_geo_t *devgeo;
438
439 devgeo = kmalloc(sizeof(*devgeo), GFP_KERNEL);
440 if (!devgeo) {
441 kfree(vers1);
442 return -ENOMEM;
443 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 if (!pccard_read_tuple(p_dev->socket, p_dev->func,
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700445 CISTPL_DEVICE_GEO, devgeo)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200446 dev_dbg(&p_dev->dev,
Dominik Brodowskiac449d62008-08-02 18:33:56 +0200447 "mem device geometry probably means "
448 "FUNCID_MEMORY\n");
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100449 mutex_lock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 p_dev->func_id = CISTPL_FUNCID_MEMORY;
451 p_dev->has_func_id = 1;
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100452 mutex_unlock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 }
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700454 kfree(devgeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 }
456
Dominik Brodowski84897fc2009-10-18 23:51:09 +0200457 if (!pccard_read_tuple(p_dev->socket, BIND_FN_ALL, CISTPL_VERS_1,
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700458 vers1)) {
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100459 mutex_lock(&p_dev->socket->ops_mutex);
Dominik Brodowskic5e09522009-10-19 00:04:25 +0200460 for (i = 0; i < min_t(unsigned int, 4, vers1->ns); i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 char *tmp;
462 unsigned int length;
Dominik Brodowski44961a02010-01-24 12:11:02 +0100463 char *new;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700465 tmp = vers1->str + vers1->ofs[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
467 length = strlen(tmp) + 1;
Janos Farkas6e3d4f22006-03-31 01:04:57 +0200468 if ((length < 2) || (length > 255))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 continue;
470
Geliang Tang7c22e642015-10-02 00:37:57 +0800471 new = kstrdup(tmp, GFP_KERNEL);
Dominik Brodowski44961a02010-01-24 12:11:02 +0100472 if (!new)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 continue;
474
Dominik Brodowski44961a02010-01-24 12:11:02 +0100475 tmp = p_dev->prod_id[i];
476 p_dev->prod_id[i] = new;
477 kfree(tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 }
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100479 mutex_unlock(&p_dev->socket->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 }
481
Ingo Molnar76fa82f2005-09-09 13:03:21 -0700482 kfree(vers1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 return 0;
484}
485
486
Dominik Brodowski5716d412010-07-11 09:51:14 +0200487static struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s,
488 unsigned int function)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489{
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100490 struct pcmcia_device *p_dev, *tmp_dev;
Dominik Brodowski44961a02010-01-24 12:11:02 +0100491 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
Dominik Brodowskidc109492005-06-27 16:28:50 -0700493 s = pcmcia_get_socket(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 if (!s)
495 return NULL;
496
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200497 pr_debug("adding device to %d, function %d\n", s->sock, function);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200498
Dominik Brodowski8084b372005-12-11 21:18:26 +0100499 p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 if (!p_dev)
501 goto err_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100503 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 p_dev->device_no = (s->device_count++);
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100505 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100506
Dominik Brodowski7d7ba8d2010-03-24 10:49:14 +0100507 /* max of 2 PFC devices */
508 if ((p_dev->device_no >= 2) && (function == 0))
509 goto err_free;
510
511 /* max of 4 devices overall */
512 if (p_dev->device_no >= 4)
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100513 goto err_free;
514
515 p_dev->socket = s;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 p_dev->func = function;
517
518 p_dev->dev.bus = &pcmcia_bus_type;
Greg Kroah-Hartman87373312006-09-12 17:00:10 +0200519 p_dev->dev.parent = s->dev.parent;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 p_dev->dev.release = pcmcia_release_dev;
James Bottomley43d9f7f2007-10-16 01:23:58 -0700521 /* by default don't allow DMA */
522 p_dev->dma_mask = DMA_MASK_NONE;
523 p_dev->dev.dma_mask = &p_dev->dma_mask;
Kay Sievers25096982008-11-01 11:46:06 +0100524 dev_set_name(&p_dev->dev, "%d.%d", p_dev->socket->sock, p_dev->device_no);
525 if (!dev_name(&p_dev->dev))
526 goto err_free;
527 p_dev->devname = kasprintf(GFP_KERNEL, "pcmcia%s", dev_name(&p_dev->dev));
Brice Goglinbd65a682005-09-09 13:03:29 -0700528 if (!p_dev->devname)
529 goto err_free;
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200530 dev_dbg(&p_dev->dev, "devname is %s\n", p_dev->devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100532 mutex_lock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100533
534 /*
535 * p_dev->function_config must be the same for all card functions.
Dominik Brodowskia60f22c2010-03-07 09:22:51 +0100536 * Note that this is serialized by ops_mutex, so that only one
537 * such struct will be created.
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100538 */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100539 list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)
540 if (p_dev->func == tmp_dev->func) {
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100541 p_dev->function_config = tmp_dev->function_config;
Komuro3e879f62008-11-02 19:33:24 +0900542 p_dev->irq = tmp_dev->irq;
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100543 kref_get(&p_dev->function_config->ref);
544 }
545
546 /* Add to the list in pcmcia_bus_socket */
Komuro6171b882006-04-02 17:39:27 +0900547 list_add(&p_dev->socket_device_list, &s->devices_list);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100548
Dominik Brodowski6f0f38c2010-04-08 20:33:16 +0200549 if (pcmcia_setup_irq(p_dev))
550 dev_warn(&p_dev->dev,
551 "IRQ setup failed -- device might not work\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100553 if (!p_dev->function_config) {
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200554 config_t *c;
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200555 dev_dbg(&p_dev->dev, "creating config_t\n");
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200556 c = kzalloc(sizeof(struct config_t), GFP_KERNEL);
557 if (!c) {
Dominik Brodowski6f0f38c2010-04-08 20:33:16 +0200558 mutex_unlock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100559 goto err_unreg;
Dominik Brodowski6f0f38c2010-04-08 20:33:16 +0200560 }
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200561 p_dev->function_config = c;
562 kref_init(&c->ref);
563 for (i = 0; i < MAX_IO_WIN; i++) {
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200564 c->io[i].name = p_dev->devname;
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200565 c->io[i].flags = IORESOURCE_IO;
566 }
Laurent Navet46f533c2013-01-21 22:16:05 +0100567 for (i = 0; i < MAX_WIN; i++) {
Dominik Brodowskiad0c7be2010-07-25 13:10:22 +0200568 c->mem[i].name = p_dev->devname;
Dominik Brodowski0ca724d2010-07-24 19:03:02 +0200569 c->mem[i].flags = IORESOURCE_MEM;
570 }
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100571 }
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200572 for (i = 0; i < MAX_IO_WIN; i++)
573 p_dev->resource[i] = &p_dev->function_config->io[i];
Dominik Brodowski0ca724d2010-07-24 19:03:02 +0200574 for (; i < (MAX_IO_WIN + MAX_WIN); i++)
575 p_dev->resource[i] = &p_dev->function_config->mem[i-MAX_IO_WIN];
Dominik Brodowski2ce49052010-07-24 13:14:44 +0200576
Dominik Brodowski6f0f38c2010-04-08 20:33:16 +0200577 mutex_unlock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100578
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700579 dev_notice(&p_dev->dev, "pcmcia: registering new device %s (IRQ: %d)\n",
Dominik Brodowskieb141202010-03-07 12:21:16 +0100580 p_dev->devname, p_dev->irq);
Dominik Brodowski807277c2005-11-12 23:34:06 +0100581
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700582 pcmcia_device_query(p_dev);
583
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100584 if (device_register(&p_dev->dev))
585 goto err_unreg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 return p_dev;
588
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100589 err_unreg:
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100590 mutex_lock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100591 list_del(&p_dev->socket_device_list);
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100592 mutex_unlock(&s->ops_mutex);
Dominik Brodowski360b65b2006-01-10 20:50:39 +0100593
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 err_free:
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100595 mutex_lock(&s->ops_mutex);
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100596 s->device_count--;
Dominik Brodowski00ce99f2010-01-16 09:14:11 +0100597 mutex_unlock(&s->ops_mutex);
Dominik Brodowskie6e4f392010-01-16 01:34:06 +0100598
Dominik Brodowski44961a02010-01-24 12:11:02 +0100599 for (i = 0; i < 4; i++)
600 kfree(p_dev->prod_id[i]);
Brice Goglinbd65a682005-09-09 13:03:29 -0700601 kfree(p_dev->devname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 kfree(p_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 err_put:
Dominik Brodowskidc109492005-06-27 16:28:50 -0700604 pcmcia_put_socket(s);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
606 return NULL;
607}
608
609
610static int pcmcia_card_add(struct pcmcia_socket *s)
611{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 cistpl_longlink_mfc_t mfc;
Dominik Brodowskic5081d52008-06-19 20:12:34 +0200613 unsigned int no_funcs, i, no_chains;
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100614 int ret = -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100616 mutex_lock(&s->ops_mutex);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200617 if (!(s->resource_setup_done)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200618 dev_dbg(&s->dev,
Dominik Brodowskiac449d62008-08-02 18:33:56 +0200619 "no resources available, delaying card_add\n");
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100620 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 return -EAGAIN; /* try again, but later... */
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200622 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200624 if (pcmcia_validate_mem(s)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200625 dev_dbg(&s->dev, "validating mem resources failed, "
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200626 "delaying card_add\n");
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100627 mutex_unlock(&s->ops_mutex);
Dominik Brodowskide759142005-09-28 19:41:56 +0200628 return -EAGAIN; /* try again, but later... */
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200629 }
Dominik Brodowskicfe5d802010-01-17 19:31:45 +0100630 mutex_unlock(&s->ops_mutex);
Dominik Brodowskide759142005-09-28 19:41:56 +0200631
Dominik Brodowski84897fc2009-10-18 23:51:09 +0200632 ret = pccard_validate_cis(s, &no_chains);
Dominik Brodowskic5081d52008-06-19 20:12:34 +0200633 if (ret || !no_chains) {
Dominik Brodowskie8e68fd2015-06-14 21:52:46 +0200634#if defined(CONFIG_MTD_PCMCIA_ANONYMOUS)
635 /* Set up as an anonymous card. If we don't have anonymous
636 memory support then just error the card as there is no
637 point trying to second guess.
638
639 Note: some cards have just a device entry, it may be
640 worth extending support to cover these in future */
641 if (ret == -EIO) {
642 dev_info(&s->dev, "no CIS, assuming an anonymous memory card.\n");
643 pcmcia_replace_cis(s, "\xFF", 1);
644 no_chains = 1;
645 ret = 0;
646 } else
647#endif
648 {
649 dev_dbg(&s->dev, "invalid CIS or invalid resources\n");
650 return -ENODEV;
651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 }
653
654 if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC, &mfc))
655 no_funcs = mfc.nfn;
656 else
657 no_funcs = 1;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500658 s->functions = no_funcs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100660 for (i = 0; i < no_funcs; i++)
Dominik Brodowskidc109492005-06-27 16:28:50 -0700661 pcmcia_device_add(s, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100663 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664}
665
666
Laurent Navet46f533c2013-01-21 22:16:05 +0100667static int pcmcia_requery_callback(struct device *dev, void *_data)
Dominik Brodowskiff1fa9e2005-06-27 16:28:09 -0700668{
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700669 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200670 if (!p_dev->dev.driver) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200671 dev_dbg(dev, "update device information\n");
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700672 pcmcia_device_query(p_dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200673 }
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700674
675 return 0;
676}
677
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100678
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100679static void pcmcia_requery(struct pcmcia_socket *s)
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700680{
Dominik Brodowski04de0812010-04-20 14:49:01 +0200681 int has_pfc;
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700682
Alan Cox84026412014-12-10 15:06:40 +0000683 if (!(s->state & SOCKET_PRESENT))
684 return;
685
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100686 if (s->functions == 0) {
687 pcmcia_card_add(s);
688 return;
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700689 }
690
691 /* some device information might have changed because of a CIS
692 * update or because we can finally read it correctly... so
693 * determine it again, overwriting old values if necessary. */
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100694 bus_for_each_dev(&pcmcia_bus_type, NULL, NULL, pcmcia_requery_callback);
695
696 /* if the CIS changed, we need to check whether the number of
697 * functions changed. */
698 if (s->fake_cis) {
699 int old_funcs, new_funcs;
700 cistpl_longlink_mfc_t mfc;
701
702 /* does this cis override add or remove functions? */
703 old_funcs = s->functions;
704
705 if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC,
706 &mfc))
707 new_funcs = mfc.nfn;
708 else
709 new_funcs = 1;
Dominik Brodowskib1095af2010-04-08 20:10:21 +0200710 if (old_funcs != new_funcs) {
711 /* we need to re-start */
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100712 pcmcia_card_remove(s, NULL);
Dominik Brodowskib83156b2010-06-07 18:31:17 +0200713 s->functions = 0;
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100714 pcmcia_card_add(s);
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100715 }
716 }
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700717
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100718 /* If the PCMCIA device consists of two pseudo devices,
719 * call pcmcia_device_add() -- which will fail if both
720 * devices are already registered. */
721 mutex_lock(&s->ops_mutex);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +0200722 has_pfc = s->pcmcia_pfc;
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100723 mutex_unlock(&s->ops_mutex);
724 if (has_pfc)
725 pcmcia_device_add(s, 0);
726
Dominik Brodowskie2f0b532005-06-27 16:28:17 -0700727 /* we re-scan all devices, not just the ones connected to this
728 * socket. This does not matter, though. */
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100729 if (bus_rescan_devices(&pcmcia_bus_type))
730 dev_warn(&s->dev, "rescanning the bus failed\n");
Dominik Brodowskiff1fa9e2005-06-27 16:28:09 -0700731}
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700732
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +0100733
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500734#ifdef CONFIG_PCMCIA_LOAD_CIS
735
736/**
737 * pcmcia_load_firmware - load CIS from userspace if device-provided is broken
Randy Dunlap78187862007-12-10 15:49:22 -0800738 * @dev: the pcmcia device which needs a CIS override
739 * @filename: requested filename in /lib/firmware/
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500740 *
741 * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if
742 * the one provided by the card is broken. The firmware files reside in
743 * /lib/firmware/ in userspace.
744 */
Laurent Navet46f533c2013-01-21 22:16:05 +0100745static int pcmcia_load_firmware(struct pcmcia_device *dev, char *filename)
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500746{
747 struct pcmcia_socket *s = dev->socket;
748 const struct firmware *fw;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500749 int ret = -ENOMEM;
Dominik Brodowskib1095af2010-04-08 20:10:21 +0200750 cistpl_longlink_mfc_t mfc;
751 int old_funcs, new_funcs = 1;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500752
753 if (!filename)
754 return -EINVAL;
755
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200756 dev_dbg(&dev->dev, "trying to load CIS file %s\n", filename);
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500757
Samuel Ortized62ace2009-05-27 00:49:35 +0200758 if (request_firmware(&fw, filename, &dev->dev) == 0) {
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200759 if (fw->size >= CISTPL_MAX_CIS_SIZE) {
760 ret = -EINVAL;
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700761 dev_err(&dev->dev, "pcmcia: CIS override is too big\n");
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500762 goto release;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200763 }
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500764
Dominik Brodowski53efec92008-07-28 19:44:05 +0200765 if (!pcmcia_replace_cis(s, fw->data, fw->size))
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500766 ret = 0;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200767 else {
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700768 dev_err(&dev->dev, "pcmcia: CIS override failed\n");
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200769 goto release;
770 }
771
Dominik Brodowskib1095af2010-04-08 20:10:21 +0200772 /* we need to re-start if the number of functions changed */
773 old_funcs = s->functions;
774 if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC,
775 &mfc))
776 new_funcs = mfc.nfn;
777
778 if (old_funcs != new_funcs)
779 ret = -EBUSY;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500780
781 /* update information */
782 pcmcia_device_query(dev);
783
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100784 /* requery (as number of functions might have changed) */
785 pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500786 }
787 release:
788 release_firmware(fw);
789
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100790 return ret;
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500791}
792
793#else /* !CONFIG_PCMCIA_LOAD_CIS */
794
Laurent Navet46f533c2013-01-21 22:16:05 +0100795static inline int pcmcia_load_firmware(struct pcmcia_device *dev,
796 char *filename)
Dominik Brodowski1d2c9042006-11-06 21:52:16 -0500797{
798 return -ENODEV;
799}
800
801#endif
802
803
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700804static inline int pcmcia_devmatch(struct pcmcia_device *dev,
Joe Perchese9fb13b2011-05-03 19:29:00 -0700805 const struct pcmcia_device_id *did)
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700806{
807 if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) {
808 if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id))
809 return 0;
810 }
811
812 if (did->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID) {
813 if ((!dev->has_card_id) || (dev->card_id != did->card_id))
814 return 0;
815 }
816
817 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION) {
818 if (dev->func != did->function)
819 return 0;
820 }
821
822 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1) {
823 if (!dev->prod_id[0])
824 return 0;
825 if (strcmp(did->prod_id[0], dev->prod_id[0]))
826 return 0;
827 }
828
829 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2) {
830 if (!dev->prod_id[1])
831 return 0;
832 if (strcmp(did->prod_id[1], dev->prod_id[1]))
833 return 0;
834 }
835
836 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3) {
837 if (!dev->prod_id[2])
838 return 0;
839 if (strcmp(did->prod_id[2], dev->prod_id[2]))
840 return 0;
841 }
842
843 if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4) {
844 if (!dev->prod_id[3])
845 return 0;
846 if (strcmp(did->prod_id[3], dev->prod_id[3]))
847 return 0;
848 }
849
850 if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {
Alexander Kurz83bf6f12010-04-25 13:44:35 +0400851 dev_dbg(&dev->dev, "this is a pseudo-multi-function device\n");
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100852 mutex_lock(&dev->socket->ops_mutex);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +0200853 dev->socket->pcmcia_pfc = 1;
Dominik Brodowskiaa584ca2010-01-24 14:36:59 +0100854 mutex_unlock(&dev->socket->ops_mutex);
Alexander Kurz83bf6f12010-04-25 13:44:35 +0400855 if (dev->device_no != did->device_no)
856 return 0;
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700857 }
858
859 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) {
Dominik Brodowski94a819f2010-01-17 18:31:34 +0100860 int ret;
861
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700862 if ((!dev->has_func_id) || (dev->func_id != did->func_id))
863 return 0;
864
865 /* if this is a pseudo-multi-function device,
866 * we need explicit matches */
Dominik Brodowskice3f9d72010-07-21 14:43:05 +0200867 if (dev->socket->pcmcia_pfc)
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700868 return 0;
869 if (dev->device_no)
870 return 0;
871
872 /* also, FUNC_ID matching needs to be activated by userspace
873 * after it has re-checked that there is no possible module
874 * with a prod_id/manf_id/card_id match.
875 */
Dominik Brodowski94a819f2010-01-17 18:31:34 +0100876 mutex_lock(&dev->socket->ops_mutex);
877 ret = dev->allow_func_id_match;
878 mutex_unlock(&dev->socket->ops_mutex);
879
880 if (!ret) {
881 dev_dbg(&dev->dev,
882 "skipping FUNC_ID match until userspace ACK\n");
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700883 return 0;
Dominik Brodowski94a819f2010-01-17 18:31:34 +0100884 }
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700885 }
886
Dominik Brodowskiea7b3882005-06-27 16:28:07 -0700887 if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200888 dev_dbg(&dev->dev, "device needs a fake CIS\n");
Dominik Brodowskidaa95172005-06-27 16:28:14 -0700889 if (!dev->socket->fake_cis)
Dominik Brodowskib1095af2010-04-08 20:10:21 +0200890 if (pcmcia_load_firmware(dev, did->cisfile))
891 return 0;
Dominik Brodowskiea7b3882005-06-27 16:28:07 -0700892 }
893
Dominik Brodowskif602ff72005-06-27 16:28:09 -0700894 if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {
895 int i;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100896 for (i = 0; i < 4; i++)
Dominik Brodowskif602ff72005-06-27 16:28:09 -0700897 if (dev->prod_id[i])
898 return 0;
899 if (dev->has_manf_id || dev->has_card_id || dev->has_func_id)
900 return 0;
901 }
902
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700903 return 1;
904}
905
906
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100907static int pcmcia_bus_match(struct device *dev, struct device_driver *drv)
908{
909 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
910 struct pcmcia_driver *p_drv = to_pcmcia_drv(drv);
Joe Perchese9fb13b2011-05-03 19:29:00 -0700911 const struct pcmcia_device_id *did = p_drv->id_table;
Bernhard Walle6179b552007-05-06 14:48:44 -0700912 struct pcmcia_dynid *dynid;
913
914 /* match dynamic devices first */
Dominik Brodowski3f565232010-01-16 13:06:40 +0100915 mutex_lock(&p_drv->dynids.lock);
Bernhard Walle6179b552007-05-06 14:48:44 -0700916 list_for_each_entry(dynid, &p_drv->dynids.list, node) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200917 dev_dbg(dev, "trying to match to %s\n", drv->name);
Bernhard Walle6179b552007-05-06 14:48:44 -0700918 if (pcmcia_devmatch(p_dev, &dynid->id)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200919 dev_dbg(dev, "matched to %s\n", drv->name);
Dominik Brodowski3f565232010-01-16 13:06:40 +0100920 mutex_unlock(&p_drv->dynids.lock);
Bernhard Walle6179b552007-05-06 14:48:44 -0700921 return 1;
922 }
923 }
Dominik Brodowski3f565232010-01-16 13:06:40 +0100924 mutex_unlock(&p_drv->dynids.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700926 while (did && did->match_flags) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200927 dev_dbg(dev, "trying to match to %s\n", drv->name);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200928 if (pcmcia_devmatch(p_dev, did)) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200929 dev_dbg(dev, "matched to %s\n", drv->name);
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700930 return 1;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +0200931 }
Dominik Brodowski1ad275e2005-06-27 16:28:06 -0700932 did++;
933 }
934
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 return 0;
936}
937
Kay Sievers7eff2e72007-08-14 15:15:12 +0200938static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700939{
940 struct pcmcia_device *p_dev;
Kay Sievers7eff2e72007-08-14 15:15:12 +0200941 int i;
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700942 u32 hash[4] = { 0, 0, 0, 0};
943
944 if (!dev)
945 return -ENODEV;
946
947 p_dev = to_pcmcia_dev(dev);
948
949 /* calculate hashes */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100950 for (i = 0; i < 4; i++) {
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700951 if (!p_dev->prod_id[i])
952 continue;
953 hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i]));
954 }
955
Kay Sievers7eff2e72007-08-14 15:15:12 +0200956 if (add_uevent_var(env, "SOCKET_NO=%u", p_dev->socket->sock))
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700957 return -ENOMEM;
958
Kay Sievers7eff2e72007-08-14 15:15:12 +0200959 if (add_uevent_var(env, "DEVICE_NO=%02X", p_dev->device_no))
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700960 return -ENOMEM;
961
Kay Sievers7eff2e72007-08-14 15:15:12 +0200962 if (add_uevent_var(env, "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
Kay Sievers312c0042005-11-16 09:00:00 +0100963 "pa%08Xpb%08Xpc%08Xpd%08X",
964 p_dev->has_manf_id ? p_dev->manf_id : 0,
965 p_dev->has_card_id ? p_dev->card_id : 0,
966 p_dev->has_func_id ? p_dev->func_id : 0,
967 p_dev->func,
968 p_dev->device_no,
969 hash[0],
970 hash[1],
971 hash[2],
972 hash[3]))
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700973 return -ENOMEM;
974
Dominik Brodowski840c2ac2005-06-27 16:28:04 -0700975 return 0;
976}
977
Alan Stern3f8df782007-07-12 16:57:22 -0400978/************************ runtime PM support ***************************/
979
Russell Kingad8d52b2016-08-31 08:49:43 +0100980static int pcmcia_dev_suspend(struct device *dev);
Alan Stern3f8df782007-07-12 16:57:22 -0400981static int pcmcia_dev_resume(struct device *dev);
982
983static int runtime_suspend(struct device *dev)
984{
985 int rc;
986
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800987 device_lock(dev);
Russell Kingad8d52b2016-08-31 08:49:43 +0100988 rc = pcmcia_dev_suspend(dev);
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800989 device_unlock(dev);
Alan Stern3f8df782007-07-12 16:57:22 -0400990 return rc;
991}
992
Dominik Brodowski933a8382009-12-29 18:21:39 +0100993static int runtime_resume(struct device *dev)
Alan Stern3f8df782007-07-12 16:57:22 -0400994{
995 int rc;
996
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800997 device_lock(dev);
Alan Stern3f8df782007-07-12 16:57:22 -0400998 rc = pcmcia_dev_resume(dev);
Greg Kroah-Hartman8e9394c2010-02-17 10:57:05 -0800999 device_unlock(dev);
Dominik Brodowski933a8382009-12-29 18:21:39 +01001000 return rc;
Alan Stern3f8df782007-07-12 16:57:22 -04001001}
1002
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003/************************ per-device sysfs output ***************************/
1004
1005#define pcmcia_device_attr(field, test, format) \
Yani Ioannoue404e272005-05-17 06:42:58 -04001006static ssize_t field##_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->test ? sprintf(buf, format, p_dev->field) : -ENODEV; \
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001010} \
1011static DEVICE_ATTR_RO(field);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
1013#define pcmcia_device_stringattr(name, field) \
Yani Ioannoue404e272005-05-17 06:42:58 -04001014static ssize_t name##_show (struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015{ \
1016 struct pcmcia_device *p_dev = to_pcmcia_dev(dev); \
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001017 return p_dev->field ? sprintf(buf, "%s\n", p_dev->field) : -ENODEV; \
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001018} \
1019static DEVICE_ATTR_RO(name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021pcmcia_device_attr(func_id, has_func_id, "0x%02x\n");
1022pcmcia_device_attr(manf_id, has_manf_id, "0x%04x\n");
1023pcmcia_device_attr(card_id, has_card_id, "0x%04x\n");
1024pcmcia_device_stringattr(prod_id1, prod_id[0]);
1025pcmcia_device_stringattr(prod_id2, prod_id[1]);
1026pcmcia_device_stringattr(prod_id3, prod_id[2]);
1027pcmcia_device_stringattr(prod_id4, prod_id[3]);
1028
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001029static ssize_t function_show(struct device *dev, struct device_attribute *attr,
1030 char *buf)
1031{
1032 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1033 return p_dev->socket ? sprintf(buf, "0x%02x\n", p_dev->func) : -ENODEV;
1034}
1035static DEVICE_ATTR_RO(function);
1036
1037static ssize_t resources_show(struct device *dev,
1038 struct device_attribute *attr, char *buf)
Dominik Brodowski8f677ea2010-07-25 11:10:29 +02001039{
1040 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1041 char *str = buf;
1042 int i;
1043
1044 for (i = 0; i < PCMCIA_NUM_RESOURCES; i++)
1045 str += sprintf(str, "%pr\n", p_dev->resource[i]);
1046
1047 return str - buf;
1048}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001049static DEVICE_ATTR_RO(resources);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001050
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001051static ssize_t pm_state_show(struct device *dev, struct device_attribute *attr, char *buf)
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001052{
1053 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1054
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001055 if (p_dev->suspended)
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001056 return sprintf(buf, "off\n");
1057 else
1058 return sprintf(buf, "on\n");
1059}
1060
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001061static ssize_t pm_state_store(struct device *dev, struct device_attribute *attr,
1062 const char *buf, size_t count)
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001063{
1064 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1065 int ret = 0;
1066
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001067 if (!count)
1068 return -EINVAL;
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001069
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001070 if ((!p_dev->suspended) && !strncmp(buf, "off", 3))
Alan Stern3f8df782007-07-12 16:57:22 -04001071 ret = runtime_suspend(dev);
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001072 else if (p_dev->suspended && !strncmp(buf, "on", 2))
Dominik Brodowski933a8382009-12-29 18:21:39 +01001073 ret = runtime_resume(dev);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001074
1075 return ret ? ret : count;
1076}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001077static DEVICE_ATTR_RW(pm_state);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001078
Dominik Brodowski37045112005-06-30 02:58:47 -07001079static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001080{
1081 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1082 int i;
1083 u32 hash[4] = { 0, 0, 0, 0};
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001084
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001085 /* calculate hashes */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001086 for (i = 0; i < 4; i++) {
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001087 if (!p_dev->prod_id[i])
1088 continue;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001089 hash[i] = crc32(0, p_dev->prod_id[i],
1090 strlen(p_dev->prod_id[i]));
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001091 }
1092 return sprintf(buf, "pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
1093 "pa%08Xpb%08Xpc%08Xpd%08X\n",
1094 p_dev->has_manf_id ? p_dev->manf_id : 0,
1095 p_dev->has_card_id ? p_dev->card_id : 0,
1096 p_dev->has_func_id ? p_dev->func_id : 0,
1097 p_dev->func, p_dev->device_no,
1098 hash[0], hash[1], hash[2], hash[3]);
1099}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001100static DEVICE_ATTR_RO(modalias);
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001101
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001102static ssize_t allow_func_id_match_store(struct device *dev,
Dominik Brodowski3248ff42005-06-27 16:29:01 -07001103 struct device_attribute *attr, const char *buf, size_t count)
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001104{
1105 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
Dominik Brodowskidb1019c2006-01-10 19:19:37 +01001106
1107 if (!count)
1108 return -EINVAL;
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001109
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001110 mutex_lock(&p_dev->socket->ops_mutex);
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001111 p_dev->allow_func_id_match = 1;
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001112 mutex_unlock(&p_dev->socket->ops_mutex);
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +01001113 pcmcia_parse_uevents(p_dev->socket, PCMCIA_UEVENT_REQUERY);
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001114
1115 return count;
1116}
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001117static DEVICE_ATTR_WO(allow_func_id_match);
Dominik Brodowskia5b55772005-06-27 16:28:10 -07001118
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001119static struct attribute *pcmcia_dev_attrs[] = {
1120 &dev_attr_resources.attr,
1121 &dev_attr_pm_state.attr,
1122 &dev_attr_function.attr,
1123 &dev_attr_func_id.attr,
1124 &dev_attr_manf_id.attr,
1125 &dev_attr_card_id.attr,
1126 &dev_attr_prod_id1.attr,
1127 &dev_attr_prod_id2.attr,
1128 &dev_attr_prod_id3.attr,
1129 &dev_attr_prod_id4.attr,
1130 &dev_attr_modalias.attr,
1131 &dev_attr_allow_func_id_match.attr,
1132 NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133};
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001134ATTRIBUTE_GROUPS(pcmcia_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001136/* PM support, also needed for reset */
1137
Russell Kingad8d52b2016-08-31 08:49:43 +01001138static int pcmcia_dev_suspend(struct device *dev)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001139{
1140 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1141 struct pcmcia_driver *p_drv = NULL;
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001142 int ret = 0;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001143
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001144 mutex_lock(&p_dev->socket->ops_mutex);
1145 if (p_dev->suspended) {
1146 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001147 return 0;
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001148 }
1149 p_dev->suspended = 1;
1150 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001151
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001152 dev_dbg(dev, "suspending\n");
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001153
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001154 if (dev->driver)
1155 p_drv = to_pcmcia_drv(dev->driver);
1156
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001157 if (!p_drv)
1158 goto out;
1159
1160 if (p_drv->suspend) {
Dominik Brodowski8661bb52006-03-02 00:02:33 +01001161 ret = p_drv->suspend(p_dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001162 if (ret) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001163 dev_err(dev,
1164 "pcmcia: device %s (driver %s) did not want to go to sleep (%d)\n",
1165 p_dev->devname, p_drv->name, ret);
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001166 mutex_lock(&p_dev->socket->ops_mutex);
1167 p_dev->suspended = 0;
1168 mutex_unlock(&p_dev->socket->ops_mutex);
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001169 goto out;
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001170 }
Dominik Brodowski8661bb52006-03-02 00:02:33 +01001171 }
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001172
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001173 if (p_dev->device_no == p_dev->func) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001174 dev_dbg(dev, "releasing configuration\n");
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001175 pcmcia_release_configuration(p_dev);
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001176 }
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001177
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001178 out:
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001179 return ret;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001180}
1181
1182
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001183static int pcmcia_dev_resume(struct device *dev)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001184{
1185 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001186 struct pcmcia_driver *p_drv = NULL;
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001187 int ret = 0;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001188
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001189 mutex_lock(&p_dev->socket->ops_mutex);
1190 if (!p_dev->suspended) {
1191 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001192 return 0;
Dominik Brodowski94a819f2010-01-17 18:31:34 +01001193 }
1194 p_dev->suspended = 0;
1195 mutex_unlock(&p_dev->socket->ops_mutex);
David Brownelld6b4fa62008-02-04 22:27:37 -08001196
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001197 dev_dbg(dev, "resuming\n");
Dominik Brodowskid9d9ea02006-12-02 22:11:44 +02001198
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001199 if (dev->driver)
1200 p_drv = to_pcmcia_drv(dev->driver);
1201
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001202 if (!p_drv)
1203 goto out;
1204
1205 if (p_dev->device_no == p_dev->func) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001206 dev_dbg(dev, "requesting configuration\n");
Dominik Brodowski1ac71e52010-07-29 19:27:09 +02001207 ret = pcmcia_enable_device(p_dev);
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001208 if (ret)
1209 goto out;
Dominik Brodowski8661bb52006-03-02 00:02:33 +01001210 }
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001211
Dominik Brodowskie2d40962006-03-02 00:09:29 +01001212 if (p_drv->resume)
1213 ret = p_drv->resume(p_dev);
1214
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001215 out:
Dominik Brodowskif6fbe012006-01-20 15:10:23 +01001216 return ret;
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001217}
1218
1219
Laurent Navet46f533c2013-01-21 22:16:05 +01001220static int pcmcia_bus_suspend_callback(struct device *dev, void *_data)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001221{
1222 struct pcmcia_socket *skt = _data;
1223 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1224
Alan Stern3f8df782007-07-12 16:57:22 -04001225 if (p_dev->socket != skt || p_dev->suspended)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001226 return 0;
1227
Alan Stern3f8df782007-07-12 16:57:22 -04001228 return runtime_suspend(dev);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001229}
1230
Laurent Navet46f533c2013-01-21 22:16:05 +01001231static int pcmcia_bus_resume_callback(struct device *dev, void *_data)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001232{
1233 struct pcmcia_socket *skt = _data;
1234 struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
1235
Alan Stern3f8df782007-07-12 16:57:22 -04001236 if (p_dev->socket != skt || !p_dev->suspended)
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001237 return 0;
1238
Alan Stern3f8df782007-07-12 16:57:22 -04001239 runtime_resume(dev);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001240
1241 return 0;
1242}
1243
1244static int pcmcia_bus_resume(struct pcmcia_socket *skt)
1245{
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001246 dev_dbg(&skt->dev, "resuming socket %d\n", skt->sock);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001247 bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback);
1248 return 0;
1249}
1250
1251static int pcmcia_bus_suspend(struct pcmcia_socket *skt)
1252{
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001253 dev_dbg(&skt->dev, "suspending socket %d\n", skt->sock);
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001254 if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt,
1255 pcmcia_bus_suspend_callback)) {
1256 pcmcia_bus_resume(skt);
1257 return -EIO;
1258 }
1259 return 0;
1260}
1261
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001262static int pcmcia_bus_remove(struct pcmcia_socket *skt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263{
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001264 atomic_set(&skt->present, 0);
1265 pcmcia_card_remove(skt, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001267 mutex_lock(&skt->ops_mutex);
1268 destroy_cis_cache(skt);
1269 pcmcia_cleanup_irq(skt);
1270 mutex_unlock(&skt->ops_mutex);
1271
1272 return 0;
1273}
1274
1275static int pcmcia_bus_add(struct pcmcia_socket *skt)
1276{
1277 atomic_set(&skt->present, 1);
1278
1279 mutex_lock(&skt->ops_mutex);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +02001280 skt->pcmcia_pfc = 0;
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001281 destroy_cis_cache(skt); /* to be on the safe side... */
1282 mutex_unlock(&skt->ops_mutex);
1283
1284 pcmcia_card_add(skt);
1285
1286 return 0;
1287}
1288
1289static int pcmcia_bus_early_resume(struct pcmcia_socket *skt)
1290{
Russell King025e4ab2012-02-08 17:13:41 -08001291 if (!verify_cis_cache(skt))
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001292 return 0;
Florin Malita16174062006-05-24 21:21:31 -04001293
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001294 dev_dbg(&skt->dev, "cis mismatch - different card\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001296 /* first, remove the card */
1297 pcmcia_bus_remove(skt);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +01001298
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001299 mutex_lock(&skt->ops_mutex);
1300 destroy_cis_cache(skt);
1301 kfree(skt->fake_cis);
1302 skt->fake_cis = NULL;
1303 skt->functions = 0;
1304 mutex_unlock(&skt->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001306 /* now, add the new card */
1307 pcmcia_bus_add(skt);
1308 return 0;
1309}
Dominik Brodowski88b060d2010-01-02 14:14:23 +01001310
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311
Dominik Brodowski04de0812010-04-20 14:49:01 +02001312/*
1313 * NOTE: This is racy. There's no guarantee the card will still be
1314 * physically present, even if the call to this function returns
1315 * non-NULL. Furthermore, the device driver most likely is unbound
1316 * almost immediately, so the timeframe where pcmcia_dev_present
1317 * returns NULL is probably really really small.
1318 */
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001319struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev)
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001320{
1321 struct pcmcia_device *p_dev;
1322 struct pcmcia_device *ret = NULL;
1323
1324 p_dev = pcmcia_get_dev(_p_dev);
1325 if (!p_dev)
1326 return NULL;
1327
Dominik Brodowski04de0812010-04-20 14:49:01 +02001328 if (atomic_read(&p_dev->socket->present) != 0)
1329 ret = p_dev;
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001330
Dominik Brodowski9940ec32006-03-05 11:04:33 +01001331 pcmcia_put_dev(p_dev);
1332 return ret;
1333}
1334EXPORT_SYMBOL(pcmcia_dev_present);
1335
1336
Dominik Brodowski90c6cdd2005-06-27 16:28:49 -07001337static struct pcmcia_callback pcmcia_bus_callback = {
1338 .owner = THIS_MODULE,
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001339 .add = pcmcia_bus_add,
1340 .remove = pcmcia_bus_remove,
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +01001341 .requery = pcmcia_requery,
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001342 .validate = pccard_validate_cis,
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001343 .suspend = pcmcia_bus_suspend,
Dominik Brodowski7b24e792010-07-11 10:26:53 +02001344 .early_resume = pcmcia_bus_early_resume,
Dominik Brodowski8e9e7932006-01-06 00:02:03 +01001345 .resume = pcmcia_bus_resume,
Dominik Brodowski90c6cdd2005-06-27 16:28:49 -07001346};
1347
Bill Pemberton34cdf252012-11-19 13:23:12 -05001348static int pcmcia_bus_add_socket(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001349 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001351 struct pcmcia_socket *socket = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 int ret;
1353
Dominik Brodowskidc109492005-06-27 16:28:50 -07001354 socket = pcmcia_get_socket(socket);
1355 if (!socket) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001356 dev_err(dev, "PCMCIA obtaining reference to socket failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 return -ENODEV;
1358 }
1359
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001360 ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
1361 if (ret) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001362 dev_err(dev, "PCMCIA registration failed\n");
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001363 pcmcia_put_socket(socket);
1364 return ret;
1365 }
1366
Dominik Brodowskidc109492005-06-27 16:28:50 -07001367 INIT_LIST_HEAD(&socket->devices_list);
Dominik Brodowskice3f9d72010-07-21 14:43:05 +02001368 socket->pcmcia_pfc = 0;
Dominik Brodowskidc109492005-06-27 16:28:50 -07001369 socket->device_count = 0;
Dominik Brodowskie4f1ac22010-06-19 14:33:56 +02001370 atomic_set(&socket->present, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
Dominik Brodowski90c6cdd2005-06-27 16:28:49 -07001372 ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 if (ret) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -07001374 dev_err(dev, "PCMCIA registration failed\n");
Dominik Brodowskidc109492005-06-27 16:28:50 -07001375 pcmcia_put_socket(socket);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001376 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 }
1378
1379 return 0;
1380}
1381
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001382static void pcmcia_bus_remove_socket(struct device *dev,
Dmitry Torokhovd8539d82005-09-15 02:01:36 -05001383 struct class_interface *class_intf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384{
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001385 struct pcmcia_socket *socket = dev_get_drvdata(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386
Dominik Brodowskidc109492005-06-27 16:28:50 -07001387 if (!socket)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 return;
1389
1390 pccard_register_pcmcia(socket, NULL);
1391
Daniel Ritzdfbc9e92006-11-18 22:19:34 -08001392 /* unregister any unbound devices */
Daniel Ritz8e4d9dc2006-11-25 11:09:17 -08001393 mutex_lock(&socket->skt_mutex);
Daniel Ritzdfbc9e92006-11-18 22:19:34 -08001394 pcmcia_card_remove(socket, NULL);
Dominik Brodowski180c33e2010-01-02 17:34:09 +01001395 release_cis_mem(socket);
Daniel Ritz8e4d9dc2006-11-25 11:09:17 -08001396 mutex_unlock(&socket->skt_mutex);
Daniel Ritzdfbc9e92006-11-18 22:19:34 -08001397
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001398 sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr);
1399
Dominik Brodowskidc109492005-06-27 16:28:50 -07001400 pcmcia_put_socket(socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
1402 return;
1403}
1404
1405
1406/* the pcmcia_bus_interface is used to handle pcmcia socket devices */
Sam Ravnborged49f5d2008-05-01 04:34:50 -07001407static struct class_interface pcmcia_bus_interface __refdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 .class = &pcmcia_socket_class,
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001409 .add_dev = &pcmcia_bus_add_socket,
1410 .remove_dev = &pcmcia_bus_remove_socket,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411};
1412
Russell Kingad8d52b2016-08-31 08:49:43 +01001413static const struct dev_pm_ops pcmcia_bus_pm_ops = {
1414 SET_SYSTEM_SLEEP_PM_OPS(pcmcia_dev_suspend, pcmcia_dev_resume)
1415};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001417struct bus_type pcmcia_bus_type = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 .name = "pcmcia",
Kay Sievers312c0042005-11-16 09:00:00 +01001419 .uevent = pcmcia_bus_uevent,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 .match = pcmcia_bus_match,
Greg Kroah-Hartmanb9b2f362013-10-06 23:55:46 -07001421 .dev_groups = pcmcia_dev_groups,
Russell King1d0baa32006-01-05 14:40:58 +00001422 .probe = pcmcia_device_probe,
1423 .remove = pcmcia_device_remove,
Russell Kingad8d52b2016-08-31 08:49:43 +01001424 .pm = &pcmcia_bus_pm_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426
1427
1428static int __init init_pcmcia_bus(void)
1429{
Randy Dunlapace7d472006-10-20 14:44:12 -07001430 int ret;
1431
Randy Dunlapace7d472006-10-20 14:44:12 -07001432 ret = bus_register(&pcmcia_bus_type);
1433 if (ret < 0) {
1434 printk(KERN_WARNING "pcmcia: bus_register error: %d\n", ret);
1435 return ret;
1436 }
1437 ret = class_interface_register(&pcmcia_bus_interface);
1438 if (ret < 0) {
1439 printk(KERN_WARNING
1440 "pcmcia: class_interface_register error: %d\n", ret);
1441 bus_unregister(&pcmcia_bus_type);
1442 return ret;
1443 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 return 0;
1446}
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001447fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 * pcmcia_socket_class is already registered */
1449
1450
1451static void __exit exit_pcmcia_bus(void)
1452{
Dominik Brodowskie7a480d2005-06-27 16:28:47 -07001453 class_interface_unregister(&pcmcia_bus_interface);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454
1455 bus_unregister(&pcmcia_bus_type);
1456}
1457module_exit(exit_pcmcia_bus);
1458
1459
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460MODULE_ALIAS("ds");