diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/pcmcia/pd6729.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/pcmcia/pd6729.c')
-rw-r--r-- | drivers/pcmcia/pd6729.c | 871 |
1 files changed, 871 insertions, 0 deletions
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c new file mode 100644 index 000000000000..3f4364341d8d --- /dev/null +++ b/drivers/pcmcia/pd6729.c | |||
@@ -0,0 +1,871 @@ | |||
1 | /* | ||
2 | * Driver for the Cirrus PD6729 PCI-PCMCIA bridge. | ||
3 | * | ||
4 | * Based on the i82092.c driver. | ||
5 | * | ||
6 | * This software may be used and distributed according to the terms of | ||
7 | * the GNU General Public License, incorporated herein by reference. | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/config.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/pci.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/workqueue.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/device.h> | ||
18 | |||
19 | #include <pcmcia/cs_types.h> | ||
20 | #include <pcmcia/ss.h> | ||
21 | #include <pcmcia/cs.h> | ||
22 | |||
23 | #include <asm/system.h> | ||
24 | #include <asm/io.h> | ||
25 | |||
26 | #include "pd6729.h" | ||
27 | #include "i82365.h" | ||
28 | #include "cirrus.h" | ||
29 | |||
30 | MODULE_LICENSE("GPL"); | ||
31 | MODULE_DESCRIPTION("Driver for the Cirrus PD6729 PCI-PCMCIA bridge"); | ||
32 | MODULE_AUTHOR("Jun Komuro <komurojun-mbn@nifty.com>"); | ||
33 | |||
34 | #define MAX_SOCKETS 2 | ||
35 | |||
36 | /* | ||
37 | * simple helper functions | ||
38 | * External clock time, in nanoseconds. 120 ns = 8.33 MHz | ||
39 | */ | ||
40 | #define to_cycles(ns) ((ns)/120) | ||
41 | |||
42 | #ifndef NO_IRQ | ||
43 | #define NO_IRQ ((unsigned int)(0)) | ||
44 | #endif | ||
45 | |||
46 | /* | ||
47 | * PARAMETERS | ||
48 | * irq_mode=n | ||
49 | * Specifies the interrupt delivery mode. The default (1) is to use PCI | ||
50 | * interrupts; a value of 0 selects ISA interrupts. This must be set for | ||
51 | * correct operation of PCI card readers. | ||
52 | * | ||
53 | * irq_list=i,j,... | ||
54 | * This list limits the set of interrupts that can be used by PCMCIA | ||
55 | * cards. | ||
56 | * The default list is 3,4,5,7,9,10,11. | ||
57 | * (irq_list parameter is not used, if irq_mode = 1) | ||
58 | */ | ||
59 | |||
60 | static int irq_mode = 1; /* 0 = ISA interrupt, 1 = PCI interrupt */ | ||
61 | static int irq_list[16]; | ||
62 | static int irq_list_count = 0; | ||
63 | |||
64 | module_param(irq_mode, int, 0444); | ||
65 | module_param_array(irq_list, int, &irq_list_count, 0444); | ||
66 | MODULE_PARM_DESC(irq_mode, | ||
67 | "interrupt delivery mode. 0 = ISA, 1 = PCI. default is 1"); | ||
68 | MODULE_PARM_DESC(irq_list, "interrupts that can be used by PCMCIA cards"); | ||
69 | |||
70 | static DEFINE_SPINLOCK(port_lock); | ||
71 | |||
72 | /* basic value read/write functions */ | ||
73 | |||
74 | static unsigned char indirect_read(struct pd6729_socket *socket, | ||
75 | unsigned short reg) | ||
76 | { | ||
77 | unsigned long port; | ||
78 | unsigned char val; | ||
79 | unsigned long flags; | ||
80 | |||
81 | spin_lock_irqsave(&port_lock, flags); | ||
82 | reg += socket->number * 0x40; | ||
83 | port = socket->io_base; | ||
84 | outb(reg, port); | ||
85 | val = inb(port + 1); | ||
86 | spin_unlock_irqrestore(&port_lock, flags); | ||
87 | |||
88 | return val; | ||
89 | } | ||
90 | |||
91 | static unsigned short indirect_read16(struct pd6729_socket *socket, | ||
92 | unsigned short reg) | ||
93 | { | ||
94 | unsigned long port; | ||
95 | unsigned short tmp; | ||
96 | unsigned long flags; | ||
97 | |||
98 | spin_lock_irqsave(&port_lock, flags); | ||
99 | reg = reg + socket->number * 0x40; | ||
100 | port = socket->io_base; | ||
101 | outb(reg, port); | ||
102 | tmp = inb(port + 1); | ||
103 | reg++; | ||
104 | outb(reg, port); | ||
105 | tmp = tmp | (inb(port + 1) << 8); | ||
106 | spin_unlock_irqrestore(&port_lock, flags); | ||
107 | |||
108 | return tmp; | ||
109 | } | ||
110 | |||
111 | static void indirect_write(struct pd6729_socket *socket, unsigned short reg, | ||
112 | unsigned char value) | ||
113 | { | ||
114 | unsigned long port; | ||
115 | unsigned long flags; | ||
116 | |||
117 | spin_lock_irqsave(&port_lock, flags); | ||
118 | reg = reg + socket->number * 0x40; | ||
119 | port = socket->io_base; | ||
120 | outb(reg, port); | ||
121 | outb(value, port + 1); | ||
122 | spin_unlock_irqrestore(&port_lock, flags); | ||
123 | } | ||
124 | |||
125 | static void indirect_setbit(struct pd6729_socket *socket, unsigned short reg, | ||
126 | unsigned char mask) | ||
127 | { | ||
128 | unsigned long port; | ||
129 | unsigned char val; | ||
130 | unsigned long flags; | ||
131 | |||
132 | spin_lock_irqsave(&port_lock, flags); | ||
133 | reg = reg + socket->number * 0x40; | ||
134 | port = socket->io_base; | ||
135 | outb(reg, port); | ||
136 | val = inb(port + 1); | ||
137 | val |= mask; | ||
138 | outb(reg, port); | ||
139 | outb(val, port + 1); | ||
140 | spin_unlock_irqrestore(&port_lock, flags); | ||
141 | } | ||
142 | |||
143 | static void indirect_resetbit(struct pd6729_socket *socket, unsigned short reg, | ||
144 | unsigned char mask) | ||
145 | { | ||
146 | unsigned long port; | ||
147 | unsigned char val; | ||
148 | unsigned long flags; | ||
149 | |||
150 | spin_lock_irqsave(&port_lock, flags); | ||
151 | reg = reg + socket->number * 0x40; | ||
152 | port = socket->io_base; | ||
153 | outb(reg, port); | ||
154 | val = inb(port + 1); | ||
155 | val &= ~mask; | ||
156 | outb(reg, port); | ||
157 | outb(val, port + 1); | ||
158 | spin_unlock_irqrestore(&port_lock, flags); | ||
159 | } | ||
160 | |||
161 | static void indirect_write16(struct pd6729_socket *socket, unsigned short reg, | ||
162 | unsigned short value) | ||
163 | { | ||
164 | unsigned long port; | ||
165 | unsigned char val; | ||
166 | unsigned long flags; | ||
167 | |||
168 | spin_lock_irqsave(&port_lock, flags); | ||
169 | reg = reg + socket->number * 0x40; | ||
170 | port = socket->io_base; | ||
171 | |||
172 | outb(reg, port); | ||
173 | val = value & 255; | ||
174 | outb(val, port + 1); | ||
175 | |||
176 | reg++; | ||
177 | |||
178 | outb(reg, port); | ||
179 | val = value >> 8; | ||
180 | outb(val, port + 1); | ||
181 | spin_unlock_irqrestore(&port_lock, flags); | ||
182 | } | ||
183 | |||
184 | /* Interrupt handler functionality */ | ||
185 | |||
186 | static irqreturn_t pd6729_interrupt(int irq, void *dev, struct pt_regs *regs) | ||
187 | { | ||
188 | struct pd6729_socket *socket = (struct pd6729_socket *)dev; | ||
189 | int i; | ||
190 | int loopcount = 0; | ||
191 | int handled = 0; | ||
192 | unsigned int events, active = 0; | ||
193 | |||
194 | while (1) { | ||
195 | loopcount++; | ||
196 | if (loopcount > 20) { | ||
197 | printk(KERN_ERR "pd6729: infinite eventloop " | ||
198 | "in interrupt\n"); | ||
199 | break; | ||
200 | } | ||
201 | |||
202 | active = 0; | ||
203 | |||
204 | for (i = 0; i < MAX_SOCKETS; i++) { | ||
205 | unsigned int csc; | ||
206 | |||
207 | /* card status change register */ | ||
208 | csc = indirect_read(&socket[i], I365_CSC); | ||
209 | if (csc == 0) /* no events on this socket */ | ||
210 | continue; | ||
211 | |||
212 | handled = 1; | ||
213 | events = 0; | ||
214 | |||
215 | if (csc & I365_CSC_DETECT) { | ||
216 | events |= SS_DETECT; | ||
217 | dprintk("Card detected in socket %i!\n", i); | ||
218 | } | ||
219 | |||
220 | if (indirect_read(&socket[i], I365_INTCTL) | ||
221 | & I365_PC_IOCARD) { | ||
222 | /* For IO/CARDS, bit 0 means "read the card" */ | ||
223 | events |= (csc & I365_CSC_STSCHG) | ||
224 | ? SS_STSCHG : 0; | ||
225 | } else { | ||
226 | /* Check for battery/ready events */ | ||
227 | events |= (csc & I365_CSC_BVD1) | ||
228 | ? SS_BATDEAD : 0; | ||
229 | events |= (csc & I365_CSC_BVD2) | ||
230 | ? SS_BATWARN : 0; | ||
231 | events |= (csc & I365_CSC_READY) | ||
232 | ? SS_READY : 0; | ||
233 | } | ||
234 | |||
235 | if (events) { | ||
236 | pcmcia_parse_events(&socket[i].socket, events); | ||
237 | } | ||
238 | active |= events; | ||
239 | } | ||
240 | |||
241 | if (active == 0) /* no more events to handle */ | ||
242 | break; | ||
243 | } | ||
244 | return IRQ_RETVAL(handled); | ||
245 | } | ||
246 | |||
247 | /* socket functions */ | ||
248 | |||
249 | static void pd6729_interrupt_wrapper(unsigned long data) | ||
250 | { | ||
251 | struct pd6729_socket *socket = (struct pd6729_socket *) data; | ||
252 | |||
253 | pd6729_interrupt(0, (void *)socket, NULL); | ||
254 | mod_timer(&socket->poll_timer, jiffies + HZ); | ||
255 | } | ||
256 | |||
257 | static int pd6729_get_status(struct pcmcia_socket *sock, u_int *value) | ||
258 | { | ||
259 | struct pd6729_socket *socket | ||
260 | = container_of(sock, struct pd6729_socket, socket); | ||
261 | unsigned int status; | ||
262 | unsigned int data; | ||
263 | struct pd6729_socket *t; | ||
264 | |||
265 | /* Interface Status Register */ | ||
266 | status = indirect_read(socket, I365_STATUS); | ||
267 | *value = 0; | ||
268 | |||
269 | if ((status & I365_CS_DETECT) == I365_CS_DETECT) { | ||
270 | *value |= SS_DETECT; | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * IO cards have a different meaning of bits 0,1 | ||
275 | * Also notice the inverse-logic on the bits | ||
276 | */ | ||
277 | if (indirect_read(socket, I365_INTCTL) & I365_PC_IOCARD) { | ||
278 | /* IO card */ | ||
279 | if (!(status & I365_CS_STSCHG)) | ||
280 | *value |= SS_STSCHG; | ||
281 | } else { | ||
282 | /* non I/O card */ | ||
283 | if (!(status & I365_CS_BVD1)) | ||
284 | *value |= SS_BATDEAD; | ||
285 | if (!(status & I365_CS_BVD2)) | ||
286 | *value |= SS_BATWARN; | ||
287 | } | ||
288 | |||
289 | if (status & I365_CS_WRPROT) | ||
290 | *value |= SS_WRPROT; /* card is write protected */ | ||
291 | |||
292 | if (status & I365_CS_READY) | ||
293 | *value |= SS_READY; /* card is not busy */ | ||
294 | |||
295 | if (status & I365_CS_POWERON) | ||
296 | *value |= SS_POWERON; /* power is applied to the card */ | ||
297 | |||
298 | t = (socket->number) ? socket : socket + 1; | ||
299 | indirect_write(t, PD67_EXT_INDEX, PD67_EXTERN_DATA); | ||
300 | data = indirect_read16(t, PD67_EXT_DATA); | ||
301 | *value |= (data & PD67_EXD_VS1(socket->number)) ? 0 : SS_3VCARD; | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | |||
307 | static int pd6729_get_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
308 | { | ||
309 | struct pd6729_socket *socket | ||
310 | = container_of(sock, struct pd6729_socket, socket); | ||
311 | unsigned char reg, vcc, vpp; | ||
312 | |||
313 | state->flags = 0; | ||
314 | state->Vcc = 0; | ||
315 | state->Vpp = 0; | ||
316 | state->io_irq = 0; | ||
317 | state->csc_mask = 0; | ||
318 | |||
319 | /* First the power status of the socket */ | ||
320 | reg = indirect_read(socket, I365_POWER); | ||
321 | |||
322 | if (reg & I365_PWR_AUTO) | ||
323 | state->flags |= SS_PWR_AUTO; /* Automatic Power Switch */ | ||
324 | |||
325 | if (reg & I365_PWR_OUT) | ||
326 | state->flags |= SS_OUTPUT_ENA; /* Output signals are enabled */ | ||
327 | |||
328 | vcc = reg & I365_VCC_MASK; vpp = reg & I365_VPP1_MASK; | ||
329 | |||
330 | if (reg & I365_VCC_5V) { | ||
331 | state->Vcc = (indirect_read(socket, PD67_MISC_CTL_1) & | ||
332 | PD67_MC1_VCC_3V) ? 33 : 50; | ||
333 | |||
334 | if (vpp == I365_VPP1_5V) { | ||
335 | if (state->Vcc == 50) | ||
336 | state->Vpp = 50; | ||
337 | else | ||
338 | state->Vpp = 33; | ||
339 | } | ||
340 | if (vpp == I365_VPP1_12V) | ||
341 | state->Vpp = 120; | ||
342 | } | ||
343 | |||
344 | /* Now the IO card, RESET flags and IO interrupt */ | ||
345 | reg = indirect_read(socket, I365_INTCTL); | ||
346 | |||
347 | if ((reg & I365_PC_RESET) == 0) | ||
348 | state->flags |= SS_RESET; | ||
349 | if (reg & I365_PC_IOCARD) | ||
350 | state->flags |= SS_IOCARD; /* This is an IO card */ | ||
351 | |||
352 | /* Set the IRQ number */ | ||
353 | state->io_irq = socket->card_irq; | ||
354 | |||
355 | /* Card status change */ | ||
356 | reg = indirect_read(socket, I365_CSCINT); | ||
357 | |||
358 | if (reg & I365_CSC_DETECT) | ||
359 | state->csc_mask |= SS_DETECT; /* Card detect is enabled */ | ||
360 | |||
361 | if (state->flags & SS_IOCARD) {/* IO Cards behave different */ | ||
362 | if (reg & I365_CSC_STSCHG) | ||
363 | state->csc_mask |= SS_STSCHG; | ||
364 | } else { | ||
365 | if (reg & I365_CSC_BVD1) | ||
366 | state->csc_mask |= SS_BATDEAD; | ||
367 | if (reg & I365_CSC_BVD2) | ||
368 | state->csc_mask |= SS_BATWARN; | ||
369 | if (reg & I365_CSC_READY) | ||
370 | state->csc_mask |= SS_READY; | ||
371 | } | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
377 | { | ||
378 | struct pd6729_socket *socket | ||
379 | = container_of(sock, struct pd6729_socket, socket); | ||
380 | unsigned char reg, data; | ||
381 | |||
382 | /* First, set the global controller options */ | ||
383 | indirect_write(socket, I365_GBLCTL, 0x00); | ||
384 | indirect_write(socket, I365_GENCTL, 0x00); | ||
385 | |||
386 | /* Values for the IGENC register */ | ||
387 | socket->card_irq = state->io_irq; | ||
388 | |||
389 | reg = 0; | ||
390 | /* The reset bit has "inverse" logic */ | ||
391 | if (!(state->flags & SS_RESET)) | ||
392 | reg |= I365_PC_RESET; | ||
393 | if (state->flags & SS_IOCARD) | ||
394 | reg |= I365_PC_IOCARD; | ||
395 | |||
396 | /* IGENC, Interrupt and General Control Register */ | ||
397 | indirect_write(socket, I365_INTCTL, reg); | ||
398 | |||
399 | /* Power registers */ | ||
400 | |||
401 | reg = I365_PWR_NORESET; /* default: disable resetdrv on resume */ | ||
402 | |||
403 | if (state->flags & SS_PWR_AUTO) { | ||
404 | dprintk("Auto power\n"); | ||
405 | reg |= I365_PWR_AUTO; /* automatic power mngmnt */ | ||
406 | } | ||
407 | if (state->flags & SS_OUTPUT_ENA) { | ||
408 | dprintk("Power Enabled\n"); | ||
409 | reg |= I365_PWR_OUT; /* enable power */ | ||
410 | } | ||
411 | |||
412 | switch (state->Vcc) { | ||
413 | case 0: | ||
414 | break; | ||
415 | case 33: | ||
416 | dprintk("setting voltage to Vcc to 3.3V on socket %i\n", | ||
417 | socket->number); | ||
418 | reg |= I365_VCC_5V; | ||
419 | indirect_setbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V); | ||
420 | break; | ||
421 | case 50: | ||
422 | dprintk("setting voltage to Vcc to 5V on socket %i\n", | ||
423 | socket->number); | ||
424 | reg |= I365_VCC_5V; | ||
425 | indirect_resetbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V); | ||
426 | break; | ||
427 | default: | ||
428 | dprintk("pd6729: pd6729_set_socket called with " | ||
429 | "invalid VCC power value: %i\n", | ||
430 | state->Vcc); | ||
431 | return -EINVAL; | ||
432 | } | ||
433 | |||
434 | switch (state->Vpp) { | ||
435 | case 0: | ||
436 | dprintk("not setting Vpp on socket %i\n", socket->number); | ||
437 | break; | ||
438 | case 33: | ||
439 | case 50: | ||
440 | dprintk("setting Vpp to Vcc for socket %i\n", socket->number); | ||
441 | reg |= I365_VPP1_5V; | ||
442 | break; | ||
443 | case 120: | ||
444 | dprintk("setting Vpp to 12.0\n"); | ||
445 | reg |= I365_VPP1_12V; | ||
446 | break; | ||
447 | default: | ||
448 | dprintk("pd6729: pd6729_set_socket called with invalid VPP power value: %i\n", | ||
449 | state->Vpp); | ||
450 | return -EINVAL; | ||
451 | } | ||
452 | |||
453 | /* only write if changed */ | ||
454 | if (reg != indirect_read(socket, I365_POWER)) | ||
455 | indirect_write(socket, I365_POWER, reg); | ||
456 | |||
457 | if (irq_mode == 1) { | ||
458 | /* all interrupts are to be done as PCI interrupts */ | ||
459 | data = PD67_EC1_INV_MGMT_IRQ | PD67_EC1_INV_CARD_IRQ; | ||
460 | } else | ||
461 | data = 0; | ||
462 | |||
463 | indirect_write(socket, PD67_EXT_INDEX, PD67_EXT_CTL_1); | ||
464 | indirect_write(socket, PD67_EXT_DATA, data); | ||
465 | |||
466 | /* Enable specific interrupt events */ | ||
467 | |||
468 | reg = 0x00; | ||
469 | if (state->csc_mask & SS_DETECT) { | ||
470 | reg |= I365_CSC_DETECT; | ||
471 | } | ||
472 | if (state->flags & SS_IOCARD) { | ||
473 | if (state->csc_mask & SS_STSCHG) | ||
474 | reg |= I365_CSC_STSCHG; | ||
475 | } else { | ||
476 | if (state->csc_mask & SS_BATDEAD) | ||
477 | reg |= I365_CSC_BVD1; | ||
478 | if (state->csc_mask & SS_BATWARN) | ||
479 | reg |= I365_CSC_BVD2; | ||
480 | if (state->csc_mask & SS_READY) | ||
481 | reg |= I365_CSC_READY; | ||
482 | } | ||
483 | if (irq_mode == 1) | ||
484 | reg |= 0x30; /* management IRQ: PCI INTA# = "irq 3" */ | ||
485 | indirect_write(socket, I365_CSCINT, reg); | ||
486 | |||
487 | reg = indirect_read(socket, I365_INTCTL); | ||
488 | if (irq_mode == 1) | ||
489 | reg |= 0x03; /* card IRQ: PCI INTA# = "irq 3" */ | ||
490 | else | ||
491 | reg |= socket->card_irq; | ||
492 | indirect_write(socket, I365_INTCTL, reg); | ||
493 | |||
494 | /* now clear the (probably bogus) pending stuff by doing a dummy read */ | ||
495 | (void)indirect_read(socket, I365_CSC); | ||
496 | |||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | static int pd6729_set_io_map(struct pcmcia_socket *sock, | ||
501 | struct pccard_io_map *io) | ||
502 | { | ||
503 | struct pd6729_socket *socket | ||
504 | = container_of(sock, struct pd6729_socket, socket); | ||
505 | unsigned char map, ioctl; | ||
506 | |||
507 | map = io->map; | ||
508 | |||
509 | /* Check error conditions */ | ||
510 | if (map > 1) { | ||
511 | dprintk("pd6729_set_io_map with invalid map"); | ||
512 | return -EINVAL; | ||
513 | } | ||
514 | |||
515 | /* Turn off the window before changing anything */ | ||
516 | if (indirect_read(socket, I365_ADDRWIN) & I365_ENA_IO(map)) | ||
517 | indirect_resetbit(socket, I365_ADDRWIN, I365_ENA_IO(map)); | ||
518 | |||
519 | /* dprintk("set_io_map: Setting range to %x - %x\n", | ||
520 | io->start, io->stop);*/ | ||
521 | |||
522 | /* write the new values */ | ||
523 | indirect_write16(socket, I365_IO(map)+I365_W_START, io->start); | ||
524 | indirect_write16(socket, I365_IO(map)+I365_W_STOP, io->stop); | ||
525 | |||
526 | ioctl = indirect_read(socket, I365_IOCTL) & ~I365_IOCTL_MASK(map); | ||
527 | |||
528 | if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map); | ||
529 | if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map); | ||
530 | if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map); | ||
531 | |||
532 | indirect_write(socket, I365_IOCTL, ioctl); | ||
533 | |||
534 | /* Turn the window back on if needed */ | ||
535 | if (io->flags & MAP_ACTIVE) | ||
536 | indirect_setbit(socket, I365_ADDRWIN, I365_ENA_IO(map)); | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static int pd6729_set_mem_map(struct pcmcia_socket *sock, | ||
542 | struct pccard_mem_map *mem) | ||
543 | { | ||
544 | struct pd6729_socket *socket | ||
545 | = container_of(sock, struct pd6729_socket, socket); | ||
546 | unsigned short base, i; | ||
547 | unsigned char map; | ||
548 | |||
549 | map = mem->map; | ||
550 | if (map > 4) { | ||
551 | printk("pd6729_set_mem_map: invalid map"); | ||
552 | return -EINVAL; | ||
553 | } | ||
554 | |||
555 | if ((mem->res->start > mem->res->end) || (mem->speed > 1000)) { | ||
556 | printk("pd6729_set_mem_map: invalid address / speed"); | ||
557 | return -EINVAL; | ||
558 | } | ||
559 | |||
560 | /* Turn off the window before changing anything */ | ||
561 | if (indirect_read(socket, I365_ADDRWIN) & I365_ENA_MEM(map)) | ||
562 | indirect_resetbit(socket, I365_ADDRWIN, I365_ENA_MEM(map)); | ||
563 | |||
564 | /* write the start address */ | ||
565 | base = I365_MEM(map); | ||
566 | i = (mem->res->start >> 12) & 0x0fff; | ||
567 | if (mem->flags & MAP_16BIT) | ||
568 | i |= I365_MEM_16BIT; | ||
569 | if (mem->flags & MAP_0WS) | ||
570 | i |= I365_MEM_0WS; | ||
571 | indirect_write16(socket, base + I365_W_START, i); | ||
572 | |||
573 | /* write the stop address */ | ||
574 | |||
575 | i= (mem->res->end >> 12) & 0x0fff; | ||
576 | switch (to_cycles(mem->speed)) { | ||
577 | case 0: | ||
578 | break; | ||
579 | case 1: | ||
580 | i |= I365_MEM_WS0; | ||
581 | break; | ||
582 | case 2: | ||
583 | i |= I365_MEM_WS1; | ||
584 | break; | ||
585 | default: | ||
586 | i |= I365_MEM_WS1 | I365_MEM_WS0; | ||
587 | break; | ||
588 | } | ||
589 | |||
590 | indirect_write16(socket, base + I365_W_STOP, i); | ||
591 | |||
592 | /* Take care of high byte */ | ||
593 | indirect_write(socket, PD67_EXT_INDEX, PD67_MEM_PAGE(map)); | ||
594 | indirect_write(socket, PD67_EXT_DATA, mem->res->start >> 24); | ||
595 | |||
596 | /* card start */ | ||
597 | |||
598 | i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff; | ||
599 | if (mem->flags & MAP_WRPROT) | ||
600 | i |= I365_MEM_WRPROT; | ||
601 | if (mem->flags & MAP_ATTRIB) { | ||
602 | /* dprintk("requesting attribute memory for socket %i\n", | ||
603 | socket->number);*/ | ||
604 | i |= I365_MEM_REG; | ||
605 | } else { | ||
606 | /* dprintk("requesting normal memory for socket %i\n", | ||
607 | socket->number);*/ | ||
608 | } | ||
609 | indirect_write16(socket, base + I365_W_OFF, i); | ||
610 | |||
611 | /* Enable the window if necessary */ | ||
612 | if (mem->flags & MAP_ACTIVE) | ||
613 | indirect_setbit(socket, I365_ADDRWIN, I365_ENA_MEM(map)); | ||
614 | |||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | static int pd6729_init(struct pcmcia_socket *sock) | ||
619 | { | ||
620 | int i; | ||
621 | struct resource res = { .end = 0x0fff }; | ||
622 | pccard_io_map io = { 0, 0, 0, 0, 1 }; | ||
623 | pccard_mem_map mem = { .res = &res, }; | ||
624 | |||
625 | pd6729_set_socket(sock, &dead_socket); | ||
626 | for (i = 0; i < 2; i++) { | ||
627 | io.map = i; | ||
628 | pd6729_set_io_map(sock, &io); | ||
629 | } | ||
630 | for (i = 0; i < 5; i++) { | ||
631 | mem.map = i; | ||
632 | pd6729_set_mem_map(sock, &mem); | ||
633 | } | ||
634 | |||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | |||
639 | /* the pccard structure and its functions */ | ||
640 | static struct pccard_operations pd6729_operations = { | ||
641 | .init = pd6729_init, | ||
642 | .get_status = pd6729_get_status, | ||
643 | .get_socket = pd6729_get_socket, | ||
644 | .set_socket = pd6729_set_socket, | ||
645 | .set_io_map = pd6729_set_io_map, | ||
646 | .set_mem_map = pd6729_set_mem_map, | ||
647 | }; | ||
648 | |||
649 | static irqreturn_t pd6729_test(int irq, void *dev, struct pt_regs *regs) | ||
650 | { | ||
651 | dprintk("-> hit on irq %d\n", irq); | ||
652 | return IRQ_HANDLED; | ||
653 | } | ||
654 | |||
655 | static int pd6729_check_irq(int irq, int flags) | ||
656 | { | ||
657 | if (request_irq(irq, pd6729_test, flags, "x", pd6729_test) != 0) | ||
658 | return -1; | ||
659 | free_irq(irq, pd6729_test); | ||
660 | return 0; | ||
661 | } | ||
662 | |||
663 | static u_int __init pd6729_isa_scan(void) | ||
664 | { | ||
665 | u_int mask0, mask = 0; | ||
666 | int i; | ||
667 | |||
668 | if (irq_mode == 1) { | ||
669 | printk(KERN_INFO "pd6729: PCI card interrupts, " | ||
670 | "PCI status changes\n"); | ||
671 | return 0; | ||
672 | } | ||
673 | |||
674 | if (irq_list_count == 0) | ||
675 | mask0 = 0xffff; | ||
676 | else | ||
677 | for (i = mask0 = 0; i < irq_list_count; i++) | ||
678 | mask0 |= (1<<irq_list[i]); | ||
679 | |||
680 | mask0 &= PD67_MASK; | ||
681 | |||
682 | /* just find interrupts that aren't in use */ | ||
683 | for (i = 0; i < 16; i++) | ||
684 | if ((mask0 & (1 << i)) && (pd6729_check_irq(i, 0) == 0)) | ||
685 | mask |= (1 << i); | ||
686 | |||
687 | printk(KERN_INFO "pd6729: ISA irqs = "); | ||
688 | for (i = 0; i < 16; i++) | ||
689 | if (mask & (1<<i)) | ||
690 | printk("%s%d", ((mask & ((1<<i)-1)) ? "," : ""), i); | ||
691 | |||
692 | if (mask == 0) printk("none!"); | ||
693 | |||
694 | printk(" polling status changes.\n"); | ||
695 | |||
696 | return mask; | ||
697 | } | ||
698 | |||
699 | static int __devinit pd6729_pci_probe(struct pci_dev *dev, | ||
700 | const struct pci_device_id *id) | ||
701 | { | ||
702 | int i, j, ret; | ||
703 | u_int mask; | ||
704 | char configbyte; | ||
705 | struct pd6729_socket *socket; | ||
706 | |||
707 | socket = kmalloc(sizeof(struct pd6729_socket) * MAX_SOCKETS, | ||
708 | GFP_KERNEL); | ||
709 | if (!socket) | ||
710 | return -ENOMEM; | ||
711 | |||
712 | memset(socket, 0, sizeof(struct pd6729_socket) * MAX_SOCKETS); | ||
713 | |||
714 | if ((ret = pci_enable_device(dev))) | ||
715 | goto err_out_free_mem; | ||
716 | |||
717 | printk(KERN_INFO "pd6729: Cirrus PD6729 PCI to PCMCIA Bridge " | ||
718 | "at 0x%lx on irq %d\n", pci_resource_start(dev, 0), dev->irq); | ||
719 | /* | ||
720 | * Since we have no memory BARs some firmware may not | ||
721 | * have had PCI_COMMAND_MEMORY enabled, yet the device needs it. | ||
722 | */ | ||
723 | pci_read_config_byte(dev, PCI_COMMAND, &configbyte); | ||
724 | if (!(configbyte & PCI_COMMAND_MEMORY)) { | ||
725 | printk(KERN_DEBUG "pd6729: Enabling PCI_COMMAND_MEMORY.\n"); | ||
726 | configbyte |= PCI_COMMAND_MEMORY; | ||
727 | pci_write_config_byte(dev, PCI_COMMAND, configbyte); | ||
728 | } | ||
729 | |||
730 | ret = pci_request_regions(dev, "pd6729"); | ||
731 | if (ret) { | ||
732 | printk(KERN_INFO "pd6729: pci request region failed.\n"); | ||
733 | goto err_out_disable; | ||
734 | } | ||
735 | |||
736 | if (dev->irq == NO_IRQ) | ||
737 | irq_mode = 0; /* fall back to ISA interrupt mode */ | ||
738 | |||
739 | mask = pd6729_isa_scan(); | ||
740 | if (irq_mode == 0 && mask == 0) { | ||
741 | printk(KERN_INFO "pd6729: no ISA interrupt is available.\n"); | ||
742 | goto err_out_free_res; | ||
743 | } | ||
744 | |||
745 | for (i = 0; i < MAX_SOCKETS; i++) { | ||
746 | socket[i].io_base = pci_resource_start(dev, 0); | ||
747 | socket[i].socket.features |= SS_CAP_PCCARD; | ||
748 | socket[i].socket.map_size = 0x1000; | ||
749 | socket[i].socket.irq_mask = mask; | ||
750 | socket[i].socket.pci_irq = dev->irq; | ||
751 | socket[i].socket.owner = THIS_MODULE; | ||
752 | |||
753 | socket[i].number = i; | ||
754 | |||
755 | socket[i].socket.ops = &pd6729_operations; | ||
756 | socket[i].socket.resource_ops = &pccard_nonstatic_ops; | ||
757 | socket[i].socket.dev.dev = &dev->dev; | ||
758 | socket[i].socket.driver_data = &socket[i]; | ||
759 | } | ||
760 | |||
761 | pci_set_drvdata(dev, socket); | ||
762 | if (irq_mode == 1) { | ||
763 | /* Register the interrupt handler */ | ||
764 | if ((ret = request_irq(dev->irq, pd6729_interrupt, SA_SHIRQ, | ||
765 | "pd6729", socket))) { | ||
766 | printk(KERN_ERR "pd6729: Failed to register irq %d, " | ||
767 | "aborting\n", dev->irq); | ||
768 | goto err_out_free_res; | ||
769 | } | ||
770 | } else { | ||
771 | /* poll Card status change */ | ||
772 | init_timer(&socket->poll_timer); | ||
773 | socket->poll_timer.function = pd6729_interrupt_wrapper; | ||
774 | socket->poll_timer.data = (unsigned long)socket; | ||
775 | socket->poll_timer.expires = jiffies + HZ; | ||
776 | add_timer(&socket->poll_timer); | ||
777 | } | ||
778 | |||
779 | for (i = 0; i < MAX_SOCKETS; i++) { | ||
780 | ret = pcmcia_register_socket(&socket[i].socket); | ||
781 | if (ret) { | ||
782 | printk(KERN_INFO "pd6729: pcmcia_register_socket " | ||
783 | "failed.\n"); | ||
784 | for (j = 0; j < i ; j++) | ||
785 | pcmcia_unregister_socket(&socket[j].socket); | ||
786 | goto err_out_free_res2; | ||
787 | } | ||
788 | } | ||
789 | |||
790 | return 0; | ||
791 | |||
792 | err_out_free_res2: | ||
793 | if (irq_mode == 1) | ||
794 | free_irq(dev->irq, socket); | ||
795 | else | ||
796 | del_timer_sync(&socket->poll_timer); | ||
797 | err_out_free_res: | ||
798 | pci_release_regions(dev); | ||
799 | err_out_disable: | ||
800 | pci_disable_device(dev); | ||
801 | |||
802 | err_out_free_mem: | ||
803 | kfree(socket); | ||
804 | return ret; | ||
805 | } | ||
806 | |||
807 | static void __devexit pd6729_pci_remove(struct pci_dev *dev) | ||
808 | { | ||
809 | int i; | ||
810 | struct pd6729_socket *socket = pci_get_drvdata(dev); | ||
811 | |||
812 | for (i = 0; i < MAX_SOCKETS; i++) { | ||
813 | /* Turn off all interrupt sources */ | ||
814 | indirect_write(&socket[i], I365_CSCINT, 0); | ||
815 | indirect_write(&socket[i], I365_INTCTL, 0); | ||
816 | |||
817 | pcmcia_unregister_socket(&socket[i].socket); | ||
818 | } | ||
819 | |||
820 | if (irq_mode == 1) | ||
821 | free_irq(dev->irq, socket); | ||
822 | else | ||
823 | del_timer_sync(&socket->poll_timer); | ||
824 | pci_release_regions(dev); | ||
825 | pci_disable_device(dev); | ||
826 | |||
827 | kfree(socket); | ||
828 | } | ||
829 | |||
830 | static int pd6729_socket_suspend(struct pci_dev *dev, pm_message_t state) | ||
831 | { | ||
832 | return pcmcia_socket_dev_suspend(&dev->dev, state); | ||
833 | } | ||
834 | |||
835 | static int pd6729_socket_resume(struct pci_dev *dev) | ||
836 | { | ||
837 | return pcmcia_socket_dev_resume(&dev->dev); | ||
838 | } | ||
839 | |||
840 | static struct pci_device_id pd6729_pci_ids[] = { | ||
841 | { | ||
842 | .vendor = PCI_VENDOR_ID_CIRRUS, | ||
843 | .device = PCI_DEVICE_ID_CIRRUS_6729, | ||
844 | .subvendor = PCI_ANY_ID, | ||
845 | .subdevice = PCI_ANY_ID, | ||
846 | }, | ||
847 | { } | ||
848 | }; | ||
849 | MODULE_DEVICE_TABLE(pci, pd6729_pci_ids); | ||
850 | |||
851 | static struct pci_driver pd6729_pci_drv = { | ||
852 | .name = "pd6729", | ||
853 | .id_table = pd6729_pci_ids, | ||
854 | .probe = pd6729_pci_probe, | ||
855 | .remove = __devexit_p(pd6729_pci_remove), | ||
856 | .suspend = pd6729_socket_suspend, | ||
857 | .resume = pd6729_socket_resume, | ||
858 | }; | ||
859 | |||
860 | static int pd6729_module_init(void) | ||
861 | { | ||
862 | return pci_register_driver(&pd6729_pci_drv); | ||
863 | } | ||
864 | |||
865 | static void pd6729_module_exit(void) | ||
866 | { | ||
867 | pci_unregister_driver(&pd6729_pci_drv); | ||
868 | } | ||
869 | |||
870 | module_init(pd6729_module_init); | ||
871 | module_exit(pd6729_module_exit); | ||