aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/tifm_7xx1.c
diff options
context:
space:
mode:
authorAlex Dubov <oakad@yahoo.com>2006-12-10 09:55:33 -0500
committerPierre Ossman <drzeus@drzeus.cx>2007-02-04 14:54:09 -0500
commit6412d927313f08808d61b7efba8da43717d4e8d2 (patch)
tree5fc40ebbf578a9d7cd15fa8d61236f270ac4f6b8 /drivers/misc/tifm_7xx1.c
parent1499ead31ede528a657c50761c4780c40f929d6d (diff)
tifm_7xx1: Merge media insert and media remove functions
Hardware does not say whether card was inserted or removed when reporting socket events. Moreover, during suspend, media can be removed or switched to some other card type without notification. Therefore, for each socket in the change set the following is performed: 1. If there's active device in the socket it's unregistered 2. Media detection is performed 3. If detection recognizes supportable media, new device is registered This patch also alters some macros and variable names to enhance clarity. Signed-off-by: Alex Dubov <oakad@yahoo.com> Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/misc/tifm_7xx1.c')
-rw-r--r--drivers/misc/tifm_7xx1.c254
1 files changed, 126 insertions, 128 deletions
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index 24b20a417a23..5ab81dd37857 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -21,47 +21,12 @@ static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
21 21
22 spin_lock_irqsave(&fm->lock, flags); 22 spin_lock_irqsave(&fm->lock, flags);
23 if (!fm->inhibit_new_cards) { 23 if (!fm->inhibit_new_cards) {
24 fm->remove_mask |= 1 << sock->socket_id; 24 fm->socket_change_set |= 1 << sock->socket_id;
25 queue_work(fm->wq, &fm->media_remover); 25 queue_work(fm->wq, &fm->media_switcher);
26 } 26 }
27 spin_unlock_irqrestore(&fm->lock, flags); 27 spin_unlock_irqrestore(&fm->lock, flags);
28} 28}
29 29
30static void tifm_7xx1_remove_media(struct work_struct *work)
31{
32 struct tifm_adapter *fm =
33 container_of(work, struct tifm_adapter, media_remover);
34 unsigned long flags;
35 int cnt;
36 struct tifm_dev *sock;
37
38 if (!class_device_get(&fm->cdev))
39 return;
40 spin_lock_irqsave(&fm->lock, flags);
41 for (cnt = 0; cnt < fm->max_sockets; cnt++) {
42 if (fm->sockets[cnt] && (fm->remove_mask & (1 << cnt))) {
43 printk(KERN_INFO DRIVER_NAME
44 ": demand removing card from socket %d\n", cnt);
45 sock = fm->sockets[cnt];
46 fm->sockets[cnt] = NULL;
47 fm->remove_mask &= ~(1 << cnt);
48
49 writel(0x0e00, sock->addr + SOCK_CONTROL);
50
51 writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
52 fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
53 writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
54 fm->addr + FM_SET_INTERRUPT_ENABLE);
55
56 spin_unlock_irqrestore(&fm->lock, flags);
57 device_unregister(&sock->dev);
58 spin_lock_irqsave(&fm->lock, flags);
59 }
60 }
61 spin_unlock_irqrestore(&fm->lock, flags);
62 class_device_put(&fm->cdev);
63}
64
65static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id) 30static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
66{ 31{
67 struct tifm_adapter *fm = dev_id; 32 struct tifm_adapter *fm = dev_id;
@@ -79,32 +44,27 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
79 if (irq_status & TIFM_IRQ_ENABLE) { 44 if (irq_status & TIFM_IRQ_ENABLE) {
80 writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); 45 writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
81 46
82 for (cnt = 0; cnt < fm->max_sockets; cnt++) { 47 for (cnt = 0; cnt < fm->num_sockets; cnt++) {
83 sock = fm->sockets[cnt]; 48 sock = fm->sockets[cnt];
84 sock_irq_status = (irq_status >> cnt) & 49 sock_irq_status = (irq_status >> cnt)
85 (TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK); 50 & (TIFM_IRQ_FIFOMASK(1)
86 51 | TIFM_IRQ_CARDMASK(1));
87 if (sock) {
88 if (sock_irq_status)
89 sock->signal_irq(sock, sock_irq_status);
90 52
91 if (irq_status & (1 << cnt)) 53 if (sock && sock_irq_status)
92 fm->remove_mask |= 1 << cnt; 54 sock->signal_irq(sock, sock_irq_status);
93 } else {
94 if (irq_status & (1 << cnt))
95 fm->insert_mask |= 1 << cnt;
96 }
97 } 55 }
56
57 fm->socket_change_set |= irq_status
58 & ((1 << fm->num_sockets) - 1);
98 } 59 }
99 writel(irq_status, fm->addr + FM_INTERRUPT_STATUS); 60 writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
100 61
101 if (!fm->inhibit_new_cards) { 62 if (!fm->inhibit_new_cards) {
102 if (!fm->remove_mask && !fm->insert_mask) { 63 if (!fm->socket_change_set) {
103 writel(TIFM_IRQ_ENABLE, 64 writel(TIFM_IRQ_ENABLE,
104 fm->addr + FM_SET_INTERRUPT_ENABLE); 65 fm->addr + FM_SET_INTERRUPT_ENABLE);
105 } else { 66 } else {
106 queue_work(fm->wq, &fm->media_remover); 67 queue_work(fm->wq, &fm->media_switcher);
107 queue_work(fm->wq, &fm->media_inserter);
108 } 68 }
109 } 69 }
110 70
@@ -163,84 +123,125 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
163 return base_addr + ((sock_num + 1) << 10); 123 return base_addr + ((sock_num + 1) << 10);
164} 124}
165 125
166static void tifm_7xx1_insert_media(struct work_struct *work) 126static void tifm_7xx1_switch_media(struct work_struct *work)
167{ 127{
168 struct tifm_adapter *fm = 128 struct tifm_adapter *fm =
169 container_of(work, struct tifm_adapter, media_inserter); 129 container_of(work, struct tifm_adapter, media_switcher);
170 unsigned long flags; 130 unsigned long flags;
171 tifm_media_id media_id; 131 tifm_media_id media_id;
172 char *card_name = "xx"; 132 char *card_name = "xx";
173 int cnt, ok_to_register; 133 int cnt;
174 unsigned int insert_mask; 134 struct tifm_dev *sock;
175 struct tifm_dev *new_sock = NULL; 135 unsigned int socket_change_set;
176 136
177 if (!class_device_get(&fm->cdev)) 137 if (!class_device_get(&fm->cdev))
178 return; 138 return;
179 spin_lock_irqsave(&fm->lock, flags); 139
180 insert_mask = fm->insert_mask; 140 while (1) {
181 fm->insert_mask = 0; 141 spin_lock_irqsave(&fm->lock, flags);
182 if (fm->inhibit_new_cards) { 142 socket_change_set = fm->socket_change_set;
143 fm->socket_change_set = 0;
144
145 dev_dbg(fm->dev, "checking media set %x\n",
146 socket_change_set);
147
148 if (fm->inhibit_new_cards)
149 socket_change_set = (1 << fm->num_sockets) - 1;
183 spin_unlock_irqrestore(&fm->lock, flags); 150 spin_unlock_irqrestore(&fm->lock, flags);
184 class_device_put(&fm->cdev);
185 return;
186 }
187 spin_unlock_irqrestore(&fm->lock, flags);
188 151
189 for (cnt = 0; cnt < fm->max_sockets; cnt++) { 152 if (!socket_change_set)
190 if (!(insert_mask & (1 << cnt))) 153 break;
191 continue; 154
192 155 spin_lock_irqsave(&fm->lock, flags);
193 media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt), 156 for (cnt = 0; cnt < fm->num_sockets; cnt++) {
194 fm->max_sockets == 2); 157 if (!(socket_change_set & (1 << cnt)))
195 if (media_id) { 158 continue;
196 ok_to_register = 0; 159 sock = fm->sockets[cnt];
197 new_sock = tifm_alloc_device(fm); 160 if (sock) {
198 if (new_sock) {
199 new_sock->addr = tifm_7xx1_sock_addr(fm->addr,
200 cnt);
201 new_sock->media_id = media_id;
202 new_sock->socket_id = cnt;
203 switch (media_id) {
204 case 1:
205 card_name = "xd";
206 break;
207 case 2:
208 card_name = "ms";
209 break;
210 case 3:
211 card_name = "sd";
212 break;
213 default:
214 break;
215 }
216 snprintf(new_sock->dev.bus_id, BUS_ID_SIZE,
217 "tifm_%s%u:%u", card_name, fm->id, cnt);
218 printk(KERN_INFO DRIVER_NAME 161 printk(KERN_INFO DRIVER_NAME
219 ": %s card detected in socket %d\n", 162 ": demand removing card from socket %d\n",
220 card_name, cnt); 163 cnt);
164 fm->sockets[cnt] = NULL;
165 spin_unlock_irqrestore(&fm->lock, flags);
166 device_unregister(&sock->dev);
221 spin_lock_irqsave(&fm->lock, flags); 167 spin_lock_irqsave(&fm->lock, flags);
222 if (!fm->sockets[cnt]) { 168 writel(0x0e00,
223 fm->sockets[cnt] = new_sock; 169 tifm_7xx1_sock_addr(fm->addr, cnt)
224 ok_to_register = 1; 170 + SOCK_CONTROL);
171 }
172 if (fm->inhibit_new_cards)
173 continue;
174
175 spin_unlock_irqrestore(&fm->lock, flags);
176 media_id = tifm_7xx1_toggle_sock_power(
177 tifm_7xx1_sock_addr(fm->addr, cnt),
178 fm->num_sockets == 2);
179 if (media_id) {
180 sock = tifm_alloc_device(fm);
181 if (sock) {
182 sock->addr = tifm_7xx1_sock_addr(fm->addr,
183 cnt);
184 sock->media_id = media_id;
185 sock->socket_id = cnt;
186 switch (media_id) {
187 case 1:
188 card_name = "xd";
189 break;
190 case 2:
191 card_name = "ms";
192 break;
193 case 3:
194 card_name = "sd";
195 break;
196 default:
197 tifm_free_device(&sock->dev);
198 spin_lock_irqsave(&fm->lock, flags);
199 continue;
200 }
201 snprintf(sock->dev.bus_id, BUS_ID_SIZE,
202 "tifm_%s%u:%u", card_name, fm->id, cnt);
203 printk(KERN_INFO DRIVER_NAME
204 ": %s card detected in socket %d\n",
205 card_name, cnt);
206 if (!device_register(&sock->dev)) {
207 spin_lock_irqsave(&fm->lock, flags);
208 if (!fm->sockets[cnt]) {
209 fm->sockets[cnt] = sock;
210 sock = NULL;
211 }
212 spin_unlock_irqrestore(&fm->lock, flags);
213 }
214 if (sock)
215 tifm_free_device(&sock->dev);
225 } 216 }
217 spin_lock_irqsave(&fm->lock, flags);
218 }
219 }
220
221 if (!fm->inhibit_new_cards) {
222 writel(TIFM_IRQ_FIFOMASK(socket_change_set)
223 | TIFM_IRQ_CARDMASK(socket_change_set),
224 fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
225 writel(TIFM_IRQ_FIFOMASK(socket_change_set)
226 | TIFM_IRQ_CARDMASK(socket_change_set),
227 fm->addr + FM_SET_INTERRUPT_ENABLE);
228 writel(TIFM_IRQ_ENABLE,
229 fm->addr + FM_SET_INTERRUPT_ENABLE);
230 spin_unlock_irqrestore(&fm->lock, flags);
231 break;
232 } else {
233 for (cnt = 0; cnt < fm->num_sockets; cnt++) {
234 if (fm->sockets[cnt])
235 fm->socket_change_set |= 1 << cnt;
236 }
237 if (!fm->socket_change_set) {
238 spin_unlock_irqrestore(&fm->lock, flags);
239 break;
240 } else {
226 spin_unlock_irqrestore(&fm->lock, flags); 241 spin_unlock_irqrestore(&fm->lock, flags);
227 if (!ok_to_register ||
228 device_register(&new_sock->dev)) {
229 spin_lock_irqsave(&fm->lock, flags);
230 fm->sockets[cnt] = NULL;
231 spin_unlock_irqrestore(&fm->lock,
232 flags);
233 tifm_free_device(&new_sock->dev);
234 }
235 } 242 }
236 } 243 }
237 writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
238 fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
239 writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
240 fm->addr + FM_SET_INTERRUPT_ENABLE);
241 } 244 }
242
243 writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
244 class_device_put(&fm->cdev); 245 class_device_put(&fm->cdev);
245} 246}
246 247
@@ -251,13 +252,12 @@ static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
251 252
252 spin_lock_irqsave(&fm->lock, flags); 253 spin_lock_irqsave(&fm->lock, flags);
253 fm->inhibit_new_cards = 1; 254 fm->inhibit_new_cards = 1;
254 fm->remove_mask = 0xf; 255 fm->socket_change_set = 0xf;
255 fm->insert_mask = 0;
256 writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); 256 writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
257 spin_unlock_irqrestore(&fm->lock, flags); 257 spin_unlock_irqrestore(&fm->lock, flags);
258 flush_workqueue(fm->wq); 258 flush_workqueue(fm->wq);
259 259
260 tifm_7xx1_remove_media(&fm->media_remover); 260 tifm_7xx1_switch_media(&fm->media_switcher);
261 261
262 pci_set_power_state(dev, PCI_D3hot); 262 pci_set_power_state(dev, PCI_D3hot);
263 pci_disable_device(dev); 263 pci_disable_device(dev);
@@ -279,9 +279,9 @@ static int tifm_7xx1_resume(struct pci_dev *dev)
279 fm->inhibit_new_cards = 0; 279 fm->inhibit_new_cards = 0;
280 writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS); 280 writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS);
281 writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); 281 writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
282 writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK, 282 writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
283 fm->addr + FM_SET_INTERRUPT_ENABLE); 283 fm->addr + FM_SET_INTERRUPT_ENABLE);
284 fm->insert_mask = 0xf; 284 fm->socket_change_set = 0xf;
285 spin_unlock_irqrestore(&fm->lock, flags); 285 spin_unlock_irqrestore(&fm->lock, flags);
286 return 0; 286 return 0;
287} 287}
@@ -318,14 +318,13 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
318 } 318 }
319 319
320 fm->dev = &dev->dev; 320 fm->dev = &dev->dev;
321 fm->max_sockets = (dev->device == 0x803B) ? 2 : 4; 321 fm->num_sockets = (dev->device == 0x803B) ? 2 : 4;
322 fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets, 322 fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets,
323 GFP_KERNEL); 323 GFP_KERNEL);
324 if (!fm->sockets) 324 if (!fm->sockets)
325 goto err_out_free; 325 goto err_out_free;
326 326
327 INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media); 327 INIT_WORK(&fm->media_switcher, tifm_7xx1_switch_media);
328 INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media);
329 fm->eject = tifm_7xx1_eject; 328 fm->eject = tifm_7xx1_eject;
330 pci_set_drvdata(dev, fm); 329 pci_set_drvdata(dev, fm);
331 330
@@ -343,10 +342,10 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
343 goto err_out_irq; 342 goto err_out_irq;
344 343
345 writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); 344 writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
346 writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK, 345 writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
347 fm->addr + FM_SET_INTERRUPT_ENABLE); 346 fm->addr + FM_SET_INTERRUPT_ENABLE);
348 347
349 fm->insert_mask = 0xf; 348 fm->socket_change_set = 0xf;
350 349
351 return 0; 350 return 0;
352 351
@@ -373,14 +372,13 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
373 372
374 spin_lock_irqsave(&fm->lock, flags); 373 spin_lock_irqsave(&fm->lock, flags);
375 fm->inhibit_new_cards = 1; 374 fm->inhibit_new_cards = 1;
376 fm->remove_mask = 0xf; 375 fm->socket_change_set = 0xf;
377 fm->insert_mask = 0;
378 writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); 376 writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
379 spin_unlock_irqrestore(&fm->lock, flags); 377 spin_unlock_irqrestore(&fm->lock, flags);
380 378
381 flush_workqueue(fm->wq); 379 flush_workqueue(fm->wq);
382 380
383 tifm_7xx1_remove_media(&fm->media_remover); 381 tifm_7xx1_switch_media(&fm->media_switcher);
384 382
385 writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE); 383 writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
386 free_irq(dev->irq, fm); 384 free_irq(dev->irq, fm);