blob: a4aacb830b80772d0f59a99a8bf029b4be6001f8 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*======================================================================
2
3 Device driver for Intel 82365 and compatible PC Card controllers.
4
5 i82365.c 1.265 1999/11/10 18:36:21
6
7 The contents of this file are subject to the Mozilla Public
8 License Version 1.1 (the "License"); you may not use this file
9 except in compliance with the License. You may obtain a copy of
10 the License at http://www.mozilla.org/MPL/
11
12 Software distributed under the License is distributed on an "AS
13 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 implied. See the License for the specific language governing
15 rights and limitations under the License.
16
17 The initial developer of the original code is David A. Hinds
18 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
19 are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
20
21 Alternatively, the contents of this file may be used under the
22 terms of the GNU General Public License version 2 (the "GPL"), in which
23 case the provisions of the GPL are applicable instead of the
24 above. If you wish to allow the use of your version of this file
25 only under the terms of the GPL and not to allow others to use
26 your version of this file under the MPL, indicate your decision
27 by deleting the provisions above and replace them with the notice
28 and other provisions required by the GPL. If you do not delete
29 the provisions above, a recipient may use your version of this
30 file under either the MPL or the GPL.
31
32======================================================================*/
33
34#include <linux/module.h>
35#include <linux/moduleparam.h>
36#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/types.h>
38#include <linux/fcntl.h>
39#include <linux/string.h>
40#include <linux/kernel.h>
41#include <linux/errno.h>
42#include <linux/timer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/slab.h>
44#include <linux/ioport.h>
45#include <linux/delay.h>
46#include <linux/workqueue.h>
47#include <linux/interrupt.h>
Russell Kingd052d1b2005-10-29 19:07:23 +010048#include <linux/platform_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <linux/bitops.h>
50#include <asm/irq.h>
51#include <asm/io.h>
52#include <asm/system.h>
53
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <pcmcia/cs_types.h>
55#include <pcmcia/ss.h>
56#include <pcmcia/cs.h>
57
58#include <linux/isapnp.h>
59
60/* ISA-bus controllers */
61#include "i82365.h"
62#include "cirrus.h"
63#include "vg468.h"
64#include "ricoh.h"
65
Dominik Brodowski7d16b652008-08-02 21:02:01 +020066#ifdef CONFIG_PCMCIA_DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -070067static const char version[] =
68"i82365.c 1.265 1999/11/10 18:36:21 (David Hinds)";
69
70static int pc_debug;
71
72module_param(pc_debug, int, 0644);
73
74#define debug(lvl, fmt, arg...) do { \
75 if (pc_debug > (lvl)) \
76 printk(KERN_DEBUG "i82365: " fmt , ## arg); \
77} while (0)
78#else
79#define debug(lvl, fmt, arg...) do { } while (0)
80#endif
81
David Howells7d12e782006-10-05 14:55:46 +010082static irqreturn_t i365_count_irq(int, void *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083static inline int _check_irq(int irq, int flags)
84{
85 if (request_irq(irq, i365_count_irq, flags, "x", i365_count_irq) != 0)
86 return -1;
87 free_irq(irq, i365_count_irq);
88 return 0;
89}
90
91/*====================================================================*/
92
93/* Parameters that can be set with 'insmod' */
94
95/* Default base address for i82365sl and other ISA chips */
96static unsigned long i365_base = 0x3e0;
97/* Should we probe at 0x3e2 for an extra ISA controller? */
98static int extra_sockets = 0;
99/* Specify a socket number to ignore */
100static int ignore = -1;
101/* Bit map or list of interrupts to choose from */
102static u_int irq_mask = 0xffff;
103static int irq_list[16];
Al Viro64a6f952007-10-14 19:35:30 +0100104static unsigned int irq_list_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105/* The card status change interrupt -- 0 means autoselect */
106static int cs_irq = 0;
107
108/* Probe for safe interrupts? */
109static int do_scan = 1;
110/* Poll status interval -- 0 means default to interrupt */
111static int poll_interval = 0;
112/* External clock time, in nanoseconds. 120 ns = 8.33 MHz */
113static int cycle_time = 120;
114
115/* Cirrus options */
116static int has_dma = -1;
117static int has_led = -1;
118static int has_ring = -1;
119static int dynamic_mode = 0;
120static int freq_bypass = -1;
121static int setup_time = -1;
122static int cmd_time = -1;
123static int recov_time = -1;
124
125/* Vadem options */
126static int async_clock = -1;
127static int cable_mode = -1;
128static int wakeup = 0;
129
130module_param(i365_base, ulong, 0444);
131module_param(ignore, int, 0444);
132module_param(extra_sockets, int, 0444);
133module_param(irq_mask, int, 0444);
134module_param_array(irq_list, int, &irq_list_count, 0444);
135module_param(cs_irq, int, 0444);
136module_param(async_clock, int, 0444);
137module_param(cable_mode, int, 0444);
138module_param(wakeup, int, 0444);
139
140module_param(do_scan, int, 0444);
141module_param(poll_interval, int, 0444);
142module_param(cycle_time, int, 0444);
143module_param(has_dma, int, 0444);
144module_param(has_led, int, 0444);
145module_param(has_ring, int, 0444);
146module_param(dynamic_mode, int, 0444);
147module_param(freq_bypass, int, 0444);
148module_param(setup_time, int, 0444);
149module_param(cmd_time, int, 0444);
150module_param(recov_time, int, 0444);
151
152/*====================================================================*/
153
154typedef struct cirrus_state_t {
155 u_char misc1, misc2;
156 u_char timer[6];
157} cirrus_state_t;
158
159typedef struct vg46x_state_t {
160 u_char ctl, ema;
161} vg46x_state_t;
162
163struct i82365_socket {
164 u_short type, flags;
165 struct pcmcia_socket socket;
166 unsigned int number;
Olof Johansson906da802008-02-04 22:27:35 -0800167 unsigned int ioaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 u_short psock;
169 u_char cs_irq, intr;
170 union {
171 cirrus_state_t cirrus;
172 vg46x_state_t vg46x;
173 } state;
174};
175
176/* Where we keep track of our sockets... */
177static int sockets = 0;
178static struct i82365_socket socket[8] = {
179 { 0, }, /* ... */
180};
181
182/* Default ISA interrupt mask */
183#define I365_MASK 0xdeb8 /* irq 15,14,12,11,10,9,7,5,4,3 */
184
185static int grab_irq;
186static DEFINE_SPINLOCK(isa_lock);
187#define ISA_LOCK(n, f) spin_lock_irqsave(&isa_lock, f)
188#define ISA_UNLOCK(n, f) spin_unlock_irqrestore(&isa_lock, f)
189
190static struct timer_list poll_timer;
191
192/*====================================================================*/
193
194/* These definitions must match the pcic table! */
195typedef enum pcic_id {
196 IS_I82365A, IS_I82365B, IS_I82365DF,
197 IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469,
198 IS_PD6710, IS_PD672X, IS_VT83C469,
199} pcic_id;
200
201/* Flags for classifying groups of controllers */
202#define IS_VADEM 0x0001
203#define IS_CIRRUS 0x0002
204#define IS_VIA 0x0010
205#define IS_UNKNOWN 0x0400
206#define IS_VG_PWR 0x0800
207#define IS_DF_PWR 0x1000
208#define IS_REGISTERED 0x2000
209#define IS_ALIVE 0x8000
210
211typedef struct pcic_t {
212 char *name;
213 u_short flags;
214} pcic_t;
215
216static pcic_t pcic[] = {
217 { "Intel i82365sl A step", 0 },
218 { "Intel i82365sl B step", 0 },
219 { "Intel i82365sl DF", IS_DF_PWR },
220 { "IBM Clone", 0 },
221 { "Ricoh RF5C296/396", 0 },
222 { "VLSI 82C146", 0 },
223 { "Vadem VG-468", IS_VADEM },
224 { "Vadem VG-469", IS_VADEM|IS_VG_PWR },
225 { "Cirrus PD6710", IS_CIRRUS },
226 { "Cirrus PD672x", IS_CIRRUS },
227 { "VIA VT83C469", IS_CIRRUS|IS_VIA },
228};
229
230#define PCIC_COUNT (sizeof(pcic)/sizeof(pcic_t))
231
232/*====================================================================*/
233
234static DEFINE_SPINLOCK(bus_lock);
235
236static u_char i365_get(u_short sock, u_short reg)
237{
238 unsigned long flags;
239 spin_lock_irqsave(&bus_lock,flags);
240 {
Olof Johansson906da802008-02-04 22:27:35 -0800241 unsigned int port = socket[sock].ioaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 u_char val;
243 reg = I365_REG(socket[sock].psock, reg);
244 outb(reg, port); val = inb(port+1);
245 spin_unlock_irqrestore(&bus_lock,flags);
246 return val;
247 }
248}
249
250static void i365_set(u_short sock, u_short reg, u_char data)
251{
252 unsigned long flags;
253 spin_lock_irqsave(&bus_lock,flags);
254 {
Olof Johansson906da802008-02-04 22:27:35 -0800255 unsigned int port = socket[sock].ioaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 u_char val = I365_REG(socket[sock].psock, reg);
257 outb(val, port); outb(data, port+1);
258 spin_unlock_irqrestore(&bus_lock,flags);
259 }
260}
261
262static void i365_bset(u_short sock, u_short reg, u_char mask)
263{
264 u_char d = i365_get(sock, reg);
265 d |= mask;
266 i365_set(sock, reg, d);
267}
268
269static void i365_bclr(u_short sock, u_short reg, u_char mask)
270{
271 u_char d = i365_get(sock, reg);
272 d &= ~mask;
273 i365_set(sock, reg, d);
274}
275
276static void i365_bflip(u_short sock, u_short reg, u_char mask, int b)
277{
278 u_char d = i365_get(sock, reg);
279 if (b)
280 d |= mask;
281 else
282 d &= ~mask;
283 i365_set(sock, reg, d);
284}
285
286static u_short i365_get_pair(u_short sock, u_short reg)
287{
288 u_short a, b;
289 a = i365_get(sock, reg);
290 b = i365_get(sock, reg+1);
291 return (a + (b<<8));
292}
293
294static void i365_set_pair(u_short sock, u_short reg, u_short data)
295{
296 i365_set(sock, reg, data & 0xff);
297 i365_set(sock, reg+1, data >> 8);
298}
299
300/*======================================================================
301
302 Code to save and restore global state information for Cirrus
303 PD67xx controllers, and to set and report global configuration
304 options.
305
306 The VIA controllers also use these routines, as they are mostly
307 Cirrus lookalikes, without the timing registers.
308
309======================================================================*/
310
311#define flip(v,b,f) (v = ((f)<0) ? v : ((f) ? ((v)|(b)) : ((v)&(~b))))
312
313static void cirrus_get_state(u_short s)
314{
315 int i;
316 cirrus_state_t *p = &socket[s].state.cirrus;
317 p->misc1 = i365_get(s, PD67_MISC_CTL_1);
318 p->misc1 &= (PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
319 p->misc2 = i365_get(s, PD67_MISC_CTL_2);
320 for (i = 0; i < 6; i++)
321 p->timer[i] = i365_get(s, PD67_TIME_SETUP(0)+i);
322}
323
324static void cirrus_set_state(u_short s)
325{
326 int i;
327 u_char misc;
328 cirrus_state_t *p = &socket[s].state.cirrus;
329
330 misc = i365_get(s, PD67_MISC_CTL_2);
331 i365_set(s, PD67_MISC_CTL_2, p->misc2);
332 if (misc & PD67_MC2_SUSPEND) mdelay(50);
333 misc = i365_get(s, PD67_MISC_CTL_1);
334 misc &= ~(PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
335 i365_set(s, PD67_MISC_CTL_1, misc | p->misc1);
336 for (i = 0; i < 6; i++)
337 i365_set(s, PD67_TIME_SETUP(0)+i, p->timer[i]);
338}
339
340static u_int __init cirrus_set_opts(u_short s, char *buf)
341{
342 struct i82365_socket *t = &socket[s];
343 cirrus_state_t *p = &socket[s].state.cirrus;
344 u_int mask = 0xffff;
345
346 if (has_ring == -1) has_ring = 1;
347 flip(p->misc2, PD67_MC2_IRQ15_RI, has_ring);
348 flip(p->misc2, PD67_MC2_DYNAMIC_MODE, dynamic_mode);
349 flip(p->misc2, PD67_MC2_FREQ_BYPASS, freq_bypass);
350 if (p->misc2 & PD67_MC2_IRQ15_RI)
351 strcat(buf, " [ring]");
352 if (p->misc2 & PD67_MC2_DYNAMIC_MODE)
353 strcat(buf, " [dyn mode]");
354 if (p->misc2 & PD67_MC2_FREQ_BYPASS)
355 strcat(buf, " [freq bypass]");
356 if (p->misc1 & PD67_MC1_INPACK_ENA)
357 strcat(buf, " [inpack]");
358 if (p->misc2 & PD67_MC2_IRQ15_RI)
359 mask &= ~0x8000;
360 if (has_led > 0) {
361 strcat(buf, " [led]");
362 mask &= ~0x1000;
363 }
364 if (has_dma > 0) {
365 strcat(buf, " [dma]");
366 mask &= ~0x0600;
367 }
368 if (!(t->flags & IS_VIA)) {
369 if (setup_time >= 0)
370 p->timer[0] = p->timer[3] = setup_time;
371 if (cmd_time > 0) {
372 p->timer[1] = cmd_time;
373 p->timer[4] = cmd_time*2+4;
374 }
375 if (p->timer[1] == 0) {
376 p->timer[1] = 6; p->timer[4] = 16;
377 if (p->timer[0] == 0)
378 p->timer[0] = p->timer[3] = 1;
379 }
380 if (recov_time >= 0)
381 p->timer[2] = p->timer[5] = recov_time;
382 buf += strlen(buf);
383 sprintf(buf, " [%d/%d/%d] [%d/%d/%d]", p->timer[0], p->timer[1],
384 p->timer[2], p->timer[3], p->timer[4], p->timer[5]);
385 }
386 return mask;
387}
388
389/*======================================================================
390
391 Code to save and restore global state information for Vadem VG468
392 and VG469 controllers, and to set and report global configuration
393 options.
394
395======================================================================*/
396
397static void vg46x_get_state(u_short s)
398{
399 vg46x_state_t *p = &socket[s].state.vg46x;
400 p->ctl = i365_get(s, VG468_CTL);
401 if (socket[s].type == IS_VG469)
402 p->ema = i365_get(s, VG469_EXT_MODE);
403}
404
405static void vg46x_set_state(u_short s)
406{
407 vg46x_state_t *p = &socket[s].state.vg46x;
408 i365_set(s, VG468_CTL, p->ctl);
409 if (socket[s].type == IS_VG469)
410 i365_set(s, VG469_EXT_MODE, p->ema);
411}
412
413static u_int __init vg46x_set_opts(u_short s, char *buf)
414{
415 vg46x_state_t *p = &socket[s].state.vg46x;
416
417 flip(p->ctl, VG468_CTL_ASYNC, async_clock);
418 flip(p->ema, VG469_MODE_CABLE, cable_mode);
419 if (p->ctl & VG468_CTL_ASYNC)
420 strcat(buf, " [async]");
421 if (p->ctl & VG468_CTL_INPACK)
422 strcat(buf, " [inpack]");
423 if (socket[s].type == IS_VG469) {
424 u_char vsel = i365_get(s, VG469_VSELECT);
425 if (vsel & VG469_VSEL_EXT_STAT) {
426 strcat(buf, " [ext mode]");
427 if (vsel & VG469_VSEL_EXT_BUS)
428 strcat(buf, " [isa buf]");
429 }
430 if (p->ema & VG469_MODE_CABLE)
431 strcat(buf, " [cable]");
432 if (p->ema & VG469_MODE_COMPAT)
433 strcat(buf, " [c step]");
434 }
435 return 0xffff;
436}
437
438/*======================================================================
439
440 Generic routines to get and set controller options
441
442======================================================================*/
443
444static void get_bridge_state(u_short s)
445{
446 struct i82365_socket *t = &socket[s];
447 if (t->flags & IS_CIRRUS)
448 cirrus_get_state(s);
449 else if (t->flags & IS_VADEM)
450 vg46x_get_state(s);
451}
452
453static void set_bridge_state(u_short s)
454{
455 struct i82365_socket *t = &socket[s];
456 if (t->flags & IS_CIRRUS)
457 cirrus_set_state(s);
458 else {
459 i365_set(s, I365_GBLCTL, 0x00);
460 i365_set(s, I365_GENCTL, 0x00);
461 }
462 i365_bflip(s, I365_INTCTL, I365_INTR_ENA, t->intr);
463 if (t->flags & IS_VADEM)
464 vg46x_set_state(s);
465}
466
467static u_int __init set_bridge_opts(u_short s, u_short ns)
468{
469 u_short i;
470 u_int m = 0xffff;
471 char buf[128];
472
473 for (i = s; i < s+ns; i++) {
474 if (socket[i].flags & IS_ALIVE) {
475 printk(KERN_INFO " host opts [%d]: already alive!\n", i);
476 continue;
477 }
478 buf[0] = '\0';
479 get_bridge_state(i);
480 if (socket[i].flags & IS_CIRRUS)
481 m = cirrus_set_opts(i, buf);
482 else if (socket[i].flags & IS_VADEM)
483 m = vg46x_set_opts(i, buf);
484 set_bridge_state(i);
485 printk(KERN_INFO " host opts [%d]:%s\n", i,
486 (*buf) ? buf : " none");
487 }
488 return m;
489}
490
491/*======================================================================
492
493 Interrupt testing code, for ISA and PCI interrupts
494
495======================================================================*/
496
497static volatile u_int irq_hits;
498static u_short irq_sock;
499
David Howells7d12e782006-10-05 14:55:46 +0100500static irqreturn_t i365_count_irq(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501{
502 i365_get(irq_sock, I365_CSC);
503 irq_hits++;
504 debug(2, "-> hit on irq %d\n", irq);
505 return IRQ_HANDLED;
506}
507
508static u_int __init test_irq(u_short sock, int irq)
509{
510 debug(2, " testing ISA irq %d\n", irq);
Thomas Gleixnerdace1452006-07-01 19:29:38 -0700511 if (request_irq(irq, i365_count_irq, IRQF_PROBE_SHARED, "scan",
Andrew Morton13e87ec2006-04-27 18:39:18 -0700512 i365_count_irq) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 return 1;
514 irq_hits = 0; irq_sock = sock;
515 msleep(10);
516 if (irq_hits) {
517 free_irq(irq, i365_count_irq);
518 debug(2, " spurious hit!\n");
519 return 1;
520 }
521
522 /* Generate one interrupt */
523 i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (irq << 4));
524 i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ);
525 udelay(1000);
526
527 free_irq(irq, i365_count_irq);
528
529 /* mask all interrupts */
530 i365_set(sock, I365_CSCINT, 0);
531 debug(2, " hits = %d\n", irq_hits);
532
533 return (irq_hits != 1);
534}
535
536static u_int __init isa_scan(u_short sock, u_int mask0)
537{
538 u_int mask1 = 0;
539 int i;
540
541#ifdef __alpha__
542#define PIC 0x4d0
543 /* Don't probe level-triggered interrupts -- reserved for PCI */
544 mask0 &= ~(inb(PIC) | (inb(PIC+1) << 8));
545#endif
546
547 if (do_scan) {
548 set_bridge_state(sock);
549 i365_set(sock, I365_CSCINT, 0);
550 for (i = 0; i < 16; i++)
551 if ((mask0 & (1 << i)) && (test_irq(sock, i) == 0))
552 mask1 |= (1 << i);
553 for (i = 0; i < 16; i++)
554 if ((mask1 & (1 << i)) && (test_irq(sock, i) != 0))
555 mask1 ^= (1 << i);
556 }
557
558 printk(KERN_INFO " ISA irqs (");
559 if (mask1) {
560 printk("scanned");
561 } else {
562 /* Fallback: just find interrupts that aren't in use */
563 for (i = 0; i < 16; i++)
Thomas Gleixnerdace1452006-07-01 19:29:38 -0700564 if ((mask0 & (1 << i)) && (_check_irq(i, IRQF_PROBE_SHARED) == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 mask1 |= (1 << i);
566 printk("default");
567 /* If scan failed, default to polled status */
568 if (!cs_irq && (poll_interval == 0)) poll_interval = HZ;
569 }
570 printk(") = ");
571
572 for (i = 0; i < 16; i++)
573 if (mask1 & (1<<i))
574 printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i);
575 if (mask1 == 0) printk("none!");
576
577 return mask1;
578}
579
580/*====================================================================*/
581
582/* Time conversion functions */
583
584static int to_cycles(int ns)
585{
586 return ns/cycle_time;
587}
588
589/*====================================================================*/
590
Olof Johansson906da802008-02-04 22:27:35 -0800591static int __init identify(unsigned int port, u_short sock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592{
593 u_char val;
594 int type = -1;
595
596 /* Use the next free entry in the socket table */
597 socket[sockets].ioaddr = port;
598 socket[sockets].psock = sock;
599
600 /* Wake up a sleepy Cirrus controller */
601 if (wakeup) {
602 i365_bclr(sockets, PD67_MISC_CTL_2, PD67_MC2_SUSPEND);
603 /* Pause at least 50 ms */
604 mdelay(50);
605 }
606
607 if ((val = i365_get(sockets, I365_IDENT)) & 0x70)
608 return -1;
609 switch (val) {
610 case 0x82:
611 type = IS_I82365A; break;
612 case 0x83:
613 type = IS_I82365B; break;
614 case 0x84:
615 type = IS_I82365DF; break;
616 case 0x88: case 0x89: case 0x8a:
617 type = IS_IBM; break;
618 }
619
620 /* Check for Vadem VG-468 chips */
621 outb(0x0e, port);
622 outb(0x37, port);
623 i365_bset(sockets, VG468_MISC, VG468_MISC_VADEMREV);
624 val = i365_get(sockets, I365_IDENT);
625 if (val & I365_IDENT_VADEM) {
626 i365_bclr(sockets, VG468_MISC, VG468_MISC_VADEMREV);
627 type = ((val & 7) >= 4) ? IS_VG469 : IS_VG468;
628 }
629
630 /* Check for Ricoh chips */
631 val = i365_get(sockets, RF5C_CHIP_ID);
632 if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396))
633 type = IS_RF5Cx96;
634
635 /* Check for Cirrus CL-PD67xx chips */
636 i365_set(sockets, PD67_CHIP_INFO, 0);
637 val = i365_get(sockets, PD67_CHIP_INFO);
638 if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {
639 val = i365_get(sockets, PD67_CHIP_INFO);
640 if ((val & PD67_INFO_CHIP_ID) == 0) {
641 type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710;
642 i365_set(sockets, PD67_EXT_INDEX, 0xe5);
643 if (i365_get(sockets, PD67_EXT_INDEX) != 0xe5)
644 type = IS_VT83C469;
645 }
646 }
647 return type;
648} /* identify */
649
650/*======================================================================
651
652 See if a card is present, powered up, in IO mode, and already
653 bound to a (non PC Card) Linux driver. We leave these alone.
654
655 We make an exception for cards that seem to be serial devices.
656
657======================================================================*/
658
659static int __init is_alive(u_short sock)
660{
661 u_char stat;
Olof Johansson906da802008-02-04 22:27:35 -0800662 unsigned int start, stop;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
664 stat = i365_get(sock, I365_STATUS);
665 start = i365_get_pair(sock, I365_IO(0)+I365_W_START);
666 stop = i365_get_pair(sock, I365_IO(0)+I365_W_STOP);
667 if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) &&
668 (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) &&
669 (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) &&
Dominik Brodowskif3549422005-06-27 16:28:55 -0700670 ((start & 0xfeef) != 0x02e8)) {
671 if (!request_region(start, stop-start+1, "i82365"))
672 return 1;
673 release_region(start, stop-start+1);
674 }
675
676 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677}
678
679/*====================================================================*/
680
Olof Johansson906da802008-02-04 22:27:35 -0800681static void __init add_socket(unsigned int port, int psock, int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682{
683 socket[sockets].ioaddr = port;
684 socket[sockets].psock = psock;
685 socket[sockets].type = type;
686 socket[sockets].flags = pcic[type].flags;
687 if (is_alive(sockets))
688 socket[sockets].flags |= IS_ALIVE;
689 sockets++;
690}
691
692static void __init add_pcic(int ns, int type)
693{
694 u_int mask = 0, i, base;
695 int isa_irq = 0;
696 struct i82365_socket *t = &socket[sockets-ns];
697
698 base = sockets-ns;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 if (base == 0) printk("\n");
700 printk(KERN_INFO " %s", pcic[type].name);
Olof Johansson906da802008-02-04 22:27:35 -0800701 printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 t->ioaddr, t->psock*0x40);
703 printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : ""));
704
705 /* Set host options, build basic interrupt mask */
706 if (irq_list_count == 0)
707 mask = irq_mask;
708 else
709 for (i = mask = 0; i < irq_list_count; i++)
710 mask |= (1<<irq_list[i]);
711 mask &= I365_MASK & set_bridge_opts(base, ns);
712 /* Scan for ISA interrupts */
713 mask = isa_scan(base, mask);
714
715 /* Poll if only two interrupts available */
716 if (!poll_interval) {
717 u_int tmp = (mask & 0xff20);
718 tmp = tmp & (tmp-1);
719 if ((tmp & (tmp-1)) == 0)
720 poll_interval = HZ;
721 }
722 /* Only try an ISA cs_irq if this is the first controller */
723 if (!grab_irq && (cs_irq || !poll_interval)) {
724 /* Avoid irq 12 unless it is explicitly requested */
725 u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
726 for (cs_irq = 15; cs_irq > 0; cs_irq--)
727 if ((cs_mask & (1 << cs_irq)) &&
Thomas Gleixnerdace1452006-07-01 19:29:38 -0700728 (_check_irq(cs_irq, IRQF_PROBE_SHARED) == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 break;
730 if (cs_irq) {
731 grab_irq = 1;
732 isa_irq = cs_irq;
733 printk(" status change on irq %d\n", cs_irq);
734 }
735 }
736
737 if (!isa_irq) {
738 if (poll_interval == 0)
739 poll_interval = HZ;
740 printk(" polling interval = %d ms\n",
741 poll_interval * 1000 / HZ);
742
743 }
744
745 /* Update socket interrupt information, capabilities */
746 for (i = 0; i < ns; i++) {
747 t[i].socket.features |= SS_CAP_PCCARD;
748 t[i].socket.map_size = 0x1000;
749 t[i].socket.irq_mask = mask;
750 t[i].cs_irq = isa_irq;
751 }
752
753} /* add_pcic */
754
755/*====================================================================*/
756
757#ifdef CONFIG_PNP
758static struct isapnp_device_id id_table[] __initdata = {
759 { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
760 ISAPNP_FUNCTION(0x0e00), (unsigned long) "Intel 82365-Compatible" },
761 { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
762 ISAPNP_FUNCTION(0x0e01), (unsigned long) "Cirrus Logic CL-PD6720" },
763 { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
764 ISAPNP_FUNCTION(0x0e02), (unsigned long) "VLSI VL82C146" },
765 { 0 }
766};
767MODULE_DEVICE_TABLE(isapnp, id_table);
768
769static struct pnp_dev *i82365_pnpdev;
770#endif
771
772static void __init isa_probe(void)
773{
774 int i, j, sock, k, ns, id;
Olof Johansson906da802008-02-04 22:27:35 -0800775 unsigned int port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776#ifdef CONFIG_PNP
777 struct isapnp_device_id *devid;
778 struct pnp_dev *dev;
779
780 for (devid = id_table; devid->vendor; devid++) {
781 if ((dev = pnp_find_dev(NULL, devid->vendor, devid->function, NULL))) {
782
783 if (pnp_device_attach(dev) < 0)
784 continue;
785
786 if (pnp_activate_dev(dev) < 0) {
787 printk("activate failed\n");
788 pnp_device_detach(dev);
789 break;
790 }
791
792 if (!pnp_port_valid(dev, 0)) {
793 printk("invalid resources ?\n");
794 pnp_device_detach(dev);
795 break;
796 }
797 i365_base = pnp_port_start(dev, 0);
798 i82365_pnpdev = dev;
799 break;
800 }
801 }
802#endif
803
Dominik Brodowskif3549422005-06-27 16:28:55 -0700804 if (!request_region(i365_base, 2, "i82365")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 if (sockets == 0)
806 printk("port conflict at %#lx\n", i365_base);
807 return;
808 }
809
810 id = identify(i365_base, 0);
811 if ((id == IS_I82365DF) && (identify(i365_base, 1) != id)) {
812 for (i = 0; i < 4; i++) {
813 if (i == ignore) continue;
814 port = i365_base + ((i & 1) << 2) + ((i & 2) << 1);
815 sock = (i & 1) << 1;
816 if (identify(port, sock) == IS_I82365DF) {
817 add_socket(port, sock, IS_VLSI);
818 add_pcic(1, IS_VLSI);
819 }
820 }
821 } else {
822 for (i = 0; i < 8; i += 2) {
823 if (sockets && !extra_sockets && (i == 4))
824 break;
825 port = i365_base + 2*(i>>2);
826 sock = (i & 3);
827 id = identify(port, sock);
828 if (id < 0) continue;
829
830 for (j = ns = 0; j < 2; j++) {
831 /* Does the socket exist? */
832 if ((ignore == i+j) || (identify(port, sock+j) < 0))
833 continue;
834 /* Check for bad socket decode */
835 for (k = 0; k <= sockets; k++)
836 i365_set(k, I365_MEM(0)+I365_W_OFF, k);
837 for (k = 0; k <= sockets; k++)
838 if (i365_get(k, I365_MEM(0)+I365_W_OFF) != k)
839 break;
840 if (k <= sockets) break;
841 add_socket(port, sock+j, id); ns++;
842 }
843 if (ns != 0) add_pcic(ns, id);
844 }
845 }
846}
847
848/*====================================================================*/
849
David Howells7d12e782006-10-05 14:55:46 +0100850static irqreturn_t pcic_interrupt(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851{
852 int i, j, csc;
853 u_int events, active;
854 u_long flags = 0;
855 int handled = 0;
856
857 debug(4, "pcic_interrupt(%d)\n", irq);
858
859 for (j = 0; j < 20; j++) {
860 active = 0;
861 for (i = 0; i < sockets; i++) {
862 if (socket[i].cs_irq != irq)
863 continue;
864 handled = 1;
865 ISA_LOCK(i, flags);
866 csc = i365_get(i, I365_CSC);
867 if ((csc == 0) || (i365_get(i, I365_IDENT) & 0x70)) {
868 ISA_UNLOCK(i, flags);
869 continue;
870 }
871 events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0;
872
873 if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD)
874 events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
875 else {
876 events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;
877 events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
878 events |= (csc & I365_CSC_READY) ? SS_READY : 0;
879 }
880 ISA_UNLOCK(i, flags);
881 debug(2, "socket %d event 0x%02x\n", i, events);
882
883 if (events)
884 pcmcia_parse_events(&socket[i].socket, events);
885
886 active |= events;
887 }
888 if (!active) break;
889 }
890 if (j == 20)
891 printk(KERN_NOTICE "i82365: infinite loop in interrupt handler\n");
892
893 debug(4, "interrupt done\n");
894 return IRQ_RETVAL(handled);
895} /* pcic_interrupt */
896
897static void pcic_interrupt_wrapper(u_long data)
898{
David Howells7d12e782006-10-05 14:55:46 +0100899 pcic_interrupt(0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 poll_timer.expires = jiffies + poll_interval;
901 add_timer(&poll_timer);
902}
903
904/*====================================================================*/
905
906static int i365_get_status(u_short sock, u_int *value)
907{
908 u_int status;
909
910 status = i365_get(sock, I365_STATUS);
911 *value = ((status & I365_CS_DETECT) == I365_CS_DETECT)
912 ? SS_DETECT : 0;
913
914 if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD)
915 *value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
916 else {
917 *value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD;
918 *value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN;
919 }
920 *value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
921 *value |= (status & I365_CS_READY) ? SS_READY : 0;
922 *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
923
924 if (socket[sock].type == IS_VG469) {
925 status = i365_get(sock, VG469_VSENSE);
926 if (socket[sock].psock & 1) {
927 *value |= (status & VG469_VSENSE_B_VS1) ? 0 : SS_3VCARD;
928 *value |= (status & VG469_VSENSE_B_VS2) ? 0 : SS_XVCARD;
929 } else {
930 *value |= (status & VG469_VSENSE_A_VS1) ? 0 : SS_3VCARD;
931 *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD;
932 }
933 }
934
935 debug(1, "GetStatus(%d) = %#4.4x\n", sock, *value);
936 return 0;
937} /* i365_get_status */
938
939/*====================================================================*/
940
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941static int i365_set_socket(u_short sock, socket_state_t *state)
942{
943 struct i82365_socket *t = &socket[sock];
944 u_char reg;
945
946 debug(1, "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
947 "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
948 state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
949
950 /* First set global controller options */
951 set_bridge_state(sock);
952
953 /* IO card, RESET flag, IO interrupt */
954 reg = t->intr;
955 reg |= state->io_irq;
956 reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
957 reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
958 i365_set(sock, I365_INTCTL, reg);
959
960 reg = I365_PWR_NORESET;
961 if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO;
962 if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT;
963
964 if (t->flags & IS_CIRRUS) {
965 if (state->Vpp != 0) {
966 if (state->Vpp == 120)
967 reg |= I365_VPP1_12V;
968 else if (state->Vpp == state->Vcc)
969 reg |= I365_VPP1_5V;
970 else return -EINVAL;
971 }
972 if (state->Vcc != 0) {
973 reg |= I365_VCC_5V;
974 if (state->Vcc == 33)
975 i365_bset(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
976 else if (state->Vcc == 50)
977 i365_bclr(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
978 else return -EINVAL;
979 }
980 } else if (t->flags & IS_VG_PWR) {
981 if (state->Vpp != 0) {
982 if (state->Vpp == 120)
983 reg |= I365_VPP1_12V;
984 else if (state->Vpp == state->Vcc)
985 reg |= I365_VPP1_5V;
986 else return -EINVAL;
987 }
988 if (state->Vcc != 0) {
989 reg |= I365_VCC_5V;
990 if (state->Vcc == 33)
991 i365_bset(sock, VG469_VSELECT, VG469_VSEL_VCC);
992 else if (state->Vcc == 50)
993 i365_bclr(sock, VG469_VSELECT, VG469_VSEL_VCC);
994 else return -EINVAL;
995 }
996 } else if (t->flags & IS_DF_PWR) {
997 switch (state->Vcc) {
998 case 0: break;
999 case 33: reg |= I365_VCC_3V; break;
1000 case 50: reg |= I365_VCC_5V; break;
1001 default: return -EINVAL;
1002 }
1003 switch (state->Vpp) {
1004 case 0: break;
1005 case 50: reg |= I365_VPP1_5V; break;
1006 case 120: reg |= I365_VPP1_12V; break;
1007 default: return -EINVAL;
1008 }
1009 } else {
1010 switch (state->Vcc) {
1011 case 0: break;
1012 case 50: reg |= I365_VCC_5V; break;
1013 default: return -EINVAL;
1014 }
1015 switch (state->Vpp) {
1016 case 0: break;
1017 case 50: reg |= I365_VPP1_5V | I365_VPP2_5V; break;
1018 case 120: reg |= I365_VPP1_12V | I365_VPP2_12V; break;
1019 default: return -EINVAL;
1020 }
1021 }
1022
1023 if (reg != i365_get(sock, I365_POWER))
1024 i365_set(sock, I365_POWER, reg);
1025
1026 /* Chipset-specific functions */
1027 if (t->flags & IS_CIRRUS) {
1028 /* Speaker control */
1029 i365_bflip(sock, PD67_MISC_CTL_1, PD67_MC1_SPKR_ENA,
1030 state->flags & SS_SPKR_ENA);
1031 }
1032
1033 /* Card status change interrupt mask */
1034 reg = t->cs_irq << 4;
1035 if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
1036 if (state->flags & SS_IOCARD) {
1037 if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG;
1038 } else {
1039 if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1;
1040 if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2;
1041 if (state->csc_mask & SS_READY) reg |= I365_CSC_READY;
1042 }
1043 i365_set(sock, I365_CSCINT, reg);
1044 i365_get(sock, I365_CSC);
1045
1046 return 0;
1047} /* i365_set_socket */
1048
1049/*====================================================================*/
1050
1051static int i365_set_io_map(u_short sock, struct pccard_io_map *io)
1052{
1053 u_char map, ioctl;
1054
1055 debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, "
Randy Dunlap01373042009-10-11 18:50:09 -07001056 "%#llx-%#llx)\n", sock, io->map, io->flags, io->speed,
1057 (unsigned long long)io->start, (unsigned long long)io->stop);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 map = io->map;
1059 if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
1060 (io->stop < io->start)) return -EINVAL;
1061 /* Turn off the window before changing anything */
1062 if (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(map))
1063 i365_bclr(sock, I365_ADDRWIN, I365_ENA_IO(map));
1064 i365_set_pair(sock, I365_IO(map)+I365_W_START, io->start);
1065 i365_set_pair(sock, I365_IO(map)+I365_W_STOP, io->stop);
1066 ioctl = i365_get(sock, I365_IOCTL) & ~I365_IOCTL_MASK(map);
1067 if (io->speed) ioctl |= I365_IOCTL_WAIT(map);
1068 if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map);
1069 if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map);
1070 if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map);
1071 i365_set(sock, I365_IOCTL, ioctl);
1072 /* Turn on the window if necessary */
1073 if (io->flags & MAP_ACTIVE)
1074 i365_bset(sock, I365_ADDRWIN, I365_ENA_IO(map));
1075 return 0;
1076} /* i365_set_io_map */
1077
1078/*====================================================================*/
1079
1080static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
1081{
1082 u_short base, i;
1083 u_char map;
1084
Greg Kroah-Hartman490ab722006-06-12 15:17:34 -07001085 debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, %#llx-%#llx, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 "%#x)\n", sock, mem->map, mem->flags, mem->speed,
Greg Kroah-Hartman490ab722006-06-12 15:17:34 -07001087 (unsigned long long)mem->res->start,
1088 (unsigned long long)mem->res->end, mem->card_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
1090 map = mem->map;
1091 if ((map > 4) || (mem->card_start > 0x3ffffff) ||
1092 (mem->res->start > mem->res->end) || (mem->speed > 1000))
1093 return -EINVAL;
1094 if ((mem->res->start > 0xffffff) || (mem->res->end > 0xffffff))
1095 return -EINVAL;
1096
1097 /* Turn off the window before changing anything */
1098 if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map))
1099 i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map));
1100
1101 base = I365_MEM(map);
1102 i = (mem->res->start >> 12) & 0x0fff;
1103 if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT;
1104 if (mem->flags & MAP_0WS) i |= I365_MEM_0WS;
1105 i365_set_pair(sock, base+I365_W_START, i);
1106
1107 i = (mem->res->end >> 12) & 0x0fff;
1108 switch (to_cycles(mem->speed)) {
1109 case 0: break;
1110 case 1: i |= I365_MEM_WS0; break;
1111 case 2: i |= I365_MEM_WS1; break;
1112 default: i |= I365_MEM_WS1 | I365_MEM_WS0; break;
1113 }
1114 i365_set_pair(sock, base+I365_W_STOP, i);
1115
1116 i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff;
1117 if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT;
1118 if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG;
1119 i365_set_pair(sock, base+I365_W_OFF, i);
1120
1121 /* Turn on the window if necessary */
1122 if (mem->flags & MAP_ACTIVE)
1123 i365_bset(sock, I365_ADDRWIN, I365_ENA_MEM(map));
1124 return 0;
1125} /* i365_set_mem_map */
1126
1127#if 0 /* driver model ordering issue */
1128/*======================================================================
1129
1130 Routines for accessing socket information and register dumps via
1131 /sys/class/pcmcia_socket/...
1132
1133======================================================================*/
1134
1135static ssize_t show_info(struct class_device *class_dev, char *buf)
1136{
1137 struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev);
1138 return sprintf(buf, "type: %s\npsock: %d\n",
1139 pcic[s->type].name, s->psock);
1140}
1141
1142static ssize_t show_exca(struct class_device *class_dev, char *buf)
1143{
1144 struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev);
1145 unsigned short sock;
1146 int i;
1147 ssize_t ret = 0;
1148 unsigned long flags = 0;
1149
1150 sock = s->number;
1151
1152 ISA_LOCK(sock, flags);
1153 for (i = 0; i < 0x40; i += 4) {
1154 ret += sprintf(buf, "%02x %02x %02x %02x%s",
1155 i365_get(sock,i), i365_get(sock,i+1),
1156 i365_get(sock,i+2), i365_get(sock,i+3),
1157 ((i % 16) == 12) ? "\n" : " ");
1158 buf += ret;
1159 }
1160 ISA_UNLOCK(sock, flags);
1161
1162 return ret;
1163}
1164
1165static CLASS_DEVICE_ATTR(exca, S_IRUGO, show_exca, NULL);
1166static CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL);
1167#endif
1168
1169/*====================================================================*/
1170
1171/* this is horribly ugly... proper locking needs to be done here at
1172 * some time... */
1173#define LOCKED(x) do { \
1174 int retval; \
1175 unsigned long flags; \
1176 spin_lock_irqsave(&isa_lock, flags); \
1177 retval = x; \
1178 spin_unlock_irqrestore(&isa_lock, flags); \
1179 return retval; \
1180} while (0)
1181
1182
1183static int pcic_get_status(struct pcmcia_socket *s, u_int *value)
1184{
1185 unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
1186
1187 if (socket[sock].flags & IS_ALIVE) {
1188 *value = 0;
1189 return -EINVAL;
1190 }
1191
1192 LOCKED(i365_get_status(sock, value));
1193}
1194
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195static int pcic_set_socket(struct pcmcia_socket *s, socket_state_t *state)
1196{
1197 unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
1198
1199 if (socket[sock].flags & IS_ALIVE)
1200 return -EINVAL;
1201
1202 LOCKED(i365_set_socket(sock, state));
1203}
1204
1205static int pcic_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
1206{
1207 unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
1208 if (socket[sock].flags & IS_ALIVE)
1209 return -EINVAL;
1210
1211 LOCKED(i365_set_io_map(sock, io));
1212}
1213
1214static int pcic_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem)
1215{
1216 unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
1217 if (socket[sock].flags & IS_ALIVE)
1218 return -EINVAL;
1219
1220 LOCKED(i365_set_mem_map(sock, mem));
1221}
1222
1223static int pcic_init(struct pcmcia_socket *s)
1224{
1225 int i;
1226 struct resource res = { .start = 0, .end = 0x1000 };
1227 pccard_io_map io = { 0, 0, 0, 0, 1 };
1228 pccard_mem_map mem = { .res = &res, };
1229
1230 for (i = 0; i < 2; i++) {
1231 io.map = i;
1232 pcic_set_io_map(s, &io);
1233 }
1234 for (i = 0; i < 5; i++) {
1235 mem.map = i;
1236 pcic_set_mem_map(s, &mem);
1237 }
1238 return 0;
1239}
1240
Ming Lei7a192ec2009-02-06 23:40:12 +08001241static int i82365_drv_pcmcia_suspend(struct platform_device *dev,
1242 pm_message_t state)
1243{
Rafael J. Wysocki827b4642009-09-29 00:10:41 +02001244 return pcmcia_socket_dev_suspend(&dev->dev);
Ming Lei7a192ec2009-02-06 23:40:12 +08001245}
1246
1247static int i82365_drv_pcmcia_resume(struct platform_device *dev)
1248{
1249 return pcmcia_socket_dev_resume(&dev->dev);
1250}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251static struct pccard_operations pcic_operations = {
1252 .init = pcic_init,
1253 .get_status = pcic_get_status,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 .set_socket = pcic_set_socket,
1255 .set_io_map = pcic_set_io_map,
1256 .set_mem_map = pcic_set_mem_map,
1257};
1258
1259/*====================================================================*/
1260
Ming Lei7a192ec2009-02-06 23:40:12 +08001261static struct platform_driver i82365_driver = {
1262 .driver = {
1263 .name = "i82365",
1264 .owner = THIS_MODULE,
1265 },
1266 .suspend = i82365_drv_pcmcia_suspend,
1267 .resume = i82365_drv_pcmcia_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268};
1269
Dominik Brodowskidfb279c2005-11-10 16:26:13 +01001270static struct platform_device *i82365_device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271
1272static int __init init_i82365(void)
1273{
1274 int i, ret;
1275
Ming Lei7a192ec2009-02-06 23:40:12 +08001276 ret = platform_driver_register(&i82365_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 if (ret)
Leonardo Potenza2df69702008-04-01 23:47:09 +02001278 goto err_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
Dominik Brodowskidfb279c2005-11-10 16:26:13 +01001280 i82365_device = platform_device_alloc("i82365", 0);
1281 if (i82365_device) {
1282 ret = platform_device_add(i82365_device);
1283 if (ret)
1284 platform_device_put(i82365_device);
1285 } else
1286 ret = -ENOMEM;
1287
Leonardo Potenza2df69702008-04-01 23:47:09 +02001288 if (ret)
1289 goto err_driver_unregister;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
1291 printk(KERN_INFO "Intel ISA PCIC probe: ");
1292 sockets = 0;
1293
1294 isa_probe();
1295
1296 if (sockets == 0) {
1297 printk("not found.\n");
Leonardo Potenza2df69702008-04-01 23:47:09 +02001298 ret = -ENODEV;
1299 goto err_dev_unregister;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 }
1301
1302 /* Set up interrupt handler(s) */
1303 if (grab_irq != 0)
Leonardo Potenza2df69702008-04-01 23:47:09 +02001304 ret = request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt);
1305
1306 if (ret)
1307 goto err_socket_release;
1308
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 /* register sockets with the pcmcia core */
1310 for (i = 0; i < sockets; i++) {
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001311 socket[i].socket.dev.parent = &i82365_device->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 socket[i].socket.ops = &pcic_operations;
1313 socket[i].socket.resource_ops = &pccard_nonstatic_ops;
1314 socket[i].socket.owner = THIS_MODULE;
1315 socket[i].number = i;
1316 ret = pcmcia_register_socket(&socket[i].socket);
1317 if (!ret)
1318 socket[i].flags |= IS_REGISTERED;
1319
1320#if 0 /* driver model ordering issue */
1321 class_device_create_file(&socket[i].socket.dev,
1322 &class_device_attr_info);
1323 class_device_create_file(&socket[i].socket.dev,
1324 &class_device_attr_exca);
1325#endif
1326 }
1327
1328 /* Finally, schedule a polling interrupt */
1329 if (poll_interval != 0) {
1330 poll_timer.function = pcic_interrupt_wrapper;
1331 poll_timer.data = 0;
1332 init_timer(&poll_timer);
1333 poll_timer.expires = jiffies + poll_interval;
1334 add_timer(&poll_timer);
1335 }
1336
1337 return 0;
Leonardo Potenza2df69702008-04-01 23:47:09 +02001338err_socket_release:
1339 for (i = 0; i < sockets; i++) {
1340 /* Turn off all interrupt sources! */
1341 i365_set(i, I365_CSCINT, 0);
1342 release_region(socket[i].ioaddr, 2);
1343 }
1344err_dev_unregister:
1345 platform_device_unregister(i82365_device);
1346 release_region(i365_base, 2);
1347#ifdef CONFIG_PNP
1348 if (i82365_pnpdev)
1349 pnp_disable_dev(i82365_pnpdev);
1350#endif
1351err_driver_unregister:
Ming Lei7a192ec2009-02-06 23:40:12 +08001352 platform_driver_unregister(&i82365_driver);
Leonardo Potenza2df69702008-04-01 23:47:09 +02001353err_out:
1354 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355} /* init_i82365 */
1356
1357static void __exit exit_i82365(void)
1358{
1359 int i;
1360
1361 for (i = 0; i < sockets; i++) {
1362 if (socket[i].flags & IS_REGISTERED)
1363 pcmcia_unregister_socket(&socket[i].socket);
1364 }
Dominik Brodowskidfb279c2005-11-10 16:26:13 +01001365 platform_device_unregister(i82365_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 if (poll_interval != 0)
1367 del_timer_sync(&poll_timer);
1368 if (grab_irq != 0)
1369 free_irq(cs_irq, pcic_interrupt);
1370 for (i = 0; i < sockets; i++) {
1371 /* Turn off all interrupt sources! */
1372 i365_set(i, I365_CSCINT, 0);
1373 release_region(socket[i].ioaddr, 2);
1374 }
Dominik Brodowskif3549422005-06-27 16:28:55 -07001375 release_region(i365_base, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376#ifdef CONFIG_PNP
1377 if (i82365_pnpdev)
1378 pnp_disable_dev(i82365_pnpdev);
1379#endif
Ming Lei7a192ec2009-02-06 23:40:12 +08001380 platform_driver_unregister(&i82365_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381} /* exit_i82365 */
1382
1383module_init(init_i82365);
1384module_exit(exit_i82365);
1385MODULE_LICENSE("Dual MPL/GPL");
1386/*====================================================================*/