Line data Source code
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 0 : struct mmc_host *host = cls_dev_to_mmc_host(dev);
30 0 : kfree(host);
31 0 : }
32 :
33 1 : 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 3 : return class_register(&mmc_host_class);
41 1 : }
42 :
43 : void mmc_unregister_host_class(void)
44 : {
45 3 : class_unregister(&mmc_host_class);
46 3 : }
47 :
48 1 : static DEFINE_IDR(mmc_host_idr);
49 1 : 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 0 : int err;
61 0 : struct mmc_host *host;
62 0 :
63 0 : if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
64 0 : return NULL;
65 0 :
66 0 : host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
67 0 : if (!host)
68 0 : return NULL;
69 :
70 0 : spin_lock(&mmc_host_lock);
71 0 : err = idr_get_new(&mmc_host_idr, host, &host->index);
72 0 : spin_unlock(&mmc_host_lock);
73 0 : if (err)
74 0 : goto free;
75 :
76 0 : dev_set_name(&host->class_dev, "mmc%d", host->index);
77 :
78 0 : host->parent = dev;
79 0 : host->class_dev.parent = dev;
80 0 : host->class_dev.class = &mmc_host_class;
81 0 : device_initialize(&host->class_dev);
82 :
83 0 : spin_lock_init(&host->lock);
84 0 : init_waitqueue_head(&host->wq);
85 0 : INIT_DELAYED_WORK(&host->detect, mmc_rescan);
86 0 : INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable);
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 0 : host->max_hw_segs = 1;
93 0 : host->max_phys_segs = 1;
94 0 : host->max_seg_size = PAGE_CACHE_SIZE;
95 :
96 0 : host->max_req_size = PAGE_CACHE_SIZE;
97 0 : host->max_blk_size = 512;
98 0 : host->max_blk_count = PAGE_CACHE_SIZE / 512;
99 :
100 0 : return host;
101 0 :
102 : free:
103 0 : kfree(host);
104 0 : 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 0 : int err;
120 0 :
121 0 : WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
122 : !host->ops->enable_sdio_irq);
123 :
124 : led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
125 :
126 0 : err = device_add(&host->class_dev);
127 0 : if (err)
128 0 : return err;
129 :
130 : #ifdef CONFIG_DEBUG_FS
131 : mmc_add_host_debugfs(host);
132 : #endif
133 :
134 0 : mmc_start_host(host);
135 :
136 0 : 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 0 : mmc_stop_host(host);
152 :
153 : #ifdef CONFIG_DEBUG_FS
154 : mmc_remove_host_debugfs(host);
155 : #endif
156 :
157 0 : device_del(&host->class_dev);
158 0 :
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 0 : spin_lock(&mmc_host_lock);
173 0 : idr_remove(&mmc_host_idr, host->index);
174 0 : spin_unlock(&mmc_host_lock);
175 :
176 0 : put_device(&host->class_dev);
177 0 : }
178 :
179 : EXPORT_SYMBOL(mmc_free_host);
180 :
|