xref: /386bsd/usr/src/kernel/isa/isa.c (revision dc8b130e)
1 /*
2  * Copyright (c) 1989, 1990, 1991, 1992, 1994 William F. Jolitz, TeleMuse
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This software is a component of "386BSD" developed by
16  *	William F. Jolitz, TeleMuse.
17  * 4. Neither the name of the developer nor the name "386BSD"
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  * 5. Non-commercial distribution of this complete file in either source and/or
21  *    binary form at no charge to the user (such as from an official Internet
22  *    archive site) is permitted.
23  * 6. Commercial distribution and sale of this complete file in either source
24  *    and/or binary form on any media, including that of floppies, tape, or
25  *    CD-ROM, or through a per-charge download such as that of a BBS, is not
26  *    permitted without specific prior written permission.
27  * 7. Non-commercial and/or commercial distribution of an incomplete, altered,
28  *    or otherwise modified file in either source and/or binary form is not
29  *    permitted.
30  *
31  * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
32  * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
33  * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
34  * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
35  * NOT MAKE USE OF THIS WORK.
36  *
37  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
38  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40  * ARE DISCLAIMED.  IN NO EVENT SHALL THE DEVELOPER BE LIABLE
41  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  *
49  * $Id: isa.c,v 1.1 94/06/24 18:49:31 bill Exp Locker: bill $
50  *
51  * ISA Bus adapter.
52  */
53 static char *isa_config =
54 	"isa	32.	# bus device (/dev/isa) $Revision$";
55 
56 #include "sys/param.h"
57 #include "sys/errno.h"
58 #include "sys/time.h"
59 #include "sys/file.h"
60 #include "sys/syslog.h"
61 #include "kernel.h"	/* hz */
62 #include "proc.h"
63 #include "buf.h"
64 #include "uio.h"
65 #include "malloc.h"
66 #include "rlist.h"
67 #include "modconfig.h"
68 #include "prototypes.h"
69 
70 #include "vm.h"
71 
72 #include "machine/cpu.h"
73 #include "machine/pcb.h"
74 #include "machine/psl.h"
75 
76 
77 #include "isa_driver.h"
78 #include "isa_stdports.h"
79 #include "isa_irq.h"
80 #include "isa_mem.h"
81 #include "machine/icu.h"
82 #include "i8237.h"
83 #include "i8042.h"
84 
85 
86 #include "machine/inline/io.h"
87 
88 int config_isadev(struct isa_device *);
89 u_short getit(int unit, int timer);
90 
91 #define	IDTVEC(name)	__CONCAT(X,name)
92 /* assignable interrupt vector table entries */
93 extern	IDTVEC(irq0), IDTVEC(irq1), IDTVEC(irq2), IDTVEC(irq3),
94 	IDTVEC(irq4), IDTVEC(irq5), IDTVEC(irq6), IDTVEC(irq7),
95 	IDTVEC(irq8), IDTVEC(irq9), IDTVEC(irq10), IDTVEC(irq11),
96 	IDTVEC(irq12), IDTVEC(irq13), IDTVEC(irq14), IDTVEC(irq15);
97 
98 static *irqvec[16] = {
99 	&IDTVEC(irq0), &IDTVEC(irq1), &IDTVEC(irq2), &IDTVEC(irq3),
100 	&IDTVEC(irq4), &IDTVEC(irq5), &IDTVEC(irq6), &IDTVEC(irq7),
101 	&IDTVEC(irq8), &IDTVEC(irq9), &IDTVEC(irq10), &IDTVEC(irq11),
102 	&IDTVEC(irq12), &IDTVEC(irq13), &IDTVEC(irq14), &IDTVEC(irq15) };
103 
104 struct isa_driver *driver_for_intr[16];
105 u_short isa_mask[16];
106 void	(*isa_vec[16])();
107 int	isa_unit[16];
108 extern	char *intrnames[16];
109 
110 unsigned volatile it_ticks;
111 unsigned it_ticksperintr;
112 int loops_per_usec;
113 
114 /*
115  * Unfinished:
116  *
117  * Bus discovery causes motherboard low-level configuration. Drivers
118  * are discovered by kernel, which do depth-first resource discovery and
119  * low-level configuration, signalling changes to the higher levels. On
120  * arrival to higher-level kernel layer, message is discovered and
121  * configuration is reconciled (top down) via symbolic call to registered
122  * bus configuration function(s).
123  *
124  * Bus drivers provide services via registered interfaces to the kernel,
125  * and to drivers via symbolic calls only. Bus resources must be recorded
126  * as being assigned to the arc linking the bus driver to a ordinary driver
127  * so that if either is unloaded/reloaded, resources can be reclaimed/reconciled
128  * in a stateless manner (e.g. if still referenced, the attempt to unload
129  * is followed by an immediate reload of the same driver -- resources are
130  * independant of the driver instance/implementation itself).
131  */
132 
BUS_MODCONFIG()133 BUS_MODCONFIG() {
134 
135 	/*printf("isa: "); */
136 	/*isa_configure(init++) */
137 }
138 
139 /*
140  * Configure all ISA devices
141  */
isa_configure()142 isa_configure()
143 {
144 	struct isa_device *dvp;
145 	struct isa_driver *dp;
146 	register cnt;
147 	int tick, x;
148 
149 	/*
150 	 * Configure bus interrupts with processor
151 	 */
152 	isa_defaultirq();
153 	splhigh();	/* XXX */
154 
155 	/*
156 	 * Configure motherboard
157 	 */
158 
159 	/* initialize 8253 clock */
160 	it_ticksperintr = 1193182/hz;
161 	outb (IO_TIMER1+3, 0x34);
162 	outb (IO_TIMER1, it_ticksperintr);
163 	outb (IO_TIMER1, it_ticksperintr/256);
164 
165 	/*
166 	 * Find out how many loops we need to DELAY() a microsecond
167 	 */
168 
169 	/* wait till overflow to insure no wrap around */
170 	do
171 		tick = getit(0,0);
172 	while (tick < getit(0,0));
173 
174 	/* time a while loop */
175 	cnt = 1000;
176 	tick = getit(0,0);
177 	while (cnt-- > 0)
178 		;
179 	tick -= getit(0,0);
180 
181 	/* scale to microseconds per 1000 "loops" */
182 	tick *= 1000000;
183 	tick /= 1193182;
184 	loops_per_usec = (10000/tick + 5) / 10;
185 
186 	/*
187 	 * Configure ISA devices. XXX
188 	 */
189 	splhigh();
190 	INTREN(IRQ_SLAVE);
191 	modscaninit(MODT_DRIVER);
192 
193 	/*
194 	 * Finish configuration of ISA devices.
195 	 */
196 	ttymask |= biomask + netmask;
197 	netmask |= biomask;
198 	/* biomask |= ttymask ;  can some tty devices use buffers? */
199 	/*printf("biomask %x ttymask %x netmask %x\n", biomask, ttymask, netmask); */
200 
201 	/* splat masks into place */
202 	for (x = 0; x < 16; x++)
203 	{
204 		if (driver_for_intr[x] && driver_for_intr[x]->mask)
205 			isa_mask[x] = *(driver_for_intr[x]->mask);
206 		if (intrnames[x] == 0)
207 			intrnames[x] = "** unassigned **";
208 	}
209 	splnone();
210 }
211 
212 /* parse and evaluate an ISA device */
cfg_isadev(char ** ptr,char * modname,struct isa_device * idp)213 cfg_isadev(char **ptr, char *modname, struct isa_device *idp) {
214 	char *lp = *ptr;
215 	int val;
216 
217 
218 	/* default fields */
219 	idp->id_iobase = 0;
220 	idp->id_irq = 0;
221 	idp->id_drq = -1;
222 	idp->id_maddr= (caddr_t) 0;
223 	idp->id_msize = 0;
224 	idp->id_unit = '?';
225 	idp->id_flags = 0;
226 
227 	/* list of values or '?' */
228 	if (cfg_char(&lp, '(') && cfg_number(&lp, &val)) {
229 		/* specify all or partial list (if device can guess rest) */
230 		idp->id_iobase = val;
231 
232 		if (cfg_number(&lp, &val)) {	/* XXX use "," to spec multiples */
233 			if (val >= 0)
234 				idp->id_irq = 1 << val;
235 		}
236 
237 		if (cfg_number(&lp, &val))
238 			idp->id_drq = val;
239 
240 		if (cfg_number(&lp, &val))
241 			idp->id_maddr = (caddr_t)val;
242 
243 		if (cfg_number(&lp, &val))
244 			idp->id_msize = val;
245 
246 		if (cfg_number(&lp, &val))
247 			idp->id_unit = val;
248 
249 		if (cfg_number(&lp, &val))
250 			idp->id_flags = val;
251 
252 		if (cfg_char(&lp, ')')) {
253 			*ptr = lp;
254 			return (1);
255 		}
256 		goto nope;
257 
258 	}
259 	else if (cfg_char(&lp, '?')) {
260 		/* driver attempts to do everything for device */
261 		idp->id_iobase = '?';
262 		*ptr = lp;
263 		return (1);
264 	}
265 nope:
266 	if (modname)
267 		printf("module %s: cannot find ISA port spec\n", modname);
268 
269 	return (0);
270 }
271 
272 #ifdef notyet
273 /* print a isa dev entry */
274 void
print_isadev(struct isa_device * idp)275 print_isadev(struct isa_device *idp) {
276 
277 	if (idp->id_iobase) {
278 		printf ("port: ");
279 		if (idp->id_iobase == '?')
280 			printf("? ");
281 		else
282 			printf("%x ", idp->id_iobase);
283 	}
284 	if (idp->id_irq) /* XXX iterate over bitfield */
285 		printf ("irq%d ", ffs(idp->id_irq)-1);
286 	if (idp->id_drq != -1)
287 		printf ("drq%d ",  idp->id_drq);
288 	if (idp->id_maddr)
289 		printf ("maddr: %x + %d ",
290 			kmem_phys(idp->id_maddr), idp->id_msize);
291 	printf ("unit: ");
292 	if (idp->id_unit == '?')
293 		printf("? ");
294 	else
295 		printf("%d ", idp->id_unit);
296 
297 	/* if (idp->id_flags)
298 		printf("flags: %x ", idp->id_flags);*/
299 }
300 #endif
301 
302 void
new_isa_configure(char ** lp,struct isa_driver * dp)303 new_isa_configure(char **lp, struct isa_driver *dp) {
304 	struct isa_device adev ;
305 
306 	adev.id_driver = dp;
307 	for(;;) {
308 		if (cfg_isadev(lp, 0, &adev)) {
309 			/*if ( */ (void)config_isadev(&adev) /* )
310 				print_isadev(&adev)  */ ;
311 				/* attach */
312 		} else break;
313 	}
314 
315 	/*printf("\n");*/
316 }
317 
318 /*
319  * Configure an ISA device.
320  */
321 config_isadev(isdp)
322 	struct isa_device *isdp;
323 {
324 	struct isa_driver *dp;
325 	int rv;
326 
327 	if (dp = isdp->id_driver) {
328 		if (isdp->id_maddr) {
329 			extern u_int atdevbase;
330 
331 			isdp->id_maddr -= 0xa0000;
332 			isdp->id_maddr += atdevbase;
333 		}
334 
335 		printf("probing for %s port %x: ", dp->name, isdp->id_iobase);
336 		isdp->id_alive = (*dp->probe)(isdp);
337 		if (isdp->id_alive) {
338 printf("\r                                                                  \r");
339 			printf("%s: ", dp->name);
340 			(*dp->attach)(isdp);
341 			printf(" ");
342 			if (isdp->id_iobase)
343 				printf("port %x ", isdp->id_iobase);
344 
345 			/* XXX handle multiple interrupts */
346 			if(isdp->id_irq) {
347 				int intrno;
348 
349 				intrno = ffs(isdp->id_irq)-1;
350 				printf("irq%d ", intrno);
351 				INTREN(isdp->id_irq);
352 
353 				if (dp->mask)
354 					INTRMASK(*(dp->mask), isdp->id_irq);
355 
356 				setirq(ICU_OFFSET + intrno, irqvec [intrno]);
357 				isa_vec[intrno] = dp->intr;
358 				isa_unit[intrno] = isdp->id_unit;
359 
360 				driver_for_intr[intrno] = dp;
361 				intrnames[intrno] = dp->name; /* XXX - allocate seperate string with unit number */
362 			}
363 
364 			if (isdp->id_drq != -1)
365 				printf("drq%d ", isdp->id_drq);
366 			printf("\n");
367 		}
368 		rv = 1;
369 	} else {
370 		DELAY(5000);
371 		rv = 0;
372 	}
373 printf("\r                                                                  \r");
374 	return(rv);
375 }
376 
377 #define	IDTVEC(name)	__CONCAT(X,name)
378 /* default interrupt vector table entries */
379 extern	IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3),
380 	IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7),
381 	IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11),
382 	IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15);
383 
384 static *defvec[16] = {
385 	&IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
386 	&IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
387 	&IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
388 	&IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) };
389 
390 /* out of range default interrupt vector gate entry */
391 extern	IDTVEC(intrdefault);
392 
393 /*
394  * Fill in default interrupt table (in case of spuruious interrupt
395  * during configuration of kernel, setup interrupt control unit
396  */
isa_defaultirq()397 isa_defaultirq() {
398 	int i;
399 
400 	/* icu vectors */
401 #define	NIDT	256
402 #define	NRSVIDT	32		/* reserved entries for cpu exceptions */
403 	for (i = NRSVIDT ; i < NRSVIDT+ICU_LEN ; i++)
404 		setirq(i, defvec[i]);
405 
406 	/* out of range vectors */
407 	for (i = NRSVIDT; i < NIDT; i++)
408 		setirq(i, &IDTVEC(intrdefault));
409 
410 	/* clear npx intr latch */
411 	outb(0xf1,0);
412 
413 	/* initialize 8259's */
414 	__outb(IO_ICU1, 0x11);		/* reset; program device, four bytes */
415 	__outb(IO_ICU1+1, NRSVIDT);	/* starting at this vector index */
416 	__outb(IO_ICU1+1, 1<<2);		/* slave on line 2 */
417 	__outb(IO_ICU1+1, 1);		/* 8086 mode */
418 	__outb(IO_ICU1+1, 0xff);		/* leave interrupts masked */
419 	__outb(IO_ICU1, /*0x60+*/8+1);		/* default to ISR on read */
420 
421 	__outb(IO_ICU2, 0x11);		/* reset; program device, four bytes */
422 	__outb(IO_ICU2+1, NRSVIDT+8);	/* staring at this vector index */
423 	__outb(IO_ICU2+1,2);		/* my slave id is 2 */
424 	__outb(IO_ICU2+1,1);		/* 8086 mode */
425 	__outb(IO_ICU2+1, 0xff);		/* leave interrupts masked */
426 	__outb(IO_ICU2, /*0x60+*/8+1);		/* default to ISR on read */
427 }
428 
429 
430 /*
431  * XXX unfinished, missing new channel code and pvc_alloc()
432  */
433 
434 /* region of physical memory known to be contiguous */
435 vm_offset_t isaphysmem;
436 static caddr_t dma_bounce[8];		/* XXX */
437 static char bounced[8];		/* XXX */
438 int dma_active;
439 #define MAXDMASZ 512		/* XXX */
440 
441 /* high byte of address is stored in this port for i-th dma channel */
442 static short dmapageport[8] =
443 	{ 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a };
444 
445 /*
446  * isa_dmacascade(): program 8237 DMA controller channel to accept
447  * external dma control by a board.
448  * N.B. drivers must manage "dma_active" manually.
449  */
isa_dmacascade(unsigned chan)450 void isa_dmacascade(unsigned chan)
451 {	int modeport;
452 
453 	if (chan > 7)
454 		panic("isa_dmacascade: impossible request");
455 
456 	/* set dma channel mode, and set dma channel mode */
457 	if ((chan & 4) == 0)
458 		modeport = IO_DMA1 + 0xb;
459 	else
460 		modeport = IO_DMA2 + 0x16;
461 	outb(modeport, DMA37MD_CASCADE | (chan & 3));
462 	if ((chan & 4) == 0)
463 		outb(modeport - 1, chan & 3);
464 	else
465 		outb(modeport - 2, chan & 3);
466 }
467 
468 /*
469  * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment
470  * problems by using a bounce buffer.
471  */
isa_dmastart(int flags,caddr_t addr,unsigned nbytes,unsigned chan)472 void isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan)
473 {	vm_offset_t phys;
474 	int modeport, waport, mskport;
475 	caddr_t newaddr;
476 
477 	if (chan > 7 || nbytes > (1<<16))
478 		panic("isa_dmastart: impossible request");
479 
480 	if (isa_dmarangecheck(addr, nbytes)) {
481 		if (dma_bounce[chan] == 0)
482 			dma_bounce[chan] =
483 				/*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/
484 				(caddr_t) isaphysmem + NBPG*chan;
485 		bounced[chan] = 1;
486 		newaddr = dma_bounce[chan];
487 		*(int *) newaddr = 0;	/* XXX */
488 
489 		/* copy bounce buffer on write */
490 		if (!(flags & B_READ))
491 			memcpy(newaddr, addr, nbytes);
492 		addr = newaddr;
493 	}
494 
495 	/* translate to physical */
496 	phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr);
497 
498 	/* set dma channel mode, and reset address ff */
499 	if ((chan & 4) == 0)
500 		modeport = IO_DMA1 + 0xb;
501 	else
502 		modeport = IO_DMA2 + 0x16;
503 	if (flags & B_READ)
504 		outb(modeport, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3));
505 	else
506 		outb(modeport, DMA37MD_SINGLE|DMA37MD_READ|(chan&3));
507 	if ((chan & 4) == 0)
508 		outb(modeport + 1, 0);
509 	else
510 		outb(modeport + 2, 0);
511 
512 	/* send start address */
513 	if ((chan & 4) == 0) {
514 		waport =  IO_DMA1 + (chan<<1);
515 		outb(waport, phys);
516 		outb(waport, phys>>8);
517 	} else {
518 		waport =  IO_DMA2 + ((chan - 4)<<2);
519 		outb(waport, phys>>1);
520 		outb(waport, phys>>9);
521 	}
522 	outb(dmapageport[chan], phys>>16);
523 
524 	/* send count */
525 	if ((chan & 4) == 0) {
526 		outb(waport + 1, --nbytes);
527 		outb(waport + 1, nbytes>>8);
528 	} else {
529 		nbytes <<= 1;
530 		outb(waport + 2, --nbytes);
531 		outb(waport + 2, nbytes>>8);
532 	}
533 
534 	/* unmask channel */
535 	if ((chan & 4) == 0)
536 		mskport =  IO_DMA1 + 0x0a;
537 	else
538 		mskport =  IO_DMA2 + 0x14;
539 	outb(mskport, chan & 3);
540 	dma_active |= 1 << chan;
541 }
542 
isa_dmadone(int flags,caddr_t addr,int nbytes,int chan)543 void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan)
544 {
545 
546 	/* copy bounce buffer on read */
547 	/*if ((flags & (B_PHYS|B_READ)) == (B_PHYS|B_READ))*/
548 	if (bounced[chan]) {
549 		memcpy(addr, dma_bounce[chan], nbytes);
550 		bounced[chan] = 0;
551 	}
552 	dma_active &= ~(1 << chan);
553 }
554 
555 /*
556  * Check for problems with the address range of a DMA transfer
557  * (non-contiguous physical pages, outside of bus address space).
558  * Return true if special handling needed.
559  */
560 
isa_dmarangecheck(caddr_t va,unsigned length)561 isa_dmarangecheck(caddr_t va, unsigned length) {
562 	vm_offset_t phys, priorpage, endva;
563 
564 	endva = (vm_offset_t)round_page(va + length);
565 	priorpage = 0;
566 	for (; va < (caddr_t) endva ; va += NBPG) {
567 		phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va));
568 		if (phys == 0)
569 			panic("isa_dmacheck: no physical page present");
570 		if (phys > ISA_RAM_END)
571 			return (1);
572 		if (priorpage && priorpage + NBPG != phys)
573 			return (1);
574 		priorpage = phys;
575 	}
576 	return (0);
577 }
578 
579 /* head of queue waiting for physmem to become available */
580 struct buf isa_physmemq;
581 
582 /* blocked waiting for resource to become free for exclusive use */
583 static isaphysmemflag;
584 /* if waited for and call requested when free (B_CALL) */
585 static void (*isaphysmemunblock)(); /* needs to be a list */
586 
587 /*
588  * Allocate contiguous physical memory for transfer, returning
589  * a *virtual* address to region. May block waiting for resource.
590  * (assumed to be called at splbio())
591  */
592 caddr_t
isa_allocphysmem(caddr_t va,unsigned length,void (* func)())593 isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) {
594 
595 	isaphysmemunblock = func;
596 	while (isaphysmemflag & B_BUSY) {
597 		isaphysmemflag |= B_WANTED;
598 		tsleep((caddr_t)&isaphysmemflag, PRIBIO, "isaphys", 0);
599 	}
600 	isaphysmemflag |= B_BUSY;
601 
602 	return((caddr_t)isaphysmem);
603 }
604 
605 /*
606  * Free contiguous physical memory used for transfer.
607  * (assumed to be called at splbio())
608  */
609 void
isa_freephysmem(caddr_t va,unsigned length)610 isa_freephysmem(caddr_t va, unsigned length) {
611 
612 	isaphysmemflag &= ~B_BUSY;
613 	if (isaphysmemflag & B_WANTED) {
614 		isaphysmemflag &= B_WANTED;
615 		wakeup((caddr_t)&isaphysmemflag);
616 		if (isaphysmemunblock)
617 			(*isaphysmemunblock)();
618 	}
619 }
620 
621 /*
622  * Handle a NMI, possibly a machine check.
623  * return true to panic system, false to ignore.
624  */
isa_nmi(cd)625 isa_nmi(cd) {
626 
627 	log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x\n", inb(0x61), inb(0x70));
628 	return(0);
629 }
630 
631 /*
632  * Caught a stray interrupt, notify
633  */
isa_strayintr(d)634 isa_strayintr(d) {
635 
636 #ifdef notdef
637 	/* DON'T BOTHER FOR NOW! */
638 	/* for some reason, we get bursts of intr #7, even if not enabled! */
639 	log(LOG_ERR,"ISA strayintr %x", d);
640 #endif
641 }
642 
643 u_short
getit(int unit,int timer)644 getit(int unit, int timer) {
645 	int port = (unit ? IO_TIMER2 : IO_TIMER1), val;
646 
647 	outb(port+ 3, timer<<6); /* emit latch command */
648 	val = inb(port + timer);
649 	val = (inb(port + timer) << 8) + val;
650 	return (val);
651 }
652 
653 void
setit(unit,timer,mode,count)654 setit(unit, timer, mode, count) {
655 	int port = (unit ? IO_TIMER2 : IO_TIMER1);
656 
657 	outb(port+ 3, (timer << 6) + mode); /* emit latch command */
658 	outb(port + timer, count);
659 	outb(port + timer, count >> 8);
660 }
661 
662 /*
663  * get time in absolute it_ticks for tracing.
664  */
getticks()665 getticks() {
666 	register unsigned val;
667 
668 	/* stop interrupts, emit latch command for timer 0, unit 0 */
669 	asm (" xorl %eax, %eax ; cli ; outb %al, $0x43 ");
670 
671 	asm (" inb $0x40, %%al ; xchgb %%al, %%ah ; inb $0x40, %%al ; xchg %%al, %%ah " : "=a" (val));
672 	/* val = inb(IO_TIMER1);
673 	val += inb(IO_TIMER1) << 8; */
674 
675 	if (val >= it_ticksperintr - 1)
676 		return (it_ticks + it_ticksperintr);
677 	else
678 		return (it_ticks + it_ticksperintr - val);
679 }
680 
681 extern int hz;
682 
683 /*
684  * get fraction of tick in units of microseconds
685  * (must be called at splclock)
686  * This routine cannot use get_it() because of underflow
687  * processing.
688  */
689 
690 void
microtime(tvp)691 microtime(tvp)
692 	register struct timeval *tvp;
693 {
694 	extern unsigned it_ticksperintr;
695 	register unsigned val;
696 
697 	/* minimize clock sampling skew by latching counter immediately after blocking interrupts */
698 	/* stop interrupts, emit latch command for timer 0, unit 0 */
699 	asm (" xorl %eax, %eax ; cli ; outb %al, $0x43 ");
700 
701 	/* obtain frozen time - optimize overhead */
702 	asm (" inb $0x84, %%al ; inb $0x84, %%al ; inb $0x40, %%al ; xchgb %%al, %%ah ; inb $0x84, %%al ; inb $0x84, %%al ; inb $0x40, %%al ; xchgb %%al, %%ah " : "=a" (val));
703 	*tvp = time;
704 
705 	/* if overflowed, account for missing clock interrupt */
706 	/* (clock can be skewed by as much as 3 ticks following interrupt due
707 	   to bus overhead in processing interrupt request (the counter drops
708 	   to value 1, signals interrupt, 8259 just misses sampling window
709 	   (~ 1 I/O bus cycle or 625ns, counter now reset to N, program emits
710 	   freeze command (another bus cycle) .... */
711 	if (val < it_ticksperintr - 2)
712 		/* clock interrupt not pending */
713 		tvp->tv_usec += (1000000 / hz) * (it_ticksperintr - val)
714 				/ it_ticksperintr;
715 	else
716 		/* clock race; interrupt pending, just add missing tick */
717 		tvp->tv_usec += 1000000 / hz;
718 
719 	/* if overflowing microsecond time, carry to seconds time */
720 	if (tvp->tv_usec > 1000000) {
721 		tvp->tv_sec++;
722 		tvp->tv_usec -= 1000000;
723 	}
724 
725 	/* re-engage interrupts, and take clock interrupt if overflowed */
726 	asm("sti");
727 }
728 
729 static beeping;
730 static
sysbeepstop(f)731 sysbeepstop(f)
732 {
733 	/* disable counter 2 */
734 	outb(0x61, inb(0x61) & 0xFC);
735 	if (f)
736 		timeout(sysbeepstop, 0, f);
737 	else
738 		beeping = 0;
739 }
740 
sysbeep(int pitch,int period)741 void sysbeep(int pitch, int period)
742 {
743 
744 	outb(0x61, inb(0x61) | 3);	/* enable counter 2 */
745 	outb(0x43, 0xb6);	/* set command for counter 2, 2 byte write */
746 
747 	outb(0x42, pitch);
748 	outb(0x42, (pitch>>8));
749 
750 	if (!beeping) {
751 		beeping = period;
752 		timeout(sysbeepstop, (caddr_t)(period/2), period);
753 	}
754 }
755 
756 /*
757  * Pass command to keyboard controller (8042)
758  */
759 void
kbd_cmd(unsigned val)760 kbd_cmd(unsigned val) {
761 	u_char r;
762 
763 	/* see if we can issue a command. clear data buffer if something present */
764 	while ((r = inb(KBSTATP)) & (KBS_IBF|KBS_DIB))
765 		if (r & KBS_DIB) {
766 			DELAY(7);
767 			printf("kc: %x", inb(KBDATAP));
768 		}
769 	DELAY(7);
770 	outb(KBCMDP, val);
771 
772 	/* wait till command is taken */
773 	while (inb(KBSTATP) & KBS_IBF)
774 		DELAY(7);
775 }
776 
777 /*
778  * Pass command thru keyboard controller to keyboard itself
779  */
780 void
kbd_wr(unsigned val)781 kbd_wr(unsigned val) {
782 	u_char r;
783 
784 	while (inb(KBSTATP) & KBS_IBF)
785 		DELAY(7);
786 
787 	while ((r = inb(KBSTATP)) & (KBS_IBF|KBS_DIB))
788 		if (r & KBS_DIB) {
789 			DELAY(7);
790 			printf("kw: %x", inb(KBDATAP));
791 		}
792 
793 	DELAY(7);
794 	outb(KBOUTP, val);
795 
796 	/* wait till data is taken */
797 	while (inb(KBSTATP) & KBS_IBF)
798 		DELAY(7);
799 }
800 
801 /*
802  * Read a character from keyboard controller
803  */
804 u_char
kbd_rd()805 kbd_rd() {
806 	int sts;
807 
808 	while (inb(KBSTATP) & KBS_IBF)
809 		DELAY(7);
810 	DELAY(7);
811 	while (((sts = inb(KBSTATP)) & KBS_DIB) == 0)
812 		DELAY(7);
813 	DELAY(7);
814 	return (inb(KBDATAP));
815 }
816 
kbd_drain()817 kbd_drain() {
818 	int sts;
819 
820 	/* do { */
821 		DELAY(1000);
822 		if ((sts = inb(KBSTATP)) & KBS_DIB)
823 			printf("kd: %x", kbd_rd());
824 	/* } while (sts & KBS_DIB); */
825 }
826 
827 /*
828  * Send the keyboard a command, wait for and return status
829  */
830 u_char
key_cmd(unsigned val)831 key_cmd(unsigned val) {
832 
833 	kbd_wr(val);
834 	return(kbd_rd());
835 }
836 
837 /*
838  * Send the aux port a command, wait for and return status
839  */
840 u_char
aux_cmd(unsigned val)841 aux_cmd(unsigned val) {
842 	u_char r;
843 
844 	kbd_cmd(K_AUXOUT);
845 	kbd_wr(val);
846 	return(kbd_rd());
847 }
848 
849 /*
850  * Execute a keyboard controller command that passes a parameter
851  */
852 void
kbd_cmd_write_param(unsigned cmd,unsigned val)853 kbd_cmd_write_param(unsigned cmd, unsigned val) {
854 	u_char r;
855 
856 	kbd_cmd(cmd);
857 	kbd_wr(val);
858 }
859 
860 /*
861  * Execute a keyboard controller command that returns a parameter
862  */
863 u_char
kbd_cmd_read_param(unsigned cmd)864 kbd_cmd_read_param(unsigned cmd) {
865 	u_char r;
866 
867 	kbd_cmd(cmd);
868 	return(kbd_rd());
869 }
870 
871 #define	CW54BCD		0x01	/* BCD instead of binary count down mode */
872 #define	CW54RATE	 0x04	/* rate operating mode */
873 #define	CW54SQUARE	 0x06	/* square wave output mode */
874 #define	CW54LSBMSB	 0x30	/* pass counter values in little endian order */
875 
876 #define	KBC42FAILDIS	 0x04	/* disable failsafe counter NMI */
877 #define	KBC42IOCHKDIS	 0x08	/* disable IOCHK NMI */
878 #define	KBC42FAILNMI	 0x40	/* NMI from failsafe timer  */
879 #define	KBC42IOCHKNMI	 0x80	/* NMI from IOCHK */
880 
881 /*
882  * Enable an NMI failsafe timer for a millisecond
883  */
884 int allownmi;
failsafe_start()885 failsafe_start() {
886 	if(allownmi) {
887 	setit(1, 0, CW54LSBMSB|CW54SQUARE, 1193000/100);
888 	outb(0x61, inb(0x61) & ~KBC42FAILDIS);
889 	outb(0x70, 0x00);
890 	}
891 }
892 
893 /*
894  * Disable the NMI failsafe timer, cancelling the timeout.
895  */
failsafe_cancel()896 failsafe_cancel() {
897 	outb(0x61, inb(0x61) | KBC42FAILDIS);
898 	outb(0x70, 0x80);
899 }
900 
901 /*
902  * Read RTC atomically
903  */
904 u_char
rtcin(u_char adr)905 rtcin(u_char  adr)
906 {
907 	int x;
908 
909 	/*
910 	 * Some RTC's (dallas smart watch) attempt to foil unintentioned
911 	 * operation of the RTC by requiring back-to-back i/o instructions
912 	 * to reference the RTC; any interviening i/o operations cancel
913 	 * the reference to the clock (e.g. the NOP).
914 	 */
915 	x = splhigh();
916 	asm volatile ("out%z0 %b0, %2 ; xorl %0, %0 ; in%z0 %3, %b0"
917 		: "=a"(adr) : "0"(adr), "i"(IO_RTC), "i"(IO_RTC + 1));
918 	splx(x);
919 	return (adr);
920 }
921 
922 /*
923  * Write RTC atomically.
924  */
925 void
rtcout(u_char adr,u_char val)926 rtcout(u_char adr, u_char val)
927 {
928 	int x;
929 
930 	/*
931 	 * Some RTC's (dallas smart watch) attempt to foil unintentioned
932 	 * operation of the RTC by requiring back-to-back i/o instructions
933 	 * to reference the RTC; any interviening i/o operations cancel
934 	 * the reference to the clock (e.g. the NOP).
935 	 */
936 	x = splhigh();
937 	asm volatile ("out%z0 %b0, %2 ; movb %1, %b0 ; out%z0 %b0, %3"
938 		:: "a"(adr), "g"(val), "i"(IO_RTC), "i"(IO_RTC+1));
939 	splx(x);
940 }
941 
942 /* XXX: framework only, unfinished */
943 static int
isaopen(dev_t dev,int flag,int mode,struct proc * p)944 isaopen(dev_t dev, int flag, int mode, struct proc *p) {
945 	struct syscframe *fp = (struct syscframe *)p->p_md.md_regs;
946 
947 	fp->sf_eflags |= PSL_IOPL;
948 	return (0);
949 }
950 
951 static int
isaclose(dev_t dev,int flag,int mode,struct proc * p)952 isaclose(dev_t dev, int flag, int mode, struct proc *p) {
953 	struct syscframe *fp = (struct syscframe *)p->p_md.md_regs;
954 
955 	fp->sf_eflags &= ~PSL_IOPL;
956 	return (0);
957 }
958 
959 static int
isaioctl(dev_t dev,int cmd,caddr_t addr,int flag,struct proc * p)960 isaioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p) {
961 
962 	/* What's missing: enable selection on irq's, controls on
963 	   [e]isa features, statistics, ... */
964 
965 	return (ENODEV);
966 }
967 
968 static int
isaselect(dev_t dev,int rw,struct proc * p)969 isaselect(dev_t dev, int rw, struct proc *p) {
970 
971 	return (ENODEV);
972 }
973 
974 static int
isammap(dev_t dev,int offset,int nprot)975 isammap(dev_t dev, int offset, int nprot)
976 {
977 	if (offset < ISA_RAM_BEGIN || offset > ISA_RAM_END)
978 		return -1;
979 
980 	return i386_btop(offset);
981 }
982 
983 static struct devif isa_devif =
984 {
985 	{0}, -1, -2, 0, 0, 0, 0, 0, 0,
986 	isaopen, isaclose, isaioctl, 0, 0, isaselect, isammap,
987 	0, 0, 0, 0,
988 	0,  0,
989 };
990 
DRIVER_MODCONFIG()991 DRIVER_MODCONFIG() {
992 	char *cfg_string = isa_config;
993 
994 	if (devif_config(&cfg_string, &isa_devif) == 0)
995 		return;
996 
997 }
998