|
|
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.