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