.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * linux/drivers/mmc/core/sdio_bus.c |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright 2007 Pierre Ossman |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License as published by |
---|
8 | | - * the Free Software Foundation; either version 2 of the License, or (at |
---|
9 | | - * your option) any later version. |
---|
10 | 6 | * |
---|
11 | 7 | * SDIO function driver model |
---|
12 | 8 | */ |
---|
.. | .. |
---|
32 | 28 | #define to_sdio_driver(d) container_of(d, struct sdio_driver, drv) |
---|
33 | 29 | |
---|
34 | 30 | /* show configuration fields */ |
---|
35 | | -#define sdio_config_attr(field, format_string) \ |
---|
| 31 | +#define sdio_config_attr(field, format_string, args...) \ |
---|
36 | 32 | static ssize_t \ |
---|
37 | 33 | field##_show(struct device *dev, struct device_attribute *attr, char *buf) \ |
---|
38 | 34 | { \ |
---|
39 | 35 | struct sdio_func *func; \ |
---|
40 | 36 | \ |
---|
41 | 37 | func = dev_to_sdio_func (dev); \ |
---|
42 | | - return sprintf (buf, format_string, func->field); \ |
---|
| 38 | + return sprintf(buf, format_string, args); \ |
---|
43 | 39 | } \ |
---|
44 | 40 | static DEVICE_ATTR_RO(field) |
---|
45 | 41 | |
---|
46 | | -sdio_config_attr(class, "0x%02x\n"); |
---|
47 | | -sdio_config_attr(vendor, "0x%04x\n"); |
---|
48 | | -sdio_config_attr(device, "0x%04x\n"); |
---|
| 42 | +sdio_config_attr(class, "0x%02x\n", func->class); |
---|
| 43 | +sdio_config_attr(vendor, "0x%04x\n", func->vendor); |
---|
| 44 | +sdio_config_attr(device, "0x%04x\n", func->device); |
---|
| 45 | +sdio_config_attr(revision, "%u.%u\n", func->major_rev, func->minor_rev); |
---|
| 46 | +sdio_config_attr(modalias, "sdio:c%02Xv%04Xd%04X\n", func->class, func->vendor, func->device); |
---|
49 | 47 | |
---|
50 | | -static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) |
---|
51 | | -{ |
---|
52 | | - struct sdio_func *func = dev_to_sdio_func (dev); |
---|
| 48 | +#define sdio_info_attr(num) \ |
---|
| 49 | +static ssize_t info##num##_show(struct device *dev, struct device_attribute *attr, char *buf) \ |
---|
| 50 | +{ \ |
---|
| 51 | + struct sdio_func *func = dev_to_sdio_func(dev); \ |
---|
| 52 | + \ |
---|
| 53 | + if (num > func->num_info) \ |
---|
| 54 | + return -ENODATA; \ |
---|
| 55 | + if (!func->info[num-1][0]) \ |
---|
| 56 | + return 0; \ |
---|
| 57 | + return sprintf(buf, "%s\n", func->info[num-1]); \ |
---|
| 58 | +} \ |
---|
| 59 | +static DEVICE_ATTR_RO(info##num) |
---|
53 | 60 | |
---|
54 | | - return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n", |
---|
55 | | - func->class, func->vendor, func->device); |
---|
56 | | -} |
---|
57 | | -static DEVICE_ATTR_RO(modalias); |
---|
| 61 | +sdio_info_attr(1); |
---|
| 62 | +sdio_info_attr(2); |
---|
| 63 | +sdio_info_attr(3); |
---|
| 64 | +sdio_info_attr(4); |
---|
58 | 65 | |
---|
59 | 66 | static struct attribute *sdio_dev_attrs[] = { |
---|
60 | 67 | &dev_attr_class.attr, |
---|
61 | 68 | &dev_attr_vendor.attr, |
---|
62 | 69 | &dev_attr_device.attr, |
---|
| 70 | + &dev_attr_revision.attr, |
---|
| 71 | + &dev_attr_info1.attr, |
---|
| 72 | + &dev_attr_info2.attr, |
---|
| 73 | + &dev_attr_info3.attr, |
---|
| 74 | + &dev_attr_info4.attr, |
---|
63 | 75 | &dev_attr_modalias.attr, |
---|
64 | 76 | NULL, |
---|
65 | 77 | }; |
---|
.. | .. |
---|
110 | 122 | sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env) |
---|
111 | 123 | { |
---|
112 | 124 | struct sdio_func *func = dev_to_sdio_func(dev); |
---|
| 125 | + unsigned int i; |
---|
113 | 126 | |
---|
114 | 127 | if (add_uevent_var(env, |
---|
115 | 128 | "SDIO_CLASS=%02X", func->class)) |
---|
.. | .. |
---|
118 | 131 | if (add_uevent_var(env, |
---|
119 | 132 | "SDIO_ID=%04X:%04X", func->vendor, func->device)) |
---|
120 | 133 | return -ENOMEM; |
---|
| 134 | + |
---|
| 135 | + if (add_uevent_var(env, |
---|
| 136 | + "SDIO_REVISION=%u.%u", func->major_rev, func->minor_rev)) |
---|
| 137 | + return -ENOMEM; |
---|
| 138 | + |
---|
| 139 | + for (i = 0; i < func->num_info; i++) { |
---|
| 140 | + if (add_uevent_var(env, "SDIO_INFO%u=%s", i+1, func->info[i])) |
---|
| 141 | + return -ENOMEM; |
---|
| 142 | + } |
---|
121 | 143 | |
---|
122 | 144 | if (add_uevent_var(env, |
---|
123 | 145 | "MODALIAS=sdio:c%02Xv%04Xd%04X", |
---|
.. | .. |
---|
142 | 164 | if (ret) |
---|
143 | 165 | return ret; |
---|
144 | 166 | |
---|
| 167 | + atomic_inc(&func->card->sdio_funcs_probed); |
---|
| 168 | + |
---|
145 | 169 | /* Unbound SDIO functions are always suspended. |
---|
146 | 170 | * During probe, the function is set active and the usage count |
---|
147 | 171 | * is incremented. If the driver supports runtime PM, |
---|
.. | .. |
---|
157 | 181 | /* Set the default block size so the driver is sure it's something |
---|
158 | 182 | * sensible. */ |
---|
159 | 183 | sdio_claim_host(func); |
---|
160 | | - ret = sdio_set_block_size(func, 0); |
---|
| 184 | + if (mmc_card_removed(func->card)) |
---|
| 185 | + ret = -ENOMEDIUM; |
---|
| 186 | + else |
---|
| 187 | + ret = sdio_set_block_size(func, 0); |
---|
161 | 188 | sdio_release_host(func); |
---|
162 | 189 | if (ret) |
---|
163 | 190 | goto disable_runtimepm; |
---|
.. | .. |
---|
169 | 196 | return 0; |
---|
170 | 197 | |
---|
171 | 198 | disable_runtimepm: |
---|
| 199 | + atomic_dec(&func->card->sdio_funcs_probed); |
---|
172 | 200 | if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) |
---|
173 | 201 | pm_runtime_put_noidle(dev); |
---|
174 | 202 | dev_pm_domain_detach(dev, false); |
---|
.. | .. |
---|
179 | 207 | { |
---|
180 | 208 | struct sdio_driver *drv = to_sdio_driver(dev->driver); |
---|
181 | 209 | struct sdio_func *func = dev_to_sdio_func(dev); |
---|
182 | | - int ret = 0; |
---|
183 | 210 | |
---|
184 | 211 | /* Make sure card is powered before invoking ->remove() */ |
---|
185 | 212 | if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) |
---|
186 | 213 | pm_runtime_get_sync(dev); |
---|
187 | 214 | |
---|
188 | 215 | drv->remove(func); |
---|
| 216 | + atomic_dec(&func->card->sdio_funcs_probed); |
---|
189 | 217 | |
---|
190 | 218 | if (func->irq_handler) { |
---|
191 | 219 | pr_warn("WARNING: driver %s did not remove its interrupt handler!\n", |
---|
.. | .. |
---|
205 | 233 | |
---|
206 | 234 | dev_pm_domain_detach(dev, false); |
---|
207 | 235 | |
---|
208 | | - return ret; |
---|
| 236 | + return 0; |
---|
209 | 237 | } |
---|
210 | 238 | |
---|
211 | 239 | static const struct dev_pm_ops sdio_bus_pm_ops = { |
---|
.. | .. |
---|
264 | 292 | { |
---|
265 | 293 | struct sdio_func *func = dev_to_sdio_func(dev); |
---|
266 | 294 | |
---|
267 | | - sdio_free_func_cis(func); |
---|
| 295 | + if (!(func->card->quirks & MMC_QUIRK_NONSTD_SDIO)) |
---|
| 296 | + sdio_free_func_cis(func); |
---|
| 297 | + |
---|
| 298 | + /* |
---|
| 299 | + * We have now removed the link to the tuples in the |
---|
| 300 | + * card structure, so remove the reference. |
---|
| 301 | + */ |
---|
| 302 | + put_device(&func->card->dev); |
---|
268 | 303 | |
---|
269 | 304 | kfree(func->info); |
---|
270 | 305 | kfree(func->tmpbuf); |
---|
.. | .. |
---|
295 | 330 | func->card = card; |
---|
296 | 331 | |
---|
297 | 332 | device_initialize(&func->dev); |
---|
| 333 | + |
---|
| 334 | + /* |
---|
| 335 | + * We may link to tuples in the card structure, |
---|
| 336 | + * we need make sure we have a reference to it. |
---|
| 337 | + */ |
---|
| 338 | + get_device(&func->card->dev); |
---|
298 | 339 | |
---|
299 | 340 | func->dev.parent = &card->dev; |
---|
300 | 341 | func->dev.bus = &sdio_bus_type; |
---|
.. | .. |
---|
349 | 390 | */ |
---|
350 | 391 | void sdio_remove_func(struct sdio_func *func) |
---|
351 | 392 | { |
---|
352 | | - if (!sdio_func_present(func)) |
---|
353 | | - return; |
---|
| 393 | + if (sdio_func_present(func)) |
---|
| 394 | + device_del(&func->dev); |
---|
354 | 395 | |
---|
355 | | - device_del(&func->dev); |
---|
356 | 396 | of_node_put(func->dev.of_node); |
---|
357 | 397 | put_device(&func->dev); |
---|
358 | 398 | } |
---|