diff options
Diffstat (limited to 'lib/libsectok/scio.c')
-rw-r--r-- | lib/libsectok/scio.c | 458 |
1 files changed, 458 insertions, 0 deletions
diff --git a/lib/libsectok/scio.c b/lib/libsectok/scio.c new file mode 100644 index 00000000000..8d5ee9cd9d6 --- /dev/null +++ b/lib/libsectok/scio.c @@ -0,0 +1,458 @@ +/* + * OS dependent part, Unix version + * + * See copyright notice at end of file + * + * Jim Rees, University of Michigan, October 1997 + */ +static char *rcsid = "$Id: scio.c,v 1.1 2001/06/07 15:17:33 rees Exp $"; + +#include <sys/ioctl.h> +#include <sys/file.h> +#include <sys/types.h> +#include <sys/time.h> +#ifdef _AIX +#include <sys/select.h> +#endif /* _AIX */ +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <termios.h> +#include <signal.h> +#include <fcntl.h> + +#include "sectok.h" +#include "todos_scrw.h" + +#ifdef __linux +static char ttynametmpl[] = "/dev/cua%01d"; +#elif _AIX +static char ttynametmpl[] = "/dev/tty%01d"; +#elif __OpenBSD__ +static char ttynametmpl[] = "/dev/cua%02d"; +#elif __sun +/*static char ttynametmpl[] = "/dev/cua/%c";*/ +static char ttynametmpl[] = "/dev/tty%c"; +#else +static char ttynametmpl[] = "/dev/tty%02d"; +#endif + +static struct { + int fd, flags, pid; + struct termios tio0, tio1; +} sc[4]; + +/* global variable */ +#ifdef BYTECOUNT +int num_getc, num_putc; +#endif /* BYTECOUNT */ + +int +todos_scopen(int ttyn, int flags, int *ep) +{ + char ttyname[32]; + int fd, i, pid, oflags; + +#ifdef BYTECOUNT + num_getc = 0; + num_putc = 0; +#endif /* BYTECOUNT */ + +#ifdef __sun + sprintf(ttyname, ttynametmpl, 'a' + ttyn); +#else + sprintf(ttyname, ttynametmpl, ttyn); +#endif + + +#ifdef DEBUG + printf ("ttyname=%s\n", ttyname); +#endif /* DEBUG */ + oflags = O_RDWR; + if (!(flags & SCODCD)) + oflags |= O_NONBLOCK; + if ((fd = open(ttyname, oflags, 0)) < 0) { + if (ep) + *ep = SCENOTTY; + return -1; + } + + if ((ttyn = todos_scfdopen(ttyn, fd, flags, ep)) < 0) { + close(fd); + return -2; + } + + /* Figure out which reader we have */ + if (ioctl(fd, TIOCMGET, &i) < 0) { + close(fd); + return 0; + } +#ifndef __sun + /* Todos has RTS wired to RI, so set RTS and see if RI goes high */ + i |= TIOCM_RTS; + ioctl(fd, TIOCMSET, &i); + ioctl(fd, TIOCMGET, &i); +#else + /* Sun serial port is broken, has no RI line */ + i = TIOCM_RI; +#endif + if (i & TIOCM_RI) { + /* Todos reader */ + todos_scsleep(20); + sc[ttyn].flags |= (SCOXCTS | SCOXDTR); + } + + if (flags & SCODSR) { + /* Wait for card present */ + while (!todos_sccardpresent(ttyn)) + sleep(1); + } + + if (flags & SCOHUP) { + /* spawn a process to wait for card removal */ + pid = fork(); + if (pid == 0) { + /* See if the card is still there */ + while (todos_sccardpresent(ttyn)) + sleep(1); + kill(getppid(), SIGHUP); + exit(0); + } + sc[ttyn].pid = pid; + } + + return ttyn; +} + +int +todos_scsetflags(int ttyn, int flags, int mask) +{ + int oflags = sc[ttyn].flags; + + sc[ttyn].flags &= ~mask; + sc[ttyn].flags |= (flags & mask); + + if ((sc[ttyn].flags & SCOINVRT) != (oflags & SCOINVRT)) { + if (sc[ttyn].flags & SCOINVRT) + sc[ttyn].tio1.c_cflag |= PARODD; + else + sc[ttyn].tio1.c_cflag &= ~PARODD; + tcsetattr(sc[ttyn].fd, TCSADRAIN, &sc[ttyn].tio1); + } + + return oflags; +} + +/* NI: for Linux */ +#if (B9600 != 9600) +struct speed_trans { + speed_t t_val; + int val; + char *s; +} speed_trans[] = { + {0, 0, "a"}, + {B9600, 9600, "a"}, + {B19200, 19200, "a"}, + {B38400, 38400, "a"}, + {B57600, 55928, "a"}, + {B57600, 57600, "a"}, + {B115200, 115200, "a"}, + {-1, -1, NULL}}; +#endif /* (B9600 != 9600) */ + +int +todos_scsetspeed(int ttyn, int speed) +{ + +#if (B9600 == 9600) + /* On OpenBSD, B9600 == 9600, and we can use the input argument + "speed" of this function as an argument to cfset[io]speed(). */ +#else + /* On Linux, B9600 != 9600, and we have to translate the input argument + to speed_t. */ + int i; + + for (i = 0; speed_trans[i].s; i++) + if (speed_trans[i].val == speed) break; + if (speed_trans[i].s == NULL) { + fprintf (stderr, "scsetspeed() failed : speed %d not supported. ignore ...\n", + speed); + return 0; + } + speed = speed_trans[i].t_val; +#endif + cfsetispeed(&sc[ttyn].tio1, speed); + cfsetospeed(&sc[ttyn].tio1, speed); + + return tcsetattr(sc[ttyn].fd, TCSADRAIN, &sc[ttyn].tio1); +} + +int +todos_scfdopen(int ttyn, int fd, int flags, int *ep) +{ + struct termios t; + + /* Get and save the tty state */ + + if (tcgetattr(fd, &t) < 0) { + if (ep) + *ep = SCENOTTY; + return -1; + } + sc[ttyn].fd = fd; + sc[ttyn].tio0 = t; + sc[ttyn].flags = flags; + + /* Now put the tty in a happy ISO state */ + + /* 9600 bps */ + cfsetispeed(&t, B9600); + cfsetospeed(&t, B9600); + + /* raw 8/E/2 */ + t.c_iflag &= ~(ISTRIP|INLCR|IGNCR|ICRNL|IXON); + t.c_iflag |= (IGNBRK|IGNPAR); + t.c_oflag &= ~OPOST; + t.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); +#ifdef CHWFLOW + t.c_cflag &= ~CHWFLOW; +#endif +#ifdef CRTSCTS + t.c_cflag &= ~CRTSCTS; +#endif +#ifdef CRTSXOFF + t.c_cflag &= ~CRTSXOFF; +#endif + t.c_cflag |= CLOCAL; + + /* 8/E/2 */ + t.c_cflag &= ~(CSIZE | PARODD); + t.c_cflag |= (CS8 | PARENB | CSTOPB); + + t.c_cc[VMIN] = 1; + t.c_cc[VTIME] = 0; + + if (tcsetattr(fd, TCSANOW, &t) < 0) { + if (ep) + *ep = SCENOTTY; + sc[ttyn].fd = -1; + return -1; + } + sc[ttyn].tio1 = t; + + /* The open may or may not have reset the card. Wait a while then flush + anything that came in on the port. */ + todos_scsleep(250); + todos_scdrain(ttyn); + + return ttyn; +} + +/* find out if there is a card in the reader */ + +int +todos_sccardpresent(int ttyn) +{ + return (sc[ttyn].flags & SCOXCTS) ? !todos_sccts(ttyn) : todos_scdsr(ttyn); +} + +/* query dsr on the port (usually indicates whether the card is present) */ + +int +todos_scdsr(int ttyn) +{ + int fd = sc[ttyn].fd; + int i; + + if (fd < 0 || ioctl(fd, TIOCMGET, &i) < 0) + return 0; + + return ((i & TIOCM_DSR) ? 1 : 0); +} + +int +todos_sccts(int ttyn) +{ + int fd = sc[ttyn].fd; + int i; + + if (fd < 0 || ioctl(fd, TIOCMGET, &i) < 0) + return 0; + + return ((i & TIOCM_CTS) ? 1 : 0); +} + +/* raise or lower dtr */ + +int +todos_scdtr(int ttyn, int cmd) +{ + int fd = sc[ttyn].fd; + int i; + + if (!todos_sccardpresent(ttyn)) + return -1; + + if (ioctl(fd, TIOCMGET, &i) < 0) + return -1; + + if (cmd) + i |= TIOCM_DTR; + else + i &= ~TIOCM_DTR; + i |= TIOCM_RTS; + + return ioctl(fd, TIOCMSET, &i); +} + +int +todos_scclose(int ttyn) +{ + int fd = sc[ttyn].fd; + + tcsetattr(fd, TCSANOW, &sc[ttyn].tio0); + close(fd); + sc[ttyn].fd = -1; + if (sc[ttyn].pid) { + kill(sc[ttyn].pid, SIGTERM); + sc[ttyn].pid = 0; + } + +#ifdef BYTECOUNT + printf("#getc=%d, #putc=%d\n", num_getc - num_putc, num_putc); +#endif /* BYTECOUNT */ + return 0; +} + +/* + * get one byte from the card. + * wait at most ms msec. 0 for poll, -1 for infinite. + * return byte in *cp. + * return 0 or error. + */ + +int +todos_scgetc(int ttyn, unsigned char *cp, int ms) +{ + int fd = sc[ttyn].fd; + fd_set fdset; + struct timeval tv, *tvp; + +#ifdef BYTECOUNT + num_getc++; +#endif /* BYTECOUNT */ + + FD_ZERO(&fdset); + FD_SET(fd, &fdset); + + if (ms == -1) + tvp = NULL; + else { + tv.tv_sec = (ms + 1) / 1000; + tv.tv_usec = (ms % 1000) * 1000; + tvp = &tv; + } + + if (select(fd + 1, &fdset, NULL, NULL, tvp) != 1) + return SCTIMEO; + + if (read(fd, cp, 1) != 1) + return SCTIMEO; + + if (sc[ttyn].flags & SCOINVRT) + *cp = todos_scinvert[*cp]; + + return SCEOK; /* 0 */ +} + +/* write one byte to the card */ + +int +todos_scputc(int ttyn, int ic) +{ + int fd = sc[ttyn].fd; + unsigned char c0, c1; + int code; + +#ifdef BYTECOUNT + num_putc++; +#endif /* BYTECOUNT */ + + c0 = (sc[ttyn].flags & SCOINVRT) ? todos_scinvert[ic] : ic; + write(fd, &c0, 1); + + /* gobble up the echo */ + code = todos_scgetc(ttyn, &c1, 200); +#ifdef GOBBLEDEBUG + if (sc[ttyn].flags & SCOINVRT) + c1 = todos_scinvert[c1]; + if (code) + printf("failed to gobble\n"); + else if (c0 != c1) + printf("misgobbled %x != %x\n", c0, c1); + else + printf("gobble gobble %x\n", c0); +#endif + return code; +} + +int todos_scputblk(int ttyn, unsigned char *bp, int n) +{ + int fd = sc[ttyn].fd; + unsigned char c; + + write(fd, bp, n); + while (n--) + todos_scgetc(ttyn, &c, 30); + + return SCEOK; +} + +void +todos_scsleep(int ms) +{ + struct timeval tv; + + if (!ms) + return; + tv.tv_sec = (ms + 1) / 1000; + tv.tv_usec = (ms % 1000) * 1000; + + select(0, NULL, NULL, NULL, &tv); +} + +void +todos_scdrain(int ttyn) +{ + tcflush(sc[ttyn].fd, TCIFLUSH); +} + +/* +copyright 1997 +the regents of the university of michigan +all rights reserved + +permission is granted to use, copy, create derivative works +and redistribute this software and such derivative works +for any purpose, so long as the name of the university of +michigan is not used in any advertising or publicity +pertaining to the use or distribution of this software +without specific, written prior authorization. if the +above copyright notice or any other identification of the +university of michigan is included in any copy of any +portion of this software, then the disclaimer below must +also be included. + +this software is provided as is, without representation +from the university of michigan as to its fitness for any +purpose, and without warranty by the university of +michigan of any kind, either express or implied, including +without limitation the implied warranties of +merchantability and fitness for a particular purpose. the +regents of the university of michigan shall not be liable +for any damages, including special, indirect, incidental, or +consequential damages, with respect to any claim arising +out of or in connection with the use of the software, even +if it has been or is hereafter advised of the possibility of +such damages. +*/ |