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