diff options
author | Pierre Ossman <drzeus@drzeus.cx> | 2007-05-19 07:39:01 -0400 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2007-07-09 15:27:56 -0400 |
commit | 4101c16a910b15afd190c6bc7d45864461cf5c25 (patch) | |
tree | 76d88e3bfd6723fc86c13c635b3c2b73c73c6978 /drivers/mmc/core/bus.c | |
parent | 7de064ebc67d9baf6c933d3a7046feb9b4eced05 (diff) |
mmc: refactor bus operations
Move bus operations to its own file for the sake of clarity. Also
delegate sysfs attributes to bus handlers in preparation for other
more exotic types.
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/core/bus.c')
-rw-r--r-- | drivers/mmc/core/bus.c | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c new file mode 100644 index 000000000000..348b566bf4fd --- /dev/null +++ b/drivers/mmc/core/bus.c | |||
@@ -0,0 +1,253 @@ | |||
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 | |||
20 | #include "sysfs.h" | ||
21 | #include "core.h" | ||
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"); | ||
37 | default: | ||
38 | return -EFAULT; | ||
39 | } | ||
40 | } | ||
41 | |||
42 | static struct device_attribute mmc_dev_attrs[] = { | ||
43 | MMC_ATTR_RO(type), | ||
44 | __ATTR_NULL, | ||
45 | }; | ||
46 | |||
47 | /* | ||
48 | * This currently matches any MMC driver to any MMC card - drivers | ||
49 | * themselves make the decision whether to drive this card in their | ||
50 | * probe method. | ||
51 | */ | ||
52 | static int mmc_bus_match(struct device *dev, struct device_driver *drv) | ||
53 | { | ||
54 | return 1; | ||
55 | } | ||
56 | |||
57 | static int | ||
58 | mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf, | ||
59 | int buf_size) | ||
60 | { | ||
61 | struct mmc_card *card = dev_to_mmc_card(dev); | ||
62 | int retval = 0, i = 0, length = 0; | ||
63 | |||
64 | #define add_env(fmt,val) do { \ | ||
65 | retval = add_uevent_var(envp, num_envp, &i, \ | ||
66 | buf, buf_size, &length, \ | ||
67 | fmt, val); \ | ||
68 | if (retval) \ | ||
69 | return retval; \ | ||
70 | } while (0); | ||
71 | |||
72 | switch (card->type) { | ||
73 | case MMC_TYPE_MMC: | ||
74 | add_env("MMC_TYPE=%s", "MMC"); | ||
75 | break; | ||
76 | case MMC_TYPE_SD: | ||
77 | add_env("MMC_TYPE=%s", "SD"); | ||
78 | break; | ||
79 | } | ||
80 | |||
81 | add_env("MMC_NAME=%s", mmc_card_name(card)); | ||
82 | |||
83 | #undef add_env | ||
84 | |||
85 | envp[i] = NULL; | ||
86 | |||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int mmc_bus_probe(struct device *dev) | ||
91 | { | ||
92 | struct mmc_driver *drv = to_mmc_driver(dev->driver); | ||
93 | struct mmc_card *card = dev_to_mmc_card(dev); | ||
94 | |||
95 | return drv->probe(card); | ||
96 | } | ||
97 | |||
98 | static int mmc_bus_remove(struct device *dev) | ||
99 | { | ||
100 | struct mmc_driver *drv = to_mmc_driver(dev->driver); | ||
101 | struct mmc_card *card = dev_to_mmc_card(dev); | ||
102 | |||
103 | drv->remove(card); | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int mmc_bus_suspend(struct device *dev, pm_message_t state) | ||
109 | { | ||
110 | struct mmc_driver *drv = to_mmc_driver(dev->driver); | ||
111 | struct mmc_card *card = dev_to_mmc_card(dev); | ||
112 | int ret = 0; | ||
113 | |||
114 | if (dev->driver && drv->suspend) | ||
115 | ret = drv->suspend(card, state); | ||
116 | return ret; | ||
117 | } | ||
118 | |||
119 | static int mmc_bus_resume(struct device *dev) | ||
120 | { | ||
121 | struct mmc_driver *drv = to_mmc_driver(dev->driver); | ||
122 | struct mmc_card *card = dev_to_mmc_card(dev); | ||
123 | int ret = 0; | ||
124 | |||
125 | if (dev->driver && drv->resume) | ||
126 | ret = drv->resume(card); | ||
127 | return ret; | ||
128 | } | ||
129 | |||
130 | static struct bus_type mmc_bus_type = { | ||
131 | .name = "mmc", | ||
132 | .dev_attrs = mmc_dev_attrs, | ||
133 | .match = mmc_bus_match, | ||
134 | .uevent = mmc_bus_uevent, | ||
135 | .probe = mmc_bus_probe, | ||
136 | .remove = mmc_bus_remove, | ||
137 | .suspend = mmc_bus_suspend, | ||
138 | .resume = mmc_bus_resume, | ||
139 | }; | ||
140 | |||
141 | int mmc_register_bus(void) | ||
142 | { | ||
143 | return bus_register(&mmc_bus_type); | ||
144 | } | ||
145 | |||
146 | void mmc_unregister_bus(void) | ||
147 | { | ||
148 | bus_unregister(&mmc_bus_type); | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * mmc_register_driver - register a media driver | ||
153 | * @drv: MMC media driver | ||
154 | */ | ||
155 | int mmc_register_driver(struct mmc_driver *drv) | ||
156 | { | ||
157 | drv->drv.bus = &mmc_bus_type; | ||
158 | return driver_register(&drv->drv); | ||
159 | } | ||
160 | |||
161 | EXPORT_SYMBOL(mmc_register_driver); | ||
162 | |||
163 | /** | ||
164 | * mmc_unregister_driver - unregister a media driver | ||
165 | * @drv: MMC media driver | ||
166 | */ | ||
167 | void mmc_unregister_driver(struct mmc_driver *drv) | ||
168 | { | ||
169 | drv->drv.bus = &mmc_bus_type; | ||
170 | driver_unregister(&drv->drv); | ||
171 | } | ||
172 | |||
173 | EXPORT_SYMBOL(mmc_unregister_driver); | ||
174 | |||
175 | static void mmc_release_card(struct device *dev) | ||
176 | { | ||
177 | struct mmc_card *card = dev_to_mmc_card(dev); | ||
178 | |||
179 | kfree(card); | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Allocate and initialise a new MMC card structure. | ||
184 | */ | ||
185 | struct mmc_card *mmc_alloc_card(struct mmc_host *host) | ||
186 | { | ||
187 | struct mmc_card *card; | ||
188 | |||
189 | card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL); | ||
190 | if (!card) | ||
191 | return ERR_PTR(-ENOMEM); | ||
192 | |||
193 | memset(card, 0, sizeof(struct mmc_card)); | ||
194 | |||
195 | card->host = host; | ||
196 | |||
197 | device_initialize(&card->dev); | ||
198 | |||
199 | card->dev.parent = mmc_classdev(host); | ||
200 | card->dev.bus = &mmc_bus_type; | ||
201 | card->dev.release = mmc_release_card; | ||
202 | |||
203 | return card; | ||
204 | } | ||
205 | |||
206 | /* | ||
207 | * Register a new MMC card with the driver model. | ||
208 | */ | ||
209 | int mmc_add_card(struct mmc_card *card) | ||
210 | { | ||
211 | int ret; | ||
212 | |||
213 | snprintf(card->dev.bus_id, sizeof(card->dev.bus_id), | ||
214 | "%s:%04x", mmc_hostname(card->host), card->rca); | ||
215 | |||
216 | card->dev.uevent_suppress = 1; | ||
217 | |||
218 | ret = device_add(&card->dev); | ||
219 | if (ret) | ||
220 | return ret; | ||
221 | |||
222 | if (card->host->bus_ops->sysfs_add) { | ||
223 | ret = card->host->bus_ops->sysfs_add(card->host, card); | ||
224 | if (ret) { | ||
225 | device_del(&card->dev); | ||
226 | return ret; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | card->dev.uevent_suppress = 0; | ||
231 | |||
232 | kobject_uevent(&card->dev.kobj, KOBJ_ADD); | ||
233 | |||
234 | mmc_card_set_present(card); | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | /* | ||
240 | * Unregister a new MMC card with the driver model, and | ||
241 | * (eventually) free it. | ||
242 | */ | ||
243 | void mmc_remove_card(struct mmc_card *card) | ||
244 | { | ||
245 | if (mmc_card_present(card)) { | ||
246 | if (card->host->bus_ops->sysfs_remove) | ||
247 | card->host->bus_ops->sysfs_remove(card->host, card); | ||
248 | device_del(&card->dev); | ||
249 | } | ||
250 | |||
251 | put_device(&card->dev); | ||
252 | } | ||
253 | |||