xref: /plan9/sys/src/9/pc/devi82365.c (revision aa72973a2891ccbd3fb042462446761159389e19)
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
rdreg(PCMslot * pp,int index)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
wrreg(PCMslot * pp,int index,uchar val)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
slotinfo(PCMslot * pp)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
vcode(int volt)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
slotena(PCMslot * pp)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
slotdis(PCMslot * pp)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
i82365intr(Ureg *,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*
pcmmap(int slotno,ulong offset,int len,int attr)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
pcmunmap(int slotno,PCMmap * m)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
increfp(PCMslot * pp)336 increfp(PCMslot *pp)
337 {
338 	lock(pp);
339 	if(pp->ref++ == 0)
340 		slotena(pp);
341 	unlock(pp);
342 }
343 
344 static void
decrefp(PCMslot * pp)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
pcmcia_pcmspecial(char * idstr,ISAConf * isa)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
pcmcia_pcmspecialclose(int slotno)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
pcmgen(Chan * c,char *,Dirtab *,int,int i,Dir * dp)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*
i82365probe(int x,int d,int dev)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
i82365dump(PCMslot * pp)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
devi82365link(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*
i82365attach(char * spec)648 i82365attach(char *spec)
649 {
650 	return devattach('y', spec);
651 }
652 
653 static Walkqid*
i82365walk(Chan * c,Chan * nc,char ** name,int nname)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
i82365stat(Chan * c,uchar * db,int n)660 i82365stat(Chan *c, uchar *db, int n)
661 {
662 	return devstat(c, db, n, 0, 0, pcmgen);
663 }
664 
665 static Chan*
i82365open(Chan * c,int omode)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
i82365close(Chan * c)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
memmoveb(uchar * to,uchar * from,int n)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
memmoves(uchar * to,uchar * from,int n)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
pcmread(int slotno,int attr,void * a,long n,vlong off)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
i82365read(Chan * c,void * a,long n,vlong off)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
pcmwrite(int dev,int attr,void * a,long n,vlong off)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
i82365write(Chan * c,void * a,long n,vlong off)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
pcmio(int slotno,ISAConf * isa)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 }
1047