| .. | .. |
|---|
| 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); |
|---|
| 268 | 297 | |
|---|
| 269 | 298 | kfree(func->info); |
|---|
| 270 | 299 | kfree(func->tmpbuf); |
|---|