aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/core')
-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.c147
-rw-r--r--drivers/mmc/core/core.h8
-rw-r--r--drivers/mmc/core/host.c156
-rw-r--r--drivers/mmc/core/host.h18
-rw-r--r--drivers/mmc/core/mmc.c65
-rw-r--r--drivers/mmc/core/sd.c63
-rw-r--r--drivers/mmc/core/sysfs.c347
-rw-r--r--drivers/mmc/core/sysfs.h19
11 files changed, 645 insertions, 456 deletions
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
index 1075b02ae754..3fdd08c7f143 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 host.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..b5d8a6d90cca 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -27,7 +27,8 @@
27#include <linux/mmc/sd.h> 27#include <linux/mmc/sd.h>
28 28
29#include "core.h" 29#include "core.h"
30#include "sysfs.h" 30#include "bus.h"
31#include "host.h"
31 32
32#include "mmc_ops.h" 33#include "mmc_ops.h"
33#include "sd_ops.h" 34#include "sd_ops.h"
@@ -35,6 +36,25 @@
35extern int mmc_attach_mmc(struct mmc_host *host, u32 ocr); 36extern int mmc_attach_mmc(struct mmc_host *host, u32 ocr);
36extern int mmc_attach_sd(struct mmc_host *host, u32 ocr); 37extern int mmc_attach_sd(struct mmc_host *host, u32 ocr);
37 38
39static struct workqueue_struct *workqueue;
40
41/*
42 * Internal function. Schedule delayed work in the MMC work queue.
43 */
44static int mmc_schedule_delayed_work(struct delayed_work *work,
45 unsigned long delay)
46{
47 return queue_delayed_work(workqueue, work, delay);
48}
49
50/*
51 * Internal function. Flush all scheduled work from the MMC work queue.
52 */
53static void mmc_flush_scheduled_work(void)
54{
55 flush_workqueue(workqueue);
56}
57
38/** 58/**
39 * mmc_request_done - finish processing an MMC request 59 * mmc_request_done - finish processing an MMC request
40 * @host: MMC host which completed request 60 * @host: MMC host which completed request
@@ -369,22 +389,6 @@ void mmc_set_timing(struct mmc_host *host, unsigned int timing)
369} 389}
370 390
371/* 391/*
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. 392 * Apply power to the MMC stack. This is a two-stage process.
389 * First, we enable power to the card without the clock running. 393 * First, we enable power to the card without the clock running.
390 * We then wait a bit for the power to stabilise. Finally, 394 * We then wait a bit for the power to stabilise. Finally,
@@ -512,7 +516,7 @@ void mmc_detect_change(struct mmc_host *host, unsigned long delay)
512EXPORT_SYMBOL(mmc_detect_change); 516EXPORT_SYMBOL(mmc_detect_change);
513 517
514 518
515static void mmc_rescan(struct work_struct *work) 519void mmc_rescan(struct work_struct *work)
516{ 520{
517 struct mmc_host *host = 521 struct mmc_host *host =
518 container_of(work, struct mmc_host, detect.work); 522 container_of(work, struct mmc_host, detect.work);
@@ -561,69 +565,13 @@ static void mmc_rescan(struct work_struct *work)
561 } 565 }
562} 566}
563 567
564 568void mmc_start_host(struct mmc_host *host)
565/**
566 * mmc_alloc_host - initialise the per-host structure.
567 * @extra: sizeof private data structure
568 * @dev: pointer to host device model structure
569 *
570 * Initialise the per-host structure.
571 */
572struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
573{ 569{
574 struct mmc_host *host; 570 mmc_power_off(host);
575 571 mmc_detect_change(host, 0);
576 host = mmc_alloc_host_sysfs(extra, dev);
577 if (host) {
578 spin_lock_init(&host->lock);
579 init_waitqueue_head(&host->wq);
580 INIT_DELAYED_WORK(&host->detect, mmc_rescan);
581
582 /*
583 * By default, hosts do not support SGIO or large requests.
584 * They have to set these according to their abilities.
585 */
586 host->max_hw_segs = 1;
587 host->max_phys_segs = 1;
588 host->max_seg_size = PAGE_CACHE_SIZE;
589
590 host->max_req_size = PAGE_CACHE_SIZE;
591 host->max_blk_size = 512;
592 host->max_blk_count = PAGE_CACHE_SIZE / 512;
593 }
594
595 return host;
596}
597
598EXPORT_SYMBOL(mmc_alloc_host);
599
600/**
601 * mmc_add_host - initialise host hardware
602 * @host: mmc host
603 */
604int mmc_add_host(struct mmc_host *host)
605{
606 int ret;
607
608 ret = mmc_add_host_sysfs(host);
609 if (ret == 0) {
610 mmc_power_off(host);
611 mmc_detect_change(host, 0);
612 }
613
614 return ret;
615} 572}
616 573
617EXPORT_SYMBOL(mmc_add_host); 574void mmc_stop_host(struct mmc_host *host)
618
619/**
620 * mmc_remove_host - remove host hardware
621 * @host: mmc host
622 *
623 * Unregister and remove all cards associated with this host,
624 * and power down the MMC bus.
625 */
626void mmc_remove_host(struct mmc_host *host)
627{ 575{
628#ifdef CONFIG_MMC_DEBUG 576#ifdef CONFIG_MMC_DEBUG
629 unsigned long flags; 577 unsigned long flags;
@@ -648,24 +596,8 @@ void mmc_remove_host(struct mmc_host *host)
648 BUG_ON(host->card); 596 BUG_ON(host->card);
649 597
650 mmc_power_off(host); 598 mmc_power_off(host);
651 mmc_remove_host_sysfs(host);
652} 599}
653 600
654EXPORT_SYMBOL(mmc_remove_host);
655
656/**
657 * mmc_free_host - free the host structure
658 * @host: mmc host
659 *
660 * Free the host once all references to it have been dropped.
661 */
662void mmc_free_host(struct mmc_host *host)
663{
664 mmc_free_host_sysfs(host);
665}
666
667EXPORT_SYMBOL(mmc_free_host);
668
669#ifdef CONFIG_PM 601#ifdef CONFIG_PM
670 602
671/** 603/**
@@ -726,4 +658,31 @@ EXPORT_SYMBOL(mmc_resume_host);
726 658
727#endif 659#endif
728 660
661static int __init mmc_init(void)
662{
663 int ret;
664
665 workqueue = create_singlethread_workqueue("kmmcd");
666 if (!workqueue)
667 return -ENOMEM;
668
669 ret = mmc_register_bus();
670 if (ret == 0) {
671 ret = mmc_register_host_class();
672 if (ret)
673 mmc_unregister_bus();
674 }
675 return ret;
676}
677
678static void __exit mmc_exit(void)
679{
680 mmc_unregister_host_class();
681 mmc_unregister_bus();
682 destroy_workqueue(workqueue);
683}
684
685module_init(mmc_init);
686module_exit(mmc_exit);
687
729MODULE_LICENSE("GPL"); 688MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 177264d090ac..ae006b30dd86 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) {
@@ -66,5 +66,9 @@ static inline void mmc_delay(unsigned int ms)
66 } 66 }
67} 67}
68 68
69void mmc_rescan(struct work_struct *work);
70void mmc_start_host(struct mmc_host *host);
71void mmc_stop_host(struct mmc_host *host);
72
69#endif 73#endif
70 74
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
new file mode 100644
index 000000000000..1433d95c40bb
--- /dev/null
+++ b/drivers/mmc/core/host.c
@@ -0,0 +1,156 @@
1/*
2 * linux/drivers/mmc/core/host.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 host class device management
12 */
13
14#include <linux/device.h>
15#include <linux/err.h>
16#include <linux/idr.h>
17#include <linux/pagemap.h>
18
19#include <linux/mmc/host.h>
20
21#include "core.h"
22#include "host.h"
23
24#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
25
26static void mmc_host_classdev_release(struct device *dev)
27{
28 struct mmc_host *host = cls_dev_to_mmc_host(dev);
29 kfree(host);
30}
31
32static struct class mmc_host_class = {
33 .name = "mmc_host",
34 .dev_release = mmc_host_classdev_release,
35};
36
37int mmc_register_host_class(void)
38{
39 return class_register(&mmc_host_class);
40}
41
42void mmc_unregister_host_class(void)
43{
44 class_unregister(&mmc_host_class);
45}
46
47static DEFINE_IDR(mmc_host_idr);
48static DEFINE_SPINLOCK(mmc_host_lock);
49
50/**
51 * mmc_alloc_host - initialise the per-host structure.
52 * @extra: sizeof private data structure
53 * @dev: pointer to host device model structure
54 *
55 * Initialise the per-host structure.
56 */
57struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
58{
59 struct mmc_host *host;
60
61 host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
62 if (!host)
63 return NULL;
64
65 memset(host, 0, sizeof(struct mmc_host) + extra);
66
67 host->parent = dev;
68 host->class_dev.parent = dev;
69 host->class_dev.class = &mmc_host_class;
70 device_initialize(&host->class_dev);
71
72 spin_lock_init(&host->lock);
73 init_waitqueue_head(&host->wq);
74 INIT_DELAYED_WORK(&host->detect, mmc_rescan);
75
76 /*
77 * By default, hosts do not support SGIO or large requests.
78 * They have to set these according to their abilities.
79 */
80 host->max_hw_segs = 1;
81 host->max_phys_segs = 1;
82 host->max_seg_size = PAGE_CACHE_SIZE;
83
84 host->max_req_size = PAGE_CACHE_SIZE;
85 host->max_blk_size = 512;
86 host->max_blk_count = PAGE_CACHE_SIZE / 512;
87
88 return host;
89}
90
91EXPORT_SYMBOL(mmc_alloc_host);
92
93/**
94 * mmc_add_host - initialise host hardware
95 * @host: mmc host
96 */
97int mmc_add_host(struct mmc_host *host)
98{
99 int err;
100
101 if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
102 return -ENOMEM;
103
104 spin_lock(&mmc_host_lock);
105 err = idr_get_new(&mmc_host_idr, host, &host->index);
106 spin_unlock(&mmc_host_lock);
107 if (err)
108 return err;
109
110 snprintf(host->class_dev.bus_id, BUS_ID_SIZE,
111 "mmc%d", host->index);
112
113 err = device_add(&host->class_dev);
114 if (err)
115 return err;
116
117 mmc_start_host(host);
118
119 return 0;
120}
121
122EXPORT_SYMBOL(mmc_add_host);
123
124/**
125 * mmc_remove_host - remove host hardware
126 * @host: mmc host
127 *
128 * Unregister and remove all cards associated with this host,
129 * and power down the MMC bus.
130 */
131void mmc_remove_host(struct mmc_host *host)
132{
133 mmc_stop_host(host);
134
135 device_del(&host->class_dev);
136
137 spin_lock(&mmc_host_lock);
138 idr_remove(&mmc_host_idr, host->index);
139 spin_unlock(&mmc_host_lock);
140}
141
142EXPORT_SYMBOL(mmc_remove_host);
143
144/**
145 * mmc_free_host - free the host structure
146 * @host: mmc host
147 *
148 * Free the host once all references to it have been dropped.
149 */
150void mmc_free_host(struct mmc_host *host)
151{
152 put_device(&host->class_dev);
153}
154
155EXPORT_SYMBOL(mmc_free_host);
156
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
new file mode 100644
index 000000000000..c2dc3d2d9f9a
--- /dev/null
+++ b/drivers/mmc/core/host.h
@@ -0,0 +1,18 @@
1/*
2 * linux/drivers/mmc/core/host.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_HOST_H
12#define _MMC_CORE_HOST_H
13
14int mmc_register_host_class(void);
15void mmc_unregister_host_class(void);
16
17#endif
18
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 42cc2867ed7d..66f85bfa8dbb 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[] = {
@@ -236,7 +237,7 @@ out:
236 * In the case of a resume, "curcard" will contain the card 237 * In the case of a resume, "curcard" will contain the card
237 * we're trying to reinitialise. 238 * we're trying to reinitialise.
238 */ 239 */
239static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, 240static int mmc_init_card(struct mmc_host *host, u32 ocr,
240 struct mmc_card *oldcard) 241 struct mmc_card *oldcard)
241{ 242{
242 struct mmc_card *card; 243 struct mmc_card *card;
@@ -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/*
@@ -453,11 +500,9 @@ static void mmc_resume(struct mmc_host *host)
453 500
454 mmc_claim_host(host); 501 mmc_claim_host(host);
455 502
456 err = mmc_sd_init_card(host, host->ocr, host->card); 503 err = mmc_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};
@@ -512,13 +559,13 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
512 /* 559 /*
513 * Detect and init the card. 560 * Detect and init the card.
514 */ 561 */
515 err = mmc_sd_init_card(host, host->ocr, NULL); 562 err = mmc_init_card(host, host->ocr, NULL);
516 if (err != MMC_ERR_NONE) 563 if (err != MMC_ERR_NONE)
517 goto err; 564 goto err;
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..00a97e70f914 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
@@ -9,352 +10,34 @@
9 * 10 *
10 * MMC sysfs/driver model support. 11 * MMC sysfs/driver model support.
11 */ 12 */
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/device.h> 13#include <linux/device.h>
15#include <linux/idr.h>
16#include <linux/workqueue.h>
17 14
18#include <linux/mmc/card.h> 15#include <linux/mmc/card.h>
19#include <linux/mmc/host.h>
20 16
21#include "sysfs.h" 17#include "sysfs.h"
22 18
23#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) 19int mmc_add_attrs(struct mmc_card *card, struct device_attribute *attrs)
24#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
27#define MMC_ATTR(name, fmt, args...) \
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{
67 struct mmc_card *card = dev_to_mmc_card(dev);
68
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
102 add_env("MMC_CCC=%s", ccc);
103 add_env("MMC_MANFID=%06x", card->cid.manfid);
104 add_env("MMC_NAME=%s", mmc_card_name(card));
105 add_env("MMC_OEMID=%04x", card->cid.oemid);
106#undef add_env
107 envp[i] = NULL;
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{ 20{
206 int ret; 21 int error = 0;
22 int i;
207 23
208 snprintf(card->dev.bus_id, sizeof(card->dev.bus_id), 24 for (i = 0; attr_name(attrs[i]); i++) {
209 "%s:%04x", mmc_hostname(card->host), card->rca); 25 error = device_create_file(&card->dev, &attrs[i]);
210 26 if (error) {
211 ret = device_add(&card->dev); 27 while (--i >= 0)
212 if (ret == 0) { 28 device_remove_file(&card->dev, &attrs[i]);
213 if (mmc_card_sd(card)) { 29 break;
214 ret = device_create_file(&card->dev, &mmc_dev_attr_scr);
215 if (ret)
216 device_del(&card->dev);
217 } 30 }
218 } 31 }
219 if (ret == 0)
220 mmc_card_set_present(card);
221 return ret;
222}
223
224/*
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{
230 if (mmc_card_present(card)) {
231 if (mmc_card_sd(card))
232 device_remove_file(&card->dev, &mmc_dev_attr_scr);
233
234 device_del(&card->dev);
235 }
236
237 put_device(&card->dev);
238}
239
240
241static void mmc_host_classdev_release(struct device *dev)
242{
243 struct mmc_host *host = cls_dev_to_mmc_host(dev);
244 kfree(host);
245}
246
247static struct class mmc_host_class = {
248 .name = "mmc_host",
249 .dev_release = mmc_host_classdev_release,
250};
251
252static DEFINE_IDR(mmc_host_idr);
253static DEFINE_SPINLOCK(mmc_host_lock);
254
255/*
256 * Internal function. Allocate a new MMC host.
257 */
258struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev)
259{
260 struct mmc_host *host;
261
262 host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
263 if (host) {
264 memset(host, 0, sizeof(struct mmc_host) + extra);
265
266 host->parent = dev;
267 host->class_dev.parent = dev;
268 host->class_dev.class = &mmc_host_class;
269 device_initialize(&host->class_dev);
270 }
271 32
272 return host; 33 return error;
273} 34}
274 35
275/* 36void mmc_remove_attrs(struct mmc_card *card, struct device_attribute *attrs)
276 * Internal function. Register a new MMC host with the MMC class.
277 */
278int mmc_add_host_sysfs(struct mmc_host *host)
279{ 37{
280 int err; 38 int i;
281
282 if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
283 return -ENOMEM;
284
285 spin_lock(&mmc_host_lock);
286 err = idr_get_new(&mmc_host_idr, host, &host->index);
287 spin_unlock(&mmc_host_lock);
288 if (err)
289 return err;
290
291 snprintf(host->class_dev.bus_id, BUS_ID_SIZE,
292 "mmc%d", host->index);
293
294 return device_add(&host->class_dev);
295}
296 39
297/* 40 for (i = 0; attr_name(attrs[i]); i++)
298 * Internal function. Unregister a MMC host with the MMC class. 41 device_remove_file(&card->dev, &attrs[i]);
299 */
300void mmc_remove_host_sysfs(struct mmc_host *host)
301{
302 device_del(&host->class_dev);
303
304 spin_lock(&mmc_host_lock);
305 idr_remove(&mmc_host_idr, host->index);
306 spin_unlock(&mmc_host_lock);
307}
308
309/*
310 * Internal function. Free a MMC host.
311 */
312void mmc_free_host_sysfs(struct mmc_host *host)
313{
314 put_device(&host->class_dev);
315}
316
317static struct workqueue_struct *workqueue;
318
319/*
320 * Internal function. Schedule delayed work in the MMC work queue.
321 */
322int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay)
323{
324 return queue_delayed_work(workqueue, work, delay);
325}
326
327/*
328 * Internal function. Flush all scheduled work from the MMC work queue.
329 */
330void mmc_flush_scheduled_work(void)
331{
332 flush_workqueue(workqueue);
333}
334
335static int __init mmc_init(void)
336{
337 int ret;
338
339 workqueue = create_singlethread_workqueue("kmmcd");
340 if (!workqueue)
341 return -ENOMEM;
342
343 ret = bus_register(&mmc_bus_type);
344 if (ret == 0) {
345 ret = class_register(&mmc_host_class);
346 if (ret)
347 bus_unregister(&mmc_bus_type);
348 }
349 return ret;
350}
351
352static void __exit mmc_exit(void)
353{
354 class_unregister(&mmc_host_class);
355 bus_unregister(&mmc_bus_type);
356 destroy_workqueue(workqueue);
357} 42}
358 43
359module_init(mmc_init);
360module_exit(mmc_exit);
diff --git a/drivers/mmc/core/sysfs.h b/drivers/mmc/core/sysfs.h
index 80e29b358282..4b8f670bd10f 100644
--- a/drivers/mmc/core/sysfs.h
+++ b/drivers/mmc/core/sysfs.h
@@ -11,17 +11,16 @@
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}
17 20
18struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev); 21#define MMC_ATTR_RO(name) __ATTR(name, S_IRUGO, mmc_##name##_show, NULL)
19int mmc_add_host_sysfs(struct mmc_host *host);
20void mmc_remove_host_sysfs(struct mmc_host *host);
21void mmc_free_host_sysfs(struct mmc_host *host);
22 22
23int mmc_schedule_work(struct work_struct *work); 23int mmc_add_attrs(struct mmc_card *card, struct device_attribute *attrs);
24int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay); 24void mmc_remove_attrs(struct mmc_card *card, struct device_attribute *attrs);
25void mmc_flush_scheduled_work(void);
26 25
27#endif 26#endif