aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2005-08-19 04:41:24 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2005-08-19 04:41:24 -0400
commit00b137cfda5276b3d2c87d44236fe4c5ee68b405 (patch)
tree2ecf68ba041d4cb94be9bf6b5e640a94ee0974a2
parentd366b6436386875b1310ce8f70e3f9dea4647bac (diff)
[MMC] Add MMC class devices
Create a mmc_host class to allow enumeration of MMC host controllers even though they have no card(s) inserted. Patch based on work by Pierre Ossman. Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--drivers/mmc/mmc.c23
-rw-r--r--drivers/mmc/mmc.h5
-rw-r--r--drivers/mmc/mmc_sysfs.c72
-rw-r--r--include/linux/mmc/host.h1
4 files changed, 87 insertions, 14 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index e02e5df80be9..3c5904834fe8 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -796,17 +796,13 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
796{ 796{
797 struct mmc_host *host; 797 struct mmc_host *host;
798 798
799 host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); 799 host = mmc_alloc_host_sysfs(extra, dev);
800 if (host) { 800 if (host) {
801 memset(host, 0, sizeof(struct mmc_host) + extra);
802
803 spin_lock_init(&host->lock); 801 spin_lock_init(&host->lock);
804 init_waitqueue_head(&host->wq); 802 init_waitqueue_head(&host->wq);
805 INIT_LIST_HEAD(&host->cards); 803 INIT_LIST_HEAD(&host->cards);
806 INIT_WORK(&host->detect, mmc_rescan, host); 804 INIT_WORK(&host->detect, mmc_rescan, host);
807 805
808 host->dev = dev;
809
810 /* 806 /*
811 * By default, hosts do not support SGIO or large requests. 807 * By default, hosts do not support SGIO or large requests.
812 * They have to set these according to their abilities. 808 * They have to set these according to their abilities.
@@ -828,15 +824,15 @@ EXPORT_SYMBOL(mmc_alloc_host);
828 */ 824 */
829int mmc_add_host(struct mmc_host *host) 825int mmc_add_host(struct mmc_host *host)
830{ 826{
831 static unsigned int host_num; 827 int ret;
832 828
833 snprintf(host->host_name, sizeof(host->host_name), 829 ret = mmc_add_host_sysfs(host);
834 "mmc%d", host_num++); 830 if (ret == 0) {
835 831 mmc_power_off(host);
836 mmc_power_off(host); 832 mmc_detect_change(host);
837 mmc_detect_change(host); 833 }
838 834
839 return 0; 835 return ret;
840} 836}
841 837
842EXPORT_SYMBOL(mmc_add_host); 838EXPORT_SYMBOL(mmc_add_host);
@@ -859,6 +855,7 @@ void mmc_remove_host(struct mmc_host *host)
859 } 855 }
860 856
861 mmc_power_off(host); 857 mmc_power_off(host);
858 mmc_remove_host_sysfs(host);
862} 859}
863 860
864EXPORT_SYMBOL(mmc_remove_host); 861EXPORT_SYMBOL(mmc_remove_host);
@@ -872,7 +869,7 @@ EXPORT_SYMBOL(mmc_remove_host);
872void mmc_free_host(struct mmc_host *host) 869void mmc_free_host(struct mmc_host *host)
873{ 870{
874 flush_scheduled_work(); 871 flush_scheduled_work();
875 kfree(host); 872 mmc_free_host_sysfs(host);
876} 873}
877 874
878EXPORT_SYMBOL(mmc_free_host); 875EXPORT_SYMBOL(mmc_free_host);
diff --git a/drivers/mmc/mmc.h b/drivers/mmc/mmc.h
index b498dffe0b11..97bae00292fa 100644
--- a/drivers/mmc/mmc.h
+++ b/drivers/mmc/mmc.h
@@ -13,4 +13,9 @@
13void mmc_init_card(struct mmc_card *card, struct mmc_host *host); 13void mmc_init_card(struct mmc_card *card, struct mmc_host *host);
14int mmc_register_card(struct mmc_card *card); 14int mmc_register_card(struct mmc_card *card);
15void mmc_remove_card(struct mmc_card *card); 15void mmc_remove_card(struct mmc_card *card);
16
17struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev);
18int mmc_add_host_sysfs(struct mmc_host *host);
19void mmc_remove_host_sysfs(struct mmc_host *host);
20void mmc_free_host_sysfs(struct mmc_host *host);
16#endif 21#endif
diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c
index 3a6b325a9149..96c192057df3 100644
--- a/drivers/mmc/mmc_sysfs.c
+++ b/drivers/mmc/mmc_sysfs.c
@@ -20,6 +20,7 @@
20 20
21#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) 21#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev)
22#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) 22#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
23#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
23 24
24#define MMC_ATTR(name, fmt, args...) \ 25#define MMC_ATTR(name, fmt, args...) \
25static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \ 26static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf) \
@@ -224,13 +225,82 @@ void mmc_remove_card(struct mmc_card *card)
224} 225}
225 226
226 227
228static void mmc_host_classdev_release(struct class_device *dev)
229{
230 struct mmc_host *host = cls_dev_to_mmc_host(dev);
231 kfree(host);
232}
233
234static struct class mmc_host_class = {
235 .name = "mmc_host",
236 .release = mmc_host_classdev_release,
237};
238
239/*
240 * Internal function. Allocate a new MMC host.
241 */
242struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev)
243{
244 struct mmc_host *host;
245
246 host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
247 if (host) {
248 memset(host, 0, sizeof(struct mmc_host) + extra);
249
250 host->dev = dev;
251 host->class_dev.dev = host->dev;
252 host->class_dev.class = &mmc_host_class;
253 class_device_initialize(&host->class_dev);
254 }
255
256 return host;
257}
258
259/*
260 * Internal function. Register a new MMC host with the MMC class.
261 */
262int mmc_add_host_sysfs(struct mmc_host *host)
263{
264 static unsigned int host_num;
265
266 snprintf(host->host_name, sizeof(host->host_name),
267 "mmc%d", host_num++);
268
269 strlcpy(host->class_dev.class_id, host->host_name, BUS_ID_SIZE);
270 return class_device_add(&host->class_dev);
271}
272
273/*
274 * Internal function. Unregister a MMC host with the MMC class.
275 */
276void mmc_remove_host_sysfs(struct mmc_host *host)
277{
278 class_device_del(&host->class_dev);
279}
280
281/*
282 * Internal function. Free a MMC host.
283 */
284void mmc_free_host_sysfs(struct mmc_host *host)
285{
286 class_device_put(&host->class_dev);
287}
288
289
227static int __init mmc_init(void) 290static int __init mmc_init(void)
228{ 291{
229 return bus_register(&mmc_bus_type); 292 int ret = bus_register(&mmc_bus_type);
293 if (ret == 0) {
294 ret = class_register(&mmc_host_class);
295 if (ret)
296 bus_unregister(&mmc_bus_type);
297 }
298 return ret;
230} 299}
231 300
232static void __exit mmc_exit(void) 301static void __exit mmc_exit(void)
233{ 302{
303 class_unregister(&mmc_host_class);
234 bus_unregister(&mmc_bus_type); 304 bus_unregister(&mmc_bus_type);
235} 305}
236 306
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 307862308596..a74a810a1302 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -63,6 +63,7 @@ struct device;
63 63
64struct mmc_host { 64struct mmc_host {
65 struct device *dev; 65 struct device *dev;
66 struct class_device class_dev;
66 struct mmc_host_ops *ops; 67 struct mmc_host_ops *ops;
67 unsigned int f_min; 68 unsigned int f_min;
68 unsigned int f_max; 69 unsigned int f_max;