home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / d / dec92.zip / 1012063A < prev    next >
Text File  |  1992-10-13  |  16KB  |  726 lines

  1. /* 
  2.  * mpu.c 
  3.  * device driver for mpu-401 midi card
  4.  */
  5.  
  6. #include "../h/param.h"
  7. #include "../h/types.h"
  8. #include "../h/dir.h"
  9. #include "../h/signal.h"
  10. #include "../h/page.h"
  11. #include "../h/seg.h"
  12. #include "../h/user.h"
  13. #include "../h/file.h"
  14. #include "../h/tty.h"
  15. #include "../h/systm.h"
  16. #include "../h/conf.h"
  17. #include "../h/errno.h"
  18. #include "mpu.h"
  19.  
  20. /* external support prototypes */
  21.  
  22. int inb(int);
  23. void outb(int, int);
  24. caddr_t cvttoaddr(faddr_t);
  25. int fubyte(faddr_t);
  26. void subyte(char *, int);
  27. int copyin(faddr_t, char *, int);
  28.  
  29. void printcfg(char *, int, int, int, int, char *, ...);
  30. void printf(char *, ...);
  31. int getchar(void);
  32. void putchar(int);
  33.  
  34. int sleep(caddr_t, int);
  35. void wakeup(caddr_t);
  36. int timeout(int (*)(), caddr_t, int);
  37. void untimeout(int);
  38.  
  39. int spl6(void);
  40. void splx(int);
  41.  
  42. int cpass(void);
  43. int passc(int);
  44. int getc(struct clist *);
  45. int putc(int, struct clist *);
  46.  
  47. #define DRIVERID  0x00  /* driver version */
  48.  
  49. /* I/O addresses and vector */
  50. /* if using IRQ 2, set VECTOR to 25 (030+VECTOR-1) */
  51. #define VECTOR  25
  52. #define BASE    0x220     /* I/O address of mpu card */
  53. #define CMD     (BASE+1)  /* command output port */
  54. #define STATUS  (BASE+1)  /* mpu status port */
  55. #define DATA    BASE      /* data input port */
  56.  
  57. /* Status flags (neg logic) */
  58. #define RR_F    0x40      /* mpu ready to receive */
  59. #define DA_F    0x80      /* data available flag */
  60.  
  61. /* Test RR and DA flags */
  62. #define RR()    (!(INB(STATUS)&RR_F))
  63. #define rr()    (!(inb(STATUS)&RR_F))
  64. #define DA()    (!(INB(STATUS)&DA_F))
  65. #define da()    (!(inb(STATUS)&DA_F))
  66.  
  67. /* Device interrupt level */
  68. #define SPLINT  spl6
  69.  
  70. /* Busy-wait looping count */
  71. #define SPIN    100000
  72.  
  73. #define ACK     0xFE    /* mpu command acknowledge */
  74.  
  75. #define YES     1
  76. #define NO      0
  77.  
  78. #define E_OK      0     /* ok return code */
  79. #define E_TIMEOUT 1     /* timeout return code */
  80. #define E_INTR    2     /* interrupt return code */
  81.  
  82. #define PRI (PZERO+1)   /* sleep/wakeup priority */
  83.  
  84. static struct clist in_q;   /* input queue */
  85. static int busy = NO;       /* driver busy flag */
  86. static int exist = NO;      /* mpu card found flag */
  87. static int isopen = NO;     /* exclusive use flag */
  88. static int debug = 0;       /* debugging level */
  89. static int waitda = 0;      /* result DA timer */
  90.  
  91. /* local prototypes */
  92.  
  93. static int reset(void);
  94. static int waitRR(void);
  95. static int mpucmd(int);
  96. static int mpuinb(int);
  97. static void mpuoutb(int, int);
  98.  
  99. #define OUTB(addr,byte)   mpuoutb((addr),(byte))
  100. #define INB(addr)         mpuinb(addr)
  101.  
  102. /*-----------------------------------------------------
  103.  * mpuinit - determine if device exists at BASE address
  104.  */
  105.  
  106. void mpuinit()
  107. {
  108.   int i, ver = 0, rev = 0;
  109.  
  110.   in_q.c_cc = 0;  /* input q is empty */
  111.  
  112.   /*
  113.    * see if it's there by trying to reset
  114.    */
  115.   outb(CMD, MPU_RESET);
  116.   for (i = 0; i < SPIN; ++i)
  117.     if (da())
  118.       break;
  119.   if (i == SPIN) {
  120.     outb(CMD, MPU_RESET);
  121.     for (i = 0; i < SPIN; ++i)
  122.       if (da())
  123.         break;
  124.     if (i == SPIN)
  125.       goto NOTFOUND;
  126.   }
  127.   if (inb(DATA) != ACK)
  128.     goto NOTFOUND;
  129.  
  130.   /*
  131.    * get firmware version
  132.    */
  133.   for (i = 0; i < SPIN; ++i)  /* wait for RR */
  134.     if (rr())
  135.       break;
  136.   if (i == SPIN)              /* timed out */
  137.     goto NOTFOUND;
  138.   outb(CMD, MPU_VERSION);     /* send request */
  139.   for (i = 0; i < SPIN; ++i)  /* wait for ack */
  140.     if (da() && inb(DATA) == ACK)
  141.       break;
  142.   if (i == SPIN)              /* timed out */
  143.     goto NOTFOUND;
  144.   for (i = 0; i < SPIN; ++i)  /* wait for data */
  145.     if (da()) {
  146.       ver = inb(DATA);        /* read version */
  147.       break;
  148.     }
  149.   if (i == SPIN)              /* timed out */
  150.     goto NOTFOUND;
  151.  
  152.   /*
  153.    * get firmware revision
  154.    */
  155.   for (i = 0; i < SPIN; ++i)  /* wait for RR */
  156.     if (rr())
  157.       break;
  158.   if (i == SPIN)              /* timed out */
  159.     goto NOTFOUND;
  160.   outb(CMD, MPU_REVISION);    /* send request */
  161.   for (i = 0; i < SPIN; ++i)  /* wait for ACK */
  162.     if (da() && inb(DATA) == ACK)
  163.       break;
  164.   if (i == SPIN)              /* timed out */
  165.     goto NOTFOUND;
  166.   for (i = 0; i < SPIN; ++i)  /* wait for data */
  167.     if (da()) {
  168.       rev = inb(DATA);        /* read revision */
  169.       break;
  170.     }
  171.  
  172.   printcfg("mpu", BASE, 1, VECTOR, -1,
  173.    "ver=%d rev=%d did=%d", ver, rev, DRIVERID);
  174.   exist = YES;
  175.   return;
  176.  
  177. NOTFOUND:
  178.   printf("MPU not found at %x\n", BASE);
  179. }
  180.  
  181. /*-----------------------------------------------------
  182.  * mpuopen - check device availability and
  183.  *           ensure exclusive access
  184.  */
  185.  
  186. void mpuopen(dev, flag, id)
  187. int dev, flag, id;
  188. {
  189.   if (debug)
  190.     printf("open: dev=%x flag=%x id=%x\n", dev, flag,
  191.             id);
  192.  
  193.   if (!exist) {
  194.     u.u_error = ENXIO;
  195.     if (debug)
  196.       printf("open: device doesn't exist\n");
  197.     return;
  198.   }
  199.   if (isopen) {
  200.     u.u_error = EBUSY;
  201.     if (debug)
  202.       printf("open: failed EBUSY\n");
  203.     return;
  204.   }
  205.   isopen = YES;
  206.   if (reset() != E_OK) {
  207.     u.u_error = EIO;
  208.     if (debug)
  209.       printf("open: failed can't reset mpu\n");
  210.     isopen = NO;
  211.   }
  212. }
  213.  
  214. /*-----------------------------------------------------
  215.  * mpuclose - reset mpu and give up exclusive access
  216.  */
  217.  
  218. void mpuclose(dev, flag)
  219. int dev, flag;
  220. {
  221.   if (debug)
  222.     printf("close: dev=%x flag=%x\n", dev, flag);
  223.  
  224.   (void) reset();
  225.   while (getc(&in_q) != -1)   /* eat in_q */
  226.     ;
  227.   busy = isopen = NO;
  228. }
  229.  
  230. /*-----------------------------------------------------
  231.  * mpuread - read data from mpu
  232.  */
  233.  
  234. void mpuread(dev)
  235. int dev;
  236. {
  237.   int byte, oldpri;
  238.  
  239.   if (debug)
  240.     printf("read: dev=%x u.u_count=%d\n", dev,
  241.            u.u_count);
  242.  
  243.   /* wait till it's ok to enter */
  244.  
  245.   while (busy)
  246.     sleep((caddr_t) &busy, PRI);
  247.   busy = YES;
  248.  
  249.   /* first get bytes from input q */
  250.  
  251.   while (u.u_count) {
  252.     byte = getc(&in_q);
  253.     if (byte == -1)
  254.       break;    /* used up input q */
  255.     if (passc(byte) == -1) {
  256.       busy = NO;
  257.       wakeup((caddr_t) &busy);
  258.       return;     /* satisfied request */
  259.     }
  260.   }
  261.  
  262.   /* now get straight from device */
  263.  
  264.   while (u.u_count) {
  265.     oldpri = SPLINT();
  266.     while (!DA())
  267.       if (sleep((caddr_t) mpuread, PRI|PCATCH) != 0) {
  268.         splx(oldpri);
  269.         u.u_error = EINTR;
  270.         if (debug)
  271.           printf("read: caught software interrupt\n");
  272.         busy = NO;
  273.         wakeup((caddr_t) &busy);
  274.         return;
  275.       }
  276.       splx(oldpri);
  277.       if (passc(INB(DATA)) == -1)
  278.         break;      /* satisfied request */
  279.   }
  280.  
  281.   busy = NO;
  282.   wakeup((caddr_t) &busy);
  283. }
  284.  
  285. /*-----------------------------------------------------
  286.  * mpuwrite - write data to mpu
  287.  */
  288.  
  289. void mpuwrite(dev)
  290. int dev;
  291. {
  292.   int ret;
  293.  
  294.   if (debug)
  295.     printf("write: dev=%x u.u_count=%d\n", dev,
  296.            u.u_count);
  297.  
  298.   /* wait till it's ok to enter */
  299.  
  300.   while (busy)
  301.     sleep((caddr_t) &busy, PRI);
  302.   busy = YES;
  303.  
  304.   while (u.u_count) {
  305.     ret = waitRR();
  306.     if (ret == E_TIMEOUT) {
  307.       if (debug)
  308.         printf("write: waitRR timed out\n");
  309.       u.u_error = EIO;
  310.       break;
  311.     } else if (ret == E_INTR) {
  312.       if (debug)
  313.         printf("write: waitRR caught software int\n");
  314.       u.u_error = EINTR;
  315.       break;
  316.     } else
  317.       OUTB(DATA, cpass());
  318.   }
  319.  
  320.   busy = NO;
  321.   wakeup((caddr_t) &busy);
  322. }
  323.  
  324. /*-----------------------------------------------------
  325.  * mpuioctl
  326.  */
  327.  
  328. void mpuioctl(dev, cmd, arg, mode)
  329. int dev, cmd;
  330. faddr_t arg;
  331. int mode;
  332. {
  333.   struct mpustuff m;
  334.   int byte, ret, got_intr = NO, oldpri, timeouts;
  335.  
  336.   if (debug)
  337.     printf("ioctl: dev=%x cmd=%x mode=%x ", dev, cmd,
  338.            mode);
  339.  
  340.   /* convert ptr on 286 callers */
  341.  
  342.   if (!IS386())
  343.     arg = (faddr_t) cvttoaddr(arg);
  344.  
  345.   /* make local copy of mpustuff in m */
  346.  
  347.   if (copyin(arg, (char *) &m, sizeof(struct mpustuff))
  348.       == -1) {
  349.     u.u_error = EFAULT;
  350.     if (debug)
  351.       printf("\nioctl: copyin error EFAULT\n");
  352.     return;
  353.   }
  354.   if (!IS386()) {
  355.     m.opbuf = (char *) cvttoaddr(m.opbuf);
  356.     m.resbuf = (char *) cvttoaddr(m.resbuf);
  357.   }
  358.  
  359.   if (debug)
  360.     printf("opsize=%d ressize=%d\n", m.opsize,
  361.            m.ressize);
  362.  
  363.   /* handle driver commands */
  364.  
  365.   if (cmd > MPU_RESET) {
  366.     switch (cmd) {
  367.     case MPU_DRIVERID:
  368.       if (m.ressize != 1) {
  369.         u.u_error = EINVAL;
  370.         return;
  371.       }
  372.       subyte(m.resbuf, DRIVERID);
  373.       return;
  374.     case MPU_SETDEBUG:
  375.       if (m.opsize != 1) {
  376.         u.u_error = EINVAL;
  377.         return;
  378.       }
  379.       byte = fubyte(m.opbuf);
  380.       if (byte < 0 || byte > 3) {
  381.         u.u_error = EINVAL;
  382.         return;
  383.       }
  384.       debug = byte;
  385.       return;
  386.     case MPU_GETDEBUG:
  387.       if (m.ressize != 1) {
  388.         u.u_error = EINVAL;
  389.         return;
  390.       }
  391.       subyte(m.resbuf, debug);
  392.       return;
  393.     default:
  394.       u.u_error = EINVAL;
  395.       return;
  396.     }
  397.   }
  398.  
  399.   got_intr = NO;
  400.  
  401.   /* wait till it's ok to enter */
  402.  
  403.   while (busy)
  404.     sleep((caddr_t) &busy, PRI);
  405.   busy = YES;
  406.  
  407.   /* handle reset command specially */
  408.  
  409.   if (cmd == MPU_RESET)
  410.     ret = reset();
  411.   else
  412.     ret = mpucmd(cmd);
  413.  
  414.   if (ret == E_TIMEOUT) {
  415.     if (debug)
  416.       printf("ioctl: reset() or mpucmd() timed out\n");
  417.     u.u_error = EIO;
  418.     goto done;
  419.   } else if (ret == E_INTR) {
  420.     if (debug)
  421.       printf(
  422.    "ioctl: reset() or mpucmd() caught software int\n");
  423.     u.u_error = EINTR;
  424.     goto done;
  425.   }
  426.  
  427.   /* output parameters */
  428.  
  429.   timeouts = 0;
  430.   while (m.opsize > 0) {
  431.     ret = waitRR();
  432.     if (ret == E_TIMEOUT) {
  433.       if (debug)
  434.         printf("ioctl: waitRR timed out\n");
  435.       if (++timeouts > 2) {
  436.         u.u_error = EIO;
  437.         busy = NO;
  438.         wakeup((caddr_t) &busy);
  439.         return;
  440.       }
  441.     } else if (ret == E_INTR) {
  442.       if (debug)
  443.         printf("ioctl: waitRR caught software int\n");
  444.       got_intr = YES;
  445.     } else {
  446.       OUTB(DATA, fubyte(m.opbuf++));
  447.       --m.opsize;
  448.     }
  449.   }
  450.  
  451.   /* retrieve result bytes */
  452.  
  453.   if (m.ressize > 0) {
  454.     oldpri = SPLINT();
  455.     while (m.ressize > 0) {
  456.       while (!DA()) {
  457.         /* wait no longer than */
  458.         /* 2 clock ticks */
  459.         waitda = 2;
  460.         if (sleep((caddr_t)mpuread, PRI|PCATCH) != 0) {
  461.           if (debug)
  462.             printf(
  463.               "ioctl: DA sleep caught software int\n");
  464.           got_intr = YES;
  465.         }
  466.         if (waitda <= 0) {
  467.           /* woke up because */
  468.           /* of timeout */
  469.           if (debug)
  470.             printf(
  471.              "ioctl: timed out awaiting cmd result\n");
  472.           u.u_error = EINVAL;
  473.           break;
  474.         }
  475.         waitda = 0;   /* cancel alarm */
  476.       }
  477.       subyte(m.resbuf++, INB(DATA));
  478.       --m.ressize;
  479.     }
  480.     splx(oldpri);
  481.   }
  482.  
  483. done:
  484.   busy = NO;
  485.   wakeup((caddr_t) &busy);
  486.   if (got_intr)
  487.     u.u_error = EINTR;
  488.   return;
  489. }
  490.  
  491. /*-----------------------------------------------------
  492.  * mpuintr - interrupt routine; just wakes up reader
  493.  */
  494.  
  495. void mpuintr(vector)
  496. int vector;
  497. {
  498.   if (debug)
  499.     printf("intr: vec=%d\n", vector);
  500.   wakeup((caddr_t) mpuread);
  501. }
  502.  
  503. /*-----------------------------------------------------
  504.  * mpuhalt - reset mpu before shutdown
  505.  */
  506.  
  507. void mpuhalt()
  508. {
  509.   if (debug)
  510.     printf("mpuhalt\n");
  511.   if (exist)
  512.     (void) reset();
  513. }
  514.  
  515. /*-----------------------------------------------------
  516.  * waitRR - wait for RR or software interrupt
  517.  *
  518.  * sets up conditions to check RR bit on every clock
  519.  * tick and returns on mpu ready to receive, timed out
  520.  * or software interrupt
  521.  *
  522.  * returns:
  523.  *   0 - ok, mpu is ready to receive
  524.  *   1 - timed out
  525.  *   2 - got software interrupt
  526.  */
  527.  
  528. static int polling = 0;
  529.  
  530. static int waitRR()
  531. {
  532.   int oldpri, retval;
  533.  
  534.   if (debug)
  535.     printf("waitRR\n");
  536.  
  537.   oldpri = SPLINT();
  538.   polling = HZ * 5;
  539.   while (1) {
  540.     if (RR()) {
  541.       retval = E_OK;    /* mpu RR */
  542.       break;
  543.     }
  544.     if (polling <= 0) {
  545.       retval = E_TIMEOUT; /* timed out */
  546.       break;
  547.     }
  548.     if (sleep((caddr_t) &polling, PRI|PCATCH) == 1) {
  549.       retval = E_INTR;  /* software intr */
  550.       break;
  551.     }
  552.   }
  553.   polling = 0;
  554.   splx(oldpri);
  555.   return retval;
  556. }
  557.  
  558. int mpupoll()
  559. {
  560.   if (waitda > 0)
  561.     if (--waitda <= 0)
  562.       wakeup((caddr_t) mpuread);
  563.  
  564.   if (polling > 0) {
  565.     if (--polling <= 0 || RR()) {
  566.       if (debug)
  567.         if (polling == 0)
  568.           printf("mpupoll: expired\n");
  569.         else
  570.           printf("mpupoll: rr\n");
  571.       polling = 0;
  572.       wakeup((caddr_t) &polling);
  573.     }
  574.   }
  575.   return 0;
  576. }
  577.  
  578. /*-----------------------------------------------------
  579.  * mpucmd - generic command outputter
  580.  *
  581.  * outputs command and waits for acknowledge; up to
  582.  * caller to output parameters and retrieve results
  583.  *
  584.  * returns
  585.  *   0 - ok, command output
  586.  *   1 - timed out
  587.  *   2 - interrupt
  588.  *
  589.  * When mpucmd returns 2, it is ok to assume the mpu is
  590.  * still in sync because mpucmd waits the full 1 second
  591.  * for ACK even if it receives a software interrupt.
  592.  * If mpucmd received ACK and got an interrupt, the mpu
  593.  * is in sync.  If mpucmd had to wait and never got
  594.  * ACK, assum the mpu wouldn't have sent one anyway
  595.  * (perhaps it was in uart mode and the command was
  596.  * reset).
  597.  *
  598.  * Another possibility is that the interrupt occurred
  599.  * while waiting for the mpu to become ready to receive
  600.  * a command.  In this case, the mpu is still in sync,
  601.  * but the command wasn't sent.
  602.  *
  603.  * When mpucmd returns 1, that means mpucmd waited a
  604.  * full 1 second for ACK or ready to receive and didn't
  605.  * get it.  OK to assume mpu still in sync, but command
  606.  * wasn't necessarily sent.
  607.  */
  608.  
  609. static int timeup;
  610.  
  611. static void mpualarm()
  612. {
  613.   if (debug)
  614.     printf("mpualarm\n");
  615.   timeup = YES;
  616.   wakeup((caddr_t) mpuread);
  617. }
  618.  
  619. static int mpucmd(cmd)
  620. int cmd;
  621. {
  622.   int ret, id, byte, got_ack, got_intr;
  623.  
  624.   if (debug)
  625.     printf("mpucmd: cmd=%x\n", cmd);
  626.  
  627.   /* wait for mpu to be ready to receive cmd */
  628.  
  629.   if ((ret = waitRR()) != E_OK)
  630.     return ret;
  631.  
  632.   /* send command */
  633.  
  634.   OUTB(CMD, cmd);
  635.  
  636.   /* wait up to 1 sec for acknowledge */
  637.  
  638.   got_ack = NO;
  639.   got_intr = NO;
  640.   timeup = NO;
  641.   id = timeout(mpualarm, (caddr_t) 0, HZ);
  642.   while (!timeup) {
  643.     while (!DA() && !timeup)
  644.       if (sleep((caddr_t) mpuread, PRI|PCATCH))
  645.         got_intr = YES;
  646.     if (DA()) {
  647.       byte = INB(DATA);
  648.       if (byte == ACK) {
  649.         got_ack = YES;
  650.         break;
  651.       } else {
  652.         while (putc(byte, &in_q) == -1) {
  653.           /* wait a while if */
  654.           /* clist shortage */
  655.           if (sleep((caddr_t)&lbolt, PRI|PCATCH) == -1)
  656.             got_intr = YES;
  657.         }
  658.       }
  659.     }
  660.   }
  661.   if (!timeup)
  662.     untimeout(id);
  663.   if (got_intr)
  664.     ret = E_INTR;
  665.   else if (got_ack)
  666.     ret = E_OK;
  667.   else
  668.     ret = E_TIMEOUT;
  669.   return ret;
  670. }
  671.  
  672. /*-----------------------------------------------------
  673.  * reset - special protocol for reset
  674.  *
  675.  * returns
  676.  *   0 - ok
  677.  *   1 - timed out
  678.  *   2 - software interrupt
  679.  */
  680.  
  681. static int reset()
  682. {
  683.   int ret;
  684.  
  685.   if (debug)
  686.     printf("reset\n");
  687.  
  688.   ret = mpucmd(MPU_RESET);
  689.   if (ret == E_OK || ret == E_INTR)
  690.     return ret;
  691.   /* timed out for some reason; zap it */
  692.   OUTB(CMD, MPU_RESET);
  693.   while (DA())  /* and eat residue */
  694.     INB(DATA);
  695.  
  696.   ret = mpucmd(MPU_RESET);  /* now try proper reset*/
  697.   while (getc(&in_q) != -1)
  698.     ;     /* eat input q */
  699.  
  700.   return ret;
  701. }
  702.  
  703. /*-----------------------------------------------------
  704.  * INB and OUTB - debug versions of inb() and outb()
  705.  */
  706.  
  707. static void mpuoutb(addr, byte)
  708. int addr, byte;
  709. {
  710.   if (debug > 1)
  711.     printf("OUTB(%x,%x)\n", addr, byte);
  712.   outb(addr, byte);
  713. }
  714.  
  715. static int mpuinb(addr)
  716. int addr;
  717. {
  718.   int byte;
  719.  
  720.   byte = inb(addr);
  721.   if (debug > 1)
  722.     printf("INB(%x) = %x\n", addr, byte);
  723.   return byte;
  724. }
  725. WRAP_EOF
  726.