home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / LXASY.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  12KB  |  542 lines

  1. /*
  2.  * File stolen from WAMPES 921229, modified for compatibility with JNOS and my
  3.  * tastes, and left to sink or swim.  Blub!  ++bsa
  4.  *
  5.  * The actual structure is much closer to that of JNOS than to WAMPES.  The
  6.  * reason is that WAMPES uses these weirdball I/O hooks... We will use the
  7.  * "classic" interface, modified by the use of register_fd().
  8.  *
  9.  * This file should really be called posixasy.c, since it uses only POSIX entry
  10.  * points (as far as I can tell).
  11.  */
  12.   
  13. #include <sys/types.h>
  14.   
  15. #include <fcntl.h>
  16. #include <termios.h>
  17. #include <sys/time.h>
  18. #include <errno.h>
  19.   
  20. #include "global.h"
  21. #include "mbuf.h"
  22. #include "proc.h"
  23. #include "iface.h"
  24. #include "asy.h"
  25. #include "timer.h"
  26. #include "lxasy.h"
  27. #include "hardware.h"
  28. #include "devparam.h"
  29.   
  30. static int find_speed __ARGS((long speed));
  31. static void pasy __ARGS((struct asy *asyp));
  32. static void asy_tx __ARGS((int, void *, void *));
  33. static void asy_input __ARGS((int, void *, void *));
  34.   
  35. struct asy Asy[ASY_MAX];
  36.   
  37. /*---------------------------------------------------------------------------*/
  38.   
  39. static struct {
  40.     long speed;
  41.     speed_t flags;
  42. } speed_table[] = {
  43. #ifdef B50
  44.     50, B50,
  45. #endif
  46. #ifdef B75
  47.     75, B75,
  48. #endif
  49. #ifdef B110
  50.     110, B110,
  51. #endif
  52. #ifdef B134
  53.     134, B134,
  54. #endif
  55. #ifdef B150
  56.     150, B150,
  57. #endif
  58. #ifdef B200
  59.     200, B200,
  60. #endif
  61. #ifdef B300
  62.     300, B300,
  63. #endif
  64. #ifdef B600
  65.     600, B600,
  66. #endif
  67. #ifdef B900
  68.     900, B900,
  69. #endif
  70. #ifdef B1200
  71.     1200, B1200,
  72. #endif
  73. #ifdef B1800
  74.     1800, B1800,
  75. #endif
  76. #ifdef B2400
  77.     2400, B2400,
  78. #endif
  79. #ifdef B3600
  80.     3600, B3600,
  81. #endif
  82. #ifdef B4800
  83.     4800, B4800,
  84. #endif
  85. #ifdef B7200
  86.     7200, B7200,
  87. #endif
  88. #ifdef B9600
  89.     9600, B9600,
  90. #endif
  91. #ifdef B19200
  92.     19200, B19200,
  93. #endif
  94. #ifdef B38400
  95.     38400, B38400,
  96. #endif
  97. #ifdef B57600
  98.     57600, B57600,
  99. #endif
  100. #ifdef B115200
  101.     115200, B115200,
  102. #endif
  103. #ifdef B230400
  104.     230400, B230400,
  105. #endif
  106. #ifdef B460800
  107.     460800, B460800,
  108. #endif
  109.     -1, 0
  110. };
  111.   
  112. /*---------------------------------------------------------------------------*/
  113.   
  114. static int
  115. find_speed(speed)
  116. long speed;
  117. {
  118.     int i;
  119.   
  120.     i = 0;
  121.     while (speed_table[i].speed < speed && speed_table[i+1].speed > 0)
  122.         i++;
  123.     return i;
  124. }
  125.   
  126. /*---------------------------------------------------------------------------*/
  127.   
  128. /* Initialize asynch port "dev" */
  129. int
  130. asy_init(dev,ifp,arg1,arg2,bufsize,trigchar,monitor,speed,force,triglevel)
  131. int dev;
  132. struct iface *ifp;
  133. char *arg1,*arg2;       /* Attach args for address and vector */
  134. int16 bufsize;
  135. int trigchar;
  136. char monitor;
  137. long speed;
  138. int force;
  139. int triglevel;
  140. {
  141.     register struct asy *ap;
  142.     char filename[80];
  143.     char *ifn;
  144.     int sp, fd;
  145.     struct termios termios;
  146.   
  147.     ap = &Asy[dev];
  148.   
  149.     /* UUCP locking with ASCII pid */
  150.     strcpy(ap->uulock, "/usr/spool/uucp/LCK..");
  151.     strcat(ap->uulock, arg1);
  152.     for (;;)
  153.     {
  154.         if ((fd = open(ap->uulock, O_WRONLY|O_CREAT|O_EXCL, 0644)) != -1 ||
  155.             errno != EEXIST)
  156.             break;
  157.         /* read pid, unlink and retry if proc no longer exists */
  158.         if ((fd = open(ap->uulock, O_RDONLY)) == -1)
  159.             continue;   /* timing is everything */
  160.         filename[read(fd, filename, 10)] = '\0';
  161.         close(fd);
  162.         sscanf(filename, "%d", &fd);
  163.         if (kill(fd, 0) == -1 && errno == ESRCH)
  164.         {
  165.             tprintf("Removing stale lockfile for %s\n", arg1);
  166.             unlink(ap->uulock);
  167.             continue;
  168.         }
  169.         tprintf("/dev/%s is locked\n", arg1);
  170.         ap->uulock[0] = '\0'; /* so it won't clobber existing lock */
  171.         goto Fail;
  172.     }
  173.     if (fd == -1)
  174.     {
  175.         tprintf("Can't lock /dev/%s: %s\n", arg1, strerror(errno));
  176.         ap->uulock[0] = '\0';
  177.         goto Fail;
  178.     }
  179.     chmod(ap->uulock, 0644); /* beware of overly restrictive umask */
  180.     sprintf(filename, "%10d\n", getpid());
  181.     write(fd, filename, 11);
  182.     close(fd);
  183.   
  184.     strcpy(filename, "/dev/");
  185.     strcat(filename, arg1);
  186.     if ((fd = open(filename, O_RDWR|O_NONBLOCK|O_NOCTTY, 0644)) == -1)
  187.     {
  188.         tprintf("Can't open port: %s\n", strerror(errno));
  189.         goto Fail;
  190.     }
  191.     ap->iface = ifp;
  192.     sp = find_speed(speed);
  193.     ap->speed = speed_table[sp].speed;
  194.     memset((char *) &termios, 0, sizeof(termios));
  195.     termios.c_iflag = IGNBRK|IGNPAR;
  196.     termios.c_cflag = CS8|CREAD|CLOCAL|speed_table[sp].flags;
  197.     if (cfsetispeed(&termios, speed_table[sp].flags) == -1)
  198.     {
  199.         tprintf("Can't set speed: %s\n", strerror(errno));
  200.         goto Fail;
  201.     }
  202.     if (cfsetospeed(&termios, speed_table[sp].flags) == -1)
  203.     {
  204.         tprintf("Can't set speed: %s\n", strerror(errno));
  205.         goto Fail;
  206.     }
  207.     if (tcsetattr(fd, TCSANOW, &termios) == -1)
  208.     {
  209.         tprintf("Can't configure port: %s\n", strerror(errno));
  210.         goto Fail;
  211.     }
  212.     /* security: port won't work until re-opened */
  213.     if ((ap->fd = open(filename, O_RDWR|O_NONBLOCK|O_NOCTTY, 0644)) == -1)
  214.     {
  215.         tprintf("Can't reopen port: %s\n", strerror(errno));
  216.         goto Fail;
  217.     }
  218.     close(fd);
  219.   
  220.     ifp->txproc = newproc(ifn = if_name(ifp," tx"),
  221.     256, asy_tx, dev, ifp, NULL, 0);
  222.     free(ifn);
  223.     ap->rxproc = newproc(ifn = if_name(ifp, " asy rx"),
  224.     256, asy_input, dev, ifp, NULL, 0);
  225.     free(ifn);
  226.   
  227.     register_io(ap->fd, &ap->fd);
  228.   
  229.     return 0;
  230.   
  231.     Fail:
  232.     rflush();       /* make sure the message gets out */
  233.     if (fd != -1)
  234.         close(fd);
  235.     /* Unlock port */
  236.     if (ap->uulock[0])
  237.         unlink(ap->uulock);
  238.     ap->uulock[0] = '\0';
  239.     ap->iface = NULLIF;
  240.     return -1;
  241. }
  242.   
  243. /*---------------------------------------------------------------------------*/
  244.   
  245. int
  246. asy_stop(ifp)
  247. struct iface *ifp;
  248. {
  249.     register struct asy *ap;
  250.   
  251.     ap = &Asy[ifp->dev];
  252.   
  253.     if(ap->iface == NULLIF)
  254.         return -1;      /* Not allocated */
  255.   
  256.     unregister_io(ap->fd);
  257.   
  258.     if (ifp->txproc)
  259.         killproc(ifp->txproc);
  260.     ifp->txproc = 0;
  261.   
  262.     if (ap->rxproc)
  263.         killproc(ap->rxproc);
  264.     ap->rxproc = 0;
  265.   
  266.     ap->iface = NULLIF;
  267.   
  268.     free_q(&ap->sndq);
  269.     close(ap->fd);
  270.   
  271.     free_q(&ap->rcvq);
  272.   
  273.     if (ap->uulock[0])
  274.         unlink(ap->uulock);
  275.     ap->uulock[0] = '\0';
  276.   
  277.     return 0;
  278. }
  279.   
  280. void
  281. detach_all_asy()
  282. {
  283.     register struct asy *ap;
  284.   
  285.     for (ap = Asy; ap != Asy + ASY_MAX; ap++)
  286.     {
  287.         if(ap->iface == NULLIF)
  288.             break;
  289.         unregister_io(ap->fd);
  290.         if (ap->iface->txproc)
  291.             killproc(ap->iface->txproc);
  292.         ap->iface->txproc = 0;
  293.         if (ap->rxproc)
  294.             killproc(ap->rxproc);
  295.         ap->rxproc = 0;
  296.         ap->iface = NULLIF;
  297.         free_q(&ap->sndq);
  298.         free_q(&ap->rcvq);
  299.         close(ap->fd);
  300.         if (ap->uulock[0])
  301.             unlink(ap->uulock);
  302.         ap->uulock[0] = '\0';
  303.     }
  304. }
  305.   
  306.   
  307. /*---------------------------------------------------------------------------*/
  308.   
  309. /* Set asynch line speed */
  310. int
  311. asy_speed(dev,bps)
  312. int dev;
  313. long bps;
  314. {
  315.   
  316.     struct asy *asyp;
  317.     int sp;
  318.     struct termios termios;
  319.   
  320.     if(bps <= 0 || dev >= ASY_MAX)
  321.         return -1;
  322.     asyp = &Asy[dev];
  323.     if(asyp->iface == NULLIF)
  324.         return -1;
  325.   
  326.     if(bps == 0)
  327.         return -1;
  328.     sp = find_speed(bps);
  329.     if (tcgetattr(asyp->fd, &termios))
  330.         return -1;
  331.     if (cfsetispeed(&termios, speed_table[sp].flags))
  332.         return -1;
  333.     if (cfsetospeed(&termios, speed_table[sp].flags))
  334.         return -1;
  335.     termios.c_cflag &= ~CBAUD;
  336.     termios.c_cflag |= speed_table[sp].flags;
  337.     if (tcsetattr(asyp->fd, TCSANOW, &termios))
  338.         return -1;
  339.     asyp->speed = speed_table[sp].speed;
  340.     return 0;
  341. }
  342.   
  343. /*---------------------------------------------------------------------------*/
  344.   
  345. /* Asynchronous line I/O control */
  346. int32
  347. asy_ioctl(ifp,cmd,set,val)
  348. struct iface *ifp;
  349. int cmd;
  350. int set;
  351. int32 val;
  352. {
  353.     struct asy *ap = &Asy[ifp->dev];
  354.   
  355.     switch(cmd){
  356.         case PARAM_SPEED:
  357.             if(set)
  358.                 asy_speed(ifp->dev,val);
  359.             return ap->speed;
  360.     }
  361.     return -1;
  362. }
  363.   
  364. /*---------------------------------------------------------------------------*/
  365.   
  366. #define RXCHUNK 64
  367.   
  368. static void
  369. asy_input(dev, arg1, arg2)
  370. int dev;
  371. void *arg1, *arg2;
  372. {
  373.     extern int errno;
  374.     struct asy *ap;
  375.     char *buf;
  376.     int i;
  377.   
  378.     buf = mallocw(RXCHUNK);
  379.     ap = &Asy[dev];
  380.     for (;;)
  381.     {
  382.         do
  383.         {
  384.             if (pwait(&ap->fd) != 0)
  385.             {
  386.                 free(buf);
  387.                 return;
  388.             }
  389.             ap->rxints++;
  390.         }
  391.         while ((i = read(ap->fd, buf, RXCHUNK)) == 0 ||
  392.         (i == -1 && errno == EWOULDBLOCK));
  393.     /* gang-reading destroys JNOS response; no benefits seen */
  394. #if 0
  395.         while (i > 0)
  396.         {
  397. #endif
  398.             ap->rxchar += i;
  399.             enqueue(&ap->rcvq, qdata(buf, i));
  400. #if 0
  401.             pwait(NULL);    /* process it to avoid monopolizing cycles */
  402.             i = read(ap->fd, buf, RXCHUNK);
  403.         }
  404. #endif
  405.         if (i == -1 && errno != EWOULDBLOCK)
  406.         {
  407.             free(buf);
  408.             return;
  409.         }
  410.     }
  411. }
  412.   
  413. int
  414. get_asy(dev)
  415. int dev;
  416. {
  417.     struct asy *ap;
  418.   
  419.     ap = &Asy[dev];
  420.     if (ap->iface == NULLIF)
  421.         return -1;
  422.     while (!ap->rcvq)
  423.     {
  424.         if (pwait(&ap->rcvq) != 0)
  425.             return -1;      /* may not be dead, e.g. alarm in dialer */
  426.     }
  427.     return PULLCHAR(&ap->rcvq);
  428. }
  429.   
  430. /*---------------------------------------------------------------------------*/
  431.   
  432. int
  433. doasystat(argc,argv,p)
  434. int argc;
  435. char *argv[];
  436. void *p;
  437. {
  438.     register struct asy *asyp;
  439.     struct iface *ifp;
  440.     int i;
  441.   
  442.     if(argc < 2){
  443.         for(asyp = Asy;asyp < &Asy[ASY_MAX];asyp++){
  444.             if(asyp->iface != NULLIF)
  445.                 pasy(asyp);
  446.         }
  447.         return 0;
  448.     }
  449.     for(i=1;i<argc;i++){
  450.         if((ifp = if_lookup(argv[i])) == NULLIF){
  451.             tprintf("Interface %s unknown\n",argv[i]);
  452.             continue;
  453.         }
  454.         for(asyp = Asy;asyp < &Asy[ASY_MAX];asyp++){
  455.             if(asyp->iface == ifp){
  456.                 pasy(asyp);
  457.                 break;
  458.             }
  459.         }
  460.         if(asyp == &Asy[ASY_MAX])
  461.             tprintf("Interface %s not asy\n",argv[i]);
  462.     }
  463.   
  464.     return 0;
  465. }
  466.   
  467. /*---------------------------------------------------------------------------*/
  468.   
  469. static void
  470. pasy(asyp)
  471. struct asy *asyp;
  472. {
  473.     tprintf("%s: %lu bps\n", asyp->iface->name, asyp->speed);
  474.     tprintf("  RX: int %lu chars %lu\n",
  475.     asyp->rxints, asyp->rxchar);
  476.     tprintf("  TX: int %lu chars %lu\n",
  477.     asyp->txints, asyp->txchar);
  478. }
  479.   
  480. /*---------------------------------------------------------------------------*/
  481.   
  482. /* Serial transmit process, common to all protocols */
  483. static void
  484. asy_tx(dev, p1, p2)
  485. int dev;
  486. void *p1, *p2;
  487. {
  488.     register struct mbuf *bp;
  489.     struct asy *asyp;
  490.   
  491.     asyp = &Asy[dev];
  492.     for (;;)
  493.     {
  494.         while (asyp->sndq == NULLBUF)
  495.         {
  496.             if (pwait(&asyp->sndq) != 0)
  497.                 return;
  498.             asyp->txints++;
  499.         }
  500.         bp = dequeue(&asyp->sndq);
  501.         while (bp != NULLBUF)
  502.         {
  503.             write(asyp->fd, bp->data, bp->cnt);
  504.             asyp->txchar += bp->cnt;
  505.             bp = free_mbuf(bp);
  506.         }
  507.         pwait(NULL);
  508.     }
  509. }
  510.   
  511. /*---------------------------------------------------------------------------*/
  512.   
  513. /* Send a message on the specified serial line */
  514. int
  515. asy_send(dev,bp)
  516. int dev;
  517. struct mbuf *bp;
  518. {
  519.     struct asy *asyp;
  520.   
  521.     if(dev < 0 || dev >= ASY_MAX){
  522.         free_p(bp);
  523.         return -1;
  524.     }
  525.     asyp = &Asy[dev];
  526.   
  527.     if(asyp->iface == NULLIF)
  528.         free_p(bp);
  529.     else
  530.         enqueue(&asyp->sndq, bp);
  531.     return 0;
  532. }
  533.   
  534. /* stub, CD not enabled at present */
  535.   
  536. int
  537. carrier_detect(dev)
  538. int dev;
  539. {
  540.     return 1;           /* assume always on, with CLOCAL it is! */
  541. }
  542.