home *** CD-ROM | disk | FTP | other *** search
/ Virtual Reality Zone / VRZONE.ISO / mac / PC / REND386 / JIREND / SGSPPT.C < prev    next >
C/C++ Source or Header  |  1993-04-11  |  18KB  |  665 lines

  1. /* Sega support routines; written by Dave Stampe, July 1992 */
  2.   
  3. /* Copyright 1992 by Dave Stampe and Bernie Roehl.
  4.    May be freely used to write software for release into the public domain;
  5.    all commercial endeavours MUST contact Bernie Roehl and Dave Stampe
  6.    for permission to incorporate any part of this software into their
  7.    products!
  8.  */
  9.   
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <dos.h>
  13. #include <bios.h>
  14. #include <signal.h>
  15. #include <string.h>
  16.   
  17. #include "rend386.h"
  18. #include "f3dkitd.h"
  19. #include "segasupp.h"
  20.   
  21. /************ INTERFACE SPECIFIC GLOVE STUFF ****************/
  22.   
  23. int port_image = 0;
  24. int sega_port_image = 0;
  25.   
  26. #define INPORT   0x379        /* i/o port addresses */
  27. #define OUTPORT  0x378
  28.   
  29. /* bits from parallel port: */
  30. #define GDATA    0x10    /* PG data in */
  31. #define GLATCH   0x02    /* PG latch out */
  32. #define GCLOCK   0x01    /* PG clock out */
  33. #define GCLOLAT  0x03    /* clock + latch */
  34.   
  35. #define GMASK    0x03    /* bits changable for glove access */
  36.   
  37. /************ GLOVE SPEED AND INTERFACE *****************/
  38.   
  39. #define FASTCOUNT 8       /* # of fast packet bytes */
  40.   
  41. #define D2BITS   12    /* BIT DELAY: microseconds */
  42. #define D2BYTES     140   /* BYTE DELAY: microseconds */
  43.   
  44. #define MAXRESET  200     /* failed reads before resetting glove */
  45.   
  46.   
  47. /***** declarations for assembly code in glovedel.asm *****/
  48.   
  49. int glove_none_mask = 0;
  50. int glove_latch_mask = GLATCH;
  51. int glove_clock_mask = GCLOCK;
  52. int glove_clock_latch = GCLOLAT;
  53.   
  54. int glove_in_port = INPORT;
  55. int glove_out_port = OUTPORT;
  56.   
  57. int glove_data_mask = GDATA;
  58. int glove_write_mask = GMASK;
  59.   
  60. int glove_bit_delay = D2BITS;
  61.   
  62. int glove_byte_delay = D2BYTES;
  63.   
  64. static int glove_892_delay = 892;
  65. static int glove_2260_delay = 2260;
  66. static int glove_7212_delay = 7212;
  67. static int glove_10000_delay = 10000;
  68.   
  69. extern unsigned int timed_glove_delay(int count);
  70.    /* returns time in 1.1925 MHZ ticks */
  71.    /* to perform <count> delay steps   */
  72.    /* call with timer at 18.2 Hz rate  */
  73.   
  74. extern int glove_delay(int count);  /* performs <count> delay steps   */
  75.   
  76. extern int get_glove_byte(void);  /* reads a byte from glove */
  77.   
  78. extern void set_glove_bits(int data);  /* sets glove clock, data lines */
  79.                                        /* and does a bit delay         */
  80.   
  81. /********* defines for output line pair control *******/
  82.   
  83. #define C0L0() set_glove_bits(glove_none_mask)    /* clock 0 latch 0 */
  84. #define C0L1() set_glove_bits(glove_latch_mask)   /* clock 0 latch 1 */
  85. #define C1L0() set_glove_bits(glove_clock_mask)   /* clock 1 latch 0 */
  86. #define C1L1() set_glove_bits(glove_clock_latch)  /* clock 1 latch 1 */
  87.   
  88. /************ status and read control **********/
  89.   
  90. static int glove_rx_try = 10; /* number of read tries: first will be rxflags */
  91. static int glove_rx_flags = 0; /* holds flags (read 10 mS after packet */
  92.   
  93.   
  94. /********************** HIRES MODE SETUP *****************/
  95.   
  96. /*  HIRES ENTRY CODES
  97.    byte:
  98.    1- any value between $05 and $31   (x,y res. divisor???)
  99.    2- only $C1 and $81 work OK (C1)(81 does garbage)
  100.    3- no effect    (08)
  101.    4- no effect    (00)
  102.    5- no effect    (02)
  103.    6- only $FF works   (FF)
  104.    7- seems to affect read rate slightly, 1 fastest (01)
  105.  */
  106.   
  107. static int glove_ignore = 0; /* # of interrupts to ignore glove so it */
  108.                              /* will recover from mode setup          */
  109.   
  110. static int hires_code[7] = { 0x05, 0xC1, 0x08, 0x00, 0x02, 0xFF, 0x01 };
  111.   
  112. static void Hires(void) /* enter HIRES mode */
  113. {
  114.    int i,j,k;
  115.    /* dummy read 4 bits from glove:  */
  116.    C1L0();
  117.    C1L1(); /* generate a reset (latch) pulse */
  118.    glove_delay(glove_bit_delay); /* delay for 6 us */
  119.    C1L0();
  120.    glove_delay(glove_bit_delay); /* delay for 6 us */
  121.   
  122.    C0L0();
  123.    C1L0(); /* pulse clock */
  124.    C0L0();
  125.    C1L0(); /* pulse clock */
  126.    C0L0();
  127.    C1L0(); /* pulse clock */
  128.    C0L0();
  129.    C1L0(); /* pulse clock */
  130.   
  131.    /* force glove to listen for setup */
  132.    C1L0();
  133.    glove_delay(glove_7212_delay); /* 7212 us delay */
  134.    C1L1();
  135.    glove_delay(glove_2260_delay); /* 2260 us delay */
  136.   
  137.    for (i = 0; i < 7; i++) /* send 7 bytes of mode data */
  138.    {
  139.       k = hires_code[i];
  140.       for (j = 0; j < 8; j++) /* 8 bits per byte, MSB first */
  141.       {
  142.          if (k & 0x80)
  143.          {
  144.             C1L1();
  145.             C0L1();
  146.             C1L1();
  147.          }
  148.          else
  149.          {
  150.             C1L0();
  151.             C0L0();
  152.             C1L0();
  153.          }
  154.          k <<= 1;
  155.       }
  156.       glove_delay(glove_byte_delay);
  157.    }
  158.   
  159.    glove_delay(glove_892_delay); /* 892 us delay (end of setup data) */
  160.   
  161.    C1L0(); /* drop the reset line */
  162.    glove_ignore = 10; /* some time for the glove controller to relax */
  163. }
  164.   
  165.   
  166. /**************** HYSTERISIS NOISE REMOVAL: x,y,z,rot *************/
  167.   
  168. #define XHYST 2          /* hysterisis for X, Y low noise reduction */
  169. #define YHYST 2          /* 2 eliminates +/-3 quanta of noise */
  170. #define ZHYST 1
  171. #define RHYST 0
  172.   
  173. static int ox = -1000; /* last x,y for hysterisis */
  174. static int oy = -1000;
  175. static int oz = -1000;
  176. static int or = -1000;
  177.   
  178. static void dehyst(glove_data *g) /* hysterisis deglitch (low noise removal) */
  179. {
  180.    int x = g->x;
  181.    int y = g->y;
  182.    int z = g->z;
  183.    int r = g->rot;
  184.    /* handle recentering ("0"key or "Center") */
  185.    if (g->keys == 0) ox = oy = oz = 0;
  186.   
  187.    if (x-ox > XHYST) ox = x-XHYST; /* X hysterisis */
  188.    else
  189.       if (ox-x > XHYST) ox = x+XHYST;
  190.   
  191.    if (y-oy > YHYST) oy = y-YHYST; /* Y hysterisis */
  192.    else
  193.       if (oy-y > YHYST) oy = y+YHYST;
  194.   
  195.    if (z-oz > ZHYST) oz = z-ZHYST; /* Z hysterisis */
  196.    else
  197.       if (oz-z > ZHYST) oz = z+ZHYST;
  198.   
  199.    if (RHYST)
  200.    {
  201.       if (or < 3 && r > 8) /* CCW around-end */
  202.          if (or > 0 || r < 11) or = r+RHYST;
  203.          else;
  204.          else
  205.             if (or > 8 && r < 3) /* CW around-end */
  206.                if (or < 11 || r > 0) or = r-RHYST;
  207.                else;
  208.                else
  209.                   if (r-or > RHYST) or = r-RHYST; /* R hysterisis */
  210.                   else
  211.                      if (or-r > RHYST) or = r+RHYST;
  212.   
  213.       if (or > 11) or -= 11;
  214.       if (or < 0) or += 11;
  215.    }
  216.    else or = r;
  217.    g->x = ox; /* replace present X,Y data */
  218.    g->y = oy;
  219.    g->z = oz;
  220.    g->rot = or;
  221. }
  222.   
  223. /****************** DEGLITCHING ***************/
  224.   
  225. #define XACC 8          /* X, Y maximum accel/decel level. Should */
  226. #define YACC 8    /* be 6-10, but too high limits gesturing */
  227.   
  228. #define XXTEND 1  /* stretches deglitching time */
  229. #define YXTEND 1
  230. #define ROTTIME 1
  231.   
  232. static int x1 = 0; /* delayed 1 sample (for smoothed velocity test) */
  233. static int y1 = 0;
  234. static int x2 = 0; /* delayed 2 samples */
  235. static int y2 = 0;
  236. static int lx = 0; /* last good X,Y speed */
  237. static int ly = 0;
  238. static int lax = 0; /* bad data "stretch" counter */
  239. static int lay = 0;
  240. static int lsx = 0; /* X,Y "hold" values to replace bad data */
  241. static int lsy = 0;
  242. static int lcx = 0; /* last X,Y speed for accel. calc. */
  243. static int lcy = 0;
  244.   
  245. static int saverot = 0;
  246. static int lastrot = 0; /* last stable rotate */
  247. static int chrot = 0; /* time its been stable */
  248.   
  249. static void deglitch(glove_data *g)
  250. {
  251.    int vx, vy;
  252.   
  253.    int x = g->x;
  254.    int y = g->y;
  255.   
  256.    if (g->keys == 0) /* reset on recentering ("0" or "Center" key) */
  257.    {
  258.       x1 = x2 = y1 = y2 = 0;
  259.       lx = ly = lax = lay = 0;
  260.       lsx = lsy = lcx = lcy = 0;
  261.       lastrot = chrot = saverot = 0;
  262.    }
  263.   
  264.    if (lastrot != g->rot)
  265.    {
  266.       chrot = 0;
  267.       lastrot = g->rot;
  268.       g->rot = saverot;
  269.    }
  270.    else
  271.    {
  272.       if (chrot < ROTTIME)
  273.       {
  274.          chrot++;
  275.          g->rot = saverot;
  276.       }
  277.       else saverot = lastrot = g->rot;
  278.    }
  279.   
  280.    vx = x-((x1+x2) >> 1); /* smoothed velocity */
  281.    vy = y-((y1+y2) >> 1);
  282.   
  283.    x2 = x1; /* update last values */
  284.    x1 = g->x;
  285.   
  286.    y2 = y1;
  287.    y1 = g->y;
  288.   
  289.    if (abs(lcx-vx) > XACC) lax = XXTEND; /* check for extreme acceleration */
  290.    if (lax == 0) lx = vx; /* save only good velocity        */
  291.    lcx = vx; /* save velocity for next accel.  */
  292.   
  293.    if (abs(lcy-vy) > YACC) lay = YXTEND; /* same deal for Y accel. */
  294.    if (lay == 0) ly = vy;
  295.    lcy = vy;
  296.   
  297.    if (lax != 0) /* hold X pos'n if glitch */
  298.    {
  299.       g->x = lsx;
  300.       lax--;
  301.    }
  302.   
  303.    if (lay != 0) /* hold Y pos'n if glitch */
  304.    {
  305.       g->y = lsy;
  306.       lay--;
  307.    }
  308.   
  309.    lsx = g->x; /* save position for X,Y hold */
  310.    lsy = g->y;
  311. }
  312.   
  313. /**************** COMPUTE COUNTS FOR TIME CALIBRATION ***********/
  314.   
  315. static float factor;
  316.   
  317. static int uconvert(int t)
  318. {
  319.    float f;
  320.    f = factor*((float)t);
  321.    if (f < 1.0) return 1;
  322.    if (f > 60000.0) return 60000;
  323.    return f;
  324. }
  325.   
  326. static void calibrate(void)
  327. {
  328.    factor = 11900.0/((float) timed_glove_delay(10000));
  329.   
  330.    glove_bit_delay = uconvert(glove_bit_delay);
  331.    glove_byte_delay = uconvert(glove_byte_delay);
  332.    glove_892_delay = uconvert(glove_892_delay);
  333.    glove_2260_delay = uconvert(glove_2260_delay);
  334.    glove_7212_delay = uconvert(glove_7212_delay);
  335.    glove_10000_delay = uconvert(glove_10000_delay);
  336. }
  337.   
  338. /******************* gesture recognition **************/
  339.   
  340. #define G_FLAT      0
  341. #define G_THUMB_IN  1
  342. #define G_INDEX_IN  2
  343. #define G_MIDDLE_IN 3
  344. #define G_RING_IN   4
  345. #define G_PINCH     5
  346. #define G_FIST      6
  347. #define G_THUMB_OUT 7
  348. #define G_POINT     8
  349. #define G_BADFINGER 9
  350. #define G_RING_OUT 10
  351. #define G_UNKNOWN  11      /* gesture classification */
  352.   
  353. long gesture_time = 0;
  354. unsigned char gesture_type = G_UNKNOWN;
  355. static unsigned char last_gesture = G_UNKNOWN;
  356.   
  357. /* more reliable mapped gestures */
  358.   
  359. static unsigned char gesture_map[12] = 
  360. {
  361.    G_FLAT, G_FLAT, G_PINCH, G_MIDDLE_IN,
  362.    G_RING_IN, G_PINCH, G_FIST, G_FIST, G_POINT,
  363.    G_BADFINGER, G_FIST, G_UNKNOWN 
  364. };
  365.   
  366. /* unmapped gestures */
  367. /*
  368. char gesture_map[12] = 
  369.    G_FLAT, G_THUMB_IN, G_INDEX_IN, G_MIDDLE_IN,
  370.    G_RING_IN, G_PINCH, G_FIST, G_THUMB_OUT,
  371.    G_POINT, G_BADFINGER, G_RING_OUT, G_UNKNOWN 
  372. };
  373. */
  374.   
  375. static int g_lookup[256]; /* compiled lookup table for gestures */
  376.   
  377. static char gs[11][8] = {
  378.    0,1, 0,0, 0,0, 0,0,
  379.    2,3, 0,0, 0,0, 0,1,
  380.    /* data is: for each gesture   */ 0,1, 2,3, 0,1, 0,1,
  381.    /* and for each finger, a max. */ 0,3, 0,1, 2,3, 0,1,
  382.    /* and min. bend value         */ 0,3, 0,1, 0,1, 2,3,
  383.    1,3, 2,3, 0,1, 0,1,
  384.    2,3, 2,3, 2,3, 1,3,
  385.    0,1, 2,3, 2,3, 1,3,
  386.    0,3, 0,1, 2,3, 1,3,
  387.    0,3, 2,3, 0,1, 1,3,
  388. 0,3, 2,3, 2,3, 0,1 };
  389.   
  390. static void init_gestures(void)
  391. {
  392.    int g,t,i,m,r,x;
  393.   
  394.    for(g = 0; g < 256; g++) g_lookup[g] = G_UNKNOWN;
  395.   
  396.    for(g = 11; g; )
  397.    {
  398.       g--;
  399.       for(t = 0; t < 4; t++)
  400.          for(i = 0; i < 4; i++)
  401.             for(m = 0; m < 4; m++)
  402.                for(r = 0; r < 4; r++)
  403.                {
  404.                   x = (t<<6)+(i<<4)+(m<<2)+r;
  405.                   if (gs[g][0] <= t && gs[g][1] >= t)
  406.                      if (gs[g][2] <= i && gs[g][3] >= i)
  407.                         if (gs[g][4] <= m && gs[g][5] >= m)
  408.                            if (gs[g][6] <= r && gs[g][7] >= r)
  409.                               g_lookup[x] = g;
  410.                }
  411.    }
  412. }
  413.   
  414. static void gesture_process(glove_data *g)
  415. {
  416.    gesture_time++;
  417.    gesture_type = g_lookup[((int)g->fingers) & 255];
  418.    gesture_type = gesture_map[gesture_type];
  419.    if (gesture_type != last_gesture) gesture_time = 0;
  420.    last_gesture = gesture_type;
  421. }
  422.   
  423.   
  424. /******************* READ GLOVE DATA PACKET *************/
  425.   
  426. void getglove(glove_data *buf) /* read 6 byte data packet */
  427. {
  428.    register unsigned char *bp = (char *) buf;
  429.    register int i;
  430.   
  431.    for (i = 0; i < FASTCOUNT; ++i)
  432.    {
  433.       *bp++ = get_glove_byte(); /* read data */
  434.       glove_delay(glove_byte_delay);
  435.    }
  436.    glove_rx_try = 0;
  437.    buf->rxflags = 0x3f; /* default all rx fired, but will be read in */
  438. }   /* 8-10 mS when glove_ready returns 2        */
  439.     /* also stored in glove_rx_flags        */
  440.   
  441. /*************** GLOVE INTERRUPT HANDLER **************/
  442.   
  443. static glove_data glove_int_data; /* our copy of the most recent data */
  444.   
  445. static unsigned unready = 0; /* number of times glove has been not ready */
  446. static int glove_deglitch; /* switches deglitching on and off */
  447.   
  448. void glove_int_handler(void)
  449. {
  450.    int n;
  451.   
  452.    if (glove_ignore) /* wait out setup time if required */
  453.    {
  454.       glove_ignore--;
  455.       return;
  456.    }
  457.   
  458.    glove_rx_try++;
  459.   
  460.    if ((n = get_glove_byte()) != 0xA0)
  461.    {
  462.       if (glove_rx_try == 1) glove_rx_flags = glove_int_data.rxflags = n;
  463.       if (++unready > MAXRESET)
  464.       { /* glove not responding... reset it */
  465.          unready = 0;
  466.          Hires();
  467.       }
  468.    }
  469.    else
  470.    { /* data ready! */
  471.       glove_delay(glove_byte_delay);
  472.       unready = 0;
  473.       getglove(&glove_int_data);
  474.       if (glove_deglitch)
  475.          deglitch(&glove_int_data); /* remove spikes and jumps */
  476.       dehyst(&glove_int_data); /* add hysteresis to remove LL noise */
  477.       gesture_process(&glove_int_data);
  478.       ++glove_int_data.nmissed; /* flag data as new */
  479.    }
  480. }
  481.   
  482. /******************* GLOVE INITIALIZATION ***************/
  483.   
  484. #define TIMER_CONTROL 0x43 /* timer control register */
  485. #define TIMER_0       0x40 /* timer zero data register */
  486. #define TIMER_MODE    0x36 /* byte to write to control register */
  487.   
  488. void glove_init(int gdeg) /* gdeg switches deglitching */
  489. {
  490.    outportb(TIMER_CONTROL, TIMER_MODE); /* reprogram timer to mod 65536 */
  491.    outportb(TIMER_0, 0); /* so calibration is correct    */
  492.    outportb(TIMER_0, 0);
  493.   
  494.    glove_deglitch = gdeg;
  495.    calibrate(); /* compute timing counts */
  496.    Hires(); /* enter hires mode */
  497.    init_gestures();
  498.    glove_int_data.nmissed = 0; /* mark no new data yet */
  499. }
  500.   
  501. /************** EXTERNAL DATA INTERFACE **************/
  502.   
  503. int glove_read(glove_data *glov) /* return copy of data packet */
  504. {
  505.    disable();
  506.    *glov = glove_int_data;
  507.    glove_int_data.nmissed = 0;
  508.    enable();
  509.    return glov->nmissed;
  510. }
  511.   
  512.                    /* data status:                   */
  513. int glove_ready(void)  /* returns 0 if no new data,      */
  514. {                  /*         1 if new data ready,   */
  515.    int lgin, lgrt; /*         2 if rxflags valid too */
  516.   
  517.    disable();
  518.    lgin = glove_int_data.nmissed;
  519.    lgrt = glove_rx_try;
  520.    enable();
  521.   
  522.    if (lgin == 0) return 0;
  523.    if (lgrt > 0) return 2;
  524.    return 1;
  525. }
  526.   
  527. /****************** SWITCHER DRIVER INTERFACE *************/
  528.   
  529.   
  530. #define SW_INIT        0
  531. #define SW_QUIT        1
  532. #define SW_ADV_SWITCH  2
  533. #define SW_SYNC_SWITCH 3
  534.   
  535. static int (*switch_driver)() = NULL;
  536.   
  537. static void sdriver_quit(void)
  538. {
  539.    if (switch_driver) switch_driver(SW_QUIT);
  540. }
  541.   
  542. void init_switch_driver(char *sdname)
  543. {
  544.    if (!stricmp(sdname, "sega"))
  545.    {
  546.       atexit(sega_off);
  547.       return;
  548.    }
  549.   
  550.    switch_driver = load_driver(sdname);
  551.   
  552.    if (switch_driver == NULL)
  553.    {
  554.       fprintf(stderr,"Cannot read switcher driver %s\n", sdname);
  555.       exit(0);
  556.    }
  557.   
  558.    switch_driver = MK_FP(FP_SEG(switch_driver), 16+FP_OFF(switch_driver)); /* entry point */
  559.    switch_driver(SW_INIT);
  560.    atexit(sdriver_quit);
  561. }
  562.   
  563.   
  564. /********************* SEGA GLASSES CONTROL *****************/
  565.   
  566. int left_page = 0; /* left image */
  567. int right_page = 1; /* right image */
  568. int has_switched; /* = 3 once both switched in */
  569.   
  570. static int adv_has_switched = 0;
  571.   
  572. #define SEGA_LEFT  0x30
  573. #define SEGA_RIGHT 0x20
  574. #define SEGA_OFF   0x00
  575.   
  576. #define SEGA_MASK  0x30    /* bits writeable for Sega */
  577.   
  578. #define COMPORT 0x3fc      /* com1 = 0x3fc, com2 = 0x2fc */
  579.   
  580. int sega_left = SEGA_LEFT;
  581. int sega_right = SEGA_RIGHT;
  582. int sega_address = COMPORT;
  583. int sega_mask = SEGA_MASK;
  584. int sega_doff = SEGA_OFF;
  585.   
  586. static int phase = 1; /* current image */
  587.   
  588. void select_sega_port(int port)
  589. {
  590.    sega_address = port;
  591. }
  592.   
  593. static void sega_write(int data)  /* write Sega data w/o disturbance */
  594. {                          /* can also handle glove, Sega on same port */
  595.    disable();
  596.    if (sega_address == glove_out_port)
  597.       sega_port_image = port_image =
  598.       (port_image & (~sega_mask)) | (data & sega_mask);
  599.    else
  600.       sega_port_image = (sega_port_image & (~sega_mask)) | (data & sega_mask);
  601.    outportb(sega_address, sega_port_image);
  602.    enable();
  603. }
  604.   
  605. void switch_sega(int to_go)  /* now gets arg, sync at 0, 1 = advanced signal */
  606. {                            /* 2-step switching ensures adr. load of VGA    */
  607.    if (switch_driver)
  608.    {
  609.       if (to_go == 1)
  610.       {
  611.          if (phase == sega_left)
  612.          {
  613.             phase = sega_right;
  614.             if (switch_driver(SW_ADV_SWITCH, 0) )
  615.                set_vpage(right_page);
  616.             adv_has_switched = 1;
  617.          }
  618.          else
  619.          {
  620.             phase = sega_left;
  621.             if (switch_driver(SW_ADV_SWITCH, 1) )
  622.                set_vpage(left_page);
  623.             adv_has_switched = 2;
  624.          }
  625.       }
  626.       if (to_go == 0)
  627.       {
  628.          switch_driver(SW_SYNC_SWITCH, (phase == sega_left) ? 1 : 0);
  629.          has_switched |= adv_has_switched;
  630.          adv_has_switched = 0;
  631.       }
  632.    }
  633.    else
  634.    {
  635.       if (to_go == 1)
  636.       {
  637.          if (phase == sega_left)
  638.          {
  639.             phase = sega_right;
  640.             set_vpage(right_page);
  641.             adv_has_switched = 1;
  642.          }
  643.          else
  644.          {
  645.             phase = sega_left;
  646.             set_vpage(left_page);
  647.             adv_has_switched = 2;
  648.          }
  649.       }
  650.       if (to_go == 0)
  651.       {
  652.          sega_write(phase);
  653.          has_switched |= adv_has_switched;
  654.          adv_has_switched = 0;
  655.       }
  656.    }
  657. }
  658.   
  659. void sega_off(void)
  660. {
  661.    sega_write(sega_doff); /* turn glasses driver off to save lcds! */
  662. }
  663.   
  664.