blob: d53d9b5659c71ba960345b5453975753de154210 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
David Howells7d12e782006-10-05 14:55:46 +010067static irqreturn_t i365_count_irq(int, void *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068static inline int _check_irq(int irq, int flags)
69{
70 if (request_irq(irq, i365_count_irq, flags, "x", i365_count_irq) != 0)
71 return -1;
72 free_irq(irq, i365_count_irq);
73 return 0;
74}
75
76/*====================================================================*/
77
78/* Parameters that can be set with 'insmod' */
79
80/* Default base address for i82365sl and other ISA chips */
81static unsigned long i365_base = 0x3e0;
82/* Should we probe at 0x3e2 for an extra ISA controller? */
83static int extra_sockets = 0;
84/* Specify a socket number to ignore */
85static int ignore = -1;
86/* Bit map or list of interrupts to choose from */
87static u_int irq_mask = 0xffff;
88static int irq_list[16];
Al Viro64a6f952007-10-14 19:35:30 +010089static unsigned int irq_list_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090/* The card status change interrupt -- 0 means autoselect */
91static int cs_irq = 0;
92
93/* Probe for safe interrupts? */
94static int do_scan = 1;
95/* Poll status interval -- 0 means default to interrupt */
96static int poll_interval = 0;
97/* External clock time, in nanoseconds. 120 ns = 8.33 MHz */
98static int cycle_time = 120;
99
100/* Cirrus options */
101static int has_dma = -1;
102static int has_led = -1;
103static int has_ring = -1;
104static int dynamic_mode = 0;
105static int freq_bypass = -1;
106static int setup_time = -1;
107static int cmd_time = -1;
108static int recov_time = -1;
109
110/* Vadem options */
111static int async_clock = -1;
112static int cable_mode = -1;
113static int wakeup = 0;
114
115module_param(i365_base, ulong, 0444);
116module_param(ignore, int, 0444);
117module_param(extra_sockets, int, 0444);
118module_param(irq_mask, int, 0444);
119module_param_array(irq_list, int, &irq_list_count, 0444);
120module_param(cs_irq, int, 0444);
121module_param(async_clock, int, 0444);
122module_param(cable_mode, int, 0444);
123module_param(wakeup, int, 0444);
124
125module_param(do_scan, int, 0444);
126module_param(poll_interval, int, 0444);
127module_param(cycle_time, int, 0444);
128module_param(has_dma, int, 0444);
129module_param(has_led, int, 0444);
130module_param(has_ring, int, 0444);
131module_param(dynamic_mode, int, 0444);
132module_param(freq_bypass, int, 0444);
133module_param(setup_time, int, 0444);
134module_param(cmd_time, int, 0444);
135module_param(recov_time, int, 0444);
136
137/*====================================================================*/
138
139typedef struct cirrus_state_t {
140 u_char misc1, misc2;
141 u_char timer[6];
142} cirrus_state_t;
143
144typedef struct vg46x_state_t {
145 u_char ctl, ema;
146} vg46x_state_t;
147
148struct i82365_socket {
149 u_short type, flags;
150 struct pcmcia_socket socket;
151 unsigned int number;
Olof Johansson906da802008-02-04 22:27:35 -0800152 unsigned int ioaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 u_short psock;
154 u_char cs_irq, intr;
155 union {
156 cirrus_state_t cirrus;
157 vg46x_state_t vg46x;
158 } state;
159};
160
161/* Where we keep track of our sockets... */
162static int sockets = 0;
163static struct i82365_socket socket[8] = {
164 { 0, }, /* ... */
165};
166
167/* Default ISA interrupt mask */
168#define I365_MASK 0xdeb8 /* irq 15,14,12,11,10,9,7,5,4,3 */
169
170static int grab_irq;
171static DEFINE_SPINLOCK(isa_lock);
172#define ISA_LOCK(n, f) spin_lock_irqsave(&isa_lock, f)
173#define ISA_UNLOCK(n, f) spin_unlock_irqrestore(&isa_lock, f)
174
175static struct timer_list poll_timer;
176
177/*====================================================================*/
178
179/* These definitions must match the pcic table! */
180typedef enum pcic_id {
181 IS_I82365A, IS_I82365B, IS_I82365DF,
182 IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469,
183 IS_PD6710, IS_PD672X, IS_VT83C469,
184} pcic_id;
185
186/* Flags for classifying groups of controllers */
187#define IS_VADEM 0x0001
188#define IS_CIRRUS 0x0002
189#define IS_VIA 0x0010
190#define IS_UNKNOWN 0x0400
191#define IS_VG_PWR 0x0800
192#define IS_DF_PWR 0x1000
193#define IS_REGISTERED 0x2000
194#define IS_ALIVE 0x8000
195
196typedef struct pcic_t {
197 char *name;
198 u_short flags;
199} pcic_t;
200
201static pcic_t pcic[] = {
202 { "Intel i82365sl A step", 0 },
203 { "Intel i82365sl B step", 0 },
204 { "Intel i82365sl DF", IS_DF_PWR },
205 { "IBM Clone", 0 },
206 { "Ricoh RF5C296/396", 0 },
207 { "VLSI 82C146", 0 },
208 { "Vadem VG-468", IS_VADEM },
209 { "Vadem VG-469", IS_VADEM|IS_VG_PWR },
210 { "Cirrus PD6710", IS_CIRRUS },
211 { "Cirrus PD672x", IS_CIRRUS },
212 { "VIA VT83C469", IS_CIRRUS|IS_VIA },
213};
214
215#define PCIC_COUNT (sizeof(pcic)/sizeof(pcic_t))
216
217/*====================================================================*/
218
219static DEFINE_SPINLOCK(bus_lock);
220
221static u_char i365_get(u_short sock, u_short reg)
222{
223 unsigned long flags;
224 spin_lock_irqsave(&bus_lock,flags);
225 {
Olof Johansson906da802008-02-04 22:27:35 -0800226 unsigned int port = socket[sock].ioaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 u_char val;
228 reg = I365_REG(socket[sock].psock, reg);
229 outb(reg, port); val = inb(port+1);
230 spin_unlock_irqrestore(&bus_lock,flags);
231 return val;
232 }
233}
234
235static void i365_set(u_short sock, u_short reg, u_char data)
236{
237 unsigned long flags;
238 spin_lock_irqsave(&bus_lock,flags);
239 {
Olof Johansson906da802008-02-04 22:27:35 -0800240 unsigned int port = socket[sock].ioaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 u_char val = I365_REG(socket[sock].psock, reg);
242 outb(val, port); outb(data, port+1);
243 spin_unlock_irqrestore(&bus_lock,flags);
244 }
245}
246
247static void i365_bset(u_short sock, u_short reg, u_char mask)
248{
249 u_char d = i365_get(sock, reg);
250 d |= mask;
251 i365_set(sock, reg, d);
252}
253
254static void i365_bclr(u_short sock, u_short reg, u_char mask)
255{
256 u_char d = i365_get(sock, reg);
257 d &= ~mask;
258 i365_set(sock, reg, d);
259}
260
261static void i365_bflip(u_short sock, u_short reg, u_char mask, int b)
262{
263 u_char d = i365_get(sock, reg);
264 if (b)
265 d |= mask;
266 else
267 d &= ~mask;
268 i365_set(sock, reg, d);
269}
270
271static u_short i365_get_pair(u_short sock, u_short reg)
272{
273 u_short a, b;
274 a = i365_get(sock, reg);
275 b = i365_get(sock, reg+1);
276 return (a + (b<<8));
277}
278
279static void i365_set_pair(u_short sock, u_short reg, u_short data)
280{
281 i365_set(sock, reg, data & 0xff);
282 i365_set(sock, reg+1, data >> 8);
283}
284
285/*======================================================================
286
287 Code to save and restore global state information for Cirrus
288 PD67xx controllers, and to set and report global configuration
289 options.
290
291 The VIA controllers also use these routines, as they are mostly
292 Cirrus lookalikes, without the timing registers.
293
294======================================================================*/
295
296#define flip(v,b,f) (v = ((f)<0) ? v : ((f) ? ((v)|(b)) : ((v)&(~b))))
297
298static void cirrus_get_state(u_short s)
299{
300 int i;
301 cirrus_state_t *p = &socket[s].state.cirrus;
302 p->misc1 = i365_get(s, PD67_MISC_CTL_1);
303 p->misc1 &= (PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
304 p->misc2 = i365_get(s, PD67_MISC_CTL_2);
305 for (i = 0; i < 6; i++)
306 p->timer[i] = i365_get(s, PD67_TIME_SETUP(0)+i);
307}
308
309static void cirrus_set_state(u_short s)
310{
311 int i;
312 u_char misc;
313 cirrus_state_t *p = &socket[s].state.cirrus;
314
315 misc = i365_get(s, PD67_MISC_CTL_2);
316 i365_set(s, PD67_MISC_CTL_2, p->misc2);
317 if (misc & PD67_MC2_SUSPEND) mdelay(50);
318 misc = i365_get(s, PD67_MISC_CTL_1);
319 misc &= ~(PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
320 i365_set(s, PD67_MISC_CTL_1, misc | p->misc1);
321 for (i = 0; i < 6; i++)
322 i365_set(s, PD67_TIME_SETUP(0)+i, p->timer[i]);
323}
324
325static u_int __init cirrus_set_opts(u_short s, char *buf)
326{
327 struct i82365_socket *t = &socket[s];
328 cirrus_state_t *p = &socket[s].state.cirrus;
329 u_int mask = 0xffff;
330
331 if (has_ring == -1) has_ring = 1;
332 flip(p->misc2, PD67_MC2_IRQ15_RI, has_ring);
333 flip(p->misc2, PD67_MC2_DYNAMIC_MODE, dynamic_mode);
334 flip(p->misc2, PD67_MC2_FREQ_BYPASS, freq_bypass);
335 if (p->misc2 & PD67_MC2_IRQ15_RI)
336 strcat(buf, " [ring]");
337 if (p->misc2 & PD67_MC2_DYNAMIC_MODE)
338 strcat(buf, " [dyn mode]");
339 if (p->misc2 & PD67_MC2_FREQ_BYPASS)
340 strcat(buf, " [freq bypass]");
341 if (p->misc1 & PD67_MC1_INPACK_ENA)
342 strcat(buf, " [inpack]");
343 if (p->misc2 & PD67_MC2_IRQ15_RI)
344 mask &= ~0x8000;
345 if (has_led > 0) {
346 strcat(buf, " [led]");
347 mask &= ~0x1000;
348 }
349 if (has_dma > 0) {
350 strcat(buf, " [dma]");
351 mask &= ~0x0600;
352 }
353 if (!(t->flags & IS_VIA)) {
354 if (setup_time >= 0)
355 p->timer[0] = p->timer[3] = setup_time;
356 if (cmd_time > 0) {
357 p->timer[1] = cmd_time;
358 p->timer[4] = cmd_time*2+4;
359 }
360 if (p->timer[1] == 0) {
361 p->timer[1] = 6; p->timer[4] = 16;
362 if (p->timer[0] == 0)
363 p->timer[0] = p->timer[3] = 1;
364 }
365 if (recov_time >= 0)
366 p->timer[2] = p->timer[5] = recov_time;
367 buf += strlen(buf);
368 sprintf(buf, " [%d/%d/%d] [%d/%d/%d]", p->timer[0], p->timer[1],
369 p->timer[2], p->timer[3], p->timer[4], p->timer[5]);
370 }
371 return mask;
372}
373
374/*======================================================================
375
376 Code to save and restore global state information for Vadem VG468
377 and VG469 controllers, and to set and report global configuration
378 options.
379
380======================================================================*/
381
382static void vg46x_get_state(u_short s)
383{
384 vg46x_state_t *p = &socket[s].state.vg46x;
385 p->ctl = i365_get(s, VG468_CTL);
386 if (socket[s].type == IS_VG469)
387 p->ema = i365_get(s, VG469_EXT_MODE);
388}
389
390static void vg46x_set_state(u_short s)
391{
392 vg46x_state_t *p = &socket[s].state.vg46x;
393 i365_set(s, VG468_CTL, p->ctl);
394 if (socket[s].type == IS_VG469)
395 i365_set(s, VG469_EXT_MODE, p->ema);
396}
397
398static u_int __init vg46x_set_opts(u_short s, char *buf)
399{
400 vg46x_state_t *p = &socket[s].state.vg46x;
401
402 flip(p->ctl, VG468_CTL_ASYNC, async_clock);
403 flip(p->ema, VG469_MODE_CABLE, cable_mode);
404 if (p->ctl & VG468_CTL_ASYNC)
405 strcat(buf, " [async]");
406 if (p->ctl & VG468_CTL_INPACK)
407 strcat(buf, " [inpack]");
408 if (socket[s].type == IS_VG469) {
409 u_char vsel = i365_get(s, VG469_VSELECT);
410 if (vsel & VG469_VSEL_EXT_STAT) {
411 strcat(buf, " [ext mode]");
412 if (vsel & VG469_VSEL_EXT_BUS)
413 strcat(buf, " [isa buf]");
414 }
415 if (p->ema & VG469_MODE_CABLE)
416 strcat(buf, " [cable]");
417 if (p->ema & VG469_MODE_COMPAT)
418 strcat(buf, " [c step]");
419 }
420 return 0xffff;
421}
422
423/*======================================================================
424
425 Generic routines to get and set controller options
426
427======================================================================*/
428
429static void get_bridge_state(u_short s)
430{
431 struct i82365_socket *t = &socket[s];
432 if (t->flags & IS_CIRRUS)
433 cirrus_get_state(s);
434 else if (t->flags & IS_VADEM)
435 vg46x_get_state(s);
436}
437
438static void set_bridge_state(u_short s)
439{
440 struct i82365_socket *t = &socket[s];
441 if (t->flags & IS_CIRRUS)
442 cirrus_set_state(s);
443 else {
444 i365_set(s, I365_GBLCTL, 0x00);
445 i365_set(s, I365_GENCTL, 0x00);
446 }
447 i365_bflip(s, I365_INTCTL, I365_INTR_ENA, t->intr);
448 if (t->flags & IS_VADEM)
449 vg46x_set_state(s);
450}
451
452static u_int __init set_bridge_opts(u_short s, u_short ns)
453{
454 u_short i;
455 u_int m = 0xffff;
456 char buf[128];
457
458 for (i = s; i < s+ns; i++) {
459 if (socket[i].flags & IS_ALIVE) {
460 printk(KERN_INFO " host opts [%d]: already alive!\n", i);
461 continue;
462 }
463 buf[0] = '\0';
464 get_bridge_state(i);
465 if (socket[i].flags & IS_CIRRUS)
466 m = cirrus_set_opts(i, buf);
467 else if (socket[i].flags & IS_VADEM)
468 m = vg46x_set_opts(i, buf);
469 set_bridge_state(i);
470 printk(KERN_INFO " host opts [%d]:%s\n", i,
471 (*buf) ? buf : " none");
472 }
473 return m;
474}
475
476/*======================================================================
477
478 Interrupt testing code, for ISA and PCI interrupts
479
480======================================================================*/
481
482static volatile u_int irq_hits;
483static u_short irq_sock;
484
David Howells7d12e782006-10-05 14:55:46 +0100485static irqreturn_t i365_count_irq(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486{
487 i365_get(irq_sock, I365_CSC);
488 irq_hits++;
Dominik Brodowskic9f50dd2009-10-23 12:56:46 +0200489 pr_debug("i82365: -> hit on irq %d\n", irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 return IRQ_HANDLED;
491}
492
493static u_int __init test_irq(u_short sock, int irq)
494{
Dominik Brodowskic9f50dd2009-10-23 12:56:46 +0200495 pr_debug("i82365: testing ISA irq %d\n", irq);
Thomas Gleixnerdace1452006-07-01 19:29:38 -0700496 if (request_irq(irq, i365_count_irq, IRQF_PROBE_SHARED, "scan",
Andrew Morton13e87ec2006-04-27 18:39:18 -0700497 i365_count_irq) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 return 1;
499 irq_hits = 0; irq_sock = sock;
500 msleep(10);
501 if (irq_hits) {
502 free_irq(irq, i365_count_irq);
Dominik Brodowskic9f50dd2009-10-23 12:56:46 +0200503 pr_debug("i82365: spurious hit!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 return 1;
505 }
506
507 /* Generate one interrupt */
508 i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (irq << 4));
509 i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ);
510 udelay(1000);
511
512 free_irq(irq, i365_count_irq);
513
514 /* mask all interrupts */
515 i365_set(sock, I365_CSCINT, 0);
Dominik Brodowskic9f50dd2009-10-23 12:56:46 +0200516 pr_debug("i82365: hits = %d\n", irq_hits);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
518 return (irq_hits != 1);
519}
520
521static u_int __init isa_scan(u_short sock, u_int mask0)
522{
523 u_int mask1 = 0;
524 int i;
525
526#ifdef __alpha__
527#define PIC 0x4d0
528 /* Don't probe level-triggered interrupts -- reserved for PCI */
529 mask0 &= ~(inb(PIC) | (inb(PIC+1) << 8));
530#endif
531
532 if (do_scan) {
533 set_bridge_state(sock);
534 i365_set(sock, I365_CSCINT, 0);
535 for (i = 0; i < 16; i++)
536 if ((mask0 & (1 << i)) && (test_irq(sock, i) == 0))
537 mask1 |= (1 << i);
538 for (i = 0; i < 16; i++)
539 if ((mask1 & (1 << i)) && (test_irq(sock, i) != 0))
540 mask1 ^= (1 << i);
541 }
542
543 printk(KERN_INFO " ISA irqs (");
544 if (mask1) {
545 printk("scanned");
546 } else {
547 /* Fallback: just find interrupts that aren't in use */
548 for (i = 0; i < 16; i++)
Thomas Gleixnerdace1452006-07-01 19:29:38 -0700549 if ((mask0 & (1 << i)) && (_check_irq(i, IRQF_PROBE_SHARED) == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 mask1 |= (1 << i);
551 printk("default");
552 /* If scan failed, default to polled status */
553 if (!cs_irq && (poll_interval == 0)) poll_interval = HZ;
554 }
555 printk(") = ");
556
557 for (i = 0; i < 16; i++)
558 if (mask1 & (1<<i))
559 printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i);
560 if (mask1 == 0) printk("none!");
561
562 return mask1;
563}
564
565/*====================================================================*/
566
567/* Time conversion functions */
568
569static int to_cycles(int ns)
570{
571 return ns/cycle_time;
572}
573
574/*====================================================================*/
575
Olof Johansson906da802008-02-04 22:27:35 -0800576static int __init identify(unsigned int port, u_short sock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577{
578 u_char val;
579 int type = -1;
580
581 /* Use the next free entry in the socket table */
582 socket[sockets].ioaddr = port;
583 socket[sockets].psock = sock;
584
585 /* Wake up a sleepy Cirrus controller */
586 if (wakeup) {
587 i365_bclr(sockets, PD67_MISC_CTL_2, PD67_MC2_SUSPEND);
588 /* Pause at least 50 ms */
589 mdelay(50);
590 }
591
592 if ((val = i365_get(sockets, I365_IDENT)) & 0x70)
593 return -1;
594 switch (val) {
595 case 0x82:
596 type = IS_I82365A; break;
597 case 0x83:
598 type = IS_I82365B; break;
599 case 0x84:
600 type = IS_I82365DF; break;
601 case 0x88: case 0x89: case 0x8a:
602 type = IS_IBM; break;
603 }
604
605 /* Check for Vadem VG-468 chips */
606 outb(0x0e, port);
607 outb(0x37, port);
608 i365_bset(sockets, VG468_MISC, VG468_MISC_VADEMREV);
609 val = i365_get(sockets, I365_IDENT);
610 if (val & I365_IDENT_VADEM) {
611 i365_bclr(sockets, VG468_MISC, VG468_MISC_VADEMREV);
612 type = ((val & 7) >= 4) ? IS_VG469 : IS_VG468;
613 }
614
615 /* Check for Ricoh chips */
616 val = i365_get(sockets, RF5C_CHIP_ID);
617 if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396))
618 type = IS_RF5Cx96;
619
620 /* Check for Cirrus CL-PD67xx chips */
621 i365_set(sockets, PD67_CHIP_INFO, 0);
622 val = i365_get(sockets, PD67_CHIP_INFO);
623 if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {
624 val = i365_get(sockets, PD67_CHIP_INFO);
625 if ((val & PD67_INFO_CHIP_ID) == 0) {
626 type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710;
627 i365_set(sockets, PD67_EXT_INDEX, 0xe5);
628 if (i365_get(sockets, PD67_EXT_INDEX) != 0xe5)
629 type = IS_VT83C469;
630 }
631 }
632 return type;
633} /* identify */
634
635/*======================================================================
636
637 See if a card is present, powered up, in IO mode, and already
638 bound to a (non PC Card) Linux driver. We leave these alone.
639
640 We make an exception for cards that seem to be serial devices.
641
642======================================================================*/
643
644static int __init is_alive(u_short sock)
645{
646 u_char stat;
Olof Johansson906da802008-02-04 22:27:35 -0800647 unsigned int start, stop;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
649 stat = i365_get(sock, I365_STATUS);
650 start = i365_get_pair(sock, I365_IO(0)+I365_W_START);
651 stop = i365_get_pair(sock, I365_IO(0)+I365_W_STOP);
652 if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) &&
653 (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) &&
654 (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) &&
Dominik Brodowskif3549422005-06-27 16:28:55 -0700655 ((start & 0xfeef) != 0x02e8)) {
656 if (!request_region(start, stop-start+1, "i82365"))
657 return 1;
658 release_region(start, stop-start+1);
659 }
660
661 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662}
663
664/*====================================================================*/
665
Olof Johansson906da802008-02-04 22:27:35 -0800666static void __init add_socket(unsigned int port, int psock, int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667{
668 socket[sockets].ioaddr = port;
669 socket[sockets].psock = psock;
670 socket[sockets].type = type;
671 socket[sockets].flags = pcic[type].flags;
672 if (is_alive(sockets))
673 socket[sockets].flags |= IS_ALIVE;
674 sockets++;
675}
676
677static void __init add_pcic(int ns, int type)
678{
679 u_int mask = 0, i, base;
680 int isa_irq = 0;
681 struct i82365_socket *t = &socket[sockets-ns];
682
683 base = sockets-ns;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 if (base == 0) printk("\n");
685 printk(KERN_INFO " %s", pcic[type].name);
Olof Johansson906da802008-02-04 22:27:35 -0800686 printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 t->ioaddr, t->psock*0x40);
688 printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : ""));
689
690 /* Set host options, build basic interrupt mask */
691 if (irq_list_count == 0)
692 mask = irq_mask;
693 else
694 for (i = mask = 0; i < irq_list_count; i++)
695 mask |= (1<<irq_list[i]);
696 mask &= I365_MASK & set_bridge_opts(base, ns);
697 /* Scan for ISA interrupts */
698 mask = isa_scan(base, mask);
699
700 /* Poll if only two interrupts available */
701 if (!poll_interval) {
702 u_int tmp = (mask & 0xff20);
703 tmp = tmp & (tmp-1);
704 if ((tmp & (tmp-1)) == 0)
705 poll_interval = HZ;
706 }
707 /* Only try an ISA cs_irq if this is the first controller */
708 if (!grab_irq && (cs_irq || !poll_interval)) {
709 /* Avoid irq 12 unless it is explicitly requested */
710 u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
711 for (cs_irq = 15; cs_irq > 0; cs_irq--)
712 if ((cs_mask & (1 << cs_irq)) &&
Thomas Gleixnerdace1452006-07-01 19:29:38 -0700713 (_check_irq(cs_irq, IRQF_PROBE_SHARED) == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 break;
715 if (cs_irq) {
716 grab_irq = 1;
717 isa_irq = cs_irq;
718 printk(" status change on irq %d\n", cs_irq);
719 }
720 }
721
722 if (!isa_irq) {
723 if (poll_interval == 0)
724 poll_interval = HZ;
725 printk(" polling interval = %d ms\n",
726 poll_interval * 1000 / HZ);
727
728 }
729
730 /* Update socket interrupt information, capabilities */
731 for (i = 0; i < ns; i++) {
732 t[i].socket.features |= SS_CAP_PCCARD;
733 t[i].socket.map_size = 0x1000;
734 t[i].socket.irq_mask = mask;
735 t[i].cs_irq = isa_irq;
736 }
737
738} /* add_pcic */
739
740/*====================================================================*/
741
742#ifdef CONFIG_PNP
743static struct isapnp_device_id id_table[] __initdata = {
744 { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
745 ISAPNP_FUNCTION(0x0e00), (unsigned long) "Intel 82365-Compatible" },
746 { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
747 ISAPNP_FUNCTION(0x0e01), (unsigned long) "Cirrus Logic CL-PD6720" },
748 { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
749 ISAPNP_FUNCTION(0x0e02), (unsigned long) "VLSI VL82C146" },
750 { 0 }
751};
752MODULE_DEVICE_TABLE(isapnp, id_table);
753
754static struct pnp_dev *i82365_pnpdev;
755#endif
756
757static void __init isa_probe(void)
758{
759 int i, j, sock, k, ns, id;
Olof Johansson906da802008-02-04 22:27:35 -0800760 unsigned int port;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761#ifdef CONFIG_PNP
762 struct isapnp_device_id *devid;
763 struct pnp_dev *dev;
764
765 for (devid = id_table; devid->vendor; devid++) {
766 if ((dev = pnp_find_dev(NULL, devid->vendor, devid->function, NULL))) {
767
768 if (pnp_device_attach(dev) < 0)
769 continue;
770
771 if (pnp_activate_dev(dev) < 0) {
772 printk("activate failed\n");
773 pnp_device_detach(dev);
774 break;
775 }
776
777 if (!pnp_port_valid(dev, 0)) {
778 printk("invalid resources ?\n");
779 pnp_device_detach(dev);
780 break;
781 }
782 i365_base = pnp_port_start(dev, 0);
783 i82365_pnpdev = dev;
784 break;
785 }
786 }
787#endif
788
Dominik Brodowskif3549422005-06-27 16:28:55 -0700789 if (!request_region(i365_base, 2, "i82365")) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 if (sockets == 0)
791 printk("port conflict at %#lx\n", i365_base);
792 return;
793 }
794
795 id = identify(i365_base, 0);
796 if ((id == IS_I82365DF) && (identify(i365_base, 1) != id)) {
797 for (i = 0; i < 4; i++) {
798 if (i == ignore) continue;
799 port = i365_base + ((i & 1) << 2) + ((i & 2) << 1);
800 sock = (i & 1) << 1;
801 if (identify(port, sock) == IS_I82365DF) {
802 add_socket(port, sock, IS_VLSI);
803 add_pcic(1, IS_VLSI);
804 }
805 }
806 } else {
807 for (i = 0; i < 8; i += 2) {
808 if (sockets && !extra_sockets && (i == 4))
809 break;
810 port = i365_base + 2*(i>>2);
811 sock = (i & 3);
812 id = identify(port, sock);
813 if (id < 0) continue;
814
815 for (j = ns = 0; j < 2; j++) {
816 /* Does the socket exist? */
817 if ((ignore == i+j) || (identify(port, sock+j) < 0))
818 continue;
819 /* Check for bad socket decode */
820 for (k = 0; k <= sockets; k++)
821 i365_set(k, I365_MEM(0)+I365_W_OFF, k);
822 for (k = 0; k <= sockets; k++)
823 if (i365_get(k, I365_MEM(0)+I365_W_OFF) != k)
824 break;
825 if (k <= sockets) break;
826 add_socket(port, sock+j, id); ns++;
827 }
828 if (ns != 0) add_pcic(ns, id);
829 }
830 }
831}
832
833/*====================================================================*/
834
David Howells7d12e782006-10-05 14:55:46 +0100835static irqreturn_t pcic_interrupt(int irq, void *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836{
837 int i, j, csc;
838 u_int events, active;
839 u_long flags = 0;
840 int handled = 0;
841
Dominik Brodowskic9f50dd2009-10-23 12:56:46 +0200842 pr_debug("pcic_interrupt(%d)\n", irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
844 for (j = 0; j < 20; j++) {
845 active = 0;
846 for (i = 0; i < sockets; i++) {
847 if (socket[i].cs_irq != irq)
848 continue;
849 handled = 1;
850 ISA_LOCK(i, flags);
851 csc = i365_get(i, I365_CSC);
852 if ((csc == 0) || (i365_get(i, I365_IDENT) & 0x70)) {
853 ISA_UNLOCK(i, flags);
854 continue;
855 }
856 events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0;
857
858 if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD)
859 events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
860 else {
861 events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;
862 events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
863 events |= (csc & I365_CSC_READY) ? SS_READY : 0;
864 }
865 ISA_UNLOCK(i, flags);
Dominik Brodowskic9f50dd2009-10-23 12:56:46 +0200866 pr_debug("socket %d event 0x%02x\n", i, events);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867
868 if (events)
869 pcmcia_parse_events(&socket[i].socket, events);
870
871 active |= events;
872 }
873 if (!active) break;
874 }
875 if (j == 20)
876 printk(KERN_NOTICE "i82365: infinite loop in interrupt handler\n");
877
Dominik Brodowskic9f50dd2009-10-23 12:56:46 +0200878 pr_debug("pcic_interrupt done\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 return IRQ_RETVAL(handled);
880} /* pcic_interrupt */
881
882static void pcic_interrupt_wrapper(u_long data)
883{
David Howells7d12e782006-10-05 14:55:46 +0100884 pcic_interrupt(0, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 poll_timer.expires = jiffies + poll_interval;
886 add_timer(&poll_timer);
887}
888
889/*====================================================================*/
890
891static int i365_get_status(u_short sock, u_int *value)
892{
893 u_int status;
894
895 status = i365_get(sock, I365_STATUS);
896 *value = ((status & I365_CS_DETECT) == I365_CS_DETECT)
897 ? SS_DETECT : 0;
898
899 if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD)
900 *value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
901 else {
902 *value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD;
903 *value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN;
904 }
905 *value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
906 *value |= (status & I365_CS_READY) ? SS_READY : 0;
907 *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
908
909 if (socket[sock].type == IS_VG469) {
910 status = i365_get(sock, VG469_VSENSE);
911 if (socket[sock].psock & 1) {
912 *value |= (status & VG469_VSENSE_B_VS1) ? 0 : SS_3VCARD;
913 *value |= (status & VG469_VSENSE_B_VS2) ? 0 : SS_XVCARD;
914 } else {
915 *value |= (status & VG469_VSENSE_A_VS1) ? 0 : SS_3VCARD;
916 *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD;
917 }
918 }
919
Dominik Brodowskic9f50dd2009-10-23 12:56:46 +0200920 pr_debug("GetStatus(%d) = %#4.4x\n", sock, *value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 return 0;
922} /* i365_get_status */
923
924/*====================================================================*/
925
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926static int i365_set_socket(u_short sock, socket_state_t *state)
927{
928 struct i82365_socket *t = &socket[sock];
929 u_char reg;
930
Dominik Brodowskic9f50dd2009-10-23 12:56:46 +0200931 pr_debug("SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
933 state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
934
935 /* First set global controller options */
936 set_bridge_state(sock);
937
938 /* IO card, RESET flag, IO interrupt */
939 reg = t->intr;
940 reg |= state->io_irq;
941 reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
942 reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
943 i365_set(sock, I365_INTCTL, reg);
944
945 reg = I365_PWR_NORESET;
946 if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO;
947 if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT;
948
949 if (t->flags & IS_CIRRUS) {
950 if (state->Vpp != 0) {
951 if (state->Vpp == 120)
952 reg |= I365_VPP1_12V;
953 else if (state->Vpp == state->Vcc)
954 reg |= I365_VPP1_5V;
955 else return -EINVAL;
956 }
957 if (state->Vcc != 0) {
958 reg |= I365_VCC_5V;
959 if (state->Vcc == 33)
960 i365_bset(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
961 else if (state->Vcc == 50)
962 i365_bclr(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
963 else return -EINVAL;
964 }
965 } else if (t->flags & IS_VG_PWR) {
966 if (state->Vpp != 0) {
967 if (state->Vpp == 120)
968 reg |= I365_VPP1_12V;
969 else if (state->Vpp == state->Vcc)
970 reg |= I365_VPP1_5V;
971 else return -EINVAL;
972 }
973 if (state->Vcc != 0) {
974 reg |= I365_VCC_5V;
975 if (state->Vcc == 33)
976 i365_bset(sock, VG469_VSELECT, VG469_VSEL_VCC);
977 else if (state->Vcc == 50)
978 i365_bclr(sock, VG469_VSELECT, VG469_VSEL_VCC);
979 else return -EINVAL;
980 }
981 } else if (t->flags & IS_DF_PWR) {
982 switch (state->Vcc) {
983 case 0: break;
984 case 33: reg |= I365_VCC_3V; break;
985 case 50: reg |= I365_VCC_5V; break;
986 default: return -EINVAL;
987 }
988 switch (state->Vpp) {
989 case 0: break;
990 case 50: reg |= I365_VPP1_5V; break;
991 case 120: reg |= I365_VPP1_12V; break;
992 default: return -EINVAL;
993 }
994 } else {
995 switch (state->Vcc) {
996 case 0: break;
997 case 50: reg |= I365_VCC_5V; break;
998 default: return -EINVAL;
999 }
1000 switch (state->Vpp) {
1001 case 0: break;
1002 case 50: reg |= I365_VPP1_5V | I365_VPP2_5V; break;
1003 case 120: reg |= I365_VPP1_12V | I365_VPP2_12V; break;
1004 default: return -EINVAL;
1005 }
1006 }
1007
1008 if (reg != i365_get(sock, I365_POWER))
1009 i365_set(sock, I365_POWER, reg);
1010
1011 /* Chipset-specific functions */
1012 if (t->flags & IS_CIRRUS) {
1013 /* Speaker control */
1014 i365_bflip(sock, PD67_MISC_CTL_1, PD67_MC1_SPKR_ENA,
1015 state->flags & SS_SPKR_ENA);
1016 }
1017
1018 /* Card status change interrupt mask */
1019 reg = t->cs_irq << 4;
1020 if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
1021 if (state->flags & SS_IOCARD) {
1022 if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG;
1023 } else {
1024 if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1;
1025 if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2;
1026 if (state->csc_mask & SS_READY) reg |= I365_CSC_READY;
1027 }
1028 i365_set(sock, I365_CSCINT, reg);
1029 i365_get(sock, I365_CSC);
1030
1031 return 0;
1032} /* i365_set_socket */
1033
1034/*====================================================================*/
1035
1036static int i365_set_io_map(u_short sock, struct pccard_io_map *io)
1037{
1038 u_char map, ioctl;
1039
Dominik Brodowskic9f50dd2009-10-23 12:56:46 +02001040 pr_debug("SetIOMap(%d, %d, %#2.2x, %d ns, "
Randy Dunlap01373042009-10-11 18:50:09 -07001041 "%#llx-%#llx)\n", sock, io->map, io->flags, io->speed,
1042 (unsigned long long)io->start, (unsigned long long)io->stop);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 map = io->map;
1044 if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
1045 (io->stop < io->start)) return -EINVAL;
1046 /* Turn off the window before changing anything */
1047 if (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(map))
1048 i365_bclr(sock, I365_ADDRWIN, I365_ENA_IO(map));
1049 i365_set_pair(sock, I365_IO(map)+I365_W_START, io->start);
1050 i365_set_pair(sock, I365_IO(map)+I365_W_STOP, io->stop);
1051 ioctl = i365_get(sock, I365_IOCTL) & ~I365_IOCTL_MASK(map);
1052 if (io->speed) ioctl |= I365_IOCTL_WAIT(map);
1053 if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map);
1054 if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map);
1055 if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map);
1056 i365_set(sock, I365_IOCTL, ioctl);
1057 /* Turn on the window if necessary */
1058 if (io->flags & MAP_ACTIVE)
1059 i365_bset(sock, I365_ADDRWIN, I365_ENA_IO(map));
1060 return 0;
1061} /* i365_set_io_map */
1062
1063/*====================================================================*/
1064
1065static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
1066{
1067 u_short base, i;
1068 u_char map;
1069
Dominik Brodowskic9f50dd2009-10-23 12:56:46 +02001070 pr_debug("SetMemMap(%d, %d, %#2.2x, %d ns, %#llx-%#llx, "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 "%#x)\n", sock, mem->map, mem->flags, mem->speed,
Greg Kroah-Hartman490ab722006-06-12 15:17:34 -07001072 (unsigned long long)mem->res->start,
1073 (unsigned long long)mem->res->end, mem->card_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
1075 map = mem->map;
1076 if ((map > 4) || (mem->card_start > 0x3ffffff) ||
1077 (mem->res->start > mem->res->end) || (mem->speed > 1000))
1078 return -EINVAL;
1079 if ((mem->res->start > 0xffffff) || (mem->res->end > 0xffffff))
1080 return -EINVAL;
1081
1082 /* Turn off the window before changing anything */
1083 if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map))
1084 i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map));
1085
1086 base = I365_MEM(map);
1087 i = (mem->res->start >> 12) & 0x0fff;
1088 if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT;
1089 if (mem->flags & MAP_0WS) i |= I365_MEM_0WS;
1090 i365_set_pair(sock, base+I365_W_START, i);
1091
1092 i = (mem->res->end >> 12) & 0x0fff;
1093 switch (to_cycles(mem->speed)) {
1094 case 0: break;
1095 case 1: i |= I365_MEM_WS0; break;
1096 case 2: i |= I365_MEM_WS1; break;
1097 default: i |= I365_MEM_WS1 | I365_MEM_WS0; break;
1098 }
1099 i365_set_pair(sock, base+I365_W_STOP, i);
1100
1101 i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff;
1102 if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT;
1103 if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG;
1104 i365_set_pair(sock, base+I365_W_OFF, i);
1105
1106 /* Turn on the window if necessary */
1107 if (mem->flags & MAP_ACTIVE)
1108 i365_bset(sock, I365_ADDRWIN, I365_ENA_MEM(map));
1109 return 0;
1110} /* i365_set_mem_map */
1111
1112#if 0 /* driver model ordering issue */
1113/*======================================================================
1114
1115 Routines for accessing socket information and register dumps via
1116 /sys/class/pcmcia_socket/...
1117
1118======================================================================*/
1119
1120static ssize_t show_info(struct class_device *class_dev, char *buf)
1121{
1122 struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev);
1123 return sprintf(buf, "type: %s\npsock: %d\n",
1124 pcic[s->type].name, s->psock);
1125}
1126
1127static ssize_t show_exca(struct class_device *class_dev, char *buf)
1128{
1129 struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev);
1130 unsigned short sock;
1131 int i;
1132 ssize_t ret = 0;
1133 unsigned long flags = 0;
1134
1135 sock = s->number;
1136
1137 ISA_LOCK(sock, flags);
1138 for (i = 0; i < 0x40; i += 4) {
1139 ret += sprintf(buf, "%02x %02x %02x %02x%s",
1140 i365_get(sock,i), i365_get(sock,i+1),
1141 i365_get(sock,i+2), i365_get(sock,i+3),
1142 ((i % 16) == 12) ? "\n" : " ");
1143 buf += ret;
1144 }
1145 ISA_UNLOCK(sock, flags);
1146
1147 return ret;
1148}
1149
1150static CLASS_DEVICE_ATTR(exca, S_IRUGO, show_exca, NULL);
1151static CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL);
1152#endif
1153
1154/*====================================================================*/
1155
1156/* this is horribly ugly... proper locking needs to be done here at
1157 * some time... */
1158#define LOCKED(x) do { \
1159 int retval; \
1160 unsigned long flags; \
1161 spin_lock_irqsave(&isa_lock, flags); \
1162 retval = x; \
1163 spin_unlock_irqrestore(&isa_lock, flags); \
1164 return retval; \
1165} while (0)
1166
1167
1168static int pcic_get_status(struct pcmcia_socket *s, u_int *value)
1169{
1170 unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
1171
1172 if (socket[sock].flags & IS_ALIVE) {
1173 *value = 0;
1174 return -EINVAL;
1175 }
1176
1177 LOCKED(i365_get_status(sock, value));
1178}
1179
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180static int pcic_set_socket(struct pcmcia_socket *s, socket_state_t *state)
1181{
1182 unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
1183
1184 if (socket[sock].flags & IS_ALIVE)
1185 return -EINVAL;
1186
1187 LOCKED(i365_set_socket(sock, state));
1188}
1189
1190static int pcic_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
1191{
1192 unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
1193 if (socket[sock].flags & IS_ALIVE)
1194 return -EINVAL;
1195
1196 LOCKED(i365_set_io_map(sock, io));
1197}
1198
1199static int pcic_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem)
1200{
1201 unsigned int sock = container_of(s, struct i82365_socket, socket)->number;
1202 if (socket[sock].flags & IS_ALIVE)
1203 return -EINVAL;
1204
1205 LOCKED(i365_set_mem_map(sock, mem));
1206}
1207
1208static int pcic_init(struct pcmcia_socket *s)
1209{
1210 int i;
1211 struct resource res = { .start = 0, .end = 0x1000 };
1212 pccard_io_map io = { 0, 0, 0, 0, 1 };
1213 pccard_mem_map mem = { .res = &res, };
1214
1215 for (i = 0; i < 2; i++) {
1216 io.map = i;
1217 pcic_set_io_map(s, &io);
1218 }
1219 for (i = 0; i < 5; i++) {
1220 mem.map = i;
1221 pcic_set_mem_map(s, &mem);
1222 }
1223 return 0;
1224}
1225
Ming Lei7a192ec2009-02-06 23:40:12 +08001226
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227static struct pccard_operations pcic_operations = {
1228 .init = pcic_init,
1229 .get_status = pcic_get_status,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 .set_socket = pcic_set_socket,
1231 .set_io_map = pcic_set_io_map,
1232 .set_mem_map = pcic_set_mem_map,
1233};
1234
1235/*====================================================================*/
1236
Ming Lei7a192ec2009-02-06 23:40:12 +08001237static struct platform_driver i82365_driver = {
1238 .driver = {
1239 .name = "i82365",
1240 .owner = THIS_MODULE,
1241 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242};
1243
Dominik Brodowskidfb279c2005-11-10 16:26:13 +01001244static struct platform_device *i82365_device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245
1246static int __init init_i82365(void)
1247{
1248 int i, ret;
1249
Ming Lei7a192ec2009-02-06 23:40:12 +08001250 ret = platform_driver_register(&i82365_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 if (ret)
Leonardo Potenza2df69702008-04-01 23:47:09 +02001252 goto err_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
Dominik Brodowskidfb279c2005-11-10 16:26:13 +01001254 i82365_device = platform_device_alloc("i82365", 0);
1255 if (i82365_device) {
1256 ret = platform_device_add(i82365_device);
1257 if (ret)
1258 platform_device_put(i82365_device);
1259 } else
1260 ret = -ENOMEM;
1261
Leonardo Potenza2df69702008-04-01 23:47:09 +02001262 if (ret)
1263 goto err_driver_unregister;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
1265 printk(KERN_INFO "Intel ISA PCIC probe: ");
1266 sockets = 0;
1267
1268 isa_probe();
1269
1270 if (sockets == 0) {
1271 printk("not found.\n");
Leonardo Potenza2df69702008-04-01 23:47:09 +02001272 ret = -ENODEV;
1273 goto err_dev_unregister;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 }
1275
1276 /* Set up interrupt handler(s) */
1277 if (grab_irq != 0)
Leonardo Potenza2df69702008-04-01 23:47:09 +02001278 ret = request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt);
1279
1280 if (ret)
1281 goto err_socket_release;
1282
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 /* register sockets with the pcmcia core */
1284 for (i = 0; i < sockets; i++) {
Greg Kroah-Hartman87373312006-09-12 17:00:10 +02001285 socket[i].socket.dev.parent = &i82365_device->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 socket[i].socket.ops = &pcic_operations;
1287 socket[i].socket.resource_ops = &pccard_nonstatic_ops;
1288 socket[i].socket.owner = THIS_MODULE;
1289 socket[i].number = i;
1290 ret = pcmcia_register_socket(&socket[i].socket);
1291 if (!ret)
1292 socket[i].flags |= IS_REGISTERED;
1293
1294#if 0 /* driver model ordering issue */
1295 class_device_create_file(&socket[i].socket.dev,
1296 &class_device_attr_info);
1297 class_device_create_file(&socket[i].socket.dev,
1298 &class_device_attr_exca);
1299#endif
1300 }
1301
1302 /* Finally, schedule a polling interrupt */
1303 if (poll_interval != 0) {
1304 poll_timer.function = pcic_interrupt_wrapper;
1305 poll_timer.data = 0;
1306 init_timer(&poll_timer);
1307 poll_timer.expires = jiffies + poll_interval;
1308 add_timer(&poll_timer);
1309 }
1310
1311 return 0;
Leonardo Potenza2df69702008-04-01 23:47:09 +02001312err_socket_release:
1313 for (i = 0; i < sockets; i++) {
1314 /* Turn off all interrupt sources! */
1315 i365_set(i, I365_CSCINT, 0);
1316 release_region(socket[i].ioaddr, 2);
1317 }
1318err_dev_unregister:
1319 platform_device_unregister(i82365_device);
1320 release_region(i365_base, 2);
1321#ifdef CONFIG_PNP
1322 if (i82365_pnpdev)
1323 pnp_disable_dev(i82365_pnpdev);
1324#endif
1325err_driver_unregister:
Ming Lei7a192ec2009-02-06 23:40:12 +08001326 platform_driver_unregister(&i82365_driver);
Leonardo Potenza2df69702008-04-01 23:47:09 +02001327err_out:
1328 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329} /* init_i82365 */
1330
1331static void __exit exit_i82365(void)
1332{
1333 int i;
1334
1335 for (i = 0; i < sockets; i++) {
1336 if (socket[i].flags & IS_REGISTERED)
1337 pcmcia_unregister_socket(&socket[i].socket);
1338 }
Dominik Brodowskidfb279c2005-11-10 16:26:13 +01001339 platform_device_unregister(i82365_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 if (poll_interval != 0)
1341 del_timer_sync(&poll_timer);
1342 if (grab_irq != 0)
1343 free_irq(cs_irq, pcic_interrupt);
1344 for (i = 0; i < sockets; i++) {
1345 /* Turn off all interrupt sources! */
1346 i365_set(i, I365_CSCINT, 0);
1347 release_region(socket[i].ioaddr, 2);
1348 }
Dominik Brodowskif3549422005-06-27 16:28:55 -07001349 release_region(i365_base, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350#ifdef CONFIG_PNP
1351 if (i82365_pnpdev)
1352 pnp_disable_dev(i82365_pnpdev);
1353#endif
Ming Lei7a192ec2009-02-06 23:40:12 +08001354 platform_driver_unregister(&i82365_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355} /* exit_i82365 */
1356
1357module_init(init_i82365);
1358module_exit(exit_i82365);
1359MODULE_LICENSE("Dual MPL/GPL");
1360/*====================================================================*/