Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "u.h"
2
#include "../port/lib.h"
3
#include "mem.h"
4
#include "dat.h"
5
#include "fns.h"
6
#include "../port/error.h"
7
#include "io.h"
8
 
9
/*
10
 *  Intel 82365SL PCIC controller and compatibles.
11
 */
12
enum
13
{
14
	/*
15
	 *  registers indices
16
	 */
17
	Rid=		0x0,		/* identification and revision */
18
	Ris=		0x1,		/* interface status */
19
	Rpc=	 	0x2,		/* power control */
20
	 Foutena=	 (1<<7),	/*  output enable */
21
	 Fautopower=	 (1<<5),	/*  automatic power switching */
22
	 Fcardena=	 (1<<4),	/*  PC card enable */
23
	Rigc= 		0x3,		/* interrupt and general control */
24
	 Fiocard=	 (1<<5),	/*  I/O card (vs memory) */
25
	 Fnotreset=	 (1<<6),	/*  reset if not set */	
26
	 FSMIena=	 (1<<4),	/*  enable change interrupt on SMI */ 
27
	Rcsc= 		0x4,		/* card status change */
28
	Rcscic= 	0x5,		/* card status change interrupt config */
29
	 Fchangeena=	 (1<<3),	/*  card changed */
30
	 Fbwarnena=	 (1<<1),	/*  card battery warning */
31
	 Fbdeadena=	 (1<<0),	/*  card battery dead */
32
	Rwe= 		0x6,		/* address window enable */
33
	 Fmem16=	 (1<<5),	/*  use A23-A12 to decode address */
34
	Rio= 		0x7,		/* I/O control */
35
	 Fwidth16=	 (1<<0),	/*  16 bit data width */
36
	 Fiocs16=	 (1<<1),	/*  IOCS16 determines data width */
37
	 Fzerows=	 (1<<2),	/*  zero wait state */
38
	 Ftiming=	 (1<<3),	/*  timing register to use */
39
	Riobtm0lo=	0x8,		/* I/O address 0 start low byte */
40
	Riobtm0hi=	0x9,		/* I/O address 0 start high byte */
41
	Riotop0lo=	0xa,		/* I/O address 0 stop low byte */
42
	Riotop0hi=	0xb,		/* I/O address 0 stop high byte */
43
	Riobtm1lo=	0xc,		/* I/O address 1 start low byte */
44
	Riobtm1hi=	0xd,		/* I/O address 1 start high byte */
45
	Riotop1lo=	0xe,		/* I/O address 1 stop low byte */
46
	Riotop1hi=	0xf,		/* I/O address 1 stop high byte */
47
	Rmap=		0x10,		/* map 0 */
48
 
49
	/*
50
	 *  CL-PD67xx extension registers
51
	 */
52
	Rmisc1=		0x16,		/* misc control 1 */
53
	 F5Vdetect=	 (1<<0),
54
	 Fvcc3V=	 (1<<1),
55
	 Fpmint=	 (1<<2),
56
	 Fpsirq=	 (1<<3),
57
	 Fspeaker=	 (1<<4),
58
	 Finpack=	 (1<<7),
59
	Rfifo=		0x17,		/* fifo control */
60
	 Fflush=	 (1<<7),	/*  flush fifo */
61
	Rmisc2=		0x1E,		/* misc control 2 */
62
	 Flowpow=	 (1<<1),	/*  low power mode */
63
	Rchipinfo=	0x1F,		/* chip information */
64
	Ratactl=	0x26,		/* ATA control */
65
 
66
	/*
67
	 *  offsets into the system memory address maps
68
	 */
69
	Mbtmlo=		0x0,		/* System mem addr mapping start low byte */
70
	Mbtmhi=		0x1,		/* System mem addr mapping start high byte */
71
	 F16bit=	 (1<<7),	/*  16-bit wide data path */
72
	Mtoplo=		0x2,		/* System mem addr mapping stop low byte */
73
	Mtophi=		0x3,		/* System mem addr mapping stop high byte */
74
	 Ftimer1=	 (1<<6),	/*  timer set 1 */
75
	Mofflo=		0x4,		/* Card memory offset address low byte */
76
	Moffhi=		0x5,		/* Card memory offset address high byte */
77
	 Fregactive=	 (1<<6),	/*  attribute memory */
78
 
79
	/*
80
	 *  configuration registers - they start at an offset in attribute
81
	 *  memory found in the CIS.
82
	 */
83
	Rconfig=	0,
84
	 Creset=	 (1<<7),	/*  reset device */
85
	 Clevel=	 (1<<6),	/*  level sensitive interrupt line */
86
	 Cirq=		 (1<<2),	/*  IRQ enable */
87
	 Cdecode=	 (1<<1),	/*  address decode */
88
	 Cfunc=		 (1<<0),	/*  function enable */
89
	Riobase0=	5,
90
	Riobase1=	6,
91
	Riosize=	9,
92
};
93
 
94
#define MAP(x,o)	(Rmap + (x)*0x8 + o)
95
 
96
typedef struct I82365	I82365;
97
 
98
/* a controller */
99
enum
100
{
101
	Ti82365,
102
	Tpd6710,
103
	Tpd6720,
104
	Tvg46x,
105
};
106
struct I82365
107
{
108
	int	type;
109
	int	dev;
110
	int	nslot;
111
	int	xreg;		/* index register address */
112
	int	dreg;		/* data register address */
113
	int	irq;
114
};
115
static I82365 *controller[4];
116
static int ncontroller;
117
static PCMslot	*slot;
118
static PCMslot	*lastslot;
119
static nslot;
120
 
121
static void	i82365intr(Ureg*, void*);
122
static int	pcmio(int, ISAConf*);
123
static long	pcmread(int, int, void*, long, vlong);
124
static long	pcmwrite(int, int, void*, long, vlong);
125
 
126
static void i82365dump(PCMslot*);
127
 
128
/*
129
 *  reading and writing card registers
130
 */
131
static uchar
132
rdreg(PCMslot *pp, int index)
133
{
134
	outb(((I82365*)pp->cp)->xreg, pp->base + index);
135
	return inb(((I82365*)pp->cp)->dreg);
136
}
137
static void
138
wrreg(PCMslot *pp, int index, uchar val)
139
{
140
	outb(((I82365*)pp->cp)->xreg, pp->base + index);
141
	outb(((I82365*)pp->cp)->dreg, val);
142
}
143
 
144
/*
145
 *  get info about card
146
 */
147
static void
148
slotinfo(PCMslot *pp)
149
{
150
	uchar isr;
151
 
152
	isr = rdreg(pp, Ris);
153
	pp->occupied = (isr & (3<<2)) == (3<<2);
154
	pp->powered = isr & (1<<6);
155
	pp->battery = (isr & 3) == 3;
156
	pp->wrprot = isr & (1<<4);
157
	pp->busy = isr & (1<<5);
158
	pp->msec = TK2MS(MACHP(0)->ticks);
159
}
160
 
161
static int
162
vcode(int volt)
163
{
164
	switch(volt){
165
	case 5:
166
		return 1;
167
	case 12:
168
		return 2;
169
	default:
170
		return 0;
171
	}
172
}
173
 
174
/*
175
 *  enable the slot card
176
 */
177
static void
178
slotena(PCMslot *pp)
179
{
180
	if(pp->enabled)
181
		return;
182
 
183
	/* power up and unreset, wait's are empirical (???) */
184
	wrreg(pp, Rpc, Fautopower|Foutena|Fcardena);
185
	delay(300);
186
	wrreg(pp, Rigc, 0);
187
	delay(100);
188
	wrreg(pp, Rigc, Fnotreset);
189
	delay(500);
190
 
191
	/* get configuration */
192
	slotinfo(pp);
193
	if(pp->occupied){
194
		pcmcisread(pp);
195
		pp->enabled = 1;
196
	} else
197
		wrreg(pp, Rpc, Fautopower);
198
}
199
 
200
/*
201
 *  disable the slot card
202
 */
203
static void
204
slotdis(PCMslot *pp)
205
{
206
	wrreg(pp, Rpc, 0);	/* turn off card power */
207
	wrreg(pp, Rwe, 0);	/* no windows */
208
	pp->enabled = 0;
209
}
210
 
211
/*
212
 *  status change interrupt
213
 */
214
static void
215
i82365intr(Ureg *, void *)
216
{
217
	uchar csc, was;
218
	PCMslot *pp;
219
 
220
	if(slot == 0)
221
		return;
222
 
223
	for(pp = slot; pp < lastslot; pp++){
224
		csc = rdreg(pp, Rcsc);
225
		was = pp->occupied;
226
		slotinfo(pp);
227
		if(csc & (1<<3) && was != pp->occupied){
228
			if(!pp->occupied)
229
				slotdis(pp);
230
		}
231
	}
232
}
233
 
234
enum
235
{
236
	Mshift=	12,
237
	Mgran=	(1<<Mshift),	/* granularity of maps */
238
	Mmask=	~(Mgran-1),	/* mask for address bits important to the chip */
239
};
240
 
241
/*
242
 *  get a map for pc card region, return corrected len
243
 */
244
PCMmap*
245
pcmmap(int slotno, ulong offset, int len, int attr)
246
{
247
	PCMslot *pp;
248
	uchar we, bit;
249
	PCMmap *m, *nm;
250
	int i;
251
	ulong e;
252
 
253
	pp = slot + slotno;
254
	lock(&pp->mlock);
255
 
256
	/* convert offset to granularity */
257
	if(len <= 0)
258
		len = 1;
259
	e = ROUND(offset+len, Mgran);
260
	offset &= Mmask;
261
	len = e - offset;
262
 
263
	/* look for a map that covers the right area */
264
	we = rdreg(pp, Rwe);
265
	bit = 1;
266
	nm = 0;
267
	for(m = pp->mmap; m < &pp->mmap[nelem(pp->mmap)]; m++){
268
		if((we & bit))
269
		if(m->attr == attr)
270
		if(offset >= m->ca && e <= m->cea){
271
 
272
			m->ref++;
273
			unlock(&pp->mlock);
274
			return m;
275
		}
276
		bit <<= 1;
277
		if(nm == 0 && m->ref == 0)
278
			nm = m;
279
	}
280
	m = nm;
281
	if(m == 0){
282
		unlock(&pp->mlock);
283
		return 0;
284
	}
285
 
286
	/* if isa space isn't big enough, free it and get more */
287
	if(m->len < len){
288
		if(m->isa){
289
			umbfree(m->isa, m->len);
290
			m->len = 0;
291
		}
292
		m->isa = PADDR(umbmalloc(0, len, Mgran));
293
		if(m->isa == 0){
294
			print("pcmmap: out of isa space\n");
295
			unlock(&pp->mlock);
296
			return 0;
297
		}
298
		m->len = len;
299
	}
300
 
301
	/* set up new map */
302
	m->ca = offset;
303
	m->cea = m->ca + m->len;
304
	m->attr = attr;
305
	i = m-pp->mmap;
306
	bit = 1<<i;
307
	wrreg(pp, Rwe, we & ~bit);		/* disable map before changing it */
308
	wrreg(pp, MAP(i, Mbtmlo), m->isa>>Mshift);
309
	wrreg(pp, MAP(i, Mbtmhi), (m->isa>>(Mshift+8)) | F16bit);
310
	wrreg(pp, MAP(i, Mtoplo), (m->isa+m->len-1)>>Mshift);
311
	wrreg(pp, MAP(i, Mtophi), ((m->isa+m->len-1)>>(Mshift+8)));
312
	offset -= m->isa;
313
	offset &= (1<<25)-1;
314
	offset >>= Mshift;
315
	wrreg(pp, MAP(i, Mofflo), offset);
316
	wrreg(pp, MAP(i, Moffhi), (offset>>8) | (attr ? Fregactive : 0));
317
	wrreg(pp, Rwe, we | bit);		/* enable map */
318
	m->ref = 1;
319
 
320
	unlock(&pp->mlock);
321
	return m;
322
}
323
 
324
void
325
pcmunmap(int slotno, PCMmap* m)
326
{
327
	PCMslot *pp;
328
 
329
	pp = slot + slotno;
330
	lock(&pp->mlock);
331
	m->ref--;
332
	unlock(&pp->mlock);
333
}
334
 
335
static void
336
increfp(PCMslot *pp)
337
{
338
	lock(pp);
339
	if(pp->ref++ == 0)
340
		slotena(pp);
341
	unlock(pp);
342
}
343
 
344
static void
345
decrefp(PCMslot *pp)
346
{
347
	lock(pp);
348
	if(pp->ref-- == 1)
349
		slotdis(pp);
350
	unlock(pp);
351
}
352
 
353
/*
354
 *  look for a card whose version contains 'idstr'
355
 */
356
static int
357
pcmcia_pcmspecial(char *idstr, ISAConf *isa)
358
{
359
	PCMslot *pp;
360
	extern char *strstr(char*, char*);
361
	int enabled;
362
 
363
	for(pp = slot; pp < lastslot; pp++){
364
		if(pp->special)
365
			continue;	/* already taken */
366
 
367
		/*
368
		 *  make sure we don't power on cards when we already know what's
369
		 *  in them.  We'll reread every two minutes if necessary
370
		 */
371
		enabled = 0;
372
		if (pp->msec == ~0 || TK2MS(MACHP(0)->ticks) - pp->msec > 120000){
373
			increfp(pp);
374
			enabled++;
375
		}
376
 
377
		if(pp->occupied) {
378
			if(strstr(pp->verstr, idstr)){
379
				if (!enabled){
380
					enabled = 1;
381
					increfp(pp);
382
				}
383
				if(isa == 0 || pcmio(pp->slotno, isa) == 0){
384
					pp->special = 1;
385
					return pp->slotno;
386
				}
387
			}
388
		} else
389
			pp->special = 1;
390
		if (enabled)
391
			decrefp(pp);
392
	}
393
	return -1;
394
}
395
 
396
static void
397
pcmcia_pcmspecialclose(int slotno)
398
{
399
	PCMslot *pp;
400
 
401
	if(slotno >= nslot)
402
		panic("pcmspecialclose");
403
	pp = slot + slotno;
404
	pp->special = 0;
405
	decrefp(pp);
406
}
407
 
408
enum
409
{
410
	Qdir,
411
	Qmem,
412
	Qattr,
413
	Qctl,
414
 
415
	Nents = 3,
416
};
417
 
418
#define SLOTNO(c)	((ulong)((c->qid.path>>8)&0xff))
419
#define TYPE(c)	((ulong)(c->qid.path&0xff))
420
#define QID(s,t)	(((s)<<8)|(t))
421
 
422
static int
423
pcmgen(Chan *c, char*, Dirtab *, int , int i, Dir *dp)
424
{
425
	int slotno;
426
	Qid qid;
427
	long len;
428
	PCMslot *pp;
429
 
430
	if(i == DEVDOTDOT){
431
		mkqid(&qid, Qdir, 0, QTDIR);
432
		devdir(c, qid, "#y", 0, eve, 0555, dp);
433
		return 1;
434
	}
435
 
436
	if(i >= Nents*nslot)
437
		return -1;
438
	slotno = i/Nents;
439
	pp = slot + slotno;
440
	len = 0;
441
	switch(i%Nents){
442
	case 0:
443
		qid.path = QID(slotno, Qmem);
444
		snprint(up->genbuf, sizeof up->genbuf, "pcm%dmem", slotno);
445
		len = pp->memlen;
446
		break;
447
	case 1:
448
		qid.path = QID(slotno, Qattr);
449
		snprint(up->genbuf, sizeof up->genbuf, "pcm%dattr", slotno);
450
		len = pp->memlen;
451
		break;
452
	case 2:
453
		qid.path = QID(slotno, Qctl);
454
		snprint(up->genbuf, sizeof up->genbuf, "pcm%dctl", slotno);
455
		break;
456
	}
457
	qid.vers = 0;
458
	qid.type = QTFILE;
459
	devdir(c, qid, up->genbuf, len, eve, 0660, dp);
460
	return 1;
461
}
462
 
463
static char *chipname[] =
464
{
465
[Ti82365]	"Intel 82365SL",
466
[Tpd6710]	"Cirrus Logic CL-PD6710",
467
[Tpd6720]	"Cirrus Logic CL-PD6720",
468
[Tvg46x]	"Vadem VG-46x",
469
};
470
 
471
static I82365*
472
i82365probe(int x, int d, int dev)
473
{
474
	uchar c, id;
475
	I82365 *cp;
476
	ISAConf isa;
477
	int i, nslot;
478
 
479
	outb(x, Rid + (dev<<7));
480
	id = inb(d);
481
	if((id & 0xf0) != 0x80)
482
		return 0;		/* not a memory & I/O card */
483
	if((id & 0x0f) == 0x00)
484
		return 0;		/* no revision number, not possible */
485
 
486
	cp = xalloc(sizeof(I82365));
487
	cp->xreg = x;
488
	cp->dreg = d;
489
	cp->dev = dev;
490
	cp->type = Ti82365;
491
	cp->nslot = 2;
492
 
493
	switch(id){
494
	case 0x82:
495
	case 0x83:
496
	case 0x84:
497
		/* could be a cirrus */
498
		outb(x, Rchipinfo + (dev<<7));
499
		outb(d, 0);
500
		c = inb(d);
501
		if((c & 0xc0) != 0xc0)
502
			break;
503
		c = inb(d);
504
		if((c & 0xc0) != 0x00)
505
			break;
506
		if(c & 0x20){
507
			cp->type = Tpd6720;
508
		} else {
509
			cp->type = Tpd6710;
510
			cp->nslot = 1;
511
		}
512
 
513
		/* low power mode */
514
		outb(x, Rmisc2 + (dev<<7));
515
		c = inb(d);
516
		outb(d, c & ~Flowpow);
517
		break;
518
	}
519
 
520
	/* if it's not a Cirrus, it could be a Vadem... */
521
	if(cp->type == Ti82365){
522
		/* unlock the Vadem extended regs */
523
		outb(x, 0x0E + (dev<<7));
524
		outb(x, 0x37 + (dev<<7));
525
 
526
		/* make the id register show the Vadem id */
527
		outb(x, 0x3A + (dev<<7));
528
		c = inb(d);
529
		outb(d, c|0xC0);
530
		outb(x, Rid + (dev<<7));
531
		c = inb(d);
532
		if(c & 0x08)
533
			cp->type = Tvg46x;
534
 
535
		/* go back to Intel compatible id */
536
		outb(x, 0x3A + (dev<<7));
537
		c = inb(d);
538
		outb(d, c & ~0xC0);
539
	}
540
 
541
	memset(&isa, 0, sizeof(ISAConf));
542
	if(isaconfig("pcmcia", ncontroller, &isa) && isa.irq)
543
		cp->irq = isa.irq;
544
	else
545
		cp->irq = IrqPCMCIA;
546
 
547
	for(i = 0; i < isa.nopt; i++){
548
		if(cistrncmp(isa.opt[i], "nslot=", 6))
549
			continue;
550
		nslot = strtol(&isa.opt[i][6], nil, 0);
551
		if(nslot > 0 && nslot <= 2)
552
			cp->nslot = nslot;
553
	}
554
 
555
	controller[ncontroller++] = cp;
556
	return cp;
557
}
558
 
559
static void
560
i82365dump(PCMslot *pp)
561
{
562
	int i;
563
 
564
	for(i = 0; i < 0x40; i++){
565
		if((i&0x0F) == 0)
566
			print("\n%2.2uX:	", i);
567
		print("%2.2uX ", rdreg(pp, i));
568
		if(((i+1) & 0x0F) == 0x08)
569
			print(" - ");
570
	}
571
	print("\n");
572
}
573
 
574
/*
575
 *  set up for slot cards
576
 */
577
void
578
devi82365link(void)
579
{
580
	static int already;
581
	int i, j;
582
	I82365 *cp;
583
	PCMslot *pp;
584
	char buf[32], *p;
585
 
586
	if(already)
587
		return;
588
	already = 1;
589
 
590
	if((p=getconf("pcmcia0")) && strncmp(p, "disabled", 8)==0)
591
		return;
592
 
593
	if(_pcmspecial)
594
		return;
595
 
596
	/* look for controllers if the ports aren't already taken */
597
	if(ioalloc(0x3E0, 2, 0, "i82365.0") >= 0){
598
		i82365probe(0x3E0, 0x3E1, 0);
599
		i82365probe(0x3E0, 0x3E1, 1);
600
		if(ncontroller == 0)
601
			iofree(0x3E0);
602
	}
603
	if(ioalloc(0x3E2, 2, 0, "i82365.1") >= 0){
604
		i = ncontroller;
605
		i82365probe(0x3E2, 0x3E3, 0);
606
		i82365probe(0x3E2, 0x3E3, 1);
607
		if(ncontroller == i)
608
			iofree(0x3E2);
609
	}
610
 
611
	if(ncontroller == 0)
612
		return;
613
 
614
	_pcmspecial = pcmcia_pcmspecial;
615
	_pcmspecialclose = pcmcia_pcmspecialclose;
616
 
617
	for(i = 0; i < ncontroller; i++)
618
		nslot += controller[i]->nslot;
619
	slot = xalloc(nslot * sizeof(PCMslot));
620
 
621
	lastslot = slot;
622
	for(i = 0; i < ncontroller; i++){
623
		cp = controller[i];
624
		print("#y%d: %d slot %s: port 0x%uX irq %d\n",
625
			i, cp->nslot, chipname[cp->type], cp->xreg, cp->irq);
626
		for(j = 0; j < cp->nslot; j++){
627
			pp = lastslot++;
628
			pp->slotno = pp - slot;
629
			pp->memlen = 64*MB;
630
			pp->base = (cp->dev<<7) | (j<<6);
631
			pp->cp = cp;
632
			pp->msec = ~0;
633
			pp->verstr[0] = 0;
634
			slotdis(pp);
635
 
636
			/* interrupt on status change */
637
			wrreg(pp, Rcscic, (cp->irq<<4) | Fchangeena);
638
			rdreg(pp, Rcsc);
639
		}
640
 
641
		/* for card management interrupts */
642
		snprint(buf, sizeof buf, "i82365.%d", i);
643
		intrenable(cp->irq, i82365intr, 0, BUSUNKNOWN, buf);
644
	}
645
}
646
 
647
static Chan*
648
i82365attach(char *spec)
649
{
650
	return devattach('y', spec);
651
}
652
 
653
static Walkqid*
654
i82365walk(Chan *c, Chan *nc, char **name, int nname)
655
{
656
	return devwalk(c, nc, name, nname, 0, 0, pcmgen);
657
}
658
 
659
static int
660
i82365stat(Chan *c, uchar *db, int n)
661
{
662
	return devstat(c, db, n, 0, 0, pcmgen);
663
}
664
 
665
static Chan*
666
i82365open(Chan *c, int omode)
667
{
668
	if(c->qid.type & QTDIR){
669
		if(omode != OREAD)
670
			error(Eperm);
671
	} else
672
		increfp(slot + SLOTNO(c));
673
	c->mode = openmode(omode);
674
	c->flag |= COPEN;
675
	c->offset = 0;
676
	return c;
677
}
678
 
679
static void
680
i82365close(Chan *c)
681
{
682
	if(c->flag & COPEN)
683
		if((c->qid.type & QTDIR) == 0)
684
			decrefp(slot+SLOTNO(c));
685
}
686
 
687
/* a memmove using only bytes */
688
static void
689
memmoveb(uchar *to, uchar *from, int n)
690
{
691
	while(n-- > 0)
692
		*to++ = *from++;
693
}
694
 
695
/* a memmove using only shorts & bytes */
696
static void
697
memmoves(uchar *to, uchar *from, int n)
698
{
699
	ushort *t, *f;
700
 
701
	if((((ulong)to) & 1) || (((ulong)from) & 1) || (n & 1)){
702
		while(n-- > 0)
703
			*to++ = *from++;
704
	} else {
705
		n = n/2;
706
		t = (ushort*)to;
707
		f = (ushort*)from;
708
		while(n-- > 0)
709
			*t++ = *f++;
710
	}
711
}
712
 
713
static long
714
pcmread(int slotno, int attr, void *a, long n, vlong off)
715
{
716
	int i, len;
717
	PCMmap *m;
718
	uchar *ac;
719
	PCMslot *pp;
720
	ulong offset = off;
721
 
722
	pp = slot + slotno;
723
	if(pp->memlen < offset)
724
		return 0;
725
	if(pp->memlen < offset + n)
726
		n = pp->memlen - offset;
727
 
728
	m = 0;
729
	if(waserror()){
730
		if(m)
731
			pcmunmap(pp->slotno, m);
732
		nexterror();
733
	}
734
 
735
	ac = a;
736
	for(len = n; len > 0; len -= i){
737
		m = pcmmap(pp->slotno, offset, 0, attr);
738
		if(m == 0)
739
			error("cannot map PCMCIA card");
740
		if(offset + len > m->cea)
741
			i = m->cea - offset;
742
		else
743
			i = len;
744
		memmoveb(ac, KADDR(m->isa + offset - m->ca), i);
745
		pcmunmap(pp->slotno, m);
746
		offset += i;
747
		ac += i;
748
	}
749
 
750
	poperror();
751
	return n;
752
}
753
 
754
static long
755
i82365read(Chan *c, void *a, long n, vlong off)
756
{
757
	char *p, *buf, *e;
758
	PCMslot *pp;
759
	ulong offset = off;
760
 
761
	switch(TYPE(c)){
762
	case Qdir:
763
		return devdirread(c, a, n, 0, 0, pcmgen);
764
	case Qmem:
765
	case Qattr:
766
		return pcmread(SLOTNO(c), TYPE(c) == Qattr, a, n, off);
767
	case Qctl:
768
		buf = p = malloc(READSTR);
769
		if(p == nil)
770
			error(Enomem);
771
		e = p + READSTR;
772
		pp = slot + SLOTNO(c);
773
 
774
		buf[0] = 0;
775
		if(pp->occupied){
776
			p = seprint(p, e, "occupied\n");
777
			if(pp->verstr[0])
778
				p = seprint(p, e, "version %s\n", pp->verstr);
779
		}
780
		if(pp->enabled)
781
			p = seprint(p, e, "enabled\n");
782
		if(pp->powered)
783
			p = seprint(p, e, "powered\n");
784
		if(pp->configed)
785
			p = seprint(p, e, "configed\n");
786
		if(pp->wrprot)
787
			p = seprint(p, e, "write protected\n");
788
		if(pp->busy)
789
			p = seprint(p, e, "busy\n");
790
		seprint(p, e, "battery lvl %d\n", pp->battery);
791
 
792
		n = readstr(offset, a, n, buf);
793
		free(buf);
794
 
795
		return n;
796
	}
797
	error(Ebadarg);
798
	return -1;	/* not reached */
799
}
800
 
801
static long
802
pcmwrite(int dev, int attr, void *a, long n, vlong off)
803
{
804
	int i, len;
805
	PCMmap *m;
806
	uchar *ac;
807
	PCMslot *pp;
808
	ulong offset = off;
809
 
810
	pp = slot + dev;
811
	if(pp->memlen < offset)
812
		return 0;
813
	if(pp->memlen < offset + n)
814
		n = pp->memlen - offset;
815
 
816
	m = 0;
817
	if(waserror()){
818
		if(m)
819
			pcmunmap(pp->slotno, m);
820
		nexterror();
821
	}
822
 
823
	ac = a;
824
	for(len = n; len > 0; len -= i){
825
		m = pcmmap(pp->slotno, offset, 0, attr);
826
		if(m == 0)
827
			error("cannot map PCMCIA card");
828
		if(offset + len > m->cea)
829
			i = m->cea - offset;
830
		else
831
			i = len;
832
		memmoveb(KADDR(m->isa + offset - m->ca), ac, i);
833
		pcmunmap(pp->slotno, m);
834
		offset += i;
835
		ac += i;
836
	}
837
 
838
	poperror();
839
	return n;
840
}
841
 
842
static long
843
i82365write(Chan *c, void *a, long n, vlong off)
844
{
845
	PCMslot *pp;
846
	char buf[32];
847
 
848
	switch(TYPE(c)){
849
	case Qctl:
850
		if(n >= sizeof(buf))
851
			n = sizeof(buf) - 1;
852
		strncpy(buf, a, n);
853
		buf[n] = 0;
854
		pp = slot + SLOTNO(c);
855
		if(!pp->occupied)
856
			error(Eio);
857
 
858
		/* set vpp on card */
859
		if(strncmp(buf, "vpp", 3) == 0)
860
			wrreg(pp, Rpc, vcode(atoi(buf+3))|Fautopower|Foutena|Fcardena);
861
		return n;
862
	case Qmem:
863
	case Qattr:
864
		pp = slot + SLOTNO(c);
865
		if(pp->occupied == 0 || pp->enabled == 0)
866
			error(Eio);
867
		n = pcmwrite(pp->slotno, TYPE(c) == Qattr, a, n, off);
868
		if(n < 0)
869
			error(Eio);
870
		return n;
871
	}
872
	error(Ebadarg);
873
	return -1;	/* not reached */
874
}
875
 
876
Dev i82365devtab = {
877
	'y',
878
	"i82365",
879
 
880
	devreset,
881
	devinit,
882
	devshutdown,
883
	i82365attach,
884
	i82365walk,
885
	i82365stat,
886
	i82365open,
887
	devcreate,
888
	i82365close,
889
	i82365read,
890
	devbread,
891
	i82365write,
892
	devbwrite,
893
	devremove,
894
	devwstat,
895
};
896
 
897
/*
898
 *  configure the PCMslot for IO.  We assume very heavily that we can read
899
 *  configuration info from the CIS.  If not, we won't set up correctly.
900
 */
901
static int
902
pcmio(int slotno, ISAConf *isa)
903
{
904
	uchar we, x, *p;
905
	PCMslot *pp;
906
	PCMconftab *ct, *et, *t;
907
	PCMmap *m;
908
	int i, index, irq;
909
	char *cp;
910
 
911
	irq = isa->irq;
912
	if(irq == 2)
913
		irq = 9;
914
 
915
	if(slotno > nslot)
916
		return -1;
917
	pp = slot + slotno;
918
 
919
	if(!pp->occupied)
920
		return -1;
921
 
922
	et = &pp->ctab[pp->nctab];
923
 
924
	ct = 0;
925
	for(i = 0; i < isa->nopt; i++){
926
		if(strncmp(isa->opt[i], "index=", 6))
927
			continue;
928
		index = strtol(&isa->opt[i][6], &cp, 0);
929
		if(cp == &isa->opt[i][6] || index >= pp->nctab)
930
			return -1;
931
		ct = &pp->ctab[index];
932
	}
933
 
934
	if(ct == 0){
935
		/* assume default is right */
936
		if(pp->def)
937
			ct = pp->def;
938
		else
939
			ct = pp->ctab;
940
 
941
		/* try for best match */
942
		if(ct->nio == 0
943
		|| ct->io[0].start != isa->port || ((1<<irq) & ct->irqs) == 0){
944
			for(t = pp->ctab; t < et; t++)
945
				if(t->nio
946
				&& t->io[0].start == isa->port
947
				&& ((1<<irq) & t->irqs)){
948
					ct = t;
949
					break;
950
				}
951
		}
952
		if(ct->nio == 0 || ((1<<irq) & ct->irqs) == 0){
953
			for(t = pp->ctab; t < et; t++)
954
				if(t->nio && ((1<<irq) & t->irqs)){
955
					ct = t;
956
					break;
957
				}
958
		}
959
		if(ct->nio == 0){
960
			for(t = pp->ctab; t < et; t++)
961
				if(t->nio){
962
					ct = t;
963
					break;
964
				}
965
		}
966
	}
967
 
968
	if(ct == et || ct->nio == 0)
969
		return -1;
970
	if(isa->port == 0 && ct->io[0].start == 0)
971
		return -1;
972
 
973
	/* route interrupts */
974
	isa->irq = irq;
975
	wrreg(pp, Rigc, irq | Fnotreset | Fiocard);
976
 
977
	/* set power and enable device */
978
	x = vcode(ct->vpp1);
979
	wrreg(pp, Rpc, x|Fautopower|Foutena|Fcardena);
980
 
981
	/* 16-bit data path */
982
	if(ct->bit16)
983
		x = Ftiming|Fiocs16|Fwidth16;
984
	else
985
		x = Ftiming;
986
	if(ct->nio == 2 && ct->io[1].start)
987
		x |= x<<4;
988
	wrreg(pp, Rio, x);
989
 
990
	/*
991
	 * enable io port map 0
992
	 * the 'top' register value includes the last valid address
993
	 */
994
	if(isa->port == 0)
995
		isa->port = ct->io[0].start;
996
	we = rdreg(pp, Rwe);
997
	wrreg(pp, Riobtm0lo, isa->port);
998
	wrreg(pp, Riobtm0hi, isa->port>>8);
999
	i = isa->port+ct->io[0].len-1;
1000
	wrreg(pp, Riotop0lo, i);
1001
	wrreg(pp, Riotop0hi, i>>8);
1002
	we |= 1<<6;
1003
	if(ct->nio >= 2 && ct->io[1].start){
1004
		wrreg(pp, Riobtm1lo, ct->io[1].start);
1005
		wrreg(pp, Riobtm1hi, ct->io[1].start>>8);
1006
		i = ct->io[1].start+ct->io[1].len-1;
1007
		wrreg(pp, Riotop1lo, i);
1008
		wrreg(pp, Riotop1hi, i>>8);
1009
		we |= 1<<7;
1010
	}
1011
	wrreg(pp, Rwe, we);
1012
 
1013
	/* only touch Rconfig if it is present */
1014
	m = pcmmap(slotno, pp->cfg[0].caddr + Rconfig, 0x20, 1);
1015
	p = KADDR(m->isa + pp->cfg[0].caddr - m->ca);
1016
	if(pp->cfg[0].cpresent & (1<<Rconfig)){
1017
		/*  Reset adapter */
1018
 
1019
		/*  set configuration and interrupt type.
1020
		 *  if level is possible on the card, use it.
1021
		 */
1022
		x = ct->index;
1023
		if(ct->irqtype & 0x20)
1024
			x |= Clevel;
1025
 
1026
		/*  enable the device, enable address decode and
1027
		 *  irq enable.
1028
		 */
1029
		x |= Cfunc|Cdecode|Cirq;
1030
 
1031
		p[0] = x;
1032
		//delay(5);
1033
		microdelay(40);
1034
	}
1035
 
1036
	if(pp->cfg[0].cpresent & (1<<Riobase0)){
1037
		/* set up the iobase 0 */
1038
		p[Riobase0 << 1] = isa->port;
1039
		p[Riobase1 << 1] = isa->port >> 8;
1040
	}
1041
 
1042
	if(pp->cfg[0].cpresent & (1<<Riosize))
1043
		p[Riosize << 1] = ct->io[0].len;
1044
	pcmunmap(slotno, m);
1045
	return 0;
1046
}