Blame view

drivers/pcmcia/pd6729.c 18.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
  /*
   * Driver for the Cirrus PD6729 PCI-PCMCIA bridge.
   *
   * Based on the i82092.c driver.
   *
   * This software may be used and distributed according to the terms of
   * the GNU General Public License, incorporated herein by reference.
   */
  
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
12
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
16
17
  #include <linux/pci.h>
  #include <linux/init.h>
  #include <linux/workqueue.h>
  #include <linux/interrupt.h>
  #include <linux/device.h>
5cbb2b941   Komuro   pd6729: Coding St...
18
  #include <linux/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  #include <pcmcia/ss.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
  
  #include <asm/system.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  
  #include "pd6729.h"
  #include "i82365.h"
  #include "cirrus.h"
  
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("Driver for the Cirrus PD6729 PCI-PCMCIA bridge");
  MODULE_AUTHOR("Jun Komuro <komurojun-mbn@nifty.com>");
  
  #define MAX_SOCKETS 2
  
  /*
   * simple helper functions
   * External clock time, in nanoseconds.  120 ns = 8.33 MHz
   */
  #define to_cycles(ns)	((ns)/120)
  
  #ifndef NO_IRQ
  #define NO_IRQ	((unsigned int)(0))
  #endif
  
  /*
   * PARAMETERS
   *  irq_mode=n
   *     Specifies the interrupt delivery mode.  The default (1) is to use PCI
   *     interrupts; a value of 0 selects ISA interrupts. This must be set for
   *     correct operation of PCI card readers.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
   */
  
  static int irq_mode = 1; /* 0 = ISA interrupt, 1 = PCI interrupt */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
  
  module_param(irq_mode, int, 0444);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
  MODULE_PARM_DESC(irq_mode,
  		"interrupt delivery mode. 0 = ISA, 1 = PCI. default is 1");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  
  static DEFINE_SPINLOCK(port_lock);
  
  /* basic value read/write functions */
  
  static unsigned char indirect_read(struct pd6729_socket *socket,
  				   unsigned short reg)
  {
  	unsigned long port;
  	unsigned char val;
  	unsigned long flags;
  
  	spin_lock_irqsave(&port_lock, flags);
  	reg += socket->number * 0x40;
  	port = socket->io_base;
  	outb(reg, port);
  	val = inb(port + 1);
  	spin_unlock_irqrestore(&port_lock, flags);
  
  	return val;
  }
  
  static unsigned short indirect_read16(struct pd6729_socket *socket,
  				      unsigned short reg)
  {
  	unsigned long port;
  	unsigned short tmp;
  	unsigned long flags;
  
  	spin_lock_irqsave(&port_lock, flags);
  	reg  = reg + socket->number * 0x40;
  	port = socket->io_base;
  	outb(reg, port);
  	tmp = inb(port + 1);
  	reg++;
  	outb(reg, port);
  	tmp = tmp | (inb(port + 1) << 8);
  	spin_unlock_irqrestore(&port_lock, flags);
  
  	return tmp;
  }
  
  static void indirect_write(struct pd6729_socket *socket, unsigned short reg,
  			   unsigned char value)
  {
  	unsigned long port;
  	unsigned long flags;
  
  	spin_lock_irqsave(&port_lock, flags);
  	reg = reg + socket->number * 0x40;
  	port = socket->io_base;
  	outb(reg, port);
  	outb(value, port + 1);
  	spin_unlock_irqrestore(&port_lock, flags);
  }
  
  static void indirect_setbit(struct pd6729_socket *socket, unsigned short reg,
  			    unsigned char mask)
  {
  	unsigned long port;
  	unsigned char val;
  	unsigned long flags;
  
  	spin_lock_irqsave(&port_lock, flags);
  	reg = reg + socket->number * 0x40;
  	port = socket->io_base;
  	outb(reg, port);
  	val = inb(port + 1);
  	val |= mask;
  	outb(reg, port);
  	outb(val, port + 1);
  	spin_unlock_irqrestore(&port_lock, flags);
  }
  
  static void indirect_resetbit(struct pd6729_socket *socket, unsigned short reg,
  			      unsigned char mask)
  {
  	unsigned long port;
  	unsigned char val;
  	unsigned long flags;
  
  	spin_lock_irqsave(&port_lock, flags);
  	reg = reg + socket->number * 0x40;
  	port = socket->io_base;
  	outb(reg, port);
  	val = inb(port + 1);
  	val &= ~mask;
  	outb(reg, port);
  	outb(val, port + 1);
  	spin_unlock_irqrestore(&port_lock, flags);
  }
  
  static void indirect_write16(struct pd6729_socket *socket, unsigned short reg,
  			     unsigned short value)
  {
  	unsigned long port;
  	unsigned char val;
  	unsigned long flags;
  
  	spin_lock_irqsave(&port_lock, flags);
  	reg = reg + socket->number * 0x40;
  	port = socket->io_base;
  
  	outb(reg, port);
  	val = value & 255;
  	outb(val, port + 1);
  
  	reg++;
  
  	outb(reg, port);
  	val = value >> 8;
  	outb(val, port + 1);
  	spin_unlock_irqrestore(&port_lock, flags);
  }
  
  /* Interrupt handler functionality */
7d12e780e   David Howells   IRQ: Maintain reg...
173
  static irqreturn_t pd6729_interrupt(int irq, void *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  {
  	struct pd6729_socket *socket = (struct pd6729_socket *)dev;
  	int i;
  	int loopcount = 0;
  	int handled = 0;
  	unsigned int events, active = 0;
  
  	while (1) {
  		loopcount++;
  		if (loopcount > 20) {
  			printk(KERN_ERR "pd6729: infinite eventloop "
  			       "in interrupt
  ");
  			break;
  		}
  
  		active = 0;
  
  		for (i = 0; i < MAX_SOCKETS; i++) {
  			unsigned int csc;
  
  			/* card status change register */
  			csc = indirect_read(&socket[i], I365_CSC);
  			if (csc == 0)  /* no events on this socket */
  				continue;
  
  			handled = 1;
  			events = 0;
  
  			if (csc & I365_CSC_DETECT) {
  				events |= SS_DETECT;
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
205
206
207
  				dev_vdbg(&socket[i].socket.dev,
  					"Card detected in socket %i!
  ", i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  			}
  
  			if (indirect_read(&socket[i], I365_INTCTL)
  						& I365_PC_IOCARD) {
  				/* For IO/CARDS, bit 0 means "read the card" */
  				events |= (csc & I365_CSC_STSCHG)
  						? SS_STSCHG : 0;
  			} else {
  				/* Check for battery/ready events */
  				events |= (csc & I365_CSC_BVD1)
  						? SS_BATDEAD : 0;
  				events |= (csc & I365_CSC_BVD2)
  						? SS_BATWARN : 0;
  				events |= (csc & I365_CSC_READY)
  						? SS_READY : 0;
  			}
5cbb2b941   Komuro   pd6729: Coding St...
224
  			if (events)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  				pcmcia_parse_events(&socket[i].socket, events);
5cbb2b941   Komuro   pd6729: Coding St...
226

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
229
230
231
232
233
234
235
236
237
238
239
240
  			active |= events;
  		}
  
  		if (active == 0) /* no more events to handle */
  			break;
  	}
  	return IRQ_RETVAL(handled);
  }
  
  /* socket functions */
  
  static void pd6729_interrupt_wrapper(unsigned long data)
  {
  	struct pd6729_socket *socket = (struct pd6729_socket *) data;
7d12e780e   David Howells   IRQ: Maintain reg...
241
  	pd6729_interrupt(0, (void *)socket);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
244
245
246
247
248
249
250
251
252
253
254
255
  	mod_timer(&socket->poll_timer, jiffies + HZ);
  }
  
  static int pd6729_get_status(struct pcmcia_socket *sock, u_int *value)
  {
  	struct pd6729_socket *socket
  			= container_of(sock, struct pd6729_socket, socket);
  	unsigned int status;
  	unsigned int data;
  	struct pd6729_socket *t;
  
  	/* Interface Status Register */
  	status = indirect_read(socket, I365_STATUS);
  	*value = 0;
5cbb2b941   Komuro   pd6729: Coding St...
256
  	if ((status & I365_CS_DETECT) == I365_CS_DETECT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
  		*value |= SS_DETECT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
  
  	/*
  	 * IO cards have a different meaning of bits 0,1
  	 * Also notice the inverse-logic on the bits
  	 */
  	if (indirect_read(socket, I365_INTCTL) & I365_PC_IOCARD) {
  		/* IO card */
  		if (!(status & I365_CS_STSCHG))
  			*value |= SS_STSCHG;
  	} else {
  		/* non I/O card */
  		if (!(status & I365_CS_BVD1))
  			*value |= SS_BATDEAD;
  		if (!(status & I365_CS_BVD2))
  			*value |= SS_BATWARN;
  	}
  
  	if (status & I365_CS_WRPROT)
  		*value |= SS_WRPROT;	/* card is write protected */
  
  	if (status & I365_CS_READY)
  		*value |= SS_READY;	/* card is not busy */
  
  	if (status & I365_CS_POWERON)
  		*value |= SS_POWERON;	/* power is applied to the card */
  
  	t = (socket->number) ? socket : socket + 1;
  	indirect_write(t, PD67_EXT_INDEX, PD67_EXTERN_DATA);
  	data = indirect_read16(t, PD67_EXT_DATA);
  	*value |= (data & PD67_EXD_VS1(socket->number)) ? 0 : SS_3VCARD;
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
294
295
296
297
298
299
300
301
302
303
304
  static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
  {
  	struct pd6729_socket *socket
  			= container_of(sock, struct pd6729_socket, socket);
  	unsigned char reg, data;
  
  	/* First, set the global controller options */
  	indirect_write(socket, I365_GBLCTL, 0x00);
  	indirect_write(socket, I365_GENCTL, 0x00);
  
  	/* Values for the IGENC register */
  	socket->card_irq = state->io_irq;
  
  	reg = 0;
5cbb2b941   Komuro   pd6729: Coding St...
305
  	/* The reset bit has "inverse" logic */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
308
309
310
311
312
313
314
315
316
317
318
  	if (!(state->flags & SS_RESET))
  		reg |= I365_PC_RESET;
  	if (state->flags & SS_IOCARD)
  		reg |= I365_PC_IOCARD;
  
  	/* IGENC, Interrupt and General Control Register */
  	indirect_write(socket, I365_INTCTL, reg);
  
  	/* Power registers */
  
  	reg = I365_PWR_NORESET; /* default: disable resetdrv on resume */
  
  	if (state->flags & SS_PWR_AUTO) {
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
319
320
  		dev_dbg(&sock->dev, "Auto power
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
322
323
  		reg |= I365_PWR_AUTO;	/* automatic power mngmnt */
  	}
  	if (state->flags & SS_OUTPUT_ENA) {
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
324
325
  		dev_dbg(&sock->dev, "Power Enabled
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
330
331
332
  		reg |= I365_PWR_OUT;	/* enable power */
  	}
  
  	switch (state->Vcc) {
  	case 0:
  		break;
  	case 33:
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
333
334
335
  		dev_dbg(&sock->dev,
  			"setting voltage to Vcc to 3.3V on socket %i
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
338
339
340
  			socket->number);
  		reg |= I365_VCC_5V;
  		indirect_setbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
  		break;
  	case 50:
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
341
342
343
  		dev_dbg(&sock->dev,
  			"setting voltage to Vcc to 5V on socket %i
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
  			socket->number);
  		reg |= I365_VCC_5V;
  		indirect_resetbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
  		break;
  	default:
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
349
350
351
352
  		dev_dbg(&sock->dev,
  			"pd6729_set_socket called with invalid VCC power "
  			"value: %i
  ", state->Vcc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
355
356
357
  		return -EINVAL;
  	}
  
  	switch (state->Vpp) {
  	case 0:
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
358
359
360
  		dev_dbg(&sock->dev, "not setting Vpp on socket %i
  ",
  			socket->number);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
363
  		break;
  	case 33:
  	case 50:
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
364
365
366
  		dev_dbg(&sock->dev, "setting Vpp to Vcc for socket %i
  ",
  			socket->number);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
  		reg |= I365_VPP1_5V;
  		break;
  	case 120:
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
370
371
  		dev_dbg(&sock->dev, "setting Vpp to 12.0
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
374
  		reg |= I365_VPP1_12V;
  		break;
  	default:
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
375
376
377
  		dev_dbg(&sock->dev, "pd6729: pd6729_set_socket called with "
  			"invalid VPP power value: %i
  ", state->Vpp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
380
381
382
383
384
385
  		return -EINVAL;
  	}
  
  	/* only write if changed */
  	if (reg != indirect_read(socket, I365_POWER))
  		indirect_write(socket, I365_POWER, reg);
  
  	if (irq_mode == 1) {
5cbb2b941   Komuro   pd6729: Coding St...
386
  		/* all interrupts are to be done as PCI interrupts */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
389
390
391
392
393
394
395
396
  		data = PD67_EC1_INV_MGMT_IRQ | PD67_EC1_INV_CARD_IRQ;
  	} else
  		data = 0;
  
  	indirect_write(socket, PD67_EXT_INDEX, PD67_EXT_CTL_1);
  	indirect_write(socket, PD67_EXT_DATA, data);
  
  	/* Enable specific interrupt events */
  
  	reg = 0x00;
5cbb2b941   Komuro   pd6729: Coding St...
397
  	if (state->csc_mask & SS_DETECT)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
  		reg |= I365_CSC_DETECT;
5cbb2b941   Komuro   pd6729: Coding St...
399

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  	if (state->flags & SS_IOCARD) {
  		if (state->csc_mask & SS_STSCHG)
  			reg |= I365_CSC_STSCHG;
  	} else {
  		if (state->csc_mask & SS_BATDEAD)
  			reg |= I365_CSC_BVD1;
  		if (state->csc_mask & SS_BATWARN)
  			reg |= I365_CSC_BVD2;
  		if (state->csc_mask & SS_READY)
  			reg |= I365_CSC_READY;
  	}
  	if (irq_mode == 1)
  		reg |= 0x30;	/* management IRQ: PCI INTA# = "irq 3" */
  	indirect_write(socket, I365_CSCINT, reg);
  
  	reg = indirect_read(socket, I365_INTCTL);
  	if (irq_mode == 1)
  		reg |= 0x03;	/* card IRQ: PCI INTA# = "irq 3" */
  	else
  		reg |= socket->card_irq;
  	indirect_write(socket, I365_INTCTL, reg);
  
  	/* now clear the (probably bogus) pending stuff by doing a dummy read */
  	(void)indirect_read(socket, I365_CSC);
  
  	return 0;
  }
  
  static int pd6729_set_io_map(struct pcmcia_socket *sock,
  			     struct pccard_io_map *io)
  {
  	struct pd6729_socket *socket
  			= container_of(sock, struct pd6729_socket, socket);
  	unsigned char map, ioctl;
  
  	map = io->map;
  
  	/* Check error conditions */
  	if (map > 1) {
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
439
440
  		dev_dbg(&sock->dev, "pd6729_set_io_map with invalid map
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
443
444
445
446
  		return -EINVAL;
  	}
  
  	/* Turn off the window before changing anything */
  	if (indirect_read(socket, I365_ADDRWIN) & I365_ENA_IO(map))
  		indirect_resetbit(socket, I365_ADDRWIN, I365_ENA_IO(map));
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
447
448
  	/* dev_dbg(&sock->dev, "set_io_map: Setting range to %x - %x
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
450
451
452
453
454
455
  	   io->start, io->stop);*/
  
  	/* write the new values */
  	indirect_write16(socket, I365_IO(map)+I365_W_START, io->start);
  	indirect_write16(socket, I365_IO(map)+I365_W_STOP, io->stop);
  
  	ioctl = indirect_read(socket, I365_IOCTL) & ~I365_IOCTL_MASK(map);
5cbb2b941   Komuro   pd6729: Coding St...
456
457
458
459
460
461
  	if (io->flags & MAP_0WS)
  		ioctl |= I365_IOCTL_0WS(map);
  	if (io->flags & MAP_16BIT)
  		ioctl |= I365_IOCTL_16BIT(map);
  	if (io->flags & MAP_AUTOSZ)
  		ioctl |= I365_IOCTL_IOCS16(map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
  
  	indirect_write(socket, I365_IOCTL, ioctl);
  
  	/* Turn the window back on if needed */
  	if (io->flags & MAP_ACTIVE)
  		indirect_setbit(socket, I365_ADDRWIN, I365_ENA_IO(map));
  
  	return 0;
  }
  
  static int pd6729_set_mem_map(struct pcmcia_socket *sock,
  			      struct pccard_mem_map *mem)
  {
  	struct pd6729_socket *socket
  			 = container_of(sock, struct pd6729_socket, socket);
  	unsigned short base, i;
  	unsigned char map;
  
  	map = mem->map;
  	if (map > 4) {
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
482
483
  		dev_warn(&sock->dev, "invalid map requested
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
486
487
  		return -EINVAL;
  	}
  
  	if ((mem->res->start > mem->res->end) || (mem->speed > 1000)) {
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
488
489
  		dev_warn(&sock->dev, "invalid invalid address / speed
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
  		return -EINVAL;
  	}
  
  	/* Turn off the window before changing anything */
  	if (indirect_read(socket, I365_ADDRWIN) & I365_ENA_MEM(map))
  		indirect_resetbit(socket, I365_ADDRWIN, I365_ENA_MEM(map));
  
  	/* write the start address */
  	base = I365_MEM(map);
  	i = (mem->res->start >> 12) & 0x0fff;
  	if (mem->flags & MAP_16BIT)
  		i |= I365_MEM_16BIT;
  	if (mem->flags & MAP_0WS)
  		i |= I365_MEM_0WS;
  	indirect_write16(socket, base + I365_W_START, i);
  
  	/* write the stop address */
5cbb2b941   Komuro   pd6729: Coding St...
507
  	i = (mem->res->end >> 12) & 0x0fff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
  	switch (to_cycles(mem->speed)) {
  	case 0:
  		break;
  	case 1:
  		i |= I365_MEM_WS0;
  		break;
  	case 2:
  		i |= I365_MEM_WS1;
  		break;
  	default:
  		i |= I365_MEM_WS1 | I365_MEM_WS0;
  		break;
  	}
  
  	indirect_write16(socket, base + I365_W_STOP, i);
  
  	/* Take care of high byte */
  	indirect_write(socket, PD67_EXT_INDEX, PD67_MEM_PAGE(map));
  	indirect_write(socket, PD67_EXT_DATA, mem->res->start >> 24);
  
  	/* card start */
  
  	i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff;
  	if (mem->flags & MAP_WRPROT)
  		i |= I365_MEM_WRPROT;
  	if (mem->flags & MAP_ATTRIB) {
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
534
535
536
  		/* dev_dbg(&sock->dev, "requesting attribute memory for "
  		   "socket %i
  ", socket->number);*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
  		i |= I365_MEM_REG;
  	} else {
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
539
540
541
  		/* dev_dbg(&sock->dev, "requesting normal memory for "
  		   "socket %i
  ", socket->number);*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
  	}
  	indirect_write16(socket, base + I365_W_OFF, i);
  
  	/* Enable the window if necessary */
  	if (mem->flags & MAP_ACTIVE)
  		indirect_setbit(socket, I365_ADDRWIN, I365_ENA_MEM(map));
  
  	return 0;
  }
  
  static int pd6729_init(struct pcmcia_socket *sock)
  {
  	int i;
  	struct resource res = { .end = 0x0fff };
  	pccard_io_map io = { 0, 0, 0, 0, 1 };
  	pccard_mem_map mem = { .res = &res, };
  
  	pd6729_set_socket(sock, &dead_socket);
  	for (i = 0; i < 2; i++) {
  		io.map = i;
  		pd6729_set_io_map(sock, &io);
  	}
  	for (i = 0; i < 5; i++) {
  		mem.map = i;
  		pd6729_set_mem_map(sock, &mem);
  	}
  
  	return 0;
  }
  
  
  /* the pccard structure and its functions */
  static struct pccard_operations pd6729_operations = {
5cbb2b941   Komuro   pd6729: Coding St...
575
  	.init			= pd6729_init,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
  	.get_status		= pd6729_get_status,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
578
579
580
  	.set_socket		= pd6729_set_socket,
  	.set_io_map		= pd6729_set_io_map,
  	.set_mem_map		= pd6729_set_mem_map,
  };
7d12e780e   David Howells   IRQ: Maintain reg...
581
  static irqreturn_t pd6729_test(int irq, void *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
  {
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
583
584
  	pr_devel("-> hit on irq %d
  ", irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
  	return IRQ_HANDLED;
  }
3e022d0c7   Komuro   [PATCH] pcmcia: a...
587
  static int pd6729_check_irq(int irq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
  {
5cbb2b941   Komuro   pd6729: Coding St...
589
590
591
592
593
594
  	int ret;
  
  	ret = request_irq(irq, pd6729_test, IRQF_PROBE_SHARED, "x",
  			  pd6729_test);
  	if (ret)
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
595
596
597
  	free_irq(irq, pd6729_test);
  	return 0;
  }
9781b8b05   Andrew Morton   [PATCH] pd6729 se...
598
  static u_int __devinit pd6729_isa_scan(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
601
602
603
604
  {
  	u_int mask0, mask = 0;
  	int i;
  
  	if (irq_mode == 1) {
  		printk(KERN_INFO "pd6729: PCI card interrupts, "
5cbb2b941   Komuro   pd6729: Coding St...
605
606
  		       "PCI status changes
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
608
  		return 0;
  	}
f9097dce5   Komuro   pcmcia: remove ir...
609
  	mask0 = PD67_MASK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
611
612
  
  	/* just find interrupts that aren't in use */
  	for (i = 0; i < 16; i++)
3e022d0c7   Komuro   [PATCH] pcmcia: a...
613
  		if ((mask0 & (1 << i)) && (pd6729_check_irq(i) == 0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
615
616
617
618
619
  			mask |= (1 << i);
  
  	printk(KERN_INFO "pd6729: ISA irqs = ");
  	for (i = 0; i < 16; i++)
  		if (mask & (1<<i))
  			printk("%s%d", ((mask & ((1<<i)-1)) ? "," : ""), i);
5cbb2b941   Komuro   pd6729: Coding St...
620
621
622
623
624
  	if (mask == 0)
  		printk("none!");
  	else
  		printk("  polling status changes.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
627
628
629
630
631
632
633
634
635
  
  	return mask;
  }
  
  static int __devinit pd6729_pci_probe(struct pci_dev *dev,
  				      const struct pci_device_id *id)
  {
  	int i, j, ret;
  	u_int mask;
  	char configbyte;
  	struct pd6729_socket *socket;
8084b372a   Dominik Brodowski   [PATCH] pcmcia: k...
636
  	socket = kzalloc(sizeof(struct pd6729_socket) * MAX_SOCKETS,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
  			 GFP_KERNEL);
5cbb2b941   Komuro   pd6729: Coding St...
638
639
640
  	if (!socket) {
  		dev_warn(&dev->dev, "failed to kzalloc socket.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
  		return -ENOMEM;
5cbb2b941   Komuro   pd6729: Coding St...
642
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643

5cbb2b941   Komuro   pd6729: Coding St...
644
645
646
647
  	ret = pci_enable_device(dev);
  	if (ret) {
  		dev_warn(&dev->dev, "failed to enable pci_device.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
  		goto err_out_free_mem;
5cbb2b941   Komuro   pd6729: Coding St...
649
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650

94efb7232   Komuro   pcmcia: do not lo...
651
  	if (!pci_resource_start(dev, 0)) {
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
652
653
654
  		dev_warn(&dev->dev, "refusing to load the driver as the "
  			"io_base is NULL.
  ");
40d24ff9b   Rahul Ruikar   pcmcia: pd6729: F...
655
  		goto err_out_disable;
94efb7232   Komuro   pcmcia: do not lo...
656
  	}
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
657
658
659
  	dev_info(&dev->dev, "Cirrus PD6729 PCI to PCMCIA Bridge at 0x%llx "
  		"on irq %d
  ",
490ab72af   Greg Kroah-Hartman   [PATCH] 64bit res...
660
  		(unsigned long long)pci_resource_start(dev, 0), dev->irq);
5cbb2b941   Komuro   pd6729: Coding St...
661
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
663
664
665
666
  	 * Since we have no memory BARs some firmware may not
  	 * have had PCI_COMMAND_MEMORY enabled, yet the device needs it.
  	 */
  	pci_read_config_byte(dev, PCI_COMMAND, &configbyte);
  	if (!(configbyte & PCI_COMMAND_MEMORY)) {
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
667
668
  		dev_dbg(&dev->dev, "pd6729: Enabling PCI_COMMAND_MEMORY.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
670
671
672
673
674
  		configbyte |= PCI_COMMAND_MEMORY;
  		pci_write_config_byte(dev, PCI_COMMAND, configbyte);
  	}
  
  	ret = pci_request_regions(dev, "pd6729");
  	if (ret) {
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
675
676
  		dev_warn(&dev->dev, "pci request region failed.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
678
679
680
681
682
683
684
  		goto err_out_disable;
  	}
  
  	if (dev->irq == NO_IRQ)
  		irq_mode = 0;	/* fall back to ISA interrupt mode */
  
  	mask = pd6729_isa_scan();
  	if (irq_mode == 0 && mask == 0) {
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
685
686
  		dev_warn(&dev->dev, "no ISA interrupt is available.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
688
689
690
691
  		goto err_out_free_res;
  	}
  
  	for (i = 0; i < MAX_SOCKETS; i++) {
  		socket[i].io_base = pci_resource_start(dev, 0);
c35e66a42   Dominik Brodowski   [PATCH] pcmcia: e...
692
  		socket[i].socket.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
694
695
  		socket[i].socket.map_size = 0x1000;
  		socket[i].socket.irq_mask = mask;
  		socket[i].socket.pci_irq  = dev->irq;
7a96e87d6   Dominik Brodowski   pcmcia: pd6729, i...
696
  		socket[i].socket.cb_dev = dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
698
699
700
701
702
  		socket[i].socket.owner = THIS_MODULE;
  
  		socket[i].number = i;
  
  		socket[i].socket.ops = &pd6729_operations;
  		socket[i].socket.resource_ops = &pccard_nonstatic_ops;
873733188   Greg Kroah-Hartman   Driver core: conv...
703
  		socket[i].socket.dev.parent = &dev->dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
705
706
707
708
709
  		socket[i].socket.driver_data = &socket[i];
  	}
  
  	pci_set_drvdata(dev, socket);
  	if (irq_mode == 1) {
  		/* Register the interrupt handler */
5cbb2b941   Komuro   pd6729: Coding St...
710
711
712
  		ret = request_irq(dev->irq, pd6729_interrupt, IRQF_SHARED,
  				  "pd6729", socket);
  		if (ret) {
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
713
714
715
  			dev_err(&dev->dev, "Failed to register irq %d
  ",
  				dev->irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
716
717
718
719
720
721
722
723
724
725
726
727
728
729
  			goto err_out_free_res;
  		}
  	} else {
  		/* poll Card status change */
  		init_timer(&socket->poll_timer);
  		socket->poll_timer.function = pd6729_interrupt_wrapper;
  		socket->poll_timer.data = (unsigned long)socket;
  		socket->poll_timer.expires = jiffies + HZ;
  		add_timer(&socket->poll_timer);
  	}
  
  	for (i = 0; i < MAX_SOCKETS; i++) {
  		ret = pcmcia_register_socket(&socket[i].socket);
  		if (ret) {
a7149f9a2   Dominik Brodowski   pcmcia: use dev_d...
730
731
  			dev_warn(&dev->dev, "pcmcia_register_socket failed.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
732
733
734
735
736
737
738
  			for (j = 0; j < i ; j++)
  				pcmcia_unregister_socket(&socket[j].socket);
  			goto err_out_free_res2;
  		}
  	}
  
  	return 0;
006839f12   Komuro   pd6729: Coding St...
739
  err_out_free_res2:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
742
743
  	if (irq_mode == 1)
  		free_irq(dev->irq, socket);
  	else
  		del_timer_sync(&socket->poll_timer);
006839f12   Komuro   pd6729: Coding St...
744
  err_out_free_res:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
  	pci_release_regions(dev);
006839f12   Komuro   pd6729: Coding St...
746
  err_out_disable:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
  	pci_disable_device(dev);
006839f12   Komuro   pd6729: Coding St...
748
  err_out_free_mem:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
  	kfree(socket);
  	return ret;
  }
  
  static void __devexit pd6729_pci_remove(struct pci_dev *dev)
  {
  	int i;
  	struct pd6729_socket *socket = pci_get_drvdata(dev);
  
  	for (i = 0; i < MAX_SOCKETS; i++) {
  		/* Turn off all interrupt sources */
  		indirect_write(&socket[i], I365_CSCINT, 0);
  		indirect_write(&socket[i], I365_INTCTL, 0);
  
  		pcmcia_unregister_socket(&socket[i].socket);
  	}
  
  	if (irq_mode == 1)
  		free_irq(dev->irq, socket);
  	else
  		del_timer_sync(&socket->poll_timer);
  	pci_release_regions(dev);
  	pci_disable_device(dev);
  
  	kfree(socket);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
776
777
778
779
780
781
782
783
784
  static struct pci_device_id pd6729_pci_ids[] = {
  	{
  		.vendor		= PCI_VENDOR_ID_CIRRUS,
  		.device		= PCI_DEVICE_ID_CIRRUS_6729,
  		.subvendor	= PCI_ANY_ID,
  		.subdevice	= PCI_ANY_ID,
  	},
  	{ }
  };
  MODULE_DEVICE_TABLE(pci, pd6729_pci_ids);
ba66ddfa6   Sam Ravnborg   pcmcia: silence s...
785
  static struct pci_driver pd6729_pci_driver = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
788
789
  	.name		= "pd6729",
  	.id_table	= pd6729_pci_ids,
  	.probe		= pd6729_pci_probe,
  	.remove		= __devexit_p(pd6729_pci_remove),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
791
792
793
  };
  
  static int pd6729_module_init(void)
  {
ba66ddfa6   Sam Ravnborg   pcmcia: silence s...
794
  	return pci_register_driver(&pd6729_pci_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
796
797
798
  }
  
  static void pd6729_module_exit(void)
  {
ba66ddfa6   Sam Ravnborg   pcmcia: silence s...
799
  	pci_unregister_driver(&pd6729_pci_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
801
802
803
  }
  
  module_init(pd6729_module_init);
  module_exit(pd6729_module_exit);