|
|
1.1 root 1: /*
2: * dg - device driver for Digiboard PC/Xe intelligent multiport controller
3: *
4: * $Header: /usr/src/sys/i8086/drv/RCS/dg.c,v 1.3 91/03/05 12:23:42 root Exp $
5: *
6: * $Log: /usr/src/sys/i8086/drv/RCS/dg.c,v $
7: * Revision 1.3 91/03/05 12:23:42 root
8: * Fix cast on dg_ram_base
9: *
10: */
11:
12: /*
13: * Various notes:
14: *
15: * FEP = front-end-processor (the 80186 on the Digiboard)
16: *
17: * At port DG_IOB:
18: * the 2's bit is 1 to enable DPRAM, 0 to disable
19: * the 4's bit is 1 to reset FEP, 0 to clear reset
20: *
21: * There is a bug in the current ldlib.a version of setivec and clrivec:
22: * they only work during xxload() and xxunload() due to use of "ucs"
23: * instead of "getcs()" to determine the CS for the interrupt routine.
24: */
25:
26: /*
27: * Definitions.
28: *
29: */
30: #define DG_RAM_LENGTH 0x10000L
31: #define DG_MEMORY_SEG 0xF000 /* dual-port ram base on FEP side */
32: #define DG_BIOS_ADDR 0xF800
33: #define DG_FEPOS_ADDR 0x2000
34: #define DG_BIOS_LOADER 0x80 /* minor number to write to BIOS */
35: #define DG_FEPOS_LOADER 0x40 /* minor number to write to FEPOS */
36: #define DG_BIOS_LENGTH 0x800 /* PC/Xe BIOS is 2k bytes */
37: #define DG_BIOS_CONFIRM 0x0C00 /* look for "GD" here */
38: #define DG_FEP_CONFIRM 0x0D20 /* look for "OS" here */
39: #define DG_BIOS_REQ 0x0C40 /* Start FEP BIOS requests here */
40: #define BIOS_GOOD ('G' + ('D'<<8)) /* "GD" */
41: #define FEPOS_GOOD ('O' + ('S'<<8)) /* "OS" */
42:
43: #define CSTART 0x400 /* start addr of command queue */
44: #define NPORT 0x0C22 /* addr of # of ports */
45: #define CIN 0x0D10 /* addr for command in pointer */
46: #define COUT 0x0D12 /* addr for command out pointer */
47: #define ISTART 0x800 /* start addr of event queue */
48: #define EIN 0x0D18 /* addr for event in pointer */
49: #define EOUT 0x0D1A /* addr for event out pointer */
50: #define INTERVAL 0x0E04 /* addr for ticks between irpts */
51: #define EVENT_LEN 4 /* bytes per FEP event */
52: #define COMMAND_LEN 4 /* bytes per FEP command */
53:
54: /*
55: * Includes.
56: */
57: #include "coherent.h"
58: #include <sys/io.h> /* IO */
59: #include <sys/sched.h> /* [CIS]VPAUSE */
60: #include <sys/uproc.h> /* u.u_error */
61: #include <sys/proc.h> /* wakeup();
62: includes sys/types.h - faddr_t, paddr_t
63: and sys/timeout.h - TIM
64: needs coherent.h for KERNEL */
65: #include <sys/con.h> /* CON */
66: #include <sys/stat.h> /* minor(dev) */
67: #include <devices.h> /* device major numbers, including PE_MAJOR */
68: #include <errno.h>
69:
70: /*
71: * Export Functions.
72: */
73:
74: /*
75: * Export variables - these may be patched in order to configure the driver.
76: */
77: long DG_RAM = 0xF0000L; /* segment for 64k of dual-port RAM */
78: int DG_IOB = 0x200; /* address of i/o byte for controller */
79: int DG_INT = 15; /* IRQ number for board's interrupt */
80:
81: /*
82: * Import Functions
83: */
84: int nulldev();
85: int nonedev();
86:
87: /*
88: * Local functions.
89: */
90: static dgload();
91: static dgunload();
92: static dgopen();
93: static dgclose();
94: static dgread();
95: static dgwrite();
96: static void dgdelay();
97: static dg_start_timing();
98: static dg_stop_timing();
99: static int dginit2();
100: static int dginit3();
101: static void dgintr();
102:
103: /*
104: * Local variables.
105: */
106: static faddr_t dg_ram_fp; /* (far *) to access screen */
107: static paddr_t dg_ram_base; /* physical address of screen base */
108: static TIM delay_tim; /* needed for calls to timeout() */
109: static TIM timeout_tim; /* needed for calls to timeout() */
110: static int dg_expired; /* TRUE after local timeout */
111: static int bios_loading; /* TRUE if minor device for BIOS load open */
112: static int fepos_loading; /* TRUE if minor device for FEPOS load open */
113: static int load_byte_ct; /* place-holder for BIOS/FEPOS load */
114: static int board_ready; /* TRUE when all board initialization done */
115: static int dg_bios_wait; /* TRUE if waiting for BIOS to be loaded */
116: static int dg_fepos_wait; /* TRUE if waiting for FEPOS to be loaded */
117: static int nport; /* number of ports on the Digiboard */
118: static int test_irq; /* TRUE during startup */
119:
120: /*
121: * Configuration table - another export variable.
122: */
123: CON dgcon ={
124: DFCHR, /* Flags */
125: PE_MAJOR, /* Major index */
126: dgopen, /* Open */
127: dgclose, /* Close */
128: nulldev, /* Block */
129: dgread, /* Read */
130: dgwrite, /* Write */
131: nulldev, /* Ioctl */
132: nulldev, /* Powerfail */
133: nulldev, /* Timeout */
134: dgload, /* Load */
135: dgunload, /* Unload */
136: nulldev /* Poll */
137: };
138:
139: /*
140: * Load Routine.
141: */
142: static dgload()
143: {
144: char v;
145:
146: setivec(DG_INT, dgintr);
147: /*
148: * Allocate a selector to map onto the dual-port RAM. ptov() will
149: * return the first available selector of the 8,192 possible.
150: */
151: dg_ram_base = (paddr_t)((long)(unsigned)DG_RAM << 4);
152: dg_ram_fp = ptov(dg_ram_base, (fsize_t)DG_RAM_LENGTH);
153:
154: /*
155: * Reset the board and wait.
156: * Actual delay is a tick = 0.01 sec; only need 1msec.
157: */
158: outb(DG_IOB, 0x04);
159: dgdelay(1);
160:
161: /*
162: * Read board ID.
163: */
164: v = inb(DG_IOB);
165: if ((v & 0x01) == 0x01) {
166: printf("Error - board type is PC/Xi\n");
167: return;
168: } else {
169: outb(DG_IOB, 0x05); /* hold FEP reset */
170: v = inb(DG_IOB);
171: if ((v & 0x01) == 0x01) {
172: printf("Error - board type is PC/Xm\n");
173: return;
174: } else
175: printf("PC/Xe ID found\n");
176: }
177:
178: /*
179: * Board Reset.
180: */
181: outb(DG_IOB, 0x04); /* reset board */
182: dg_start_timing(100); /* start 1-second timer */
183: while ((inb(DG_IOB) & 0x0E) != 0x04) {
184: if (dg_expired) {
185: printf("Error - PC/Xe failed to reset\n");
186: return;
187: }
188: dgdelay(10);
189: }
190: outb(DG_IOB, 0x06); /* enable memory */
191: printf("PC/Xe passed reset\n");
192:
193: /*
194: * Minimal test of PC/Xe's 64k of dual-ported RAM.
195: */
196: sfword(dg_ram_fp, 0xA55A); /* store a "far" word */
197: sfword(dg_ram_fp + 2, 0x3CC3);
198: sfword(dg_ram_fp + 0xFFFC, 0xA55A);
199: sfword(dg_ram_fp + 0xFFFE, 0x3CC3);
200: if (ffword(dg_ram_fp) != 0xA55A /* fetch a "far" word */
201: || ffword(dg_ram_fp + 2) != 0x3CC3
202: || ffword(dg_ram_fp + 0xFFFC) != 0xA55A
203: || ffword(dg_ram_fp + 0xFFFE) != 0x3CC3) {
204: printf("Error - PC/Xe failed memory test\n");
205: return;
206: } else
207: printf("PC/Xe passed memory test\n");
208:
209: /*
210: * Load and execute the PC/Xe BIOS
211: */
212: outb(DG_IOB, 0x06); /* enable memory */
213: dg_bios_wait = 1;
214: printf("PC/Xe waiting for BIOS load\n");
215: }
216:
217: static dgunload()
218: {
219: if (board_ready) {
220: board_ready = 0;
221: }
222:
223: /*
224: * Turn off and unhook interrupts from FEPOS
225: */
226: sfword(dg_ram_fp+INTERVAL, 0); /* stop host interrupts */
227: outb(DG_IOB, 0x04); /* Disable DPRAM and hold FEP reset */
228: clrivec(DG_INT);
229:
230: /*
231: * We have to free up the selector now that we're done using it.
232: */
233: vrelse(dg_ram_fp);
234: }
235:
236: /*
237: * Open Routine.
238: */
239: static dgopen( dev, mode )
240: dev_t dev;
241: {
242: /*
243: * If minor number has 128's bit set to 1, this is an attempt to
244: * transfer the BIOS to the FEP.
245: */
246: if (minor(dev) & DG_BIOS_LOADER) {
247: if (bios_loading) {
248: u.u_error = EDBUSY;
249: return;
250: } else {
251: /*
252: * Only allow BIOS xfer if we are waiting for it.
253: */
254: if (dg_bios_wait) {
255: bios_loading = 1;
256: load_byte_ct = 0;
257: } else {
258: u.u_error = EIO;
259: return;
260: }
261: }
262: /*
263: * If minor number has 64's bit set to 1, this is an attempt to
264: * transfer the FEPOS to the FEP.
265: */
266: } else if (minor(dev) & DG_FEPOS_LOADER) {
267: if (fepos_loading) {
268: u.u_error = EDBUSY;
269: return;
270: } else {
271: /*
272: * Only allow FEPOS xfer if we are waiting for it.
273: */
274: if (dg_fepos_wait) {
275: fepos_loading = 1;
276: load_byte_ct = 0;
277: } else {
278: u.u_error = EIO;
279: return;
280: }
281: }
282: } else {
283: }
284: }
285:
286: /*
287: * Close Routine.
288: */
289: static dgclose( dev )
290: dev_t dev;
291: {
292: /*
293: * If minor number has 128's bit set to 1, this is an attempt to
294: * transfer the BIOS to the FEP.
295: */
296: if (minor(dev) & DG_BIOS_LOADER) {
297: bios_loading = 0;
298: /*
299: * Only set dg_fepos_wait if enough bytes got written.
300: */
301: if (load_byte_ct == DG_BIOS_LENGTH) {
302: /*
303: * After BIOS is xferred, try to finish
304: * PC/Xe initialization.
305: */
306: if (dginit2()) {
307: dg_bios_wait = 0;
308: dg_fepos_wait = 1;
309: printf("PC/Xe waiting for FEPOS load\n");
310: }
311: }
312: /*
313: * If minor number has 64's bit set to 1, this is an attempt to
314: * transfer the FEPOS to the FEP.
315: */
316: } else if (minor(dev) & DG_FEPOS_LOADER) {
317: fepos_loading = 0;
318: /*
319: * After BIOS is xferred, try to finish
320: * PC/Xe initialization.
321: */
322: if (dginit3()) {
323: dg_fepos_wait = 0;
324: board_ready = 1;
325: printf("PC/Xe ready for use\n");
326: }
327: } else {
328: }
329: }
330:
331: /*
332: * Read Routine.
333: */
334: static dgread( dev, iop )
335: dev_t dev;
336: register IO * iop;
337: {
338: #if 0
339: static int offset;
340: int c;
341: /*
342: * Read a character code from video RAM
343: * Start reading RAM just after where previous read ended
344: *
345: * Note that "offset" is the value of the displacement into
346: * the screen RAM. Any expression which results in a value
347: * which is less than DG_RAM_LENGTH is OK here.
348: */
349: while(iop->io_ioc) {
350: c = ffbyte(dg_ram_fp + offset); /* fetch a "far" byte */
351: if(ioputc(c, iop) == -1)
352: break;
353: offset += 2;
354: offset %= DG_RAM_LENGTH;
355: }
356: #endif
357: }
358:
359: /*
360: * Write Routine.
361: */
362: static dgwrite( dev, iop )
363: dev_t dev;
364: register IO * iop;
365: {
366: /*
367: * If minor number has 128's bit set to 1, this is an attempt to
368: * transfer the BIOS to the FEP.
369: */
370: if (minor(dev) & DG_BIOS_LOADER) {
371: int c;
372:
373: while ((c = iogetc(iop)) >= 0 && load_byte_ct < DG_BIOS_LENGTH) {
374: sfbyte(dg_ram_fp + DG_BIOS_ADDR + load_byte_ct, c);
375: load_byte_ct++;
376: }
377: /*
378: * If minor number has 64's bit set to 1, this is an attempt to
379: * transfer the FEPOS to the FEP.
380: */
381: } else if (minor(dev) & DG_FEPOS_LOADER) {
382: int c;
383:
384: while ((c = iogetc(iop)) >= 0) {
385: sfbyte(dg_ram_fp + DG_FEPOS_ADDR + load_byte_ct, c);
386: load_byte_ct++;
387: }
388: } else {
389: }
390: }
391:
392: /*
393: * Delay for some number of clock ticks.
394: * 286/386 kernel ticks are at 100Hz
395: * Use kernel function sleep(), which is NOT the system call by that name.
396: */
397: static void dgdelay(ticks)
398: int ticks;
399: {
400: timeout(&delay_tim, ticks, wakeup, (int)&delay_tim);
401: sleep((char *)&delay_tim, CVPAUSE, IVPAUSE, SVPAUSE);
402: }
403:
404: /*
405: * Start a timeout for some number of ticks.
406: * Caller knows timer has expired when "dg_expired" goes to 1.
407: *
408: * Sample invocation:
409: * dg_start_timing(n);
410: * while (check for desired event fails) {
411: * if (dg_expired) {
412: * ...failure stuff..
413: * break;
414: * }
415: * dgdelay(m); <= needed to allow kernel to update timers
416: * }
417: */
418: static dg_start_timing(ticks)
419: int ticks;
420: {
421: dg_expired = 0;
422: timeout(&timeout_tim, ticks, dg_stop_timing, 1);
423: }
424:
425: /*
426: * Stub function called only by dg_start_timing()
427: */
428: static dg_stop_timing(flagval)
429: int flagval;
430: {
431: dg_expired = flagval;
432: }
433:
434: /*
435: * Second part of PC/Xe initialization - done after the BIOS has been
436: * written to dual-ported RAM.
437: */
438: static int dginit2()
439: {
440: /*
441: * Execute FEP BIOS
442: */
443: sfword(dg_ram_fp + DG_BIOS_CONFIRM, 0); /* clear confirm word */
444: outb(DG_IOB, 0x02); /* Release reset */
445: dg_start_timing(1000); /* start 10-second timer */
446:
447: while (ffword(dg_ram_fp + DG_BIOS_CONFIRM) != BIOS_GOOD) {
448: if (dg_expired) {
449: printf("Error - PC/Xe BIOS won't start\n");
450: return 0;
451: }
452: dgdelay(10);
453: }
454: printf("PC/Xe BIOS started\n");
455:
456: return 1;
457: }
458:
459: /*
460: * Third part of PC/Xe initialization - done after the FEPOS has been
461: * written to dual-ported RAM.
462: */
463: static int dginit3()
464: {
465: int cmd;
466:
467: /*
468: * Ask FEP BIOS to move FEPOS into host memory.
469: */
470: sfword(dg_ram_fp + DG_BIOS_REQ, 0x0002);
471: sfword(dg_ram_fp + DG_BIOS_REQ+2, DG_MEMORY_SEG+0x200);
472: sfword(dg_ram_fp + DG_BIOS_REQ+4, 0x0000);
473: sfword(dg_ram_fp + DG_BIOS_REQ+6, 0x0200);
474: sfword(dg_ram_fp + DG_BIOS_REQ+8, 0x0000);
475: sfword(dg_ram_fp + DG_BIOS_REQ+0xA, 0x2000);
476: outb(DG_IOB, 0x0A); /* Toggle interrupt */
477: outb(DG_IOB, 0x02);
478: dg_start_timing(100); /* start 1-second timer */
479: while (ffword(dg_ram_fp + DG_BIOS_REQ) != 0) {
480: if (dg_expired) {
481: printf("Error - PC/Xe FEPOS move failed\n");
482: return;
483: }
484: dgdelay(10);
485: }
486: printf("PC/Xe FEPOS relocated to host RAM\n");
487:
488: /*
489: * Execute FEPOS
490: */
491: sfword(dg_ram_fp + DG_BIOS_REQ, 0x0001);
492: sfword(dg_ram_fp + DG_BIOS_REQ+2, 0x0200);
493: sfword(dg_ram_fp + DG_BIOS_REQ+4, 0x0004);
494: sfword(dg_ram_fp + DG_FEP_CONFIRM, 0); /* clear confirm word */
495: outb(DG_IOB, 0x0A); /* Toggle interrupt */
496: outb(DG_IOB, 0x02);
497: dg_start_timing(500); /* start 5-second timer */
498: while (ffword(dg_ram_fp + DG_FEP_CONFIRM) != FEPOS_GOOD) {
499: if (dg_expired) {
500: printf("Error - PC/Xe FEPOS won't start\n");
501: printf("Failure code (%x)\n",
502: ffword(dg_ram_fp + DG_BIOS_REQ));
503: return 0;
504: }
505: dgdelay(10);
506: }
507: printf("PC/Xe FEPOS started\n");
508: nport = ffbyte(dg_ram_fp+NPORT);
509:
510: /*
511: * Enable and test interrupts from FEP
512: */
513: sfword(dg_ram_fp+INTERVAL, 1); /* request host interrupts */
514: cmd = ffword(dg_ram_fp+CIN); /* get command pointer */
515: sfword(dg_ram_fp+CSTART+cmd, 0xA1FF); /* send an invalid command */
516: sfword(dg_ram_fp+CSTART+cmd+2, 0xC3B2);
517: sfword(dg_ram_fp+CIN, (cmd+4)&0x3ff); /* update command pointer */
518: dg_start_timing(100); /* start 1-second timer */
519: test_irq = 1;
520: while (test_irq) {
521: if (dg_expired) {
522: printf("Error - PC/Xe no FEPOS interrupts\n");
523: return 0;
524: }
525: dgdelay(10);
526: }
527: printf("PC/Xe interrupts working\n");
528:
529: return 1;
530: }
531:
532: /*
533: * Interrupt handler.
534: *
535: * No specific action is needed to clear the interrupt
536: * as it was a pulse sent from the FEPOS to host's IRQ line.
537: */
538: static void dgintr()
539: {
540: int cin, cout, ein, eout;
541: unsigned char event[EVENT_LEN];
542: int i;
543:
544: cin = ffword(dg_ram_fp+CIN);
545: cout = ffword(dg_ram_fp+COUT);
546: ein = ffword(dg_ram_fp+EIN);
547: eout = ffword(dg_ram_fp+EOUT);
548:
549: if (board_ready) {
550: /*
551: * Remove all packets from event queue.
552: */
553: while (ffword(dg_ram_fp+EIN) != ffword(dg_ram_fp+EOUT)) {
554: eout = ffword(dg_ram_fp+EOUT);
555: for (i = 0; i < EVENT_LEN; i++)
556: event[i] = ffbyte(dg_ram_fp+ISTART+eout+i);
557: printf("%x %x %x %x\n", event[0],event[1],event[2],event[3]);
558: sfword(dg_ram_fp+EOUT, (eout+4)&0x3ff);
559: }
560: } else { /* e.g., if test_irq is TRUE */
561: test_irq = 0;
562: /*
563: * Attempt to clear the IRQ condition in the FEP.
564: */
565: sfword(dg_ram_fp+EOUT, ffword(dg_ram_fp+EIN));
566: }
567: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.