Commit | Line | Data |
---|---|---|
4101c16a PO |
1 | /* |
2 | * linux/drivers/mmc/core/bus.c | |
3 | * | |
4 | * Copyright (C) 2003 Russell King, All Rights Reserved. | |
5 | * Copyright (C) 2007 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 card bus driver model | |
12 | */ | |
13 | ||
14 | #include <linux/device.h> | |
15 | #include <linux/err.h> | |
16 | ||
17 | #include <linux/mmc/card.h> | |
18 | #include <linux/mmc/host.h> | |
19 | ||
4101c16a | 20 | #include "core.h" |
1a632f8c | 21 | #include "sdio_cis.h" |
4101c16a PO |
22 | #include "bus.h" |
23 | ||
24 | #define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) | |
25 | #define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) | |
26 | ||
27 | static ssize_t mmc_type_show(struct device *dev, | |
28 | struct device_attribute *attr, char *buf) | |
29 | { | |
30 | struct mmc_card *card = dev_to_mmc_card(dev); | |
31 | ||
32 | switch (card->type) { | |
33 | case MMC_TYPE_MMC: | |
34 | return sprintf(buf, "MMC\n"); | |
35 | case MMC_TYPE_SD: | |
36 | return sprintf(buf, "SD\n"); | |
5c4e6f13 PO |
37 | case MMC_TYPE_SDIO: |
38 | return sprintf(buf, "SDIO\n"); | |
4101c16a PO |
39 | default: |
40 | return -EFAULT; | |
41 | } | |
42 | } | |
43 | ||
44 | static struct device_attribute mmc_dev_attrs[] = { | |
51ec92e2 | 45 | __ATTR(type, S_IRUGO, mmc_type_show, NULL), |
4101c16a PO |
46 | __ATTR_NULL, |
47 | }; | |
48 | ||
49 | /* | |
50 | * This currently matches any MMC driver to any MMC card - drivers | |
51 | * themselves make the decision whether to drive this card in their | |
52 | * probe method. | |
53 | */ | |
54 | static int mmc_bus_match(struct device *dev, struct device_driver *drv) | |
55 | { | |
56 | return 1; | |
57 | } | |
58 | ||
59 | static int | |
7eff2e7a | 60 | mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) |
4101c16a PO |
61 | { |
62 | struct mmc_card *card = dev_to_mmc_card(dev); | |
9eb3a94d | 63 | const char *type; |
7eff2e7a | 64 | int retval = 0; |
4101c16a PO |
65 | |
66 | switch (card->type) { | |
67 | case MMC_TYPE_MMC: | |
9eb3a94d | 68 | type = "MMC"; |
4101c16a PO |
69 | break; |
70 | case MMC_TYPE_SD: | |
9eb3a94d | 71 | type = "SD"; |
4101c16a | 72 | break; |
5c4e6f13 | 73 | case MMC_TYPE_SDIO: |
9eb3a94d | 74 | type = "SDIO"; |
5c4e6f13 | 75 | break; |
9eb3a94d PO |
76 | default: |
77 | type = NULL; | |
4101c16a PO |
78 | } |
79 | ||
9eb3a94d | 80 | if (type) { |
7eff2e7a KS |
81 | retval = add_uevent_var(env, "MMC_TYPE=%s", type); |
82 | if (retval) | |
83 | return retval; | |
9eb3a94d | 84 | } |
4101c16a | 85 | |
7eff2e7a | 86 | retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card)); |
4101c16a | 87 | |
7eff2e7a | 88 | return retval; |
4101c16a PO |
89 | } |
90 | ||
91 | static int mmc_bus_probe(struct device *dev) | |
92 | { | |
93 | struct mmc_driver *drv = to_mmc_driver(dev->driver); | |
94 | struct mmc_card *card = dev_to_mmc_card(dev); | |
95 | ||
96 | return drv->probe(card); | |
97 | } | |
98 | ||
99 | static int mmc_bus_remove(struct device *dev) | |
100 | { | |
101 | struct mmc_driver *drv = to_mmc_driver(dev->driver); | |
102 | struct mmc_card *card = dev_to_mmc_card(dev); | |
103 | ||
104 | drv->remove(card); | |
105 | ||
106 | return 0; | |
107 | } | |
108 | ||
109 | static int mmc_bus_suspend(struct device *dev, pm_message_t state) | |
110 | { | |
111 | struct mmc_driver *drv = to_mmc_driver(dev->driver); | |
112 | struct mmc_card *card = dev_to_mmc_card(dev); | |
113 | int ret = 0; | |
114 | ||
115 | if (dev->driver && drv->suspend) | |
116 | ret = drv->suspend(card, state); | |
117 | return ret; | |
118 | } | |
119 | ||
120 | static int mmc_bus_resume(struct device *dev) | |
121 | { | |
122 | struct mmc_driver *drv = to_mmc_driver(dev->driver); | |
123 | struct mmc_card *card = dev_to_mmc_card(dev); | |
124 | int ret = 0; | |
125 | ||
126 | if (dev->driver && drv->resume) | |
127 | ret = drv->resume(card); | |
128 | return ret; | |
129 | } | |
130 | ||
131 | static struct bus_type mmc_bus_type = { | |
132 | .name = "mmc", | |
133 | .dev_attrs = mmc_dev_attrs, | |
134 | .match = mmc_bus_match, | |
135 | .uevent = mmc_bus_uevent, | |
136 | .probe = mmc_bus_probe, | |
137 | .remove = mmc_bus_remove, | |
138 | .suspend = mmc_bus_suspend, | |
139 | .resume = mmc_bus_resume, | |
140 | }; | |
141 | ||
142 | int mmc_register_bus(void) | |
143 | { | |
144 | return bus_register(&mmc_bus_type); | |
145 | } | |
146 | ||
147 | void mmc_unregister_bus(void) | |
148 | { | |
149 | bus_unregister(&mmc_bus_type); | |
150 | } | |
151 | ||
152 | /** | |
153 | * mmc_register_driver - register a media driver | |
154 | * @drv: MMC media driver | |
155 | */ | |
156 | int mmc_register_driver(struct mmc_driver *drv) | |
157 | { | |
158 | drv->drv.bus = &mmc_bus_type; | |
159 | return driver_register(&drv->drv); | |
160 | } | |
161 | ||
162 | EXPORT_SYMBOL(mmc_register_driver); | |
163 | ||
164 | /** | |
165 | * mmc_unregister_driver - unregister a media driver | |
166 | * @drv: MMC media driver | |
167 | */ | |
168 | void mmc_unregister_driver(struct mmc_driver *drv) | |
169 | { | |
170 | drv->drv.bus = &mmc_bus_type; | |
171 | driver_unregister(&drv->drv); | |
172 | } | |
173 | ||
174 | EXPORT_SYMBOL(mmc_unregister_driver); | |
175 | ||
176 | static void mmc_release_card(struct device *dev) | |
177 | { | |
178 | struct mmc_card *card = dev_to_mmc_card(dev); | |
179 | ||
1a632f8c PO |
180 | sdio_free_common_cis(card); |
181 | ||
759bdc7a PO |
182 | if (card->info) |
183 | kfree(card->info); | |
184 | ||
4101c16a PO |
185 | kfree(card); |
186 | } | |
187 | ||
188 | /* | |
189 | * Allocate and initialise a new MMC card structure. | |
190 | */ | |
51ec92e2 | 191 | struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type) |
4101c16a PO |
192 | { |
193 | struct mmc_card *card; | |
194 | ||
733cb1e4 | 195 | card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL); |
4101c16a PO |
196 | if (!card) |
197 | return ERR_PTR(-ENOMEM); | |
198 | ||
4101c16a PO |
199 | card->host = host; |
200 | ||
201 | device_initialize(&card->dev); | |
202 | ||
203 | card->dev.parent = mmc_classdev(host); | |
204 | card->dev.bus = &mmc_bus_type; | |
205 | card->dev.release = mmc_release_card; | |
51ec92e2 | 206 | card->dev.type = type; |
4101c16a PO |
207 | |
208 | return card; | |
209 | } | |
210 | ||
211 | /* | |
212 | * Register a new MMC card with the driver model. | |
213 | */ | |
214 | int mmc_add_card(struct mmc_card *card) | |
215 | { | |
216 | int ret; | |
109b5bed | 217 | const char *type; |
4101c16a PO |
218 | |
219 | snprintf(card->dev.bus_id, sizeof(card->dev.bus_id), | |
220 | "%s:%04x", mmc_hostname(card->host), card->rca); | |
221 | ||
109b5bed PO |
222 | switch (card->type) { |
223 | case MMC_TYPE_MMC: | |
224 | type = "MMC"; | |
225 | break; | |
226 | case MMC_TYPE_SD: | |
227 | type = "SD"; | |
228 | if (mmc_card_blockaddr(card)) | |
229 | type = "SDHC"; | |
230 | break; | |
5c4e6f13 PO |
231 | case MMC_TYPE_SDIO: |
232 | type = "SDIO"; | |
233 | break; | |
109b5bed PO |
234 | default: |
235 | type = "?"; | |
236 | break; | |
237 | } | |
238 | ||
af517150 DB |
239 | if (mmc_host_is_spi(card->host)) { |
240 | printk(KERN_INFO "%s: new %s%s card on SPI\n", | |
241 | mmc_hostname(card->host), | |
242 | mmc_card_highspeed(card) ? "high speed " : "", | |
243 | type); | |
244 | } else { | |
245 | printk(KERN_INFO "%s: new %s%s card at address %04x\n", | |
246 | mmc_hostname(card->host), | |
247 | mmc_card_highspeed(card) ? "high speed " : "", | |
248 | type, card->rca); | |
249 | } | |
109b5bed | 250 | |
4101c16a PO |
251 | ret = device_add(&card->dev); |
252 | if (ret) | |
253 | return ret; | |
254 | ||
f4b7f927 HS |
255 | #ifdef CONFIG_DEBUG_FS |
256 | mmc_add_card_debugfs(card); | |
257 | #endif | |
258 | ||
4101c16a PO |
259 | mmc_card_set_present(card); |
260 | ||
261 | return 0; | |
262 | } | |
263 | ||
264 | /* | |
265 | * Unregister a new MMC card with the driver model, and | |
266 | * (eventually) free it. | |
267 | */ | |
268 | void mmc_remove_card(struct mmc_card *card) | |
269 | { | |
f4b7f927 HS |
270 | #ifdef CONFIG_DEBUG_FS |
271 | mmc_remove_card_debugfs(card); | |
272 | #endif | |
273 | ||
4101c16a | 274 | if (mmc_card_present(card)) { |
af517150 DB |
275 | if (mmc_host_is_spi(card->host)) { |
276 | printk(KERN_INFO "%s: SPI card removed\n", | |
277 | mmc_hostname(card->host)); | |
278 | } else { | |
279 | printk(KERN_INFO "%s: card %04x removed\n", | |
280 | mmc_hostname(card->host), card->rca); | |
281 | } | |
4101c16a PO |
282 | device_del(&card->dev); |
283 | } | |
284 | ||
285 | put_device(&card->dev); | |
286 | } | |
287 |