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