aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-05 00:44:34 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-05 00:44:34 -0400
commit62ea6d80211ecc88ef516927ecebf64cb505be3f (patch)
tree1920de8cd3671aedcc912afb8e5ddb2a7c674b05 /drivers/misc
parentfa24aa561a3cf91cf25b5d4066470b08a2d24206 (diff)
parentd3af5abe9a809becbe4b413144b607844560d445 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc: (46 commits) mmc-omap: Clean up omap set_ios and make MMC_POWER_ON work mmc-omap: Fix omap to use MMC_POWER_ON mmc-omap: add missing '\n' mmc: make tifm_sd_set_dma_data() static mmc: remove old card states mmc: support unsafe resume of cards mmc: separate out reading EXT_CSD mmc: break apart switch function MMC: Fix handling of low-voltage cards MMC: Consolidate voltage definitions mmc: add bus handler wbsd: check for data opcode earlier mmc: Separate out protocol ops mmc: Move core functions to subdir mmc: deprecate mmc bus topology mmc: remove card upon suspend mmc: allow suspended block driver to be removed mmc: Flush pending detects on host removal mmc: Move host and card drivers to subdirs mmc: Move queue functions to mmc_block ...
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/tifm_7xx1.c332
-rw-r--r--drivers/misc/tifm_core.c305
2 files changed, 323 insertions, 314 deletions
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index bc60e2fc3c2c..1ba6c085419a 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -11,10 +11,20 @@
11 11
12#include <linux/tifm.h> 12#include <linux/tifm.h>
13#include <linux/dma-mapping.h> 13#include <linux/dma-mapping.h>
14#include <linux/freezer.h>
15 14
16#define DRIVER_NAME "tifm_7xx1" 15#define DRIVER_NAME "tifm_7xx1"
17#define DRIVER_VERSION "0.7" 16#define DRIVER_VERSION "0.8"
17
18#define TIFM_IRQ_ENABLE 0x80000000
19#define TIFM_IRQ_SOCKMASK(x) (x)
20#define TIFM_IRQ_CARDMASK(x) ((x) << 8)
21#define TIFM_IRQ_FIFOMASK(x) ((x) << 16)
22#define TIFM_IRQ_SETALL 0xffffffff
23
24static void tifm_7xx1_dummy_eject(struct tifm_adapter *fm,
25 struct tifm_dev *sock)
26{
27}
18 28
19static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock) 29static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
20{ 30{
@@ -22,7 +32,7 @@ static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
22 32
23 spin_lock_irqsave(&fm->lock, flags); 33 spin_lock_irqsave(&fm->lock, flags);
24 fm->socket_change_set |= 1 << sock->socket_id; 34 fm->socket_change_set |= 1 << sock->socket_id;
25 wake_up_all(&fm->change_set_notify); 35 tifm_queue_work(&fm->media_switcher);
26 spin_unlock_irqrestore(&fm->lock, flags); 36 spin_unlock_irqrestore(&fm->lock, flags);
27} 37}
28 38
@@ -30,8 +40,7 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
30{ 40{
31 struct tifm_adapter *fm = dev_id; 41 struct tifm_adapter *fm = dev_id;
32 struct tifm_dev *sock; 42 struct tifm_dev *sock;
33 unsigned int irq_status; 43 unsigned int irq_status, cnt;
34 unsigned int sock_irq_status, cnt;
35 44
36 spin_lock(&fm->lock); 45 spin_lock(&fm->lock);
37 irq_status = readl(fm->addr + FM_INTERRUPT_STATUS); 46 irq_status = readl(fm->addr + FM_INTERRUPT_STATUS);
@@ -45,12 +54,12 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
45 54
46 for (cnt = 0; cnt < fm->num_sockets; cnt++) { 55 for (cnt = 0; cnt < fm->num_sockets; cnt++) {
47 sock = fm->sockets[cnt]; 56 sock = fm->sockets[cnt];
48 sock_irq_status = (irq_status >> cnt) 57 if (sock) {
49 & (TIFM_IRQ_FIFOMASK(1) 58 if ((irq_status >> cnt) & TIFM_IRQ_FIFOMASK(1))
50 | TIFM_IRQ_CARDMASK(1)); 59 sock->data_event(sock);
51 60 if ((irq_status >> cnt) & TIFM_IRQ_CARDMASK(1))
52 if (sock && sock_irq_status) 61 sock->card_event(sock);
53 sock->signal_irq(sock, sock_irq_status); 62 }
54 } 63 }
55 64
56 fm->socket_change_set |= irq_status 65 fm->socket_change_set |= irq_status
@@ -58,57 +67,57 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
58 } 67 }
59 writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); 68 writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
60 69
61 if (!fm->socket_change_set) 70 if (fm->finish_me)
71 complete_all(fm->finish_me);
72 else if (!fm->socket_change_set)
62 writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE); 73 writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
63 else 74 else
64 wake_up_all(&fm->change_set_notify); 75 tifm_queue_work(&fm->media_switcher);
65 76
66 spin_unlock(&fm->lock); 77 spin_unlock(&fm->lock);
67 return IRQ_HANDLED; 78 return IRQ_HANDLED;
68} 79}
69 80
70static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, 81static unsigned char tifm_7xx1_toggle_sock_power(char __iomem *sock_addr)
71 int is_x2)
72{ 82{
73 unsigned int s_state; 83 unsigned int s_state;
74 int cnt; 84 int cnt;
75 85
76 writel(0x0e00, sock_addr + SOCK_CONTROL); 86 writel(0x0e00, sock_addr + SOCK_CONTROL);
77 87
78 for (cnt = 0; cnt < 100; cnt++) { 88 for (cnt = 16; cnt <= 256; cnt <<= 1) {
79 if (!(TIFM_SOCK_STATE_POWERED 89 if (!(TIFM_SOCK_STATE_POWERED
80 & readl(sock_addr + SOCK_PRESENT_STATE))) 90 & readl(sock_addr + SOCK_PRESENT_STATE)))
81 break; 91 break;
82 msleep(10); 92
93 msleep(cnt);
83 } 94 }
84 95
85 s_state = readl(sock_addr + SOCK_PRESENT_STATE); 96 s_state = readl(sock_addr + SOCK_PRESENT_STATE);
86 if (!(TIFM_SOCK_STATE_OCCUPIED & s_state)) 97 if (!(TIFM_SOCK_STATE_OCCUPIED & s_state))
87 return FM_NULL; 98 return 0;
88
89 if (is_x2) {
90 writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL);
91 } else {
92 // SmartMedia cards need extra 40 msec
93 if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7) == 1)
94 msleep(40);
95 writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED,
96 sock_addr + SOCK_CONTROL);
97 msleep(10);
98 writel((s_state & 0x7) | 0x0c00 | TIFM_CTRL_LED,
99 sock_addr + SOCK_CONTROL);
100 }
101 99
102 for (cnt = 0; cnt < 100; cnt++) { 100 writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED,
101 sock_addr + SOCK_CONTROL);
102
103 /* xd needs some extra time before power on */
104 if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7)
105 == TIFM_TYPE_XD)
106 msleep(40);
107
108 writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL);
109 /* wait for power to stabilize */
110 msleep(20);
111 for (cnt = 16; cnt <= 256; cnt <<= 1) {
103 if ((TIFM_SOCK_STATE_POWERED 112 if ((TIFM_SOCK_STATE_POWERED
104 & readl(sock_addr + SOCK_PRESENT_STATE))) 113 & readl(sock_addr + SOCK_PRESENT_STATE)))
105 break; 114 break;
106 msleep(10); 115
116 msleep(cnt);
107 } 117 }
108 118
109 if (!is_x2) 119 writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED),
110 writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED), 120 sock_addr + SOCK_CONTROL);
111 sock_addr + SOCK_CONTROL);
112 121
113 return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7; 122 return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7;
114} 123}
@@ -119,127 +128,77 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
119 return base_addr + ((sock_num + 1) << 10); 128 return base_addr + ((sock_num + 1) << 10);
120} 129}
121 130
122static int tifm_7xx1_switch_media(void *data) 131static void tifm_7xx1_switch_media(struct work_struct *work)
123{ 132{
124 struct tifm_adapter *fm = data; 133 struct tifm_adapter *fm = container_of(work, struct tifm_adapter,
125 unsigned long flags; 134 media_switcher);
126 tifm_media_id media_id;
127 char *card_name = "xx";
128 int cnt, rc;
129 struct tifm_dev *sock; 135 struct tifm_dev *sock;
130 unsigned int socket_change_set; 136 unsigned long flags;
131 137 unsigned char media_id;
132 while (1) { 138 unsigned int socket_change_set, cnt;
133 rc = wait_event_interruptible(fm->change_set_notify,
134 fm->socket_change_set);
135 if (rc == -ERESTARTSYS)
136 try_to_freeze();
137 139
138 spin_lock_irqsave(&fm->lock, flags); 140 spin_lock_irqsave(&fm->lock, flags);
139 socket_change_set = fm->socket_change_set; 141 socket_change_set = fm->socket_change_set;
140 fm->socket_change_set = 0; 142 fm->socket_change_set = 0;
141 143
142 dev_dbg(fm->dev, "checking media set %x\n", 144 dev_dbg(fm->cdev.dev, "checking media set %x\n",
143 socket_change_set); 145 socket_change_set);
144 146
145 if (kthread_should_stop()) 147 if (!socket_change_set) {
146 socket_change_set = (1 << fm->num_sockets) - 1;
147 spin_unlock_irqrestore(&fm->lock, flags); 148 spin_unlock_irqrestore(&fm->lock, flags);
149 return;
150 }
148 151
149 if (!socket_change_set) 152 for (cnt = 0; cnt < fm->num_sockets; cnt++) {
153 if (!(socket_change_set & (1 << cnt)))
150 continue; 154 continue;
151 155 sock = fm->sockets[cnt];
152 spin_lock_irqsave(&fm->lock, flags); 156 if (sock) {
153 for (cnt = 0; cnt < fm->num_sockets; cnt++) { 157 printk(KERN_INFO
154 if (!(socket_change_set & (1 << cnt))) 158 "%s : demand removing card from socket %u:%u\n",
155 continue; 159 fm->cdev.class_id, fm->id, cnt);
156 sock = fm->sockets[cnt]; 160 fm->sockets[cnt] = NULL;
157 if (sock) {
158 printk(KERN_INFO DRIVER_NAME
159 ": demand removing card from socket %d\n",
160 cnt);
161 fm->sockets[cnt] = NULL;
162 spin_unlock_irqrestore(&fm->lock, flags);
163 device_unregister(&sock->dev);
164 spin_lock_irqsave(&fm->lock, flags);
165 writel(0x0e00,
166 tifm_7xx1_sock_addr(fm->addr, cnt)
167 + SOCK_CONTROL);
168 }
169 if (kthread_should_stop())
170 continue;
171
172 spin_unlock_irqrestore(&fm->lock, flags); 161 spin_unlock_irqrestore(&fm->lock, flags);
173 media_id = tifm_7xx1_toggle_sock_power( 162 device_unregister(&sock->dev);
174 tifm_7xx1_sock_addr(fm->addr, cnt), 163 spin_lock_irqsave(&fm->lock, flags);
175 fm->num_sockets == 2); 164 writel(0x0e00, tifm_7xx1_sock_addr(fm->addr, cnt)
176 if (media_id) { 165 + SOCK_CONTROL);
177 sock = tifm_alloc_device(fm);
178 if (sock) {
179 sock->addr = tifm_7xx1_sock_addr(fm->addr,
180 cnt);
181 sock->media_id = media_id;
182 sock->socket_id = cnt;
183 switch (media_id) {
184 case 1:
185 card_name = "xd";
186 break;
187 case 2:
188 card_name = "ms";
189 break;
190 case 3:
191 card_name = "sd";
192 break;
193 default:
194 tifm_free_device(&sock->dev);
195 spin_lock_irqsave(&fm->lock, flags);
196 continue;
197 }
198 snprintf(sock->dev.bus_id, BUS_ID_SIZE,
199 "tifm_%s%u:%u", card_name,
200 fm->id, cnt);
201 printk(KERN_INFO DRIVER_NAME
202 ": %s card detected in socket %d\n",
203 card_name, cnt);
204 if (!device_register(&sock->dev)) {
205 spin_lock_irqsave(&fm->lock, flags);
206 if (!fm->sockets[cnt]) {
207 fm->sockets[cnt] = sock;
208 sock = NULL;
209 }
210 spin_unlock_irqrestore(&fm->lock, flags);
211 }
212 if (sock)
213 tifm_free_device(&sock->dev);
214 }
215 spin_lock_irqsave(&fm->lock, flags);
216 }
217 } 166 }
218 167
219 if (!kthread_should_stop()) { 168 spin_unlock_irqrestore(&fm->lock, flags);
220 writel(TIFM_IRQ_FIFOMASK(socket_change_set) 169
221 | TIFM_IRQ_CARDMASK(socket_change_set), 170 media_id = tifm_7xx1_toggle_sock_power(
222 fm->addr + FM_CLEAR_INTERRUPT_ENABLE); 171 tifm_7xx1_sock_addr(fm->addr, cnt));
223 writel(TIFM_IRQ_FIFOMASK(socket_change_set) 172
224 | TIFM_IRQ_CARDMASK(socket_change_set), 173 // tifm_alloc_device will check if media_id is valid
225 fm->addr + FM_SET_INTERRUPT_ENABLE); 174 sock = tifm_alloc_device(fm, cnt, media_id);
226 writel(TIFM_IRQ_ENABLE, 175 if (sock) {
227 fm->addr + FM_SET_INTERRUPT_ENABLE); 176 sock->addr = tifm_7xx1_sock_addr(fm->addr, cnt);
228 spin_unlock_irqrestore(&fm->lock, flags); 177
229 } else { 178 if (!device_register(&sock->dev)) {
230 for (cnt = 0; cnt < fm->num_sockets; cnt++) { 179 spin_lock_irqsave(&fm->lock, flags);
231 if (fm->sockets[cnt]) 180 if (!fm->sockets[cnt]) {
232 fm->socket_change_set |= 1 << cnt; 181 fm->sockets[cnt] = sock;
233 } 182 sock = NULL;
234 if (!fm->socket_change_set) { 183 }
235 spin_unlock_irqrestore(&fm->lock, flags);
236 return 0;
237 } else {
238 spin_unlock_irqrestore(&fm->lock, flags); 184 spin_unlock_irqrestore(&fm->lock, flags);
239 } 185 }
186 if (sock)
187 tifm_free_device(&sock->dev);
240 } 188 }
189 spin_lock_irqsave(&fm->lock, flags);
241 } 190 }
242 return 0; 191
192 writel(TIFM_IRQ_FIFOMASK(socket_change_set)
193 | TIFM_IRQ_CARDMASK(socket_change_set),
194 fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
195
196 writel(TIFM_IRQ_FIFOMASK(socket_change_set)
197 | TIFM_IRQ_CARDMASK(socket_change_set),
198 fm->addr + FM_SET_INTERRUPT_ENABLE);
199
200 writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
201 spin_unlock_irqrestore(&fm->lock, flags);
243} 202}
244 203
245#ifdef CONFIG_PM 204#ifdef CONFIG_PM
@@ -258,9 +217,11 @@ static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
258static int tifm_7xx1_resume(struct pci_dev *dev) 217static int tifm_7xx1_resume(struct pci_dev *dev)
259{ 218{
260 struct tifm_adapter *fm = pci_get_drvdata(dev); 219 struct tifm_adapter *fm = pci_get_drvdata(dev);
261 int cnt, rc; 220 int rc;
221 unsigned int good_sockets = 0, bad_sockets = 0;
262 unsigned long flags; 222 unsigned long flags;
263 tifm_media_id new_ids[fm->num_sockets]; 223 unsigned char new_ids[fm->num_sockets];
224 DECLARE_COMPLETION_ONSTACK(finish_resume);
264 225
265 pci_set_power_state(dev, PCI_D0); 226 pci_set_power_state(dev, PCI_D0);
266 pci_restore_state(dev); 227 pci_restore_state(dev);
@@ -271,45 +232,49 @@ static int tifm_7xx1_resume(struct pci_dev *dev)
271 232
272 dev_dbg(&dev->dev, "resuming host\n"); 233 dev_dbg(&dev->dev, "resuming host\n");
273 234
274 for (cnt = 0; cnt < fm->num_sockets; cnt++) 235 for (rc = 0; rc < fm->num_sockets; rc++)
275 new_ids[cnt] = tifm_7xx1_toggle_sock_power( 236 new_ids[rc] = tifm_7xx1_toggle_sock_power(
276 tifm_7xx1_sock_addr(fm->addr, cnt), 237 tifm_7xx1_sock_addr(fm->addr, rc));
277 fm->num_sockets == 2);
278 spin_lock_irqsave(&fm->lock, flags); 238 spin_lock_irqsave(&fm->lock, flags);
279 fm->socket_change_set = 0; 239 for (rc = 0; rc < fm->num_sockets; rc++) {
280 for (cnt = 0; cnt < fm->num_sockets; cnt++) { 240 if (fm->sockets[rc]) {
281 if (fm->sockets[cnt]) { 241 if (fm->sockets[rc]->type == new_ids[rc])
282 if (fm->sockets[cnt]->media_id == new_ids[cnt]) 242 good_sockets |= 1 << rc;
283 fm->socket_change_set |= 1 << cnt; 243 else
284 244 bad_sockets |= 1 << rc;
285 fm->sockets[cnt]->media_id = new_ids[cnt];
286 } 245 }
287 } 246 }
288 247
289 writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), 248 writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
290 fm->addr + FM_SET_INTERRUPT_ENABLE); 249 fm->addr + FM_SET_INTERRUPT_ENABLE);
291 if (!fm->socket_change_set) { 250 dev_dbg(&dev->dev, "change sets on resume: good %x, bad %x\n",
292 spin_unlock_irqrestore(&fm->lock, flags); 251 good_sockets, bad_sockets);
293 return 0; 252
294 } else { 253 fm->socket_change_set = 0;
295 fm->socket_change_set = 0; 254 if (good_sockets) {
255 fm->finish_me = &finish_resume;
296 spin_unlock_irqrestore(&fm->lock, flags); 256 spin_unlock_irqrestore(&fm->lock, flags);
257 rc = wait_for_completion_timeout(&finish_resume, HZ);
258 dev_dbg(&dev->dev, "wait returned %d\n", rc);
259 writel(TIFM_IRQ_FIFOMASK(good_sockets)
260 | TIFM_IRQ_CARDMASK(good_sockets),
261 fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
262 writel(TIFM_IRQ_FIFOMASK(good_sockets)
263 | TIFM_IRQ_CARDMASK(good_sockets),
264 fm->addr + FM_SET_INTERRUPT_ENABLE);
265 spin_lock_irqsave(&fm->lock, flags);
266 fm->finish_me = NULL;
267 fm->socket_change_set ^= good_sockets & fm->socket_change_set;
297 } 268 }
298 269
299 wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ); 270 fm->socket_change_set |= bad_sockets;
271 if (fm->socket_change_set)
272 tifm_queue_work(&fm->media_switcher);
300 273
301 spin_lock_irqsave(&fm->lock, flags); 274 spin_unlock_irqrestore(&fm->lock, flags);
302 writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
303 | TIFM_IRQ_CARDMASK(fm->socket_change_set),
304 fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
305 writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
306 | TIFM_IRQ_CARDMASK(fm->socket_change_set),
307 fm->addr + FM_SET_INTERRUPT_ENABLE);
308 writel(TIFM_IRQ_ENABLE, 275 writel(TIFM_IRQ_ENABLE,
309 fm->addr + FM_SET_INTERRUPT_ENABLE); 276 fm->addr + FM_SET_INTERRUPT_ENABLE);
310 fm->socket_change_set = 0;
311 277
312 spin_unlock_irqrestore(&fm->lock, flags);
313 return 0; 278 return 0;
314} 279}
315 280
@@ -345,20 +310,14 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
345 310
346 pci_intx(dev, 1); 311 pci_intx(dev, 1);
347 312
348 fm = tifm_alloc_adapter(); 313 fm = tifm_alloc_adapter(dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM
314 ? 4 : 2, &dev->dev);
349 if (!fm) { 315 if (!fm) {
350 rc = -ENOMEM; 316 rc = -ENOMEM;
351 goto err_out_int; 317 goto err_out_int;
352 } 318 }
353 319
354 fm->dev = &dev->dev; 320 INIT_WORK(&fm->media_switcher, tifm_7xx1_switch_media);
355 fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM)
356 ? 4 : 2;
357 fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets,
358 GFP_KERNEL);
359 if (!fm->sockets)
360 goto err_out_free;
361
362 fm->eject = tifm_7xx1_eject; 321 fm->eject = tifm_7xx1_eject;
363 pci_set_drvdata(dev, fm); 322 pci_set_drvdata(dev, fm);
364 323
@@ -367,19 +326,16 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
367 if (!fm->addr) 326 if (!fm->addr)
368 goto err_out_free; 327 goto err_out_free;
369 328
370 rc = request_irq(dev->irq, tifm_7xx1_isr, IRQF_SHARED, DRIVER_NAME, fm); 329 rc = request_irq(dev->irq, tifm_7xx1_isr, SA_SHIRQ, DRIVER_NAME, fm);
371 if (rc) 330 if (rc)
372 goto err_out_unmap; 331 goto err_out_unmap;
373 332
374 init_waitqueue_head(&fm->change_set_notify); 333 rc = tifm_add_adapter(fm);
375 rc = tifm_add_adapter(fm, tifm_7xx1_switch_media);
376 if (rc) 334 if (rc)
377 goto err_out_irq; 335 goto err_out_irq;
378 336
379 writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
380 writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1), 337 writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
381 fm->addr + FM_SET_INTERRUPT_ENABLE); 338 fm->addr + FM_SET_INTERRUPT_ENABLE);
382 wake_up_process(fm->media_switcher);
383 return 0; 339 return 0;
384 340
385err_out_irq: 341err_out_irq:
@@ -401,18 +357,12 @@ err_out:
401static void tifm_7xx1_remove(struct pci_dev *dev) 357static void tifm_7xx1_remove(struct pci_dev *dev)
402{ 358{
403 struct tifm_adapter *fm = pci_get_drvdata(dev); 359 struct tifm_adapter *fm = pci_get_drvdata(dev);
404 unsigned long flags;
405 360
361 fm->eject = tifm_7xx1_dummy_eject;
406 writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); 362 writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
407 mmiowb(); 363 mmiowb();
408 free_irq(dev->irq, fm); 364 free_irq(dev->irq, fm);
409 365
410 spin_lock_irqsave(&fm->lock, flags);
411 fm->socket_change_set = (1 << fm->num_sockets) - 1;
412 spin_unlock_irqrestore(&fm->lock, flags);
413
414 kthread_stop(fm->media_switcher);
415
416 tifm_remove_adapter(fm); 366 tifm_remove_adapter(fm);
417 367
418 pci_set_drvdata(dev, NULL); 368 pci_set_drvdata(dev, NULL);
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index 6b10ebe9d936..d195fb088f4a 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -14,71 +14,124 @@
14#include <linux/idr.h> 14#include <linux/idr.h>
15 15
16#define DRIVER_NAME "tifm_core" 16#define DRIVER_NAME "tifm_core"
17#define DRIVER_VERSION "0.7" 17#define DRIVER_VERSION "0.8"
18 18
19static struct workqueue_struct *workqueue;
19static DEFINE_IDR(tifm_adapter_idr); 20static DEFINE_IDR(tifm_adapter_idr);
20static DEFINE_SPINLOCK(tifm_adapter_lock); 21static DEFINE_SPINLOCK(tifm_adapter_lock);
21 22
22static tifm_media_id *tifm_device_match(tifm_media_id *ids, 23static const char *tifm_media_type_name(unsigned char type, unsigned char nt)
23 struct tifm_dev *dev)
24{ 24{
25 while (*ids) { 25 const char *card_type_name[3][3] = {
26 if (dev->media_id == *ids) 26 { "SmartMedia/xD", "MemoryStick", "MMC/SD" },
27 return ids; 27 { "XD", "MS", "SD"},
28 ids++; 28 { "xd", "ms", "sd"}
29 } 29 };
30 return NULL; 30
31 if (nt > 2 || type < 1 || type > 3)
32 return NULL;
33 return card_type_name[nt][type - 1];
31} 34}
32 35
33static int tifm_match(struct device *dev, struct device_driver *drv) 36static int tifm_dev_match(struct tifm_dev *sock, struct tifm_device_id *id)
34{ 37{
35 struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); 38 if (sock->type == id->type)
36 struct tifm_driver *fm_drv;
37
38 fm_drv = container_of(drv, struct tifm_driver, driver);
39 if (!fm_drv->id_table)
40 return -EINVAL;
41 if (tifm_device_match(fm_drv->id_table, fm_dev))
42 return 1; 39 return 1;
43 return -ENODEV; 40 return 0;
41}
42
43static int tifm_bus_match(struct device *dev, struct device_driver *drv)
44{
45 struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
46 struct tifm_driver *fm_drv = container_of(drv, struct tifm_driver,
47 driver);
48 struct tifm_device_id *ids = fm_drv->id_table;
49
50 if (ids) {
51 while (ids->type) {
52 if (tifm_dev_match(sock, ids))
53 return 1;
54 ++ids;
55 }
56 }
57 return 0;
44} 58}
45 59
46static int tifm_uevent(struct device *dev, char **envp, int num_envp, 60static int tifm_uevent(struct device *dev, char **envp, int num_envp,
47 char *buffer, int buffer_size) 61 char *buffer, int buffer_size)
48{ 62{
49 struct tifm_dev *fm_dev; 63 struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
50 int i = 0; 64 int i = 0;
51 int length = 0; 65 int length = 0;
52 const char *card_type_name[] = {"INV", "SM", "MS", "SD"};
53 66
54 if (!dev || !(fm_dev = container_of(dev, struct tifm_dev, dev)))
55 return -ENODEV;
56 if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, 67 if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
57 "TIFM_CARD_TYPE=%s", card_type_name[fm_dev->media_id])) 68 "TIFM_CARD_TYPE=%s",
69 tifm_media_type_name(sock->type, 1)))
58 return -ENOMEM; 70 return -ENOMEM;
59 71
60 return 0; 72 return 0;
61} 73}
62 74
75static int tifm_device_probe(struct device *dev)
76{
77 struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
78 struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
79 driver);
80 int rc = -ENODEV;
81
82 get_device(dev);
83 if (dev->driver && drv->probe) {
84 rc = drv->probe(sock);
85 if (!rc)
86 return 0;
87 }
88 put_device(dev);
89 return rc;
90}
91
92static void tifm_dummy_event(struct tifm_dev *sock)
93{
94 return;
95}
96
97static int tifm_device_remove(struct device *dev)
98{
99 struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
100 struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
101 driver);
102
103 if (dev->driver && drv->remove) {
104 sock->card_event = tifm_dummy_event;
105 sock->data_event = tifm_dummy_event;
106 drv->remove(sock);
107 sock->dev.driver = NULL;
108 }
109
110 put_device(dev);
111 return 0;
112}
113
63#ifdef CONFIG_PM 114#ifdef CONFIG_PM
64 115
65static int tifm_device_suspend(struct device *dev, pm_message_t state) 116static int tifm_device_suspend(struct device *dev, pm_message_t state)
66{ 117{
67 struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); 118 struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
68 struct tifm_driver *drv = fm_dev->drv; 119 struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
120 driver);
69 121
70 if (drv && drv->suspend) 122 if (dev->driver && drv->suspend)
71 return drv->suspend(fm_dev, state); 123 return drv->suspend(sock, state);
72 return 0; 124 return 0;
73} 125}
74 126
75static int tifm_device_resume(struct device *dev) 127static int tifm_device_resume(struct device *dev)
76{ 128{
77 struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); 129 struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
78 struct tifm_driver *drv = fm_dev->drv; 130 struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
131 driver);
79 132
80 if (drv && drv->resume) 133 if (dev->driver && drv->resume)
81 return drv->resume(fm_dev); 134 return drv->resume(sock);
82 return 0; 135 return 0;
83} 136}
84 137
@@ -89,19 +142,33 @@ static int tifm_device_resume(struct device *dev)
89 142
90#endif /* CONFIG_PM */ 143#endif /* CONFIG_PM */
91 144
145static ssize_t type_show(struct device *dev, struct device_attribute *attr,
146 char *buf)
147{
148 struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
149 return sprintf(buf, "%x", sock->type);
150}
151
152static struct device_attribute tifm_dev_attrs[] = {
153 __ATTR(type, S_IRUGO, type_show, NULL),
154 __ATTR_NULL
155};
156
92static struct bus_type tifm_bus_type = { 157static struct bus_type tifm_bus_type = {
93 .name = "tifm", 158 .name = "tifm",
94 .match = tifm_match, 159 .dev_attrs = tifm_dev_attrs,
95 .uevent = tifm_uevent, 160 .match = tifm_bus_match,
96 .suspend = tifm_device_suspend, 161 .uevent = tifm_uevent,
97 .resume = tifm_device_resume 162 .probe = tifm_device_probe,
163 .remove = tifm_device_remove,
164 .suspend = tifm_device_suspend,
165 .resume = tifm_device_resume
98}; 166};
99 167
100static void tifm_free(struct class_device *cdev) 168static void tifm_free(struct class_device *cdev)
101{ 169{
102 struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev); 170 struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
103 171
104 kfree(fm->sockets);
105 kfree(fm); 172 kfree(fm);
106} 173}
107 174
@@ -110,28 +177,25 @@ static struct class tifm_adapter_class = {
110 .release = tifm_free 177 .release = tifm_free
111}; 178};
112 179
113struct tifm_adapter *tifm_alloc_adapter(void) 180struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
181 struct device *dev)
114{ 182{
115 struct tifm_adapter *fm; 183 struct tifm_adapter *fm;
116 184
117 fm = kzalloc(sizeof(struct tifm_adapter), GFP_KERNEL); 185 fm = kzalloc(sizeof(struct tifm_adapter)
186 + sizeof(struct tifm_dev*) * num_sockets, GFP_KERNEL);
118 if (fm) { 187 if (fm) {
119 fm->cdev.class = &tifm_adapter_class; 188 fm->cdev.class = &tifm_adapter_class;
120 spin_lock_init(&fm->lock); 189 fm->cdev.dev = dev;
121 class_device_initialize(&fm->cdev); 190 class_device_initialize(&fm->cdev);
191 spin_lock_init(&fm->lock);
192 fm->num_sockets = num_sockets;
122 } 193 }
123 return fm; 194 return fm;
124} 195}
125EXPORT_SYMBOL(tifm_alloc_adapter); 196EXPORT_SYMBOL(tifm_alloc_adapter);
126 197
127void tifm_free_adapter(struct tifm_adapter *fm) 198int tifm_add_adapter(struct tifm_adapter *fm)
128{
129 class_device_put(&fm->cdev);
130}
131EXPORT_SYMBOL(tifm_free_adapter);
132
133int tifm_add_adapter(struct tifm_adapter *fm,
134 int (*mediathreadfn)(void *data))
135{ 199{
136 int rc; 200 int rc;
137 201
@@ -141,59 +205,80 @@ int tifm_add_adapter(struct tifm_adapter *fm,
141 spin_lock(&tifm_adapter_lock); 205 spin_lock(&tifm_adapter_lock);
142 rc = idr_get_new(&tifm_adapter_idr, fm, &fm->id); 206 rc = idr_get_new(&tifm_adapter_idr, fm, &fm->id);
143 spin_unlock(&tifm_adapter_lock); 207 spin_unlock(&tifm_adapter_lock);
144 if (!rc) { 208 if (rc)
145 snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id); 209 return rc;
146 fm->media_switcher = kthread_create(mediathreadfn,
147 fm, "tifm/%u", fm->id);
148
149 if (!IS_ERR(fm->media_switcher))
150 return class_device_add(&fm->cdev);
151 210
211 snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
212 rc = class_device_add(&fm->cdev);
213 if (rc) {
152 spin_lock(&tifm_adapter_lock); 214 spin_lock(&tifm_adapter_lock);
153 idr_remove(&tifm_adapter_idr, fm->id); 215 idr_remove(&tifm_adapter_idr, fm->id);
154 spin_unlock(&tifm_adapter_lock); 216 spin_unlock(&tifm_adapter_lock);
155 rc = -ENOMEM;
156 } 217 }
218
157 return rc; 219 return rc;
158} 220}
159EXPORT_SYMBOL(tifm_add_adapter); 221EXPORT_SYMBOL(tifm_add_adapter);
160 222
161void tifm_remove_adapter(struct tifm_adapter *fm) 223void tifm_remove_adapter(struct tifm_adapter *fm)
162{ 224{
163 class_device_del(&fm->cdev); 225 unsigned int cnt;
226
227 flush_workqueue(workqueue);
228 for (cnt = 0; cnt < fm->num_sockets; ++cnt) {
229 if (fm->sockets[cnt])
230 device_unregister(&fm->sockets[cnt]->dev);
231 }
164 232
165 spin_lock(&tifm_adapter_lock); 233 spin_lock(&tifm_adapter_lock);
166 idr_remove(&tifm_adapter_idr, fm->id); 234 idr_remove(&tifm_adapter_idr, fm->id);
167 spin_unlock(&tifm_adapter_lock); 235 spin_unlock(&tifm_adapter_lock);
236 class_device_del(&fm->cdev);
168} 237}
169EXPORT_SYMBOL(tifm_remove_adapter); 238EXPORT_SYMBOL(tifm_remove_adapter);
170 239
171void tifm_free_device(struct device *dev) 240void tifm_free_adapter(struct tifm_adapter *fm)
172{ 241{
173 struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); 242 class_device_put(&fm->cdev);
174 kfree(fm_dev);
175} 243}
176EXPORT_SYMBOL(tifm_free_device); 244EXPORT_SYMBOL(tifm_free_adapter);
177 245
178static void tifm_dummy_signal_irq(struct tifm_dev *sock, 246void tifm_free_device(struct device *dev)
179 unsigned int sock_irq_status)
180{ 247{
181 return; 248 struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
249 kfree(sock);
182} 250}
251EXPORT_SYMBOL(tifm_free_device);
183 252
184struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm) 253struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id,
254 unsigned char type)
185{ 255{
186 struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL); 256 struct tifm_dev *sock = NULL;
187 257
188 if (dev) { 258 if (!tifm_media_type_name(type, 0))
189 spin_lock_init(&dev->lock); 259 return sock;
190 260
191 dev->dev.parent = fm->dev; 261 sock = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
192 dev->dev.bus = &tifm_bus_type; 262 if (sock) {
193 dev->dev.release = tifm_free_device; 263 spin_lock_init(&sock->lock);
194 dev->signal_irq = tifm_dummy_signal_irq; 264 sock->type = type;
265 sock->socket_id = id;
266 sock->card_event = tifm_dummy_event;
267 sock->data_event = tifm_dummy_event;
268
269 sock->dev.parent = fm->cdev.dev;
270 sock->dev.bus = &tifm_bus_type;
271 sock->dev.dma_mask = fm->cdev.dev->dma_mask;
272 sock->dev.release = tifm_free_device;
273
274 snprintf(sock->dev.bus_id, BUS_ID_SIZE,
275 "tifm_%s%u:%u", tifm_media_type_name(type, 2),
276 fm->id, id);
277 printk(KERN_INFO DRIVER_NAME
278 ": %s card detected in socket %u:%u\n",
279 tifm_media_type_name(type, 0), fm->id, id);
195 } 280 }
196 return dev; 281 return sock;
197} 282}
198EXPORT_SYMBOL(tifm_alloc_device); 283EXPORT_SYMBOL(tifm_alloc_device);
199 284
@@ -218,54 +303,15 @@ void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
218} 303}
219EXPORT_SYMBOL(tifm_unmap_sg); 304EXPORT_SYMBOL(tifm_unmap_sg);
220 305
221static int tifm_device_probe(struct device *dev) 306void tifm_queue_work(struct work_struct *work)
222{
223 struct tifm_driver *drv;
224 struct tifm_dev *fm_dev;
225 int rc = 0;
226 const tifm_media_id *id;
227
228 drv = container_of(dev->driver, struct tifm_driver, driver);
229 fm_dev = container_of(dev, struct tifm_dev, dev);
230 get_device(dev);
231 if (!fm_dev->drv && drv->probe && drv->id_table) {
232 rc = -ENODEV;
233 id = tifm_device_match(drv->id_table, fm_dev);
234 if (id)
235 rc = drv->probe(fm_dev);
236 if (rc >= 0) {
237 rc = 0;
238 fm_dev->drv = drv;
239 }
240 }
241 if (rc)
242 put_device(dev);
243 return rc;
244}
245
246static int tifm_device_remove(struct device *dev)
247{ 307{
248 struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev); 308 queue_work(workqueue, work);
249 struct tifm_driver *drv = fm_dev->drv;
250
251 if (drv) {
252 fm_dev->signal_irq = tifm_dummy_signal_irq;
253 if (drv->remove)
254 drv->remove(fm_dev);
255 fm_dev->drv = NULL;
256 }
257
258 put_device(dev);
259 return 0;
260} 309}
310EXPORT_SYMBOL(tifm_queue_work);
261 311
262int tifm_register_driver(struct tifm_driver *drv) 312int tifm_register_driver(struct tifm_driver *drv)
263{ 313{
264 drv->driver.bus = &tifm_bus_type; 314 drv->driver.bus = &tifm_bus_type;
265 drv->driver.probe = tifm_device_probe;
266 drv->driver.remove = tifm_device_remove;
267 drv->driver.suspend = tifm_device_suspend;
268 drv->driver.resume = tifm_device_resume;
269 315
270 return driver_register(&drv->driver); 316 return driver_register(&drv->driver);
271} 317}
@@ -279,13 +325,25 @@ EXPORT_SYMBOL(tifm_unregister_driver);
279 325
280static int __init tifm_init(void) 326static int __init tifm_init(void)
281{ 327{
282 int rc = bus_register(&tifm_bus_type); 328 int rc;
283 329
284 if (!rc) { 330 workqueue = create_freezeable_workqueue("tifm");
285 rc = class_register(&tifm_adapter_class); 331 if (!workqueue)
286 if (rc) 332 return -ENOMEM;
287 bus_unregister(&tifm_bus_type); 333
288 } 334 rc = bus_register(&tifm_bus_type);
335
336 if (rc)
337 goto err_out_wq;
338
339 rc = class_register(&tifm_adapter_class);
340 if (!rc)
341 return 0;
342
343 bus_unregister(&tifm_bus_type);
344
345err_out_wq:
346 destroy_workqueue(workqueue);
289 347
290 return rc; 348 return rc;
291} 349}
@@ -294,6 +352,7 @@ static void __exit tifm_exit(void)
294{ 352{
295 class_unregister(&tifm_adapter_class); 353 class_unregister(&tifm_adapter_class);
296 bus_unregister(&tifm_bus_type); 354 bus_unregister(&tifm_bus_type);
355 destroy_workqueue(workqueue);
297} 356}
298 357
299subsys_initcall(tifm_init); 358subsys_initcall(tifm_init);