aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorPierre Ossman <drzeus@drzeus.cx>2007-05-19 07:39:01 -0400
committerPierre Ossman <drzeus@drzeus.cx>2007-07-09 15:27:56 -0400
commit4101c16a910b15afd190c6bc7d45864461cf5c25 (patch)
tree76d88e3bfd6723fc86c13c635b3c2b73c73c6978 /drivers
parent7de064ebc67d9baf6c933d3a7046feb9b4eced05 (diff)
mmc: refactor bus operations
Move bus operations to its own file for the sake of clarity. Also delegate sysfs attributes to bus handlers in preparation for other more exotic types. Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/core/Makefile3
-rw-r--r--drivers/mmc/core/bus.c253
-rw-r--r--drivers/mmc/core/bus.h22
-rw-r--r--drivers/mmc/core/core.c16
-rw-r--r--drivers/mmc/core/core.h4
-rw-r--r--drivers/mmc/core/mmc.c59
-rw-r--r--drivers/mmc/core/sd.c63
-rw-r--r--drivers/mmc/core/sysfs.c228
-rw-r--r--drivers/mmc/core/sysfs.h14
9 files changed, 418 insertions, 244 deletions
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
index 1075b02ae754..54261e3724c4 100644
--- a/drivers/mmc/core/Makefile
+++ b/drivers/mmc/core/Makefile
@@ -7,5 +7,6 @@ ifeq ($(CONFIG_MMC_DEBUG),y)
7endif 7endif
8 8
9obj-$(CONFIG_MMC) += mmc_core.o 9obj-$(CONFIG_MMC) += mmc_core.o
10mmc_core-y := core.o sysfs.o mmc.o mmc_ops.o sd.o sd_ops.o 10mmc_core-y := core.o sysfs.o bus.o \
11 mmc.o mmc_ops.o sd.o sd_ops.o
11 12
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
new file mode 100644
index 000000000000..348b566bf4fd
--- /dev/null
+++ b/drivers/mmc/core/bus.c
@@ -0,0 +1,253 @@
1/*
2 * linux/drivers/mmc/core/bus.c
3 *
4 * Copyright (C) 2003 Russell King, All Rights Reserved.
5 * Copyright (C) 2007 Pierre Ossman
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * MMC card bus driver model
12 */
13
14#include <linux/device.h>
15#include <linux/err.h>
16
17#include <linux/mmc/card.h>
18#include <linux/mmc/host.h>
19
20#include "sysfs.h"
21#include "core.h"
22#include "bus.h"
23
24#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev)
25#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
26
27static ssize_t mmc_type_show(struct device *dev,
28 struct device_attribute *attr, char *buf)
29{
30 struct mmc_card *card = dev_to_mmc_card(dev);
31
32 switch (card->type) {
33 case MMC_TYPE_MMC:
34 return sprintf(buf, "MMC\n");
35 case MMC_TYPE_SD:
36 return sprintf(buf, "SD\n");
37 default:
38 return -EFAULT;
39 }
40}
41
42static struct device_attribute mmc_dev_attrs[] = {
43 MMC_ATTR_RO(type),
44 __ATTR_NULL,
45};
46
47/*
48 * This currently matches any MMC driver to any MMC card - drivers
49 * themselves make the decision whether to drive this card in their
50 * probe method.
51 */
52static int mmc_bus_match(struct device *dev, struct device_driver *drv)
53{
54 return 1;
55}
56
57static int
58mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
59 int buf_size)
60{
61 struct mmc_card *card = dev_to_mmc_card(dev);
62 int retval = 0, i = 0, length = 0;
63
64#define add_env(fmt,val) do { \
65 retval = add_uevent_var(envp, num_envp, &i, \
66 buf, buf_size, &length, \
67 fmt, val); \
68 if (retval) \
69 return retval; \
70} while (0);
71
72 switch (card->type) {
73 case MMC_TYPE_MMC:
74 add_env("MMC_TYPE=%s", "MMC");
75 break;
76 case MMC_TYPE_SD:
77 add_env("MMC_TYPE=%s", "SD");
78 break;
79 }
80
81 add_env("MMC_NAME=%s", mmc_card_name(card));
82
83#undef add_env
84
85 envp[i] = NULL;
86
87 return 0;
88}
89
90static int mmc_bus_probe(struct device *dev)
91{
92 struct mmc_driver *drv = to_mmc_driver(dev->driver);
93 struct mmc_card *card = dev_to_mmc_card(dev);
94
95 return drv->probe(card);
96}
97
98static int mmc_bus_remove(struct device *dev)
99{
100 struct mmc_driver *drv = to_mmc_driver(dev->driver);
101 struct mmc_card *card = dev_to_mmc_card(dev);
102
103 drv->remove(card);
104
105 return 0;
106}
107
108static int mmc_bus_suspend(struct device *dev, pm_message_t state)
109{
110 struct mmc_driver *drv = to_mmc_driver(dev->driver);
111 struct mmc_card *card = dev_to_mmc_card(dev);
112 int ret = 0;
113
114 if (dev->driver && drv->suspend)
115 ret = drv->suspend(card, state);
116 return ret;
117}
118
119static int mmc_bus_resume(struct device *dev)
120{
121 struct mmc_driver *drv = to_mmc_driver(dev->driver);
122 struct mmc_card *card = dev_to_mmc_card(dev);
123 int ret = 0;
124
125 if (dev->driver && drv->resume)
126 ret = drv->resume(card);
127 return ret;
128}
129
130static struct bus_type mmc_bus_type = {
131 .name = "mmc",
132 .dev_attrs = mmc_dev_attrs,
133 .match = mmc_bus_match,
134 .uevent = mmc_bus_uevent,
135 .probe = mmc_bus_probe,
136 .remove = mmc_bus_remove,
137 .suspend = mmc_bus_suspend,
138 .resume = mmc_bus_resume,
139};
140
141int mmc_register_bus(void)
142{
143 return bus_register(&mmc_bus_type);
144}
145
146void mmc_unregister_bus(void)
147{
148 bus_unregister(&mmc_bus_type);
149}
150
151/**
152 * mmc_register_driver - register a media driver
153 * @drv: MMC media driver
154 */
155int mmc_register_driver(struct mmc_driver *drv)
156{
157 drv->drv.bus = &mmc_bus_type;
158 return driver_register(&drv->drv);
159}
160
161EXPORT_SYMBOL(mmc_register_driver);
162
163/**
164 * mmc_unregister_driver - unregister a media driver
165 * @drv: MMC media driver
166 */
167void mmc_unregister_driver(struct mmc_driver *drv)
168{
169 drv->drv.bus = &mmc_bus_type;
170 driver_unregister(&drv->drv);
171}
172
173EXPORT_SYMBOL(mmc_unregister_driver);
174
175static void mmc_release_card(struct device *dev)
176{
177 struct mmc_card *card = dev_to_mmc_card(dev);
178
179 kfree(card);
180}
181
182/*
183 * Allocate and initialise a new MMC card structure.
184 */
185struct mmc_card *mmc_alloc_card(struct mmc_host *host)
186{
187 struct mmc_card *card;
188
189 card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL);
190 if (!card)
191 return ERR_PTR(-ENOMEM);
192
193 memset(card, 0, sizeof(struct mmc_card));
194
195 card->host = host;
196
197 device_initialize(&card->dev);
198
199 card->dev.parent = mmc_classdev(host);
200 card->dev.bus = &mmc_bus_type;
201 card->dev.release = mmc_release_card;
202
203 return card;
204}
205
206/*
207 * Register a new MMC card with the driver model.
208 */
209int mmc_add_card(struct mmc_card *card)
210{
211 int ret;
212
213 snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
214 "%s:%04x", mmc_hostname(card->host), card->rca);
215
216 card->dev.uevent_suppress = 1;
217
218 ret = device_add(&card->dev);
219 if (ret)
220 return ret;
221
222 if (card->host->bus_ops->sysfs_add) {
223 ret = card->host->bus_ops->sysfs_add(card->host, card);
224 if (ret) {
225 device_del(&card->dev);
226 return ret;
227 }
228 }
229
230 card->dev.uevent_suppress = 0;
231
232 kobject_uevent(&card->dev.kobj, KOBJ_ADD);
233
234 mmc_card_set_present(card);
235
236 return 0;
237}
238
239/*
240 * Unregister a new MMC card with the driver model, and
241 * (eventually) free it.
242 */
243void mmc_remove_card(struct mmc_card *card)
244{
245 if (mmc_card_present(card)) {
246 if (card->host->bus_ops->sysfs_remove)
247 card->host->bus_ops->sysfs_remove(card->host, card);
248 device_del(&card->dev);
249 }
250
251 put_device(&card->dev);
252}
253
diff --git a/drivers/mmc/core/bus.h b/drivers/mmc/core/bus.h
new file mode 100644
index 000000000000..4f35431116a8
--- /dev/null
+++ b/drivers/mmc/core/bus.h
@@ -0,0 +1,22 @@
1/*
2 * linux/drivers/mmc/core/bus.h
3 *
4 * Copyright (C) 2003 Russell King, All Rights Reserved.
5 * Copyright 2007 Pierre Ossman
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#ifndef _MMC_CORE_BUS_H
12#define _MMC_CORE_BUS_H
13
14struct mmc_card *mmc_alloc_card(struct mmc_host *host);
15int mmc_add_card(struct mmc_card *card);
16void mmc_remove_card(struct mmc_card *card);
17
18int mmc_register_bus(void);
19void mmc_unregister_bus(void);
20
21#endif
22
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 7385acfa1dd9..d876adf4bd4e 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -369,22 +369,6 @@ void mmc_set_timing(struct mmc_host *host, unsigned int timing)
369} 369}
370 370
371/* 371/*
372 * Allocate a new MMC card
373 */
374struct mmc_card *mmc_alloc_card(struct mmc_host *host)
375{
376 struct mmc_card *card;
377
378 card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL);
379 if (!card)
380 return ERR_PTR(-ENOMEM);
381
382 mmc_init_card(card, host);
383
384 return card;
385}
386
387/*
388 * Apply power to the MMC stack. This is a two-stage process. 372 * Apply power to the MMC stack. This is a two-stage process.
389 * First, we enable power to the card without the clock running. 373 * First, we enable power to the card without the clock running.
390 * We then wait a bit for the power to stabilise. Finally, 374 * We then wait a bit for the power to stabilise. Finally,
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 177264d090ac..1be86c792a52 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -18,6 +18,8 @@
18struct mmc_bus_ops { 18struct mmc_bus_ops {
19 void (*remove)(struct mmc_host *); 19 void (*remove)(struct mmc_host *);
20 void (*detect)(struct mmc_host *); 20 void (*detect)(struct mmc_host *);
21 int (*sysfs_add)(struct mmc_host *, struct mmc_card *card);
22 void (*sysfs_remove)(struct mmc_host *, struct mmc_card *card);
21 void (*suspend)(struct mmc_host *); 23 void (*suspend)(struct mmc_host *);
22 void (*resume)(struct mmc_host *); 24 void (*resume)(struct mmc_host *);
23}; 25};
@@ -54,8 +56,6 @@ void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
54u32 mmc_select_voltage(struct mmc_host *host, u32 ocr); 56u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
55void mmc_set_timing(struct mmc_host *host, unsigned int timing); 57void mmc_set_timing(struct mmc_host *host, unsigned int timing);
56 58
57struct mmc_card *mmc_alloc_card(struct mmc_host *host);
58
59static inline void mmc_delay(unsigned int ms) 59static inline void mmc_delay(unsigned int ms)
60{ 60{
61 if (ms < 1000 / HZ) { 61 if (ms < 1000 / HZ) {
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 42cc2867ed7d..e4371555160a 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -18,6 +18,7 @@
18 18
19#include "core.h" 19#include "core.h"
20#include "sysfs.h" 20#include "sysfs.h"
21#include "bus.h"
21#include "mmc_ops.h" 22#include "mmc_ops.h"
22 23
23static const unsigned int tran_exp[] = { 24static const unsigned int tran_exp[] = {
@@ -413,8 +414,7 @@ static void mmc_detect(struct mmc_host *host)
413 mmc_release_host(host); 414 mmc_release_host(host);
414 415
415 if (err != MMC_ERR_NONE) { 416 if (err != MMC_ERR_NONE) {
416 mmc_remove_card(host->card); 417 mmc_remove(host);
417 host->card = NULL;
418 418
419 mmc_claim_host(host); 419 mmc_claim_host(host);
420 mmc_detach_bus(host); 420 mmc_detach_bus(host);
@@ -422,6 +422,53 @@ static void mmc_detect(struct mmc_host *host)
422 } 422 }
423} 423}
424 424
425MMC_ATTR_FN(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
426 card->raw_cid[2], card->raw_cid[3]);
427MMC_ATTR_FN(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
428 card->raw_csd[2], card->raw_csd[3]);
429MMC_ATTR_FN(date, "%02d/%04d\n", card->cid.month, card->cid.year);
430MMC_ATTR_FN(fwrev, "0x%x\n", card->cid.fwrev);
431MMC_ATTR_FN(hwrev, "0x%x\n", card->cid.hwrev);
432MMC_ATTR_FN(manfid, "0x%06x\n", card->cid.manfid);
433MMC_ATTR_FN(name, "%s\n", card->cid.prod_name);
434MMC_ATTR_FN(oemid, "0x%04x\n", card->cid.oemid);
435MMC_ATTR_FN(serial, "0x%08x\n", card->cid.serial);
436
437static struct device_attribute mmc_dev_attrs[] = {
438 MMC_ATTR_RO(cid),
439 MMC_ATTR_RO(csd),
440 MMC_ATTR_RO(date),
441 MMC_ATTR_RO(fwrev),
442 MMC_ATTR_RO(hwrev),
443 MMC_ATTR_RO(manfid),
444 MMC_ATTR_RO(name),
445 MMC_ATTR_RO(oemid),
446 MMC_ATTR_RO(serial),
447 __ATTR_NULL,
448};
449
450/*
451 * Adds sysfs entries as relevant.
452 */
453static int mmc_sysfs_add(struct mmc_host *host, struct mmc_card *card)
454{
455 int ret;
456
457 ret = mmc_add_attrs(card, mmc_dev_attrs);
458 if (ret < 0)
459 return ret;
460
461 return 0;
462}
463
464/*
465 * Removes the sysfs entries added by mmc_sysfs_add().
466 */
467static void mmc_sysfs_remove(struct mmc_host *host, struct mmc_card *card)
468{
469 mmc_remove_attrs(card, mmc_dev_attrs);
470}
471
425#ifdef CONFIG_MMC_UNSAFE_RESUME 472#ifdef CONFIG_MMC_UNSAFE_RESUME
426 473
427/* 474/*
@@ -455,9 +502,7 @@ static void mmc_resume(struct mmc_host *host)
455 502
456 err = mmc_sd_init_card(host, host->ocr, host->card); 503 err = mmc_sd_init_card(host, host->ocr, host->card);
457 if (err != MMC_ERR_NONE) { 504 if (err != MMC_ERR_NONE) {
458 mmc_remove_card(host->card); 505 mmc_remove(host);
459 host->card = NULL;
460
461 mmc_detach_bus(host); 506 mmc_detach_bus(host);
462 } 507 }
463 508
@@ -474,6 +519,8 @@ static void mmc_resume(struct mmc_host *host)
474static const struct mmc_bus_ops mmc_ops = { 519static const struct mmc_bus_ops mmc_ops = {
475 .remove = mmc_remove, 520 .remove = mmc_remove,
476 .detect = mmc_detect, 521 .detect = mmc_detect,
522 .sysfs_add = mmc_sysfs_add,
523 .sysfs_remove = mmc_sysfs_remove,
477 .suspend = mmc_suspend, 524 .suspend = mmc_suspend,
478 .resume = mmc_resume, 525 .resume = mmc_resume,
479}; 526};
@@ -518,7 +565,7 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
518 565
519 mmc_release_host(host); 566 mmc_release_host(host);
520 567
521 err = mmc_register_card(host->card); 568 err = mmc_add_card(host->card);
522 if (err) 569 if (err)
523 goto reclaim_host; 570 goto reclaim_host;
524 571
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 918477c490b0..1240684083f1 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -19,11 +19,10 @@
19 19
20#include "core.h" 20#include "core.h"
21#include "sysfs.h" 21#include "sysfs.h"
22#include "bus.h"
22#include "mmc_ops.h" 23#include "mmc_ops.h"
23#include "sd_ops.h" 24#include "sd_ops.h"
24 25
25#include "core.h"
26
27static const unsigned int tran_exp[] = { 26static const unsigned int tran_exp[] = {
28 10000, 100000, 1000000, 10000000, 27 10000, 100000, 1000000, 10000000,
29 0, 0, 0, 0 28 0, 0, 0, 0
@@ -487,8 +486,7 @@ static void mmc_sd_detect(struct mmc_host *host)
487 mmc_release_host(host); 486 mmc_release_host(host);
488 487
489 if (err != MMC_ERR_NONE) { 488 if (err != MMC_ERR_NONE) {
490 mmc_remove_card(host->card); 489 mmc_sd_remove(host);
491 host->card = NULL;
492 490
493 mmc_claim_host(host); 491 mmc_claim_host(host);
494 mmc_detach_bus(host); 492 mmc_detach_bus(host);
@@ -496,6 +494,55 @@ static void mmc_sd_detect(struct mmc_host *host)
496 } 494 }
497} 495}
498 496
497MMC_ATTR_FN(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
498 card->raw_cid[2], card->raw_cid[3]);
499MMC_ATTR_FN(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
500 card->raw_csd[2], card->raw_csd[3]);
501MMC_ATTR_FN(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
502MMC_ATTR_FN(date, "%02d/%04d\n", card->cid.month, card->cid.year);
503MMC_ATTR_FN(fwrev, "0x%x\n", card->cid.fwrev);
504MMC_ATTR_FN(hwrev, "0x%x\n", card->cid.hwrev);
505MMC_ATTR_FN(manfid, "0x%06x\n", card->cid.manfid);
506MMC_ATTR_FN(name, "%s\n", card->cid.prod_name);
507MMC_ATTR_FN(oemid, "0x%04x\n", card->cid.oemid);
508MMC_ATTR_FN(serial, "0x%08x\n", card->cid.serial);
509
510static struct device_attribute mmc_sd_dev_attrs[] = {
511 MMC_ATTR_RO(cid),
512 MMC_ATTR_RO(csd),
513 MMC_ATTR_RO(scr),
514 MMC_ATTR_RO(date),
515 MMC_ATTR_RO(fwrev),
516 MMC_ATTR_RO(hwrev),
517 MMC_ATTR_RO(manfid),
518 MMC_ATTR_RO(name),
519 MMC_ATTR_RO(oemid),
520 MMC_ATTR_RO(serial),
521 __ATTR_NULL,
522};
523
524/*
525 * Adds sysfs entries as relevant.
526 */
527static int mmc_sd_sysfs_add(struct mmc_host *host, struct mmc_card *card)
528{
529 int ret;
530
531 ret = mmc_add_attrs(card, mmc_sd_dev_attrs);
532 if (ret < 0)
533 return ret;
534
535 return 0;
536}
537
538/*
539 * Removes the sysfs entries added by mmc_sysfs_add().
540 */
541static void mmc_sd_sysfs_remove(struct mmc_host *host, struct mmc_card *card)
542{
543 mmc_remove_attrs(card, mmc_sd_dev_attrs);
544}
545
499#ifdef CONFIG_MMC_UNSAFE_RESUME 546#ifdef CONFIG_MMC_UNSAFE_RESUME
500 547
501/* 548/*
@@ -529,9 +576,7 @@ static void mmc_sd_resume(struct mmc_host *host)
529 576
530 err = mmc_sd_init_card(host, host->ocr, host->card); 577 err = mmc_sd_init_card(host, host->ocr, host->card);
531 if (err != MMC_ERR_NONE) { 578 if (err != MMC_ERR_NONE) {
532 mmc_remove_card(host->card); 579 mmc_sd_remove(host);
533 host->card = NULL;
534
535 mmc_detach_bus(host); 580 mmc_detach_bus(host);
536 } 581 }
537 582
@@ -548,6 +593,8 @@ static void mmc_sd_resume(struct mmc_host *host)
548static const struct mmc_bus_ops mmc_sd_ops = { 593static const struct mmc_bus_ops mmc_sd_ops = {
549 .remove = mmc_sd_remove, 594 .remove = mmc_sd_remove,
550 .detect = mmc_sd_detect, 595 .detect = mmc_sd_detect,
596 .sysfs_add = mmc_sd_sysfs_add,
597 .sysfs_remove = mmc_sd_sysfs_remove,
551 .suspend = mmc_sd_suspend, 598 .suspend = mmc_sd_suspend,
552 .resume = mmc_sd_resume, 599 .resume = mmc_sd_resume,
553}; 600};
@@ -599,7 +646,7 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
599 646
600 mmc_release_host(host); 647 mmc_release_host(host);
601 648
602 err = mmc_register_card(host->card); 649 err = mmc_add_card(host->card);
603 if (err) 650 if (err)
604 goto reclaim_host; 651 goto reclaim_host;
605 652
diff --git a/drivers/mmc/core/sysfs.c b/drivers/mmc/core/sysfs.c
index 843b1fbba557..a43a96c22811 100644
--- a/drivers/mmc/core/sysfs.c
+++ b/drivers/mmc/core/sysfs.c
@@ -2,6 +2,7 @@
2 * linux/drivers/mmc/core/sysfs.c 2 * linux/drivers/mmc/core/sysfs.c
3 * 3 *
4 * Copyright (C) 2003 Russell King, All Rights Reserved. 4 * Copyright (C) 2003 Russell King, All Rights Reserved.
5 * Copyright 2007 Pierre Ossman
5 * 6 *
6 * This program is free software; you can redistribute it and/or modify 7 * 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 * it under the terms of the GNU General Public License version 2 as
@@ -18,226 +19,37 @@
18#include <linux/mmc/card.h> 19#include <linux/mmc/card.h>
19#include <linux/mmc/host.h> 20#include <linux/mmc/host.h>
20 21
22#include "bus.h"
21#include "sysfs.h" 23#include "sysfs.h"
22 24
23#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev)
24#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) 25#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
25#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev) 26#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
26 27
27#define MMC_ATTR(name, fmt, args...) \ 28int mmc_add_attrs(struct mmc_card *card, struct device_attribute *attrs)
28static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \
29{ \
30 struct mmc_card *card = dev_to_mmc_card(dev); \
31 return sprintf(buf, fmt, args); \
32}
33
34MMC_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
35 card->raw_cid[2], card->raw_cid[3]);
36MMC_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
37 card->raw_csd[2], card->raw_csd[3]);
38MMC_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
39MMC_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
40MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
41MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
42MMC_ATTR(manfid, "0x%06x\n", card->cid.manfid);
43MMC_ATTR(name, "%s\n", card->cid.prod_name);
44MMC_ATTR(oemid, "0x%04x\n", card->cid.oemid);
45MMC_ATTR(serial, "0x%08x\n", card->cid.serial);
46
47#define MMC_ATTR_RO(name) __ATTR(name, S_IRUGO, mmc_##name##_show, NULL)
48
49static struct device_attribute mmc_dev_attrs[] = {
50 MMC_ATTR_RO(cid),
51 MMC_ATTR_RO(csd),
52 MMC_ATTR_RO(date),
53 MMC_ATTR_RO(fwrev),
54 MMC_ATTR_RO(hwrev),
55 MMC_ATTR_RO(manfid),
56 MMC_ATTR_RO(name),
57 MMC_ATTR_RO(oemid),
58 MMC_ATTR_RO(serial),
59 __ATTR_NULL
60};
61
62static struct device_attribute mmc_dev_attr_scr = MMC_ATTR_RO(scr);
63
64
65static void mmc_release_card(struct device *dev)
66{ 29{
67 struct mmc_card *card = dev_to_mmc_card(dev); 30 int error = 0;
68 31 int i;
69 kfree(card);
70}
71
72/*
73 * This currently matches any MMC driver to any MMC card - drivers
74 * themselves make the decision whether to drive this card in their
75 * probe method.
76 */
77static int mmc_bus_match(struct device *dev, struct device_driver *drv)
78{
79 return 1;
80}
81
82static int
83mmc_bus_uevent(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 retval = 0, i = 0, length = 0;
89
90#define add_env(fmt,val) do { \
91 retval = add_uevent_var(envp, num_envp, &i, \
92 buf, buf_size, &length, \
93 fmt, val); \
94 if (retval) \
95 return retval; \
96} while (0);
97
98 for (i = 0; i < 12; i++)
99 ccc[i] = card->csd.cmdclass & (1 << i) ? '1' : '0';
100 ccc[12] = '\0';
101 32
102 add_env("MMC_CCC=%s", ccc); 33 for (i = 0; attr_name(attrs[i]); i++) {
103 add_env("MMC_MANFID=%06x", card->cid.manfid); 34 error = device_create_file(&card->dev, &attrs[i]);
104 add_env("MMC_NAME=%s", mmc_card_name(card)); 35 if (error) {
105 add_env("MMC_OEMID=%04x", card->cid.oemid); 36 while (--i >= 0)
106#undef add_env 37 device_remove_file(&card->dev, &attrs[i]);
107 envp[i] = NULL; 38 break;
108
109 return 0;
110}
111
112static int mmc_bus_suspend(struct device *dev, pm_message_t state)
113{
114 struct mmc_driver *drv = to_mmc_driver(dev->driver);
115 struct mmc_card *card = dev_to_mmc_card(dev);
116 int ret = 0;
117
118 if (dev->driver && drv->suspend)
119 ret = drv->suspend(card, state);
120 return ret;
121}
122
123static int mmc_bus_resume(struct device *dev)
124{
125 struct mmc_driver *drv = to_mmc_driver(dev->driver);
126 struct mmc_card *card = dev_to_mmc_card(dev);
127 int ret = 0;
128
129 if (dev->driver && drv->resume)
130 ret = drv->resume(card);
131 return ret;
132}
133
134static int mmc_bus_probe(struct device *dev)
135{
136 struct mmc_driver *drv = to_mmc_driver(dev->driver);
137 struct mmc_card *card = dev_to_mmc_card(dev);
138
139 return drv->probe(card);
140}
141
142static int mmc_bus_remove(struct device *dev)
143{
144 struct mmc_driver *drv = to_mmc_driver(dev->driver);
145 struct mmc_card *card = dev_to_mmc_card(dev);
146
147 drv->remove(card);
148
149 return 0;
150}
151
152static struct bus_type mmc_bus_type = {
153 .name = "mmc",
154 .dev_attrs = mmc_dev_attrs,
155 .match = mmc_bus_match,
156 .uevent = mmc_bus_uevent,
157 .probe = mmc_bus_probe,
158 .remove = mmc_bus_remove,
159 .suspend = mmc_bus_suspend,
160 .resume = mmc_bus_resume,
161};
162
163/**
164 * mmc_register_driver - register a media driver
165 * @drv: MMC media driver
166 */
167int mmc_register_driver(struct mmc_driver *drv)
168{
169 drv->drv.bus = &mmc_bus_type;
170 return driver_register(&drv->drv);
171}
172
173EXPORT_SYMBOL(mmc_register_driver);
174
175/**
176 * mmc_unregister_driver - unregister a media driver
177 * @drv: MMC media driver
178 */
179void mmc_unregister_driver(struct mmc_driver *drv)
180{
181 drv->drv.bus = &mmc_bus_type;
182 driver_unregister(&drv->drv);
183}
184
185EXPORT_SYMBOL(mmc_unregister_driver);
186
187
188/*
189 * Internal function. Initialise a MMC card structure.
190 */
191void mmc_init_card(struct mmc_card *card, struct mmc_host *host)
192{
193 memset(card, 0, sizeof(struct mmc_card));
194 card->host = host;
195 device_initialize(&card->dev);
196 card->dev.parent = mmc_classdev(host);
197 card->dev.bus = &mmc_bus_type;
198 card->dev.release = mmc_release_card;
199}
200
201/*
202 * Internal function. Register a new MMC card with the driver model.
203 */
204int mmc_register_card(struct mmc_card *card)
205{
206 int ret;
207
208 snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
209 "%s:%04x", mmc_hostname(card->host), card->rca);
210
211 ret = device_add(&card->dev);
212 if (ret == 0) {
213 if (mmc_card_sd(card)) {
214 ret = device_create_file(&card->dev, &mmc_dev_attr_scr);
215 if (ret)
216 device_del(&card->dev);
217 } 39 }
218 } 40 }
219 if (ret == 0) 41
220 mmc_card_set_present(card); 42 return error;
221 return ret;
222} 43}
223 44
224/* 45void mmc_remove_attrs(struct mmc_card *card, struct device_attribute *attrs)
225 * Internal function. Unregister a new MMC card with the
226 * driver model, and (eventually) free it.
227 */
228void mmc_remove_card(struct mmc_card *card)
229{ 46{
230 if (mmc_card_present(card)) { 47 int i;
231 if (mmc_card_sd(card))
232 device_remove_file(&card->dev, &mmc_dev_attr_scr);
233
234 device_del(&card->dev);
235 }
236 48
237 put_device(&card->dev); 49 for (i = 0; attr_name(attrs[i]); i++)
50 device_remove_file(&card->dev, &attrs[i]);
238} 51}
239 52
240
241static void mmc_host_classdev_release(struct device *dev) 53static void mmc_host_classdev_release(struct device *dev)
242{ 54{
243 struct mmc_host *host = cls_dev_to_mmc_host(dev); 55 struct mmc_host *host = cls_dev_to_mmc_host(dev);
@@ -340,11 +152,11 @@ static int __init mmc_init(void)
340 if (!workqueue) 152 if (!workqueue)
341 return -ENOMEM; 153 return -ENOMEM;
342 154
343 ret = bus_register(&mmc_bus_type); 155 ret = mmc_register_bus();
344 if (ret == 0) { 156 if (ret == 0) {
345 ret = class_register(&mmc_host_class); 157 ret = class_register(&mmc_host_class);
346 if (ret) 158 if (ret)
347 bus_unregister(&mmc_bus_type); 159 mmc_unregister_bus();
348 } 160 }
349 return ret; 161 return ret;
350} 162}
@@ -352,7 +164,7 @@ static int __init mmc_init(void)
352static void __exit mmc_exit(void) 164static void __exit mmc_exit(void)
353{ 165{
354 class_unregister(&mmc_host_class); 166 class_unregister(&mmc_host_class);
355 bus_unregister(&mmc_bus_type); 167 mmc_unregister_bus();
356 destroy_workqueue(workqueue); 168 destroy_workqueue(workqueue);
357} 169}
358 170
diff --git a/drivers/mmc/core/sysfs.h b/drivers/mmc/core/sysfs.h
index 80e29b358282..2a326a5b83c6 100644
--- a/drivers/mmc/core/sysfs.h
+++ b/drivers/mmc/core/sysfs.h
@@ -11,9 +11,17 @@
11#ifndef _MMC_CORE_SYSFS_H 11#ifndef _MMC_CORE_SYSFS_H
12#define _MMC_CORE_SYSFS_H 12#define _MMC_CORE_SYSFS_H
13 13
14void mmc_init_card(struct mmc_card *card, struct mmc_host *host); 14#define MMC_ATTR_FN(name, fmt, args...) \
15int mmc_register_card(struct mmc_card *card); 15static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \
16void mmc_remove_card(struct mmc_card *card); 16{ \
17 struct mmc_card *card = container_of(dev, struct mmc_card, dev);\
18 return sprintf(buf, fmt, args); \
19}
20
21#define MMC_ATTR_RO(name) __ATTR(name, S_IRUGO, mmc_##name##_show, NULL)
22
23int mmc_add_attrs(struct mmc_card *card, struct device_attribute *attrs);
24void mmc_remove_attrs(struct mmc_card *card, struct device_attribute *attrs);
17 25
18struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev); 26struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev);
19int mmc_add_host_sysfs(struct mmc_host *host); 27int mmc_add_host_sysfs(struct mmc_host *host);