Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 77b2555b52a894a2e39a42e43d993df875c46a6a 341 lines 7.9 kB view raw
1/* 2 * linux/drivers/mmc/mmc_sysfs.c 3 * 4 * Copyright (C) 2003 Russell King, All Rights Reserved. 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 version 2 as 8 * published by the Free Software Foundation. 9 * 10 * MMC sysfs/driver model support. 11 */ 12#include <linux/module.h> 13#include <linux/init.h> 14#include <linux/device.h> 15#include <linux/idr.h> 16 17#include <linux/mmc/card.h> 18#include <linux/mmc/host.h> 19 20#include "mmc.h" 21 22#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) 23#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) 24#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev) 25 26#define MMC_ATTR(name, fmt, args...) \ 27static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \ 28{ \ 29 struct mmc_card *card = dev_to_mmc_card(dev); \ 30 return sprintf(buf, fmt, args); \ 31} 32 33MMC_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1], 34 card->raw_cid[2], card->raw_cid[3]); 35MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], 36 card->raw_csd[2], card->raw_csd[3]); 37MMC_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]); 38MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year); 39MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev); 40MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev); 41MMC_ATTR(manfid, "0x%06x\n", card->cid.manfid); 42MMC_ATTR(name, "%s\n", card->cid.prod_name); 43MMC_ATTR(oemid, "0x%04x\n", card->cid.oemid); 44MMC_ATTR(serial, "0x%08x\n", card->cid.serial); 45 46#define MMC_ATTR_RO(name) __ATTR(name, S_IRUGO, mmc_##name##_show, NULL) 47 48static struct device_attribute mmc_dev_attrs[] = { 49 MMC_ATTR_RO(cid), 50 MMC_ATTR_RO(csd), 51 MMC_ATTR_RO(date), 52 MMC_ATTR_RO(fwrev), 53 MMC_ATTR_RO(hwrev), 54 MMC_ATTR_RO(manfid), 55 MMC_ATTR_RO(name), 56 MMC_ATTR_RO(oemid), 57 MMC_ATTR_RO(serial), 58 __ATTR_NULL 59}; 60 61static struct device_attribute mmc_dev_attr_scr = MMC_ATTR_RO(scr); 62 63 64static void mmc_release_card(struct device *dev) 65{ 66 struct mmc_card *card = dev_to_mmc_card(dev); 67 68 kfree(card); 69} 70 71/* 72 * This currently matches any MMC driver to any MMC card - drivers 73 * themselves make the decision whether to drive this card in their 74 * probe method. However, we force "bad" cards to fail. 75 */ 76static int mmc_bus_match(struct device *dev, struct device_driver *drv) 77{ 78 struct mmc_card *card = dev_to_mmc_card(dev); 79 return !mmc_card_bad(card); 80} 81 82static int 83mmc_bus_hotplug(struct device *dev, char **envp, int num_envp, char *buf, 84 int buf_size) 85{ 86 struct mmc_card *card = dev_to_mmc_card(dev); 87 char ccc[13]; 88 int i = 0; 89 90#define add_env(fmt,val) \ 91 ({ \ 92 int len, ret = -ENOMEM; \ 93 if (i < num_envp) { \ 94 envp[i++] = buf; \ 95 len = snprintf(buf, buf_size, fmt, val) + 1; \ 96 buf_size -= len; \ 97 buf += len; \ 98 if (buf_size >= 0) \ 99 ret = 0; \ 100 } \ 101 ret; \ 102 }) 103 104 for (i = 0; i < 12; i++) 105 ccc[i] = card->csd.cmdclass & (1 << i) ? '1' : '0'; 106 ccc[12] = '\0'; 107 108 i = 0; 109 add_env("MMC_CCC=%s", ccc); 110 add_env("MMC_MANFID=%06x", card->cid.manfid); 111 add_env("MMC_NAME=%s", mmc_card_name(card)); 112 add_env("MMC_OEMID=%04x", card->cid.oemid); 113 114 return 0; 115} 116 117static int mmc_bus_suspend(struct device *dev, pm_message_t state) 118{ 119 struct mmc_driver *drv = to_mmc_driver(dev->driver); 120 struct mmc_card *card = dev_to_mmc_card(dev); 121 int ret = 0; 122 123 if (dev->driver && drv->suspend) 124 ret = drv->suspend(card, state); 125 return ret; 126} 127 128static int mmc_bus_resume(struct device *dev) 129{ 130 struct mmc_driver *drv = to_mmc_driver(dev->driver); 131 struct mmc_card *card = dev_to_mmc_card(dev); 132 int ret = 0; 133 134 if (dev->driver && drv->resume) 135 ret = drv->resume(card); 136 return ret; 137} 138 139static struct bus_type mmc_bus_type = { 140 .name = "mmc", 141 .dev_attrs = mmc_dev_attrs, 142 .match = mmc_bus_match, 143 .hotplug = mmc_bus_hotplug, 144 .suspend = mmc_bus_suspend, 145 .resume = mmc_bus_resume, 146}; 147 148 149static int mmc_drv_probe(struct device *dev) 150{ 151 struct mmc_driver *drv = to_mmc_driver(dev->driver); 152 struct mmc_card *card = dev_to_mmc_card(dev); 153 154 return drv->probe(card); 155} 156 157static int mmc_drv_remove(struct device *dev) 158{ 159 struct mmc_driver *drv = to_mmc_driver(dev->driver); 160 struct mmc_card *card = dev_to_mmc_card(dev); 161 162 drv->remove(card); 163 164 return 0; 165} 166 167 168/** 169 * mmc_register_driver - register a media driver 170 * @drv: MMC media driver 171 */ 172int mmc_register_driver(struct mmc_driver *drv) 173{ 174 drv->drv.bus = &mmc_bus_type; 175 drv->drv.probe = mmc_drv_probe; 176 drv->drv.remove = mmc_drv_remove; 177 return driver_register(&drv->drv); 178} 179 180EXPORT_SYMBOL(mmc_register_driver); 181 182/** 183 * mmc_unregister_driver - unregister a media driver 184 * @drv: MMC media driver 185 */ 186void mmc_unregister_driver(struct mmc_driver *drv) 187{ 188 drv->drv.bus = &mmc_bus_type; 189 driver_unregister(&drv->drv); 190} 191 192EXPORT_SYMBOL(mmc_unregister_driver); 193 194 195/* 196 * Internal function. Initialise a MMC card structure. 197 */ 198void mmc_init_card(struct mmc_card *card, struct mmc_host *host) 199{ 200 memset(card, 0, sizeof(struct mmc_card)); 201 card->host = host; 202 device_initialize(&card->dev); 203 card->dev.parent = card->host->dev; 204 card->dev.bus = &mmc_bus_type; 205 card->dev.release = mmc_release_card; 206} 207 208/* 209 * Internal function. Register a new MMC card with the driver model. 210 */ 211int mmc_register_card(struct mmc_card *card) 212{ 213 int ret; 214 215 snprintf(card->dev.bus_id, sizeof(card->dev.bus_id), 216 "%s:%04x", mmc_hostname(card->host), card->rca); 217 218 ret = device_add(&card->dev); 219 if (ret == 0) { 220 if (mmc_card_sd(card)) { 221 ret = device_create_file(&card->dev, &mmc_dev_attr_scr); 222 if (ret) 223 device_del(&card->dev); 224 } 225 } 226 return ret; 227} 228 229/* 230 * Internal function. Unregister a new MMC card with the 231 * driver model, and (eventually) free it. 232 */ 233void mmc_remove_card(struct mmc_card *card) 234{ 235 if (mmc_card_present(card)) { 236 if (mmc_card_sd(card)) 237 device_remove_file(&card->dev, &mmc_dev_attr_scr); 238 239 device_del(&card->dev); 240 } 241 242 put_device(&card->dev); 243} 244 245 246static void mmc_host_classdev_release(struct class_device *dev) 247{ 248 struct mmc_host *host = cls_dev_to_mmc_host(dev); 249 kfree(host); 250} 251 252static struct class mmc_host_class = { 253 .name = "mmc_host", 254 .release = mmc_host_classdev_release, 255}; 256 257static DEFINE_IDR(mmc_host_idr); 258static DEFINE_SPINLOCK(mmc_host_lock); 259 260/* 261 * Internal function. Allocate a new MMC host. 262 */ 263struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev) 264{ 265 struct mmc_host *host; 266 267 host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); 268 if (host) { 269 memset(host, 0, sizeof(struct mmc_host) + extra); 270 271 host->dev = dev; 272 host->class_dev.dev = host->dev; 273 host->class_dev.class = &mmc_host_class; 274 class_device_initialize(&host->class_dev); 275 } 276 277 return host; 278} 279 280/* 281 * Internal function. Register a new MMC host with the MMC class. 282 */ 283int mmc_add_host_sysfs(struct mmc_host *host) 284{ 285 int err; 286 287 if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL)) 288 return -ENOMEM; 289 290 spin_lock(&mmc_host_lock); 291 err = idr_get_new(&mmc_host_idr, host, &host->index); 292 spin_unlock(&mmc_host_lock); 293 if (err) 294 return err; 295 296 snprintf(host->class_dev.class_id, BUS_ID_SIZE, 297 "mmc%d", host->index); 298 299 return class_device_add(&host->class_dev); 300} 301 302/* 303 * Internal function. Unregister a MMC host with the MMC class. 304 */ 305void mmc_remove_host_sysfs(struct mmc_host *host) 306{ 307 class_device_del(&host->class_dev); 308 309 spin_lock(&mmc_host_lock); 310 idr_remove(&mmc_host_idr, host->index); 311 spin_unlock(&mmc_host_lock); 312} 313 314/* 315 * Internal function. Free a MMC host. 316 */ 317void mmc_free_host_sysfs(struct mmc_host *host) 318{ 319 class_device_put(&host->class_dev); 320} 321 322 323static int __init mmc_init(void) 324{ 325 int ret = bus_register(&mmc_bus_type); 326 if (ret == 0) { 327 ret = class_register(&mmc_host_class); 328 if (ret) 329 bus_unregister(&mmc_bus_type); 330 } 331 return ret; 332} 333 334static void __exit mmc_exit(void) 335{ 336 class_unregister(&mmc_host_class); 337 bus_unregister(&mmc_bus_type); 338} 339 340module_init(mmc_init); 341module_exit(mmc_exit);