1 /* 2 * linux/drivers/mmc/core/host.c 3 * 4 * Copyright (C) 2003 Russell King, All Rights Reserved. 5 * Copyright (C) 2007-2008 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 #include <linux/leds.h> 19 20 #include <linux/mmc/host.h> 21 22 #include "core.h" 23 #include "host.h" 24 25 #define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev) 26 27 static void mmc_host_classdev_release(struct device *dev) 28 { 29 struct mmc_host *host = cls_dev_to_mmc_host(dev); 30 kfree(host); 31 } 32 33 static struct class mmc_host_class = { 34 .name = "mmc_host", 35 .dev_release = mmc_host_classdev_release, 36 }; 37 38 int mmc_register_host_class(void) 39 { 40 return class_register(&mmc_host_class); 41 } 42 43 void mmc_unregister_host_class(void) 44 { 45 class_unregister(&mmc_host_class); 46 } 47 48 static DEFINE_IDR(mmc_host_idr); 49 static DEFINE_SPINLOCK(mmc_host_lock); 50 51 /** 52 * mmc_alloc_host - initialise the per-host structure. 53 * @extra: sizeof private data structure 54 * @dev: pointer to host device model structure 55 * 56 * Initialise the per-host structure. 57 */ 58 struct mmc_host *mmc_alloc_host(int extra, struct device *dev) 59 { 60 int err; 61 struct mmc_host *host; 62 63 if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL)) 64 return NULL; 65 66 host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL); 67 if (!host) 68 return NULL; 69 70 spin_lock(&mmc_host_lock); 71 err = idr_get_new(&mmc_host_idr, host, &host->index); 72 spin_unlock(&mmc_host_lock); 73 if (err) 74 goto free; 75 76 snprintf(host->class_dev.bus_id, BUS_ID_SIZE, 77 "mmc%d", host->index); 78 79 host->parent = dev; 80 host->class_dev.parent = dev; 81 host->class_dev.class = &mmc_host_class; 82 device_initialize(&host->class_dev); 83 84 spin_lock_init(&host->lock); 85 init_waitqueue_head(&host->wq); 86 INIT_DELAYED_WORK(&host->detect, mmc_rescan); 87 88 /* 89 * By default, hosts do not support SGIO or large requests. 90 * They have to set these according to their abilities. 91 */ 92 host->max_hw_segs = 1; 93 host->max_phys_segs = 1; 94 host->max_seg_size = PAGE_CACHE_SIZE; 95 96 host->max_req_size = PAGE_CACHE_SIZE; 97 host->max_blk_size = 512; 98 host->max_blk_count = PAGE_CACHE_SIZE / 512; 99 100 return host; 101 102 free: 103 kfree(host); 104 return NULL; 105 } 106 107 EXPORT_SYMBOL(mmc_alloc_host); 108 109 /** 110 * mmc_add_host - initialise host hardware 111 * @host: mmc host 112 * 113 * Register the host with the driver model. The host must be 114 * prepared to start servicing requests before this function 115 * completes. 116 */ 117 int mmc_add_host(struct mmc_host *host) 118 { 119 int err; 120 121 WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) && 122 !host->ops->enable_sdio_irq); 123 124 led_trigger_register_simple(host->class_dev.bus_id, &host->led); 125 126 err = device_add(&host->class_dev); 127 if (err) 128 return err; 129 130 #ifdef CONFIG_DEBUG_FS 131 mmc_add_host_debugfs(host); 132 #endif 133 134 mmc_start_host(host); 135 136 return 0; 137 } 138 139 EXPORT_SYMBOL(mmc_add_host); 140 141 /** 142 * mmc_remove_host - remove host hardware 143 * @host: mmc host 144 * 145 * Unregister and remove all cards associated with this host, 146 * and power down the MMC bus. No new requests will be issued 147 * after this function has returned. 148 */ 149 void mmc_remove_host(struct mmc_host *host) 150 { 151 mmc_stop_host(host); 152 153 #ifdef CONFIG_DEBUG_FS 154 mmc_remove_host_debugfs(host); 155 #endif 156 157 device_del(&host->class_dev); 158 159 led_trigger_unregister_simple(host->led); 160 } 161 162 EXPORT_SYMBOL(mmc_remove_host); 163 164 /** 165 * mmc_free_host - free the host structure 166 * @host: mmc host 167 * 168 * Free the host once all references to it have been dropped. 169 */ 170 void mmc_free_host(struct mmc_host *host) 171 { 172 spin_lock(&mmc_host_lock); 173 idr_remove(&mmc_host_idr, host->index); 174 spin_unlock(&mmc_host_lock); 175 176 put_device(&host->class_dev); 177 } 178 179 EXPORT_SYMBOL(mmc_free_host); 180 181