Commit | Line | Data |
---|---|---|
ab05af3a WJ |
1 | /*- |
2 | * Copyright (c) 1991 The Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * William Jolitz. | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | |
15 | * documentation and/or other materials provided with the distribution. | |
16 | * 3. All advertising materials mentioning features or use of this software | |
17 | * must display the following acknowledgement: | |
18 | * This product includes software developed by the University of | |
19 | * California, Berkeley and its contributors. | |
20 | * 4. Neither the name of the University nor the names of its contributors | |
21 | * may be used to endorse or promote products derived from this software | |
22 | * without specific prior written permission. | |
23 | * | |
24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
34 | * SUCH DAMAGE. | |
35 | * | |
36 | * @(#)isa.c 7.2 (Berkeley) 5/13/91 | |
e39f1b2b FM |
37 | * |
38 | * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE | |
39 | * -------------------- ----- ---------------------- | |
6b9305fd | 40 | * CURRENT PATCH LEVEL: 2 00117 |
e39f1b2b FM |
41 | * -------------------- ----- ---------------------- |
42 | * | |
43 | * 18 Aug 92 Frank Maclachlan *See comments below | |
6b9305fd PS |
44 | * 25 Mar 93 Rodney W. Grimes Added counter for stray interrupt, |
45 | * turned on logging of stray interrupts, | |
46 | * Now prints maddr, msize, and flags | |
47 | * after finding a device. | |
ab05af3a WJ |
48 | */ |
49 | static char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/isa/RCS/isa.c,v 1.2 92/01/21 14:34:23 william Exp Locker: root $"; | |
50 | ||
51 | /* | |
52 | * code to manage AT bus | |
e39f1b2b FM |
53 | * |
54 | * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com): | |
55 | * Fixed uninitialized variable problem and added code to deal | |
56 | * with DMA page boundaries in isa_dmarangecheck(). Fixed word | |
57 | * mode DMA count compution and reorganized DMA setup code in | |
58 | * isa_dmastart() | |
ab05af3a WJ |
59 | */ |
60 | ||
61 | #include "param.h" | |
62 | #include "systm.h" | |
63 | #include "conf.h" | |
64 | #include "file.h" | |
65 | #include "buf.h" | |
66 | #include "uio.h" | |
67 | #include "syslog.h" | |
68 | #include "malloc.h" | |
69 | #include "rlist.h" | |
70 | #include "machine/segments.h" | |
71 | #include "vm/vm.h" | |
72 | #include "i386/isa/isa_device.h" | |
73 | #include "i386/isa/isa.h" | |
74 | #include "i386/isa/icu.h" | |
75 | #include "i386/isa/ic/i8237.h" | |
76 | #include "i386/isa/ic/i8042.h" | |
77 | ||
e39f1b2b FM |
78 | /* |
79 | ** Register definitions for DMA controller 1 (channels 0..3): | |
80 | */ | |
81 | #define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */ | |
82 | #define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */ | |
83 | #define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */ | |
84 | #define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */ | |
85 | ||
86 | /* | |
87 | ** Register definitions for DMA controller 2 (channels 4..7): | |
88 | */ | |
89 | #define DMA2_CHN(c) (IO_DMA1 + 2*(2*(c))) /* addr reg for channel c */ | |
90 | #define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */ | |
91 | #define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */ | |
92 | #define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */ | |
93 | ||
ab05af3a WJ |
94 | int config_isadev(struct isa_device *, u_short *); |
95 | #ifdef notyet | |
96 | struct rlist *isa_iomem; | |
97 | ||
98 | /* | |
99 | * Configure all ISA devices | |
100 | */ | |
101 | isa_configure() { | |
102 | struct isa_device *dvp; | |
103 | struct isa_driver *dp; | |
104 | ||
105 | splhigh(); | |
106 | INTREN(IRQ_SLAVE); | |
107 | /*rlist_free(&isa_iomem, 0xa0000, 0xfffff);*/ | |
108 | for (dvp = isa_devtab_tty; dvp; dvp++) | |
109 | (void) config_isadev(dvp, &ttymask); | |
110 | for (dvp = isa_devtab_bio; dvp; dvp++) | |
111 | (void) config_isadev(dvp, &biomask); | |
112 | for (dvp = isa_devtab_net; dvp; dvp++) | |
113 | (void) config_isadev(dvp, &netmask); | |
114 | for (dvp = isa_devtab_null; dvp; dvp++) | |
115 | (void) config_isadev(dvp, 0); | |
116 | #include "sl.h" | |
117 | #if NSL > 0 | |
118 | netmask |= ttymask; | |
119 | ttymask |= netmask; | |
120 | #endif | |
121 | /* printf("biomask %x ttymask %x netmask %x\n", biomask, ttymask, netmask); */ | |
122 | splnone(); | |
123 | } | |
124 | ||
125 | /* | |
126 | * Configure an ISA device. | |
127 | */ | |
128 | config_isadev(isdp, mp) | |
129 | struct isa_device *isdp; | |
130 | u_short *mp; | |
131 | { | |
132 | struct isa_driver *dp; | |
133 | static short drqseen, irqseen; | |
134 | ||
135 | if (dp = isdp->id_driver) { | |
136 | /* if a device with i/o memory, convert to virtual address */ | |
137 | if (isdp->id_maddr) { | |
138 | extern unsigned int atdevbase; | |
139 | ||
140 | isdp->id_maddr -= IOM_BEGIN; | |
141 | isdp->id_maddr += atdevbase; | |
142 | } | |
143 | isdp->id_alive = (*dp->probe)(isdp); | |
144 | if (isdp->id_alive) { | |
145 | ||
146 | printf("%s%d at port 0x%x ", dp->name, | |
147 | isdp->id_unit, isdp->id_iobase); | |
148 | ||
149 | /* check for conflicts */ | |
150 | if (irqseen & isdp->id_irq) { | |
151 | printf("INTERRUPT CONFLICT - irq%d\n", | |
152 | ffs(isdp->id_irq) - 1); | |
153 | return (0); | |
154 | } | |
155 | if (isdp->id_drq != -1 | |
156 | && (drqseen & (1<<isdp->id_drq))) { | |
157 | printf("DMA CONFLICT - drq%d\n", isdp->id_drq); | |
158 | return (0); | |
159 | } | |
160 | /* NEED TO CHECK IOMEM CONFLICT HERE */ | |
161 | ||
162 | /* allocate and wire in device */ | |
163 | if(isdp->id_irq) { | |
164 | int intrno; | |
165 | ||
166 | intrno = ffs(isdp->id_irq)-1; | |
167 | printf("irq %d ", intrno); | |
168 | INTREN(isdp->id_irq); | |
169 | if(mp)INTRMASK(*mp,isdp->id_irq); | |
170 | setidt(NRSVIDT + intrno, isdp->id_intr, | |
171 | SDT_SYS386IGT, SEL_KPL); | |
172 | irqseen |= isdp->id_irq; | |
173 | } | |
174 | if (isdp->id_drq != -1) { | |
175 | printf("drq %d ", isdp->id_drq); | |
176 | drqseen |= 1 << isdp->id_drq; | |
177 | } | |
178 | ||
179 | (*dp->attach)(isdp); | |
180 | ||
181 | printf("on isa\n"); | |
182 | } | |
183 | return (1); | |
184 | } else return(0); | |
185 | } | |
6b9305fd | 186 | #else /* notyet */ |
ab05af3a WJ |
187 | /* |
188 | * Configure all ISA devices | |
189 | */ | |
190 | isa_configure() { | |
191 | struct isa_device *dvp; | |
192 | struct isa_driver *dp; | |
193 | ||
194 | splhigh(); | |
195 | INTREN(IRQ_SLAVE); | |
196 | for (dvp = isa_devtab_tty; config_isadev(dvp,&ttymask); dvp++); | |
197 | for (dvp = isa_devtab_bio; config_isadev(dvp,&biomask); dvp++); | |
198 | for (dvp = isa_devtab_net; config_isadev(dvp,&netmask); dvp++); | |
199 | for (dvp = isa_devtab_null; config_isadev(dvp,0); dvp++); | |
200 | #include "sl.h" | |
201 | #if NSL > 0 | |
202 | netmask |= ttymask; | |
203 | ttymask |= netmask; | |
204 | #endif | |
205 | /* biomask |= ttymask ; can some tty devices use buffers? */ | |
206 | /* printf("biomask %x ttymask %x netmask %x\n", biomask, ttymask, netmask); */ | |
207 | splnone(); | |
208 | } | |
209 | ||
210 | /* | |
211 | * Configure an ISA device. | |
212 | */ | |
213 | config_isadev(isdp, mp) | |
214 | struct isa_device *isdp; | |
215 | u_short *mp; | |
216 | { | |
217 | struct isa_driver *dp; | |
218 | ||
219 | if (dp = isdp->id_driver) { | |
220 | if (isdp->id_maddr) { | |
221 | extern u_int atdevbase; | |
222 | ||
223 | isdp->id_maddr -= 0xa0000; | |
224 | isdp->id_maddr += atdevbase; | |
225 | } | |
226 | isdp->id_alive = (*dp->probe)(isdp); | |
227 | if (isdp->id_alive) { | |
228 | printf("%s%d", dp->name, isdp->id_unit); | |
6b9305fd PS |
229 | /* |
230 | * The attach should really be after all the printf's | |
231 | * but until all the drivers are fixed do it here. | |
232 | * There is a comment below that shows where this | |
233 | * really belongs. Rod Grimes 04/10/93 | |
234 | */ | |
ab05af3a | 235 | (*dp->attach)(isdp); |
6b9305fd PS |
236 | printf(" at 0x%x", isdp->id_iobase); |
237 | if ((isdp->id_iobase + isdp->id_alive - 1) != | |
238 | isdp->id_iobase) | |
239 | printf("-0x%x", | |
240 | isdp->id_iobase + isdp->id_alive - 1); | |
241 | printf(" "); | |
242 | if(isdp->id_irq) | |
243 | printf("irq %d ", ffs(isdp->id_irq)-1); | |
244 | if (isdp->id_drq != -1) | |
245 | printf("drq %d ", isdp->id_drq); | |
246 | if (isdp->id_maddr != 0) | |
247 | printf("maddr 0x%x ", kvtop(isdp->id_maddr)); | |
248 | if (isdp->id_msize != 0) | |
249 | printf("msize %d ", isdp->id_msize); | |
250 | if (isdp->id_flags != 0) | |
251 | printf("flags 0x%x ", isdp->id_flags); | |
252 | printf("on isa\n"); | |
253 | ||
254 | /* This is the place the attach should be done! */ | |
ab05af3a WJ |
255 | if(isdp->id_irq) { |
256 | int intrno; | |
257 | ||
258 | intrno = ffs(isdp->id_irq)-1; | |
ab05af3a | 259 | INTREN(isdp->id_irq); |
6b9305fd PS |
260 | if(mp) |
261 | INTRMASK(*mp,isdp->id_irq); | |
ab05af3a WJ |
262 | setidt(ICU_OFFSET+intrno, isdp->id_intr, |
263 | SDT_SYS386IGT, SEL_KPL); | |
264 | } | |
ab05af3a WJ |
265 | } |
266 | return (1); | |
267 | } else return(0); | |
268 | } | |
6b9305fd | 269 | #endif /* (!) notyet */ |
ab05af3a WJ |
270 | |
271 | #define IDTVEC(name) __CONCAT(X,name) | |
272 | /* default interrupt vector table entries */ | |
273 | extern IDTVEC(intr0), IDTVEC(intr1), IDTVEC(intr2), IDTVEC(intr3), | |
274 | IDTVEC(intr4), IDTVEC(intr5), IDTVEC(intr6), IDTVEC(intr7), | |
275 | IDTVEC(intr8), IDTVEC(intr9), IDTVEC(intr10), IDTVEC(intr11), | |
276 | IDTVEC(intr12), IDTVEC(intr13), IDTVEC(intr14), IDTVEC(intr15); | |
277 | ||
278 | static *defvec[16] = { | |
279 | &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3), | |
280 | &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7), | |
281 | &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11), | |
282 | &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15) }; | |
283 | ||
284 | /* out of range default interrupt vector gate entry */ | |
285 | extern IDTVEC(intrdefault); | |
286 | ||
287 | /* | |
288 | * Fill in default interrupt table (in case of spuruious interrupt | |
289 | * during configuration of kernel, setup interrupt control unit | |
290 | */ | |
291 | isa_defaultirq() { | |
292 | int i; | |
293 | ||
294 | /* icu vectors */ | |
295 | for (i = NRSVIDT ; i < NRSVIDT+ICU_LEN ; i++) | |
296 | setidt(i, defvec[i], SDT_SYS386IGT, SEL_KPL); | |
297 | ||
298 | /* out of range vectors */ | |
299 | for (i = NRSVIDT; i < NIDT; i++) | |
300 | setidt(i, &IDTVEC(intrdefault), SDT_SYS386IGT, SEL_KPL); | |
301 | ||
302 | /* clear npx intr latch */ | |
303 | outb(0xf1,0); | |
304 | ||
305 | /* initialize 8259's */ | |
306 | outb(IO_ICU1, 0x11); /* reset; program device, four bytes */ | |
307 | outb(IO_ICU1+1, NRSVIDT); /* starting at this vector index */ | |
308 | outb(IO_ICU1+1, 1<<2); /* slave on line 2 */ | |
309 | outb(IO_ICU1+1, 1); /* 8086 mode */ | |
310 | outb(IO_ICU1+1, 0xff); /* leave interrupts masked */ | |
311 | outb(IO_ICU1, 2); /* default to ISR on read */ | |
312 | ||
313 | outb(IO_ICU2, 0x11); /* reset; program device, four bytes */ | |
314 | outb(IO_ICU2+1, NRSVIDT+8); /* staring at this vector index */ | |
315 | outb(IO_ICU2+1,2); /* my slave id is 2 */ | |
316 | outb(IO_ICU2+1,1); /* 8086 mode */ | |
317 | outb(IO_ICU2+1, 0xff); /* leave interrupts masked */ | |
318 | outb(IO_ICU2, 2); /* default to ISR on read */ | |
319 | } | |
320 | ||
321 | /* region of physical memory known to be contiguous */ | |
322 | vm_offset_t isaphysmem; | |
323 | static caddr_t dma_bounce[8]; /* XXX */ | |
324 | static char bounced[8]; /* XXX */ | |
325 | #define MAXDMASZ 512 /* XXX */ | |
326 | ||
327 | /* high byte of address is stored in this port for i-th dma channel */ | |
328 | static short dmapageport[8] = | |
329 | { 0x87, 0x83, 0x81, 0x82, 0x8f, 0x8b, 0x89, 0x8a }; | |
330 | ||
331 | /* | |
332 | * isa_dmacascade(): program 8237 DMA controller channel to accept | |
333 | * external dma control by a board. | |
334 | */ | |
335 | void isa_dmacascade(unsigned chan) | |
e39f1b2b | 336 | { |
ab05af3a WJ |
337 | if (chan > 7) |
338 | panic("isa_dmacascade: impossible request"); | |
339 | ||
340 | /* set dma channel mode, and set dma channel mode */ | |
e39f1b2b FM |
341 | if ((chan & 4) == 0) { |
342 | outb(DMA1_MODE, DMA37MD_CASCADE | chan); | |
343 | outb(DMA1_SMSK, chan); | |
344 | } else { | |
345 | outb(DMA2_MODE, DMA37MD_CASCADE | (chan & 3)); | |
346 | outb(DMA2_SMSK, chan & 3); | |
347 | } | |
ab05af3a WJ |
348 | } |
349 | ||
350 | /* | |
351 | * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment | |
352 | * problems by using a bounce buffer. | |
353 | */ | |
354 | void isa_dmastart(int flags, caddr_t addr, unsigned nbytes, unsigned chan) | |
355 | { vm_offset_t phys; | |
e39f1b2b | 356 | int waport; |
ab05af3a WJ |
357 | caddr_t newaddr; |
358 | ||
e39f1b2b FM |
359 | if ( chan > 7 |
360 | || (chan < 4 && nbytes > (1<<16)) | |
361 | || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1))) | |
ab05af3a WJ |
362 | panic("isa_dmastart: impossible request"); |
363 | ||
e39f1b2b | 364 | if (isa_dmarangecheck(addr, nbytes, chan)) { |
ab05af3a WJ |
365 | if (dma_bounce[chan] == 0) |
366 | dma_bounce[chan] = | |
367 | /*(caddr_t)malloc(MAXDMASZ, M_TEMP, M_WAITOK);*/ | |
368 | (caddr_t) isaphysmem + NBPG*chan; | |
369 | bounced[chan] = 1; | |
370 | newaddr = dma_bounce[chan]; | |
371 | *(int *) newaddr = 0; /* XXX */ | |
372 | ||
373 | /* copy bounce buffer on write */ | |
374 | if (!(flags & B_READ)) | |
375 | bcopy(addr, newaddr, nbytes); | |
376 | addr = newaddr; | |
377 | } | |
378 | ||
379 | /* translate to physical */ | |
380 | phys = pmap_extract(pmap_kernel(), (vm_offset_t)addr); | |
381 | ||
ab05af3a | 382 | if ((chan & 4) == 0) { |
e39f1b2b FM |
383 | /* |
384 | * Program one of DMA channels 0..3. These are | |
385 | * byte mode channels. | |
386 | */ | |
387 | /* set dma channel mode, and reset address ff */ | |
388 | if (flags & B_READ) | |
389 | outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan); | |
390 | else | |
391 | outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan); | |
392 | outb(DMA1_FFC, 0); | |
393 | ||
394 | /* send start address */ | |
395 | waport = DMA1_CHN(chan); | |
ab05af3a WJ |
396 | outb(waport, phys); |
397 | outb(waport, phys>>8); | |
e39f1b2b | 398 | outb(dmapageport[chan], phys>>16); |
ab05af3a | 399 | |
e39f1b2b | 400 | /* send count */ |
ab05af3a WJ |
401 | outb(waport + 1, --nbytes); |
402 | outb(waport + 1, nbytes>>8); | |
e39f1b2b FM |
403 | |
404 | /* unmask channel */ | |
405 | outb(DMA1_SMSK, chan); | |
ab05af3a | 406 | } else { |
e39f1b2b FM |
407 | /* |
408 | * Program one of DMA channels 4..7. These are | |
409 | * word mode channels. | |
410 | */ | |
411 | /* set dma channel mode, and reset address ff */ | |
412 | if (flags & B_READ) | |
413 | outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|(chan&3)); | |
414 | else | |
415 | outb(DMA2_MODE, DMA37MD_SINGLE|DMA37MD_READ|(chan&3)); | |
416 | outb(DMA2_FFC, 0); | |
417 | ||
418 | /* send start address */ | |
419 | waport = DMA2_CHN(chan - 4); | |
420 | outb(waport, phys>>1); | |
421 | outb(waport, phys>>9); | |
422 | outb(dmapageport[chan], phys>>16); | |
423 | ||
424 | /* send count */ | |
425 | nbytes >>= 1; | |
ab05af3a WJ |
426 | outb(waport + 2, --nbytes); |
427 | outb(waport + 2, nbytes>>8); | |
ab05af3a | 428 | |
e39f1b2b FM |
429 | /* unmask channel */ |
430 | outb(DMA2_SMSK, chan & 3); | |
431 | } | |
ab05af3a WJ |
432 | } |
433 | ||
434 | void isa_dmadone(int flags, caddr_t addr, int nbytes, int chan) | |
435 | { | |
436 | ||
437 | /* copy bounce buffer on read */ | |
438 | /*if ((flags & (B_PHYS|B_READ)) == (B_PHYS|B_READ))*/ | |
439 | if (bounced[chan]) { | |
440 | bcopy(dma_bounce[chan], addr, nbytes); | |
441 | bounced[chan] = 0; | |
442 | } | |
443 | } | |
444 | ||
445 | /* | |
446 | * Check for problems with the address range of a DMA transfer | |
e39f1b2b FM |
447 | * (non-contiguous physical pages, outside of bus address space, |
448 | * crossing DMA page boundaries). | |
ab05af3a WJ |
449 | * Return true if special handling needed. |
450 | */ | |
451 | ||
e39f1b2b FM |
452 | isa_dmarangecheck(caddr_t va, unsigned length, unsigned chan) { |
453 | vm_offset_t phys, priorpage = 0, endva; | |
454 | u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1); | |
ab05af3a WJ |
455 | |
456 | endva = (vm_offset_t)round_page(va + length); | |
457 | for (; va < (caddr_t) endva ; va += NBPG) { | |
458 | phys = trunc_page(pmap_extract(pmap_kernel(), (vm_offset_t)va)); | |
459 | #define ISARAM_END RAM_END | |
460 | if (phys == 0) | |
461 | panic("isa_dmacheck: no physical page present"); | |
462 | if (phys > ISARAM_END) | |
463 | return (1); | |
e39f1b2b FM |
464 | if (priorpage) { |
465 | if (priorpage + NBPG != phys) | |
466 | return (1); | |
467 | /* check if crossing a DMA page boundary */ | |
468 | if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk) | |
469 | return (1); | |
470 | } | |
ab05af3a WJ |
471 | priorpage = phys; |
472 | } | |
473 | return (0); | |
474 | } | |
475 | ||
476 | /* head of queue waiting for physmem to become available */ | |
477 | struct buf isa_physmemq; | |
478 | ||
479 | /* blocked waiting for resource to become free for exclusive use */ | |
480 | static isaphysmemflag; | |
481 | /* if waited for and call requested when free (B_CALL) */ | |
482 | static void (*isaphysmemunblock)(); /* needs to be a list */ | |
483 | ||
484 | /* | |
485 | * Allocate contiguous physical memory for transfer, returning | |
486 | * a *virtual* address to region. May block waiting for resource. | |
487 | * (assumed to be called at splbio()) | |
488 | */ | |
489 | caddr_t | |
490 | isa_allocphysmem(caddr_t va, unsigned length, void (*func)()) { | |
491 | ||
492 | isaphysmemunblock = func; | |
493 | while (isaphysmemflag & B_BUSY) { | |
494 | isaphysmemflag |= B_WANTED; | |
495 | sleep(&isaphysmemflag, PRIBIO); | |
496 | } | |
497 | isaphysmemflag |= B_BUSY; | |
498 | ||
499 | return((caddr_t)isaphysmem); | |
500 | } | |
501 | ||
502 | /* | |
503 | * Free contiguous physical memory used for transfer. | |
504 | * (assumed to be called at splbio()) | |
505 | */ | |
506 | void | |
507 | isa_freephysmem(caddr_t va, unsigned length) { | |
508 | ||
509 | isaphysmemflag &= ~B_BUSY; | |
510 | if (isaphysmemflag & B_WANTED) { | |
511 | isaphysmemflag &= B_WANTED; | |
512 | wakeup(&isaphysmemflag); | |
513 | if (isaphysmemunblock) | |
514 | (*isaphysmemunblock)(); | |
515 | } | |
516 | } | |
517 | ||
518 | /* | |
519 | * Handle a NMI, possibly a machine check. | |
520 | * return true to panic system, false to ignore. | |
521 | */ | |
522 | isa_nmi(cd) { | |
523 | ||
524 | log(LOG_CRIT, "\nNMI port 61 %x, port 70 %x\n", inb(0x61), inb(0x70)); | |
525 | return(0); | |
526 | } | |
527 | ||
528 | /* | |
529 | * Caught a stray interrupt, notify | |
530 | */ | |
531 | isa_strayintr(d) { | |
532 | ||
ab05af3a WJ |
533 | /* DON'T BOTHER FOR NOW! */ |
534 | /* for some reason, we get bursts of intr #7, even if not enabled! */ | |
6b9305fd PS |
535 | /* |
536 | * Well the reason you got bursts of intr #7 is because someone | |
537 | * raised an interrupt line and dropped it before the 8259 could | |
538 | * prioritize it. This is documented in the intel data book. This | |
539 | * means you have BAD hardware! I have changed this so that only | |
540 | * the first 5 get logged, then it quits logging them, and puts | |
541 | * out a special message. rgrimes 3/25/1993 | |
542 | */ | |
543 | extern u_long isa_stray_intrcnt; | |
544 | ||
545 | isa_stray_intrcnt++; | |
546 | if (isa_stray_intrcnt <= 5) | |
547 | log(LOG_ERR,"ISA strayintr %x\n", d); | |
548 | if (isa_stray_intrcnt == 5) | |
549 | log(LOG_CRIT,"Too many ISA strayintr not logging any more\n"); | |
ab05af3a WJ |
550 | } |
551 | ||
552 | /* | |
553 | * Wait "n" microseconds. Relies on timer 0 to have 1Mhz clock, regardless | |
554 | * of processor board speed. Note: timer had better have been programmed | |
555 | * before this is first used! | |
556 | */ | |
557 | DELAY(n) { | |
558 | int tick = getit(0,0) & 1; | |
559 | ||
560 | while (n--) { | |
561 | /* wait approximately 1 micro second */ | |
562 | while (tick == getit(0,0) & 1) ; | |
563 | ||
564 | tick = getit(0,0) & 1; | |
565 | } | |
566 | } | |
567 | ||
568 | getit(unit, timer) { | |
569 | int port = (unit ? IO_TIMER2 : IO_TIMER1) + timer, val; | |
570 | ||
571 | val = inb(port); | |
572 | val = (inb(port) << 8) + val; | |
573 | return (val); | |
574 | } | |
575 | ||
576 | extern int hz; | |
577 | ||
578 | static beeping; | |
579 | static | |
580 | sysbeepstop(f) | |
581 | { | |
582 | /* disable counter 2 */ | |
583 | outb(0x61, inb(0x61) & 0xFC); | |
584 | if (f) | |
585 | timeout(sysbeepstop, 0, f); | |
586 | else | |
587 | beeping = 0; | |
588 | } | |
589 | ||
590 | void sysbeep(int pitch, int period) | |
591 | { | |
592 | ||
593 | outb(0x61, inb(0x61) | 3); /* enable counter 2 */ | |
594 | outb(0x43, 0xb6); /* set command for counter 2, 2 byte write */ | |
595 | ||
596 | outb(0x42, pitch); | |
597 | outb(0x42, (pitch>>8)); | |
598 | ||
599 | if (!beeping) { | |
600 | beeping = period; | |
601 | timeout(sysbeepstop, period/2, period); | |
602 | } | |
603 | } | |
604 | ||
605 | /* | |
606 | * Pass command to keyboard controller (8042) | |
607 | */ | |
608 | unsigned kbc_8042cmd(val) { | |
609 | ||
610 | while (inb(KBSTATP)&KBS_IBF); | |
611 | if (val) outb(KBCMDP, val); | |
612 | while (inb(KBSTATP)&KBS_IBF); | |
613 | return (inb(KBDATAP)); | |
614 | } |