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