diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2005-08-19 09:41:24 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2005-08-19 09:41:24 +0100 |
commit | 00b137cfda5276b3d2c87d44236fe4c5ee68b405 (patch) | |
tree | 2ecf68ba041d4cb94be9bf6b5e640a94ee0974a2 | |
parent | d366b6436386875b1310ce8f70e3f9dea4647bac (diff) | |
download | linux-3.10-00b137cfda5276b3d2c87d44236fe4c5ee68b405.tar.gz linux-3.10-00b137cfda5276b3d2c87d44236fe4c5ee68b405.tar.bz2 linux-3.10-00b137cfda5276b3d2c87d44236fe4c5ee68b405.zip |
[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.c | 23 | ||||
-rw-r--r-- | drivers/mmc/mmc.h | 5 | ||||
-rw-r--r-- | drivers/mmc/mmc_sysfs.c | 72 | ||||
-rw-r--r-- | include/linux/mmc/host.h | 1 |
4 files changed, 87 insertions, 14 deletions
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index e02e5df80be..3c5904834fe 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) { struct mmc_host *host; - host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); + host = mmc_alloc_host_sysfs(extra, dev); if (host) { - memset(host, 0, sizeof(struct mmc_host) + extra); - spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); INIT_LIST_HEAD(&host->cards); INIT_WORK(&host->detect, mmc_rescan, host); - host->dev = dev; - /* * By default, hosts do not support SGIO or large requests. * They have to set these according to their abilities. @@ -828,15 +824,15 @@ EXPORT_SYMBOL(mmc_alloc_host); */ int mmc_add_host(struct mmc_host *host) { - static unsigned int host_num; + int ret; - snprintf(host->host_name, sizeof(host->host_name), - "mmc%d", host_num++); - - mmc_power_off(host); - mmc_detect_change(host); + ret = mmc_add_host_sysfs(host); + if (ret == 0) { + mmc_power_off(host); + mmc_detect_change(host); + } - return 0; + return ret; } EXPORT_SYMBOL(mmc_add_host); @@ -859,6 +855,7 @@ void mmc_remove_host(struct mmc_host *host) } mmc_power_off(host); + mmc_remove_host_sysfs(host); } EXPORT_SYMBOL(mmc_remove_host); @@ -872,7 +869,7 @@ EXPORT_SYMBOL(mmc_remove_host); void mmc_free_host(struct mmc_host *host) { flush_scheduled_work(); - kfree(host); + mmc_free_host_sysfs(host); } EXPORT_SYMBOL(mmc_free_host); diff --git a/drivers/mmc/mmc.h b/drivers/mmc/mmc.h index b498dffe0b1..97bae00292f 100644 --- a/drivers/mmc/mmc.h +++ b/drivers/mmc/mmc.h @@ -13,4 +13,9 @@ void mmc_init_card(struct mmc_card *card, struct mmc_host *host); int mmc_register_card(struct mmc_card *card); void mmc_remove_card(struct mmc_card *card); + +struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev); +int mmc_add_host_sysfs(struct mmc_host *host); +void mmc_remove_host_sysfs(struct mmc_host *host); +void mmc_free_host_sysfs(struct mmc_host *host); #endif diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c index 3a6b325a914..96c192057df 100644 --- a/drivers/mmc/mmc_sysfs.c +++ b/drivers/mmc/mmc_sysfs.c @@ -20,6 +20,7 @@ #define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) #define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) +#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev) #define MMC_ATTR(name, fmt, args...) \ static 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) } +static void mmc_host_classdev_release(struct class_device *dev) +{ + struct mmc_host *host = cls_dev_to_mmc_host(dev); + kfree(host); +} + +static struct class mmc_host_class = { + .name = "mmc_host", + .release = mmc_host_classdev_release, +}; + +/* + * Internal function. Allocate a new MMC host. + */ +struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev) +{ + struct mmc_host *host; + + host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); + if (host) { + memset(host, 0, sizeof(struct mmc_host) + extra); + + host->dev = dev; + host->class_dev.dev = host->dev; + host->class_dev.class = &mmc_host_class; + class_device_initialize(&host->class_dev); + } + + return host; +} + +/* + * Internal function. Register a new MMC host with the MMC class. + */ +int mmc_add_host_sysfs(struct mmc_host *host) +{ + static unsigned int host_num; + + snprintf(host->host_name, sizeof(host->host_name), + "mmc%d", host_num++); + + strlcpy(host->class_dev.class_id, host->host_name, BUS_ID_SIZE); + return class_device_add(&host->class_dev); +} + +/* + * Internal function. Unregister a MMC host with the MMC class. + */ +void mmc_remove_host_sysfs(struct mmc_host *host) +{ + class_device_del(&host->class_dev); +} + +/* + * Internal function. Free a MMC host. + */ +void mmc_free_host_sysfs(struct mmc_host *host) +{ + class_device_put(&host->class_dev); +} + + static int __init mmc_init(void) { - return bus_register(&mmc_bus_type); + int ret = bus_register(&mmc_bus_type); + if (ret == 0) { + ret = class_register(&mmc_host_class); + if (ret) + bus_unregister(&mmc_bus_type); + } + return ret; } static void __exit mmc_exit(void) { + class_unregister(&mmc_host_class); bus_unregister(&mmc_bus_type); } diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 30786230859..a74a810a130 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -63,6 +63,7 @@ struct device; struct mmc_host { struct device *dev; + struct class_device class_dev; struct mmc_host_ops *ops; unsigned int f_min; unsigned int f_max; |