home *** CD-ROM | disk | FTP | other *** search
/ Virtual Reality Zone / VRZONE.ISO / mac / PC / PCGLOVE / POWER386 / POWER386.SH / nes.c < prev    next >
C/C++ Source or Header  |  1994-12-20  |  9KB  |  426 lines

  1. /*
  2.  * NES streams driver.
  3.  *
  4.  * Derived, through several generations, from code typed in from 
  5.  * the AT&T Streams Programmer's Guide.
  6.  *
  7.  * Supports Nintendeo Entertainment System joysticks via a parallel port.
  8.  * No interrupts.  No zap-gun support.
  9.  *
  10.  * Each minor number corresponds to one joystick plug.  It should be possible
  11.  * to hook up a few NES gizmos via parallel port.
  12.  *
  13.  * Copyright 1991, Lance C. Norskog
  14.  *
  15.  * version 0.1 - base, running with X
  16.  * version 0.2 - switch to double-bucket input management
  17.  */
  18.  
  19. #include <sys/types.h>
  20. #include <sys/param.h>
  21. #include <sys/stream.h>
  22. #include <sys/stropts.h>
  23. #include <sys/sysmacros.h>
  24. #ifndef    __GNUC__
  25. #include <sys/inline.h>
  26. #endif
  27. #include <sys/errno.h>
  28.  
  29. static struct module_info rnes = {
  30.     3, "nes", 0, INFPSZ, 500, 100
  31. };
  32.  
  33. static struct module_info wnes = {
  34.     3, "nes", 0, INFPSZ, 500, 100
  35. };
  36.  
  37. static int nesopen(), nesclose(), neswput(), nesrsrv();
  38.  
  39. static struct qinit urqinit = {        /* Upper read */
  40.     0, nesrsrv, nesopen, nesclose, NULL, &rnes, 0
  41. };
  42.  
  43. static struct qinit uwqinit = {        /* Upper write */
  44.     neswput, 0, nesopen, nesclose, NULL, &wnes, 0
  45. };
  46.  
  47. struct streamtab nesinfo = {
  48.     &urqinit, &uwqinit, NULL, NULL
  49. };
  50.  
  51. int nes_debug = 0, nes_notimer = 0, nes_nostrobe = 0;
  52. #define    debug(mask, x)    if (nes_debug & mask) printf x;
  53. /* 1 for upper-level, 2 for lower-level, 4 for input data */
  54.  
  55. int nes_in,             /* number of input packets         */
  56.     nes_inb;            /* number of input bytes           */
  57. int nes_nomblk,         /* number of allocb failures        */
  58.     nes_nodupb,         /* number of dupb failures        */
  59.     nes_full,             /* number of buffer-full failures    */
  60.     nes_cant,             /* number of canput failures        */
  61.     nes_busy;            /* number of bucket-busy        */
  62.  
  63. int nes_bsize = 1024;        /* several seconds worth */
  64.  
  65. #define    NNES    1
  66.  
  67. #define    NES_right    0x01
  68. #define    NES_left    0x02
  69. #define    NES_down    0x04
  70. #define    NES_up        0x08
  71. #define    NES_start    0x10
  72. #define    NES_select    0x20
  73. #define    NES_B        0x40
  74. #define    NES_A        0x80
  75.  
  76. #define    NES_SWITCHES    (NES_start | NES_select | NES_A | NES_B)
  77. #define    NES_MOVES    (NES_right | NES_left | NES_up | NES_up)
  78.  
  79. struct    nes_nes {
  80.     unsigned short    ctrl_port, ctrl_clock, ctrl_reset,
  81.             data_port, data_mask,
  82.             ticks;
  83.     unsigned char    canopen;
  84.     queue_t    *rdq;
  85.     int    timer;
  86.     int    nes;            /* last buttons */
  87.     int    switches;
  88.     mblk_t    *mp, *other;        /* pointer to input blocks */
  89. } nes_nes[NNES] = {
  90. {
  91.     0x378,
  92.     1,
  93.     2,
  94.     0x379,
  95.     0x10,
  96.     HZ,
  97. }
  98. };
  99.  
  100. typedef    struct nes_nes nes_t;
  101.  
  102. int nnes = NNES;
  103.  
  104. int nes_c1 = 20;
  105. int nes_c2 = 20;
  106. int nes_c3 = 20;
  107. int nes_c4 = 20;
  108. int nes_c5 = 20;
  109.  
  110. /* move to space.c */
  111.  
  112. nesinit() {
  113.     int i, hz;
  114.  
  115.     for(i=0; i<nnes; i++) {
  116.         nes_nes[i].rdq = (queue_t *) 0;
  117.         nes_nes[i].canopen = 1;
  118.         nes_strobe_init(&nes_nes[i]);
  119.         hz = HZ / nes_nes[i].ticks;
  120.         nes_nes[i].ticks = ((hz == 0) ? 1 : hz);
  121.         nes_nes[i].switches = 0;
  122.     }
  123. }
  124.  
  125. nesopen(q, dev, flag, sflag)
  126. queue_t *q;
  127. {
  128.     nes_t    *nes;
  129.     int    nes_timer();
  130.  
  131.     if (sflag == CLONEOPEN) {
  132.         return OPENFAIL;
  133. /*        for (dev = 0; dev < nnes; dev++)
  134.             if (nes_nes[dev].rdq == (queue_t *) 0)
  135.                 break; */
  136.     } else    dev = minor(dev);
  137.     if (dev > nnes)
  138.         return OPENFAIL;
  139.     nes = &nes_nes[dev];
  140.     if (nes->rdq)
  141.         return dev;
  142.  
  143.     /* q_ptr is the q's repository for our per-chan structure */
  144.     q->q_ptr = (caddr_t) nes;
  145.     WR(q)->q_ptr = (caddr_t) nes;
  146.     nes->rdq = q;
  147.  
  148. debug(1, ("Line %d\n", __LINE__));
  149.     /* Start timer */
  150.     if (! nes_notimer) 
  151.         nes->timer = timeout(nes_timer, q, nes->ticks);    
  152.     nes->mp = allocb(nes_bsize, BPRI_LO);
  153.     nes->other = allocb(nes_bsize, BPRI_LO);
  154.     if (! nes->mp)    nes_nomblk++;
  155.  
  156. debug(1, ("Line %d\n", __LINE__));
  157.     return dev;
  158. }
  159.  
  160. static
  161. nesclose(q)
  162. queue_t *q;
  163. {
  164.     nes_t *nes = (nes_t *) q->q_ptr;
  165.     mblk_t *mp;
  166.  
  167. debug(1, ("Line %d\n", __LINE__));
  168.     untimeout(nes->timer);
  169.     nes->rdq = (queue_t *) 0;
  170.     if (nes->mp)
  171.         freemsg(nes->mp);
  172.     if (nes->other)
  173.         freemsg(nes->other);
  174.     nes->mp = (mblk_t *) 0;
  175.     nes->other = (mblk_t *) 0;
  176.     nes_strobe_init(nes);
  177. debug(1, ("Line %d\n", __LINE__));
  178. }
  179.  
  180. /* This is called when, and only when, the above reader can read. */
  181. /*
  182.  * Double-bucket method:
  183.  *    Only send up when other bucket is finished processing.
  184.  *    Always duplicate buffers before sending them up.
  185.  */
  186. nesrsrv(q)
  187. queue_t *q;
  188. {
  189.     nes_t *nes = (nes_t *) q->q_ptr;
  190.     mblk_t *mp;
  191.     int can, bytes = 0;
  192.  
  193. debug(1, ("Line %d\n", __LINE__));
  194.     if (!nes->mp)
  195.         return;
  196.     if (nes->other && (nes->other->b_datap->db_ref > 1)) {
  197.         nes_busy++;
  198.         return;
  199.     }
  200. debug(1, ("Line %d\n", __LINE__));
  201.     if (! (bytes = (nes->mp->b_wptr > nes->mp->b_rptr)))
  202.         return;
  203.     can = canput(q->q_next);
  204. debug(1, ("Line %d\n", __LINE__));
  205.     if (! can) {
  206.         nes_cant++;
  207.         return;
  208.     }
  209.     if (!(mp = dupb(nes->mp))) {
  210.         nes_nodupb++;
  211.         return;
  212.     }
  213.  
  214. debug(1, ("Line %d\n", __LINE__));
  215.     /* send up copy of current bucket */
  216.     nes_in++;
  217.     nes_inb += mp->b_wptr - mp->b_rptr;
  218.     putnext(q, mp);
  219.  
  220.     /* Swap buckets */
  221.     mp = nes->other;
  222.     nes->other = nes->mp;
  223.     nes->mp = mp;
  224.  
  225. debug(1, ("Line %d\n", __LINE__));
  226.     if (!nes->mp)
  227.         nes->mp = allocb(nes_bsize, BPRI_LO);
  228.     if (! nes->mp)    
  229.         nes_nomblk++;
  230.     else    /* reset read/write pointers of recycled bucket */
  231.         nes->mp->b_rptr = nes->mp->b_wptr = nes->mp->b_datap->db_base;
  232. }
  233.  
  234. /* This is called strioctl(), whether or not it's there!  */
  235. neswput(q, mp)
  236. queue_t *q;
  237. mblk_t *mp;
  238. {
  239.     nes_t *nes = (nes_t *) q->q_ptr;
  240.  
  241.     switch(mp->b_datap->db_type) {
  242.         case M_IOCTL:
  243.         /* process */
  244.  
  245.         mp->b_datap->db_type = M_IOCNAK;
  246.         qreply(q, mp);
  247.         break;
  248.         
  249.         /* flush handling must be here */
  250.         case M_FLUSH:
  251.         if (*mp->b_rptr & FLUSHW)
  252.             flushq(q, FLUSHDATA);
  253.         if (*mp->b_rptr & FLUSHR) {
  254.             flushq(RD(q), FLUSHDATA);
  255.             *mp->b_rptr &= ~FLUSHW;
  256.             qreply(q, mp);
  257.         } else
  258.             freemsg(mp);
  259.         break;
  260.         default:
  261.         freemsg(q, mp);
  262.     }
  263. }
  264.  
  265. nes_timer(q)
  266. queue_t *q;
  267. {
  268.     nes_t *nes = (nes_t *) q->q_ptr;
  269.     unsigned char bits, nes_strobe();
  270.     mblk_t *tmp;
  271.  
  272.     if (nes_notimer)
  273.         goto resched;
  274. debug(2, ("Line %d\n", __LINE__));
  275.     if (!nes->mp && !(nes->mp = allocb(nes_bsize, BPRI_LO))) {
  276.         nes_nomblk++;
  277.         goto resched;
  278.     }
  279.  
  280. debug(2, ("Line %d\n", __LINE__));
  281.     if (nes->mp->b_wptr == nes->mp->b_datap->db_lim) {
  282.         nes_full++;
  283.         goto resched;
  284.     }
  285.  
  286. debug(2, ("Line %d\n", __LINE__));
  287.     bits = nes_strobe(nes);
  288.     if (((bits & NES_right) && (bits & NES_left)) ||
  289.         ((bits & NES_up) && (bits & NES_down))) {
  290.         /* skip */
  291.     } else {
  292. debug(2, ("Line %d\n", __LINE__));
  293.         /* report on movement or change in switches */
  294.         if (bits || ((bits & (NES_SWITCHES)) != nes->switches)) {
  295.             *(nes->mp->b_wptr++) = bits;
  296. debug(2, ("Line %d\n", __LINE__));
  297.             qenable(nes->rdq);
  298.             nes->switches = (bits & NES_SWITCHES);
  299.         }
  300. debug(2, ("Line %d\n", __LINE__));
  301.     }
  302.    resched:
  303.     nes->timer = timeout(nes_timer, q, nes->ticks);
  304. }
  305.  
  306. /* 
  307.  * Put port in quiescent state
  308.  */
  309.  
  310. nes_strobe_init(nes)
  311. nes_t *nes;
  312. {
  313.     int i, j;
  314.  
  315.     if (nes_nostrobe)
  316.         return;
  317.     for(i = 0; i < 8; i++)
  318.         if ((1<<i) & nes->data_mask)
  319.             break;
  320.     if (i == 8) {
  321.         nes->canopen = 0;
  322.         printf("NES%d: data_mask not set!\n", nes - nes_nes);
  323.     }
  324.     outb(nes->ctrl_port, 0);
  325.     outb(nes->data_port, 0);
  326. }
  327.  
  328. #define    hold(clk)        for(slow = clk; slow; slow--);
  329.  
  330. /* Actually strobe the NES and add events to the record */
  331. unsigned char
  332. nes_strobe(nes)
  333. nes_t *nes;
  334. {
  335.     int i, slow;
  336.     unsigned char data;
  337.     unsigned short bits = 0;    /* not char! */
  338.  
  339. debug(2, ("Line %d\n", __LINE__));
  340.     if (nes_nostrobe)
  341.         return 0;
  342. /*
  343. #ifndef    __GNUC__
  344.     intr_disable();
  345. #endif
  346. */
  347. debug(2, ("Line %d\n", __LINE__));
  348.     outb(nes->ctrl_port, nes->ctrl_reset | nes->ctrl_clock);
  349.     hold(nes_c1);
  350.     outb(nes->ctrl_port, nes->ctrl_clock);
  351.     hold(nes_c2);
  352.     for(i = 0; i < 8; i++) {
  353.         data = inb(nes->data_port);
  354.         bits |= (data & nes->data_mask);
  355.         hold(nes_c3);
  356.         outb(nes->ctrl_port, 0);
  357.         hold(nes_c4);
  358.         outb(nes->ctrl_port, nes->ctrl_clock);
  359.         hold(nes_c5);
  360.         bits <<= 1;
  361.     }
  362. debug(2, ("Line %d\n", __LINE__));
  363.     /* bits now straddles word, is upwards by one */
  364.     /* downshift into place */
  365.     for(i = 0; i < 8; i++) {
  366.         bits >>= 1; 
  367.         if (nes->data_mask & (1 << i))
  368.             break;
  369.     }
  370. debug(2, ("Line %d\n", __LINE__));
  371. /*
  372. #ifndef    __GNUC__
  373.     intr_restore();
  374. #endif
  375. */
  376. debug(2, ("Line %d\n", __LINE__));
  377.     bits = ~bits;
  378. if (bits && (nes_debug & 4))
  379.         printf("Input: 0x%x\n", bits & 0x1ff);
  380.     return (unsigned char) bits;
  381. }
  382.  
  383. static char *
  384. M_string(type)
  385. {
  386.     switch(type) {
  387.         case M_DATA:    return "M_DATA";
  388.         case M_PROTO:    return "M_PROTO";
  389.         case M_BREAK:    return "M_BREAK";
  390.         case M_PASSFP:    return "M_PASSFP";
  391.         case M_SIG:    return "M_SIG";
  392.         case M_DELAY:    return "M_DELAY";
  393.         case M_CTL:    return "M_CTL";
  394.         case M_IOCTL:    return "M_IOCTL";
  395.         case M_SETOPTS:    return "M_SETOPTS";
  396.         case M_IOCACK:    return "M_IOCACK";
  397.         case M_IOCNAK:    return "M_IOCNAK";
  398.         case M_PCPROTO:    return "M_PCPROTO";
  399.         case M_PCSIG:    return "M_PCSIG";
  400.         case M_FLUSH:    return "M_FLUSH";
  401.         case M_STOP:    return "M_STOP";
  402.         case M_START:    return "M_START";
  403.         case M_HANGUP:    return "M_HANGUP";
  404.         case M_ERROR:    return "M_ERROR";
  405.         default:    return "M_UNKNOWN";
  406.     }
  407. }
  408.  
  409. nesintr() {;}
  410. /* Don't digest it here.
  411.         if (bits & NES_right)
  412.             nes->right++;
  413.         if (bits & NES_left)
  414.             nes->left++;
  415.         if (bits & NES_up)
  416.             nes->up++;
  417.         if (bits & NES_down)
  418.             nes->down++;
  419.  
  420.         if (bits & NES_A)
  421.             nes->A = 1;
  422.         if (bits & NES_B)
  423.             nes->B = 1;
  424. */
  425.  
  426.