home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / vax / stand / qdcons.c next >
Encoding:
C/C++ Source or Header  |  1991-05-09  |  32.9 KB  |  1,266 lines

  1. /*
  2.  * Copyright (c) 1988 Regents of the University of California.
  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 product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  *    @(#)qdcons.c    7.5 (Berkeley) 12/16/90
  34.  */
  35.  
  36. /*
  37.  *    derived from: @(#)qdcons.c  4.1 (ULTRIX    11/23/87
  38.  */
  39.  
  40. /************************************************************************
  41. *
  42. *    ULTRIX QDSS STANDALONE BOOT DEVICE DRIVER...
  43. *    device driver to boot system with QDSS as console
  44. *
  45. *************************************************************************/
  46. /************************************************************************
  47. *                                    *
  48. *            Copyright (c) 1985 by                *
  49. *        Digital Equipment Corporation, Maynard, MA        *
  50. *            All rights reserved.                *
  51. *                                    *
  52. *   This software is furnished under a license and may be used and    *
  53. *   copied  only  in accordance with the terms of such license and    *
  54. *   with the  inclusion  of  the  above  copyright  notice.   This    *
  55. *   software  or  any  other copies thereof may not be provided or    *
  56. *   otherwise made available to any other person.  No title to and    *
  57. *   ownership of the software is hereby transferred.            *
  58. *                                    *
  59. *   The information in this software is subject to change  without    *
  60. *   notice  and should not be construed as a commitment by Digital    *
  61. *   Equipment Corporation.                        *
  62. *                                    *
  63. *   Digital assumes no responsibility for the use  or  reliability    *
  64. *   of its software on equipment which is not supplied by Digital.    *
  65. *                                    *
  66. *************************************************************************
  67. * revision history: (should be moved into sccs comments)
  68. *************************************************************************
  69. *
  70. * 09 oct 85  longo  added uVAXII console ROM cursor reset to bottom of
  71. *            the screen.  Also spruced up qdputc() & scroll_up()
  72. * 02 oct 85  longo  changed references to ADDRESS to be ADDRESS_COMPLETE
  73. * 23 aug 85  longo  changed I/O page CSR address to be 0x1F00
  74. * 20 aug 85  longo  created
  75. *
  76. ************************************************************************/
  77.  
  78. #include "sys/types.h"
  79. #include "../include/cpu.h"
  80. #define KERNEL
  81. #include "../uba/qdioctl.h"
  82. #include "../uba/qevent.h"
  83. #include "../uba/qduser.h"
  84. #include "../uba/qdreg.h"
  85. #undef KERNEL
  86.  
  87. /*-----------------------------------------------------------------------
  88. * constants used to set VAX ROM's cursor to bottom the of the screen  */
  89.  
  90. #define NVR_ADRS    0x200B8024
  91.  
  92. #define CURRENT_ROW    0x4C    /* these are offsets to the ROM's scratch.. */
  93. #define ROW_MIN        0x4D    /* ..RAM start adrs as picked up out of NVR */
  94. #define ROW_MAX        0x4E
  95. #define CURRENT_COL    0x50
  96. #define COL_MIN        0x51
  97. #define COL_MAX        0x52
  98.  
  99. /*----------------------------------------
  100. * LK201 keyboard state tracking struct */
  101.  
  102.     struct q_keyboard {
  103.  
  104.         int shift;            /* state variables    */
  105.         int cntrl;
  106.         int lock;
  107.         char last;            /* last character    */
  108.  
  109.      } q_keyboard;
  110.  
  111.     int qdputc(), qdgetc();
  112.  
  113.     extern (*v_putc)(),(*v_getc)();
  114.  
  115. /*----------------------------
  116. * general purpose defines  */
  117.  
  118. #define BAD    -1
  119. #define GOOD    0
  120.  
  121. /*----------------------------------------------
  122. * console cursor bitmap (block cursor type)  */
  123.  
  124.     short cons_cursor[32] = {      /* white block cursor */
  125.  
  126.  /* A */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
  127.       0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
  128.  /* B */ 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF,
  129.          0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF, 0x00FF
  130.  
  131.     };
  132.  
  133. /*-------------------------------------
  134. * constants used in font operations */
  135.  
  136. #define CHARS        95            /* # of chars in the font */
  137. #define CHAR_HEIGHT    15            /* char height in pixels */
  138. #define CHAR_WIDTH    8            /* char width in pixels*/
  139. #define FONT_WIDTH    (CHAR_WIDTH * CHARS)    /* font width in pixels */
  140. #define ROWS          CHAR_HEIGHT
  141.  
  142. #define FONT_X        0            /* font's off screen adrs */
  143. #define FONT_Y        (2047 - CHAR_HEIGHT) 
  144. /*
  145. #define FONT_Y        200
  146. */
  147.  
  148.     extern char q_font[];        /* reference font object code */
  149.  
  150.     extern  char q_key[];        /* reference key xlation tables */
  151.     extern  char q_shift_key[];
  152.     extern  char *q_special[];
  153.  
  154. /*----------------------------
  155. * console cursor structure */
  156.  
  157.     struct cons_cur {
  158.         int x;
  159.         int y;
  160.     } cursor;
  161.  
  162. /*------------------------------------------
  163. * MicroVAX-II q-bus addressing constants */
  164.  
  165. #define QMEMBASE 0x30000000
  166. #define QDSSCSR  0x20001F00
  167.  
  168. #define CHUNK     (64 * 1024)
  169. #define QMEMSIZE  (1024 * 1024 * 4)
  170. #define    QDBASE    (QMEMBASE + QMEMSIZE - CHUNK)
  171.  
  172. /*------------------------------------------------------------------
  173. * QDSS register address offsets from start of QDSS address space */
  174.  
  175. #define QDSIZE      (52 * 1024)    /* size of entire QDSS foot print */
  176.  
  177. #define TMPSIZE  (16 * 1024)    /* template RAM is 8k SHORT WORDS */
  178. #define TMPSTART 0x8000        /* offset of template RAM from base adrs */
  179.  
  180. #define REGSIZE     (5 * 512)    /* regs touch 2.5k (5 pages) of addr space */
  181. #define REGSTART 0xC000        /* offset of reg pages from base adrs */
  182.  
  183. #define ADDER    (REGSTART+0x000)
  184. #define DGA    (REGSTART+0x200)
  185. #define DUART    (REGSTART+0x400)
  186. #define MEMCSR  (REGSTART+0x800)
  187.  
  188. #define    CLRSIZE  (3 * 512)        /* color map size */
  189. #define CLRSTART (REGSTART+0xA00)    /* color map start offset from base */
  190.                     /*  0x0C00 really */
  191. #define RED    (CLRSTART+0x000)
  192. #define BLUE    (CLRSTART+0x200)
  193. #define GREEN    (CLRSTART+0x400)
  194.  
  195. /*---------------------------------------
  196. * QDSS register address map structure */
  197.  
  198.     struct qdmap qdmap;
  199.  
  200. /************************************************************************
  201. *************************************************************************
  202. *************************************************************************
  203. *
  204. *    EXTERNALLY CALLED ROUTINES START HERE:
  205. *
  206. *************************************************************************
  207. *************************************************************************
  208. ************************************************************************/
  209.  
  210. /************************************************************************
  211. *
  212. *    qd_init()... init the QDSS into a physical memory system
  213. *
  214. ************************************************************************/
  215.  
  216. qd_init()
  217. {
  218.     register char *ROM_console;
  219.     register short *NVR;
  220.     register int i;
  221.  
  222.     caddr_t qdaddr;
  223.     struct dga *dga;
  224.     extern int cpu;
  225.  
  226.      qdaddr = (caddr_t) QDSSCSR;
  227.         if (badaddr(qdaddr, sizeof(short)))
  228.             return(0);
  229.  
  230.     *(short *)qdaddr = (short) (QDBASE >> 16);
  231.  
  232. /*----------------------------------------------------------------------
  233. * load qdmap struct with the physical addresses of the QDSS elements */
  234.  
  235.     qdmap.template = (caddr_t) QDBASE + TMPSTART;
  236.     qdmap.adder = (caddr_t) QDBASE + ADDER;
  237.     qdmap.dga = (caddr_t) QDBASE + DGA;
  238.     qdmap.duart = (caddr_t) QDBASE + DUART;
  239.     qdmap.memcsr = (caddr_t) QDBASE + MEMCSR;
  240.     qdmap.red = (caddr_t) QDBASE + RED;
  241.     qdmap.blue = (caddr_t) QDBASE + BLUE;
  242.     qdmap.green = (caddr_t) QDBASE + GREEN;
  243.  
  244. /*--------------------------
  245. * no interrupts allowed! */
  246.  
  247.     dga = (struct dga *) qdmap.dga;
  248.     dga->csr = HALT;
  249.     dga->csr |= CURS_ENB;
  250.  
  251. /*----------------------------
  252. * init the default values  */
  253.  
  254.     q_keyboard.shift = 0;        /* init keyboard state tracking */
  255.     q_keyboard.lock = 0;
  256.     q_keyboard.cntrl = 0;
  257.     q_keyboard.last = 0;
  258.  
  259.     cursor.x = 0;            /* init cursor to top left */
  260.     cursor.y = 0;
  261.  
  262.     set_defaults();                /* setup the default device */
  263.     ldfont();            /* PtoB the font into off-screen */
  264.  
  265. /*--------------------------------------------------------------------
  266. * tell the VAX ROM that the cursor is at the bottom of the screen  */
  267.  
  268.     if (cpu == VAX_630) {
  269.         NVR = (short *) NVR_ADRS;
  270.  
  271.         i = *NVR++ & 0xFF;
  272.         i |= (*NVR++ & 0xFF) << 8;
  273.         i |= (*NVR++ & 0xFF) << 16;
  274.         i |= (*NVR++ & 0xFF) << 24;
  275.  
  276.         ROM_console = (char *) i;
  277.  
  278.         ROM_console[CURRENT_COL] = ROM_console[COL_MIN];
  279.         ROM_console[CURRENT_ROW] = ROM_console[ROW_MAX];
  280.     }
  281.  
  282. /*----------------------------------------------------------
  283. * smash system virtual console service routine addresses */
  284.  
  285.     printf("switching console to QDSS display...\n");
  286.     v_getc = qdgetc;
  287.     v_putc = qdputc;
  288.  
  289.     return(1);
  290.  
  291. } /* qd_init */
  292.  
  293. /******************************************************************* 
  294. *
  295. *    qdputc()... output a character to the QDSS screen
  296. *
  297. ********************************************************************
  298. *
  299. *    calling convention:
  300. *
  301. *        qdputc(chr);
  302. *        char chr;         ;character to be displayed
  303. *
  304. ********/
  305.  
  306. qdputc(chr)
  307. char chr;
  308. {
  309.     register struct adder *adder;
  310.     register struct dga *dga;
  311.     register int i;
  312.  
  313.     short x;
  314.  
  315.     adder = (struct adder *) qdmap.adder;
  316.     dga = (struct dga *) qdmap.dga;
  317.  
  318. /*---------------------------
  319. * non display character?  */
  320.  
  321.     chr &= 0x7F;
  322.  
  323.     switch (chr) {
  324.  
  325.         case '\r':            /* return char */
  326.             cursor.x = 0;
  327.         dga->x_cursor = TRANX(cursor.x);
  328.             return(0);
  329.  
  330.         case '\t':            /* tab char */
  331.  
  332.             for (i = 8 - ((cursor.x >> 3) & 0x07); i > 0; --i) {
  333.                 qdputc(' ');
  334.         }
  335.         return(0);
  336.  
  337.         case '\n':            /* line feed char */
  338.  
  339.             if ((cursor.y += CHAR_HEIGHT) > (863 - CHAR_HEIGHT)) {
  340.             cursor.y -= CHAR_HEIGHT;
  341.             scroll_up(adder);
  342.         }
  343.         dga->y_cursor = TRANY(cursor.y);
  344.         return(0);
  345.  
  346.         case '\b':            /* backspace char */
  347.             if (cursor.x > 0) {
  348.                 cursor.x -= CHAR_WIDTH;
  349.             qdputc(' ');
  350.             cursor.x -= CHAR_WIDTH;
  351.             dga->x_cursor = TRANX(cursor.x);
  352.         }
  353.         return(0);
  354.  
  355.         default:
  356.         if (chr < ' ' || chr > '~') {
  357.             return(0);
  358.         }
  359.     }
  360.  
  361. /*------------------------------------------
  362. * setup VIPER operand control registers  */
  363.  
  364.     write_ID(adder, CS_UPDATE_MASK, 0x0001);  /* select plane #0 */
  365.     write_ID(adder, SRC1_OCR_B, 
  366.             EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
  367.  
  368.     write_ID(adder, CS_UPDATE_MASK, 0x00FE);  /* select other planes */
  369.     write_ID(adder, SRC1_OCR_B, 
  370.             EXT_SOURCE | INT_NONE | NO_ID | BAR_SHIFT_DELAY);
  371.  
  372.     write_ID(adder, CS_UPDATE_MASK, 0x00FF);  /* select all planes */
  373.     write_ID(adder, DST_OCR_B, 
  374.             EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
  375.  
  376.     write_ID(adder, MASK_1, 0xFFFF);
  377.     write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 1);
  378.     write_ID(adder, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
  379.  
  380. /*----------------------------------------
  381. * load DESTINATION origin and vectors  */
  382.  
  383.     adder->fast_dest_dy = 0;
  384.     adder->slow_dest_dx = 0;
  385.     adder->error_1 = 0;
  386.     adder->error_2 = 0;
  387.  
  388.     adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
  389.  
  390.     wait_status(adder, RASTEROP_COMPLETE);
  391.  
  392.     adder->destination_x = cursor.x;
  393.     adder->fast_dest_dx = CHAR_WIDTH;
  394.  
  395.     adder->destination_y = cursor.y;
  396.     adder->slow_dest_dy = CHAR_HEIGHT;
  397.  
  398. /*-----------------------------------
  399. * load SOURCE origin and vectors  */
  400.  
  401.     adder->source_1_x = FONT_X + ((chr - ' ') * CHAR_WIDTH);
  402.     adder->source_1_y = FONT_Y;
  403.  
  404.     adder->source_1_dx = CHAR_WIDTH;
  405.     adder->source_1_dy = CHAR_HEIGHT;
  406.  
  407.     write_ID(adder, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE);
  408.     adder->cmd = RASTEROP | OCRB | 0 | S1E | DTE;
  409.  
  410. /*-------------------------------------
  411. * update console cursor coordinates */
  412.  
  413.     cursor.x += CHAR_WIDTH;
  414.     dga->x_cursor = TRANX(cursor.x);
  415.  
  416.         if (cursor.x > (1024 - CHAR_WIDTH)) {
  417.         qdputc('\r');
  418.         qdputc('\n');
  419.     }
  420.  
  421. } /* qdputc */ 
  422.  
  423. /******************************************************************* 
  424. *
  425. *    qdgetc()... get a character from the LK201
  426. *
  427. *******************************************************************/
  428.  
  429. qdgetc()
  430. {
  431.     register short key;
  432.     register char chr;
  433.     register struct duart *duart;
  434.  
  435.     u_int status;
  436.  
  437.     duart = (struct duart *) qdmap.duart;
  438.  
  439.     /*--------------------------------------
  440.     * Get a character from the keyboard. */
  441.  
  442. LOOP:
  443.     while (!((status = duart->statusA) & RCV_RDY))
  444.             ;
  445.  
  446.     key = duart->dataA;
  447.     key &= 0xFF;
  448.  
  449.     /*--------------------------------------
  450.     * Check for various keyboard errors  */
  451.  
  452.     if( key == LK_POWER_ERROR || key == LK_KDOWN_ERROR ||
  453.         key == LK_INPUT_ERROR || key == LK_OUTPUT_ERROR) {
  454.         printf("Keyboard error, code = %x\n", key);
  455.         return(0);
  456.     }
  457.  
  458.     if (key < LK_LOWEST) 
  459.         return(0);
  460.  
  461.     /*---------------------------------
  462.     * See if its a state change key */
  463.  
  464.     switch (key) {
  465.  
  466.         case LOCK:
  467.         q_keyboard.lock ^= 0xffff;    /* toggle */
  468.         if (q_keyboard.lock)
  469.             led_control(LK_LED_ENABLE, LK_LED_LOCK);
  470.         else
  471.             led_control(LK_LED_DISABLE, LK_LED_LOCK);
  472.         goto LOOP;
  473.  
  474.         case SHIFT:
  475.         q_keyboard.shift ^= 0xFFFF;
  476.         goto LOOP;
  477.  
  478.         case CNTRL:
  479.         q_keyboard.cntrl ^= 0xFFFF;
  480.         goto LOOP;
  481.  
  482.         case ALLUP:
  483.         q_keyboard.cntrl = 0;
  484.         q_keyboard.shift = 0;
  485.         goto LOOP;
  486.  
  487.         case REPEAT:
  488.         chr = q_keyboard.last;
  489.         break;
  490.  
  491.         /*-------------------------------------------------------
  492.         * Test for cntrl characters. If set, see if the character
  493.         * is elligible to become a control character. */
  494.  
  495.         default:
  496.  
  497.         if (q_keyboard.cntrl) {
  498.             chr = q_key[key];
  499.             if (chr >= ' ' && chr <= '~')
  500.             chr &= 0x1F;
  501.         } 
  502.         else if ( q_keyboard.lock || q_keyboard.shift )
  503.             chr = q_shift_key[key];
  504.         else
  505.             chr = q_key[key];
  506.         break;    
  507.     }
  508.  
  509.     if (chr < ' ' && chr > '~')      /* if input is non-displayable */
  510.         return(0);            /* ..then pitch it! */
  511.  
  512.     q_keyboard.last = chr;
  513.  
  514.     /*-----------------------------------
  515.     * Check for special function keys */
  516.  
  517.     if (chr & 0x80)         /* pitch the function keys */
  518.         return(0);
  519.     else
  520.         return(chr);
  521.  
  522. } /* qdgetc */
  523.  
  524. /************************************************************************
  525. *************************************************************************
  526. *************************************************************************
  527. *
  528. *    INTERNALLY USED ROUTINES START HERE:
  529. *
  530. *************************************************************************
  531. *************************************************************************
  532. ************************************************************************/
  533.  
  534. /********************************************************************
  535. *
  536. *    ldcursor()... load the mouse cursor's template RAM bitmap
  537. *
  538. ********************************************************************/
  539.  
  540. ldcursor()
  541. {
  542.     register struct dga *dga;
  543.     register short *temp;
  544.     register int i;
  545.  
  546.     int cursor;
  547.  
  548.     dga = (struct dga *) qdmap.dga;
  549.     temp = (short *) qdmap.template;
  550.  
  551.     temp += (8 * 1024) - 32;    /* cursor is 32 WORDS from the end */
  552.                     /* ..of the 8k WORD template space */
  553.     for (i = 0; i < 32; ++i)
  554.         *temp++ = cons_cursor[i];
  555.  
  556.     return(0);
  557.  
  558. } /* ldcursor */
  559.  
  560. /**********************************************************************
  561. *
  562. *    ldfont()... put the console font in the QDSS off-screen memory
  563. *
  564. **********************************************************************/
  565.  
  566. ldfont()
  567. {
  568.     register struct adder *adder;
  569.  
  570.     int i;        /* scratch variables */
  571.     int j;
  572.     int k;
  573.     short packed;
  574.  
  575.     adder = (struct adder *) qdmap.adder;
  576.  
  577. /*------------------------------------------
  578. * setup VIPER operand control registers  */
  579.  
  580.     write_ID(adder, MASK_1, 0xFFFF);
  581.     write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
  582.     write_ID(adder, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
  583.  
  584.     write_ID(adder, SRC1_OCR_B, 
  585.             EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY);
  586.     write_ID(adder, SRC2_OCR_B, 
  587.             EXT_NONE | INT_NONE | ID | BAR_SHIFT_DELAY);
  588.     write_ID(adder, DST_OCR_B, 
  589.             EXT_SOURCE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
  590.  
  591.     adder->rasterop_mode = DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL;
  592.  
  593. /*--------------------------
  594. * load destination data  */
  595.  
  596.     wait_status(adder, RASTEROP_COMPLETE);
  597.  
  598.     adder->destination_x = FONT_X;
  599.     adder->destination_y = FONT_Y;
  600.     adder->fast_dest_dx = FONT_WIDTH;
  601.     adder->slow_dest_dy = CHAR_HEIGHT;
  602.  
  603. /*---------------------------------------
  604. * setup for processor to bitmap xfer  */
  605.  
  606.     write_ID(adder, CS_UPDATE_MASK, 0x0001);
  607.     adder->cmd = PBT | OCRB | 2 | DTE | 2;
  608.  
  609. /*-----------------------------------------------
  610. * iteratively do the processor to bitmap xfer */
  611.  
  612.     for (i = 0; i < ROWS; ++i) {
  613.  
  614.         /* PTOB a scan line */
  615.  
  616.         for (j = 0, k = i; j < 48; ++j) { 
  617.  
  618.             /* PTOB one scan of a char cell */
  619.  
  620.         packed = q_font[k];
  621.         k += ROWS;
  622.         packed |= ((short)q_font[k] << 8);
  623.         k += ROWS;
  624.  
  625.             wait_status(adder, TX_READY);
  626.             adder->id_data = packed;
  627.         }
  628.     }
  629.  
  630. }  /* ldfont */
  631.  
  632. /*********************************************************************
  633. *
  634. *    led_control()... twiddle LK-201 LED's
  635. *
  636. **********************************************************************
  637. *
  638. *    led_control(cmd, led_mask);
  639. *    int cmd;    LED enable/disable command
  640. *    int led_mask;    which LED(s) to twiddle
  641. *
  642. *************/
  643.  
  644. led_control(cmd, led_mask)
  645. int cmd;
  646. int led_mask;
  647. {
  648.     register int i;
  649.     register int status;
  650.     register struct duart *duart;
  651.  
  652.     duart = (struct duart *) qdmap.duart;
  653.  
  654.     for (i = 1000; i > 0; --i) {
  655.             if ((status = duart->statusA) & XMT_RDY) {
  656.             duart->dataA = cmd;
  657.         break;
  658.             }
  659.     }
  660.  
  661.     for (i = 1000; i > 0; --i) {
  662.             if ((status = duart->statusA) & XMT_RDY) {
  663.             duart->dataA = led_mask;
  664.         break;
  665.             }
  666.     }
  667.  
  668.     if (i == 0)
  669.         return(BAD);
  670.  
  671.     return(GOOD);
  672.  
  673. } /* led_control */
  674.  
  675. /******************************************************************* 
  676. *
  677. *    scroll_up()... move the screen up one character height
  678. *
  679. ********************************************************************
  680. *
  681. *    calling convention:
  682. *
  683. *        scroll_up(adder);
  684. *        struct adder *adder;    ;address of adder
  685. *
  686. ********/
  687.  
  688. scroll_up(adder)
  689. register struct adder *adder;
  690. {
  691.  
  692. /*------------------------------------------
  693. * setup VIPER operand control registers  */
  694.  
  695.     wait_status(adder, ADDRESS_COMPLETE);
  696.  
  697.     write_ID(adder, CS_UPDATE_MASK, 0x00FF);  /* select all planes */
  698.  
  699.     write_ID(adder, MASK_1, 0xFFFF);
  700.     write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
  701.     write_ID(adder, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
  702.  
  703.     write_ID(adder, SRC1_OCR_B, 
  704.             EXT_NONE | INT_SOURCE | ID | BAR_SHIFT_DELAY);
  705.     write_ID(adder, DST_OCR_B, 
  706.             EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY);
  707.  
  708. /*----------------------------------------
  709. * load DESTINATION origin and vectors  */
  710.  
  711.     adder->fast_dest_dy = 0;
  712.     adder->slow_dest_dx = 0;
  713.     adder->error_1 = 0;
  714.     adder->error_2 = 0;
  715.  
  716.     adder->rasterop_mode = DST_WRITE_ENABLE | NORMAL;
  717.  
  718.     adder->destination_x = 0;
  719.     adder->fast_dest_dx = 1024;
  720.  
  721.     adder->destination_y = 0;
  722.     adder->slow_dest_dy = 864 - CHAR_HEIGHT;
  723.  
  724. /*-----------------------------------
  725. * load SOURCE origin and vectors  */
  726.  
  727.     adder->source_1_x = 0;
  728.     adder->source_1_dx = 1024;
  729.  
  730.     adder->source_1_y = 0 + CHAR_HEIGHT;
  731.     adder->source_1_dy = 864 - CHAR_HEIGHT;
  732.  
  733.     write_ID(adder, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE);
  734.     adder->cmd = RASTEROP | OCRB | 0 | S1E | DTE;
  735.  
  736. /*--------------------------------------------
  737. * do a rectangle clear of last screen line */
  738.  
  739.     write_ID(adder, MASK_1, 0xffff);
  740.     write_ID(adder, SOURCE, 0xffff);
  741.     write_ID(adder,DST_OCR_B,  
  742.           (EXT_NONE | INT_NONE | NO_ID | NO_BAR_SHIFT_DELAY));
  743.     write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 0);
  744.     adder->error_1 = 0;
  745.     adder->error_2 = 0;
  746.     adder->slow_dest_dx = 0;    /* set up the width of    */
  747.     adder->slow_dest_dy = CHAR_HEIGHT;    /* rectangle */
  748.  
  749.     adder->rasterop_mode = (NORMAL | DST_WRITE_ENABLE) ;
  750.     wait_status(adder, RASTEROP_COMPLETE);
  751.     adder->destination_x = 0;
  752.     adder->destination_y = 864 - CHAR_HEIGHT;
  753.  
  754.     adder->fast_dest_dx = 1024;    /* set up the height    */
  755.     adder->fast_dest_dy = 0;    /* of rectangle        */
  756.  
  757.     write_ID(adder, LU_FUNCTION_R2, (FULL_SRC_RESOLUTION | LF_SOURCE));
  758.     adder->cmd = (RASTEROP | OCRB | LF_R2 | DTE ) ;
  759.  
  760. } /* scroll_up */ 
  761.  
  762. /**********************************************************************
  763. *
  764. *    set_defaults()... init the QDSS device and driver defaults
  765. *
  766. **********************************************************************/
  767.  
  768. set_defaults()
  769. {
  770.     setup_input();        /* init the DUART */
  771.     setup_dragon();        /* init the ADDER/VIPER stuff */
  772.     ldcursor();        /* load default cursor map */
  773.  
  774. } /* set_defaults */
  775.  
  776. /*********************************************************************
  777. *
  778. *    setup_dragon()... init the ADDER, VIPER, bitmaps, & color map
  779. *
  780. *********************************************************************/
  781.  
  782. setup_dragon()
  783. {
  784.  
  785.     register struct adder *adder;
  786.     register struct dga *dga;
  787.     short *memcsr;
  788.  
  789.     int i;            /* general purpose variables */
  790.     int status;
  791.  
  792.     short top;        /* clipping/scrolling boundaries */
  793.     short bottom;
  794.     short right;
  795.     short left;
  796.  
  797.     short *red;        /* color map pointers */
  798.     short *green;
  799.     short *blue;
  800.  
  801. /*------------------
  802. * init for setup */
  803.  
  804.     adder = (struct adder *) qdmap.adder;
  805.     dga = (struct dga *) qdmap.dga;
  806.     memcsr = (short *) qdmap.memcsr;
  807.     
  808.     *memcsr = SYNC_ON;        /* blank screen and turn off LED's */
  809.     adder->command = CANCEL;
  810.  
  811. /*----------------------
  812. * set monitor timing */
  813.  
  814.     adder->x_scan_count_0 = 0x2800;
  815.     adder->x_scan_count_1 = 0x1020;
  816.     adder->x_scan_count_2 = 0x003A;
  817.     adder->x_scan_count_3 = 0x38F0;
  818.     adder->x_scan_count_4 = 0x6128;
  819.     adder->x_scan_count_5 = 0x093A;
  820.     adder->x_scan_count_6 = 0x313C;
  821.     adder->sync_phase_adj = 0x0100;
  822.     adder->x_scan_conf = 0x00C8;
  823.  
  824. /*---------------------------------------------------------
  825. * got a bug in secound pass ADDER! lets take care of it */
  826.  
  827.     /* normally, just use the code in the following bug fix code, but to 
  828.     * make repeated demos look pretty, load the registers as if there was
  829.     * no bug and then test to see if we are getting sync */
  830.  
  831.     adder->y_scan_count_0 = 0x135F;
  832.     adder->y_scan_count_1 = 0x3363;
  833.     adder->y_scan_count_2 = 0x2366;
  834.     adder->y_scan_count_3 = 0x0388;
  835.  
  836.     /* if no sync, do the bug fix code */
  837.  
  838.     if (wait_status(adder, VSYNC) == BAD) {
  839.  
  840.         /* first load all Y scan registers with very short frame and
  841.         * wait for scroll service.  This guarantees at least one SYNC 
  842.         * to fix the pass 2 Adder initialization bug (synchronizes
  843.         * XCINCH with DMSEEDH) */
  844.  
  845.         adder->y_scan_count_0 = 0x01;
  846.         adder->y_scan_count_1 = 0x01;
  847.         adder->y_scan_count_2 = 0x01;
  848.         adder->y_scan_count_3 = 0x01;
  849.  
  850.         wait_status(adder, VSYNC);    /* delay at least 1 full frame time */
  851.         wait_status(adder, VSYNC);
  852.  
  853.         /* now load the REAL sync values (in reverse order just to
  854.         *  be safe.  */
  855.  
  856.         adder->y_scan_count_3 = 0x0388;
  857.         adder->y_scan_count_2 = 0x2366;
  858.         adder->y_scan_count_1 = 0x3363;
  859.         adder->y_scan_count_0 = 0x135F;
  860.       }
  861.  
  862. /*----------------------------
  863. * zero the index registers */
  864.  
  865.     adder->x_index_pending = 0;
  866.     adder->y_index_pending = 0;
  867.     adder->x_index_new = 0;
  868.     adder->y_index_new = 0;
  869.     adder->x_index_old = 0;
  870.     adder->y_index_old = 0;
  871.  
  872.     adder->pause = 0;
  873.  
  874. /*----------------------------------------
  875. * set rasterop mode to normal pen down */
  876.  
  877.     adder->rasterop_mode = DST_WRITE_ENABLE | DST_INDEX_ENABLE | NORMAL;
  878.  
  879. /*--------------------------------------------------
  880. * set the rasterop registers to a default values */
  881.  
  882.     adder->source_1_dx = 1;
  883.     adder->source_1_dy = 1;
  884.     adder->source_1_x = 0;
  885.     adder->source_1_y = 0;
  886.     adder->destination_x = 0;
  887.     adder->destination_y = 0;
  888.     adder->fast_dest_dx = 1;
  889.     adder->fast_dest_dy = 0;
  890.     adder->slow_dest_dx = 0;
  891.     adder->slow_dest_dy = 1;
  892.        adder->error_1 = 0;
  893.     adder->error_2 = 0;
  894.  
  895. /*------------------------
  896. * scale factor = unity */
  897.  
  898.     adder->fast_scale = UNITY;
  899.     adder->slow_scale = UNITY;
  900.  
  901. /*-------------------------------
  902. * set the source 2 parameters */
  903.  
  904.     adder->source_2_x = 0;
  905.     adder->source_2_y = 0;
  906.     adder->source_2_size = 0x0022;
  907.  
  908. /*-----------------------------------------------
  909. * initialize plane addresses for eight vipers */
  910.  
  911.     write_ID(adder, CS_UPDATE_MASK, 0x0001);
  912.     write_ID(adder, PLANE_ADDRESS, 0x0000);
  913.  
  914.     write_ID(adder, CS_UPDATE_MASK, 0x0002);
  915.     write_ID(adder, PLANE_ADDRESS, 0x0001);
  916.  
  917.     write_ID(adder, CS_UPDATE_MASK, 0x0004);
  918.     write_ID(adder, PLANE_ADDRESS, 0x0002);
  919.  
  920.     write_ID(adder, CS_UPDATE_MASK, 0x0008);
  921.     write_ID(adder, PLANE_ADDRESS, 0x0003);
  922.  
  923.     write_ID(adder, CS_UPDATE_MASK, 0x0010);
  924.     write_ID(adder, PLANE_ADDRESS, 0x0004);
  925.  
  926.     write_ID(adder, CS_UPDATE_MASK, 0x0020);
  927.     write_ID(adder, PLANE_ADDRESS, 0x0005);
  928.  
  929.     write_ID(adder, CS_UPDATE_MASK, 0x0040);
  930.     write_ID(adder, PLANE_ADDRESS, 0x0006);
  931.  
  932.     write_ID(adder, CS_UPDATE_MASK, 0x0080);
  933.     write_ID(adder, PLANE_ADDRESS, 0x0007);
  934.  
  935.     /* initialize the external registers. */
  936.  
  937.     write_ID(adder, CS_UPDATE_MASK, 0x00FF);
  938.     write_ID(adder, CS_SCROLL_MASK, 0x00FF);
  939.  
  940.     /* initialize resolution mode */
  941.  
  942.     write_ID(adder, MEMORY_BUS_WIDTH, 0x000C);     /* bus width = 16 */
  943.     write_ID(adder, RESOLUTION_MODE, 0x0000);      /* one bit/pixel */
  944.  
  945.     /* initialize viper registers */
  946.  
  947.     write_ID(adder, SCROLL_CONSTANT, SCROLL_ENABLE|VIPER_LEFT|VIPER_UP);
  948.     write_ID(adder, SCROLL_FILL, 0x0000);
  949.  
  950. /*----------------------------------------------------
  951. * set clipping and scrolling limits to full screen */
  952.  
  953.     for ( i = 1000, adder->status = 0
  954.         ; i > 0  &&  !((status = adder->status) & ADDRESS_COMPLETE)
  955.         ; --i);
  956.  
  957.     if (i == 0)
  958.         printf("timeout trying to setup clipping\n");
  959.  
  960.     top = 0;
  961.     bottom = 2048;
  962.     left = 0;
  963.     right = 1024;
  964.  
  965.     adder->x_clip_min = left;
  966.     adder->x_clip_max = right;
  967.     adder->y_clip_min = top;
  968.     adder->y_clip_max = bottom;
  969.  
  970.     adder->scroll_x_min = left;
  971.     adder->scroll_x_max = right;
  972.     adder->scroll_y_min = top;
  973.     adder->scroll_y_max = bottom;
  974.  
  975.     wait_status(adder, VSYNC);    /* wait at LEAST 1 full frame */
  976.     wait_status(adder, VSYNC);
  977.  
  978.     adder->x_index_pending = left;
  979.     adder->y_index_pending = top;
  980.     adder->x_index_new = left;
  981.     adder->y_index_new = top;
  982.     adder->x_index_old = left;
  983.     adder->y_index_old = top;
  984.  
  985.     for ( i = 1000, adder->status = 0
  986.         ; i > 0  &&  !((status = adder->status) & ADDRESS_COMPLETE)
  987.         ; --i);
  988.  
  989.     if (i == 0)
  990.         printf("timeout waiting for ADDRESS_COMPLETE bit\n");
  991.  
  992.     write_ID(adder, LEFT_SCROLL_MASK, 0x0000);
  993.     write_ID(adder, RIGHT_SCROLL_MASK, 0x0000);
  994.  
  995. /*------------------------------------------------------------
  996. * set source and the mask register to all ones (ie: white) */
  997.  
  998.     write_ID(adder, SOURCE, 0xFFFF);
  999.     write_ID(adder, MASK_1, 0xFFFF);
  1000.     write_ID(adder, VIPER_Z_LOAD | FOREGROUND_COLOR_Z, 255);
  1001.     write_ID(adder, VIPER_Z_LOAD | BACKGROUND_COLOR_Z, 0);
  1002.  
  1003. /*--------------------------------------------------------------
  1004. * initialize Operand Control Register banks for fill command */
  1005.  
  1006.     write_ID(adder, SRC1_OCR_A, EXT_NONE | INT_M1_M2  | NO_ID | WAIT);
  1007.     write_ID(adder, SRC2_OCR_A, EXT_NONE | INT_SOURCE | NO_ID | NO_WAIT);
  1008.     write_ID(adder, DST_OCR_A, EXT_NONE | INT_NONE   | NO_ID | NO_WAIT);
  1009.  
  1010.     write_ID(adder, SRC1_OCR_B, EXT_NONE | INT_SOURCE | NO_ID | WAIT);
  1011.     write_ID(adder, SRC2_OCR_B, EXT_NONE | INT_M1_M2  | NO_ID | NO_WAIT);
  1012.     write_ID(adder, DST_OCR_B, EXT_NONE | INT_NONE | NO_ID | NO_WAIT);
  1013.  
  1014. /*------------------------------------------------------------------
  1015. * init Logic Unit Function registers, (these are just common values,
  1016. * and may be changed as required).  */
  1017.  
  1018.     write_ID(adder, LU_FUNCTION_R1, FULL_SRC_RESOLUTION | LF_SOURCE);
  1019.     write_ID(adder, LU_FUNCTION_R2, FULL_SRC_RESOLUTION | LF_SOURCE | INV_M1_M2);
  1020.     write_ID(adder, LU_FUNCTION_R3, FULL_SRC_RESOLUTION | LF_D_OR_S);
  1021.     write_ID(adder, LU_FUNCTION_R4, FULL_SRC_RESOLUTION | LF_D_XOR_S);
  1022.  
  1023. /*----------------------------------------
  1024. * load the color map for black & white */
  1025.     
  1026.     for ( i = 0, adder->status = 0
  1027.         ; i < 10000  &&  !((status = adder->status) & VSYNC)
  1028.         ; ++i);
  1029.  
  1030.     if (i == 0)
  1031.         printf("timeout waiting for VSYNC bit\n");
  1032.  
  1033.     red = (short *) qdmap.red;
  1034.     green = (short *) qdmap.green;
  1035.     blue = (short *) qdmap.blue;
  1036.  
  1037.     *red++ = 0x00;            /* black */
  1038.     *green++ = 0x00;
  1039.     *blue++ = 0x00;
  1040.  
  1041.     *red-- = 0xFF;            /* white */
  1042.     *green-- = 0xFF;
  1043.     *blue-- = 0xFF;
  1044.  
  1045.     /*----------------------------------
  1046.     * set color map for mouse cursor */
  1047.  
  1048.     red += 254;
  1049.     green += 254;
  1050.     blue += 254;
  1051.  
  1052.     *red++ = 0x00;            /* black */
  1053.     *green++ = 0x00;
  1054.     *blue++ = 0x00;
  1055.  
  1056.     *red = 0xFF;            /* white */
  1057.     *green = 0xFF;
  1058.     *blue = 0xFF;
  1059.  
  1060. /*---------------------------------------------------------------------------
  1061. * clear the bitmap a piece at a time.  Since the fast scroll clear only clears
  1062. * the current displayed portion of the bitmap put a temporary value in the y
  1063. * limit register so we can access whole bitmap  */
  1064.  
  1065.     adder->x_limit = 1024;
  1066.     adder->y_limit = 2048 - CHAR_HEIGHT;
  1067.     adder->y_offset_pending = 0;
  1068.  
  1069.     wait_status(adder, VSYNC);    /* wait at LEAST 1 full frame */
  1070.     wait_status(adder, VSYNC);
  1071.  
  1072.     adder->y_scroll_constant = SCROLL_ERASE;
  1073.  
  1074.     wait_status(adder, VSYNC);
  1075.     wait_status(adder, VSYNC);
  1076.  
  1077.     adder->y_offset_pending = 864;
  1078.  
  1079.     wait_status(adder, VSYNC);
  1080.     wait_status(adder, VSYNC);
  1081.  
  1082.     adder->y_scroll_constant = SCROLL_ERASE;
  1083.  
  1084.     wait_status(adder, VSYNC);
  1085.     wait_status(adder, VSYNC);
  1086.  
  1087.     adder->y_offset_pending = 1728;
  1088.  
  1089.     wait_status(adder, VSYNC);
  1090.     wait_status(adder, VSYNC);
  1091.  
  1092.     adder->y_scroll_constant = SCROLL_ERASE;
  1093.  
  1094.     wait_status(adder, VSYNC);
  1095.     wait_status(adder, VSYNC);
  1096.  
  1097.     adder->y_offset_pending = 0;     /* back to normal */
  1098.  
  1099.     wait_status(adder, VSYNC);
  1100.     wait_status(adder, VSYNC);
  1101.  
  1102.     adder->x_limit = MAX_SCREEN_X;
  1103.     adder->y_limit = MAX_SCREEN_Y + FONT_HEIGHT;
  1104.  
  1105.     *memcsr = SYNC_ON | UNBLANK;    /* turn off leds and turn on video */
  1106.     return(0);
  1107.  
  1108. } /* setup_dragon */
  1109.  
  1110. /******************************************************************
  1111. *
  1112. *    setup_input()... init the DUART and set defaults in input
  1113. *             devices
  1114. *
  1115. ******************************************************************/
  1116.  
  1117. setup_input()
  1118. {
  1119.     register struct duart *duart;    /* DUART register structure pointer */
  1120.     register int bits;
  1121.     int i, j;            /* scratch variables */
  1122.  
  1123.     short status;
  1124.  
  1125. /*---------------
  1126. * init stuff */
  1127.  
  1128.     duart = (struct duart *) qdmap.duart;
  1129.  
  1130. /*---------------------------------------------
  1131. * setup the DUART for kbd & pointing device */
  1132.  
  1133.     duart->cmdA = RESET_M;    /* reset mode reg ptr for kbd */
  1134.     duart->modeA = 0x13;      /* 8 bits, no parity, rcv IE, */
  1135.                    /* no RTS control,char error mode */
  1136.     duart->modeA = 0x07;      /* 1 stop bit,CTS does not IE XMT */
  1137.                   /* no RTS control,no echo or loop */
  1138.     duart->auxctl = 0x00;      /* baud rate set 1 */
  1139.  
  1140.     duart->clkselA = 0x99;      /* 4800 baud for kbd */
  1141.  
  1142.         /* reset everything for keyboard */
  1143.  
  1144.     for (bits = RESET_M; bits < START_BREAK; bits += 0x10)
  1145.         duart->cmdA = bits;
  1146.  
  1147.     duart->cmdA = EN_RCV | EN_XMT; /* enbl xmt & rcv for kbd */
  1148.  
  1149. /*--------------------------
  1150. * init keyboard defaults */
  1151. /*
  1152.     for (i = 500; i > 0; --i) {
  1153.             if ((status = duart->statusA) & XMT_RDY) {
  1154.             duart->dataA = LK_DEFAULTS;
  1155.         break;
  1156.             }
  1157.     }
  1158.  
  1159.     for (j = 0; j < 3; ++j) {
  1160.         for (i = 50000; i > 0; --i) {
  1161.                 if ((status = duart->statusA) & RCV_RDY) {
  1162.             status = duart->dataA;
  1163.             break;
  1164.              }
  1165.         }
  1166.     }
  1167.  
  1168.     if (i == 0)
  1169.         printf("LK-201 init error\n");
  1170. */
  1171.  
  1172. /*--------
  1173. * exit */
  1174.  
  1175.     return(0);
  1176.  
  1177. } /* setup_input */
  1178.  
  1179. /**********************************************************************
  1180. *
  1181. *    wait_status()... delay for at least one display frame time
  1182. *
  1183. ***********************************************************************
  1184. *
  1185. *    calling convention:
  1186. *
  1187. *        wait_status(adder, mask);
  1188. *        struct *adder adder;
  1189. *        int mask;
  1190. *
  1191. *    return: BAD means that we timed out without ever seeing the
  1192. *                  vertical sync status bit
  1193. *        GOOD otherwise
  1194. *
  1195. **************/
  1196.  
  1197. wait_status(adder, mask)
  1198. register struct adder *adder;
  1199. register int mask;
  1200. {
  1201.     register short status;
  1202.     int i;
  1203.  
  1204.     for ( i = 10000, adder->status = 0
  1205.         ; i > 0  &&  !((status = adder->status) & mask)
  1206.         ; --i);
  1207.  
  1208.     if (i == 0) {
  1209.         printf("timeout polling for 0x%x in adder->status\n", mask);
  1210.         return(BAD);
  1211.     }
  1212.  
  1213.     return(GOOD);
  1214.  
  1215. } /* wait_status */
  1216.  
  1217. /**********************************************************************
  1218. *
  1219. *    write_ID()... write out onto the ID bus
  1220. *
  1221. ***********************************************************************
  1222. *
  1223. *    calling convention:
  1224. *
  1225. *        struct *adder adder;    ;pntr to ADDER structure
  1226. *        short adrs;        ;VIPER address
  1227. *        short data;        ;data to be written
  1228. *        write_ID(adder);
  1229. *
  1230. *    return: BAD means that we timed out waiting for status bits
  1231. *              VIPER-access-specific status bits
  1232. *        GOOD otherwise
  1233. *
  1234. **************/
  1235.  
  1236. write_ID(adder, adrs, data)
  1237. register struct adder *adder;
  1238. register short adrs;
  1239. register short data;
  1240. {
  1241.     int i;
  1242.     short status;
  1243.  
  1244.     for ( i = 100000, adder->status = 0
  1245.         ; i > 0  &&  !((status = adder->status) & ADDRESS_COMPLETE)
  1246.         ; --i);
  1247.  
  1248.     if (i == 0)
  1249.         goto ERR;
  1250.  
  1251.     for ( i = 100000, adder->status = 0
  1252.         ; i > 0  &&  !((status = adder->status) & TX_READY)
  1253.         ; --i);
  1254.  
  1255.     if (i > 0) {
  1256.         adder->id_data = data;
  1257.         adder->command = ID_LOAD | adrs;
  1258.         return(GOOD);
  1259.     }
  1260.  
  1261. ERR:
  1262.     printf("timeout trying to write to VIPER\n");
  1263.     return(BAD);
  1264.  
  1265. } /* write_ID */
  1266.