⬢ DragonFlyBSD Kernel Audit
DF-5422 / uftdi_live.c
← back to finding ↓ download raw
/* uftdi_live.c — live uftdi/cuaU0 exercise rig (DF-5422 pack)
 * modes:
 *   t        : baseline timings: open + tcsetattr(115200) + tcsetattr(9600) + close
 *   w <n>    : write n bytes, print md5-ish checksum of pattern written
 *   r <n> <t>: read up to n bytes with timeout t ms, dump hex of first 64
 *   s        : status ioctls: TIOCMGET, TIOCMSET toggle, break on/off
 *   bad      : invalid termios speeds (expect EINVAL), CS5..CS8 sweep
 *   o        : keep fd open and pause (for unplug/reset races) - sleeps 30s
 */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/endian.h>

static double now(void) {
    struct timeval tv; gettimeofday(&tv, 0);
    return tv.tv_sec + tv.tv_usec / 1e6;
}

static int openport(void) {
    int fd = open("/dev/cuaU0", O_RDWR | O_NONBLOCK);
    if (fd < 0) perror("open /dev/cuaU0");
    return fd;
}

int main(int argc, char **argv) {
    const char *mode = argc > 1 ? argv[1] : "t";
    int fd, i, rc;

    if (!strcmp(mode, "t")) {
        for (i = 0; i < 3; i++) {
            double t0 = now();
            fd = openport(); if (fd < 0) return 1;
            double t1 = now();
            struct termios ti;
            rc = tcgetattr(fd, &ti);
            cfmakeraw(&ti);
            cfsetspeed(&ti, 115200);
            rc = tcsetattr(fd, TCSANOW, &ti);
            double t2 = now();
            cfsetspeed(&ti, 9600);
            rc = tcsetattr(fd, TCSANOW, &ti);
            double t3 = now();
            rc = close(fd);
            double t4 = now();
            printf("run %d: open=%.1fms set115200=%.1fms set9600=%.1fms close=%.1fms rc=%d\n",
                i, (t1-t0)*1e3, (t2-t1)*1e3, (t3-t2)*1e3, (t4-t3)*1e3, rc);
        }
        return 0;
    }
    if (!strcmp(mode, "w")) {
        int n = argc > 2 ? atoi(argv[2]) : 4096;
        char *buf = malloc(n);
        for (i = 0; i < n; i++) buf[i] = (i * 7 + 3) & 0xff;
        fd = openport(); if (fd < 0) return 1;
        { struct termios t2; tcgetattr(fd, &t2); cfmakeraw(&t2); cfsetspeed(&t2, 115200); tcsetattr(fd, TCSANOW, &t2); }
        fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK);
        int off = 0;
        while (off < n) {
            rc = write(fd, buf + off, n - off);
            if (rc < 0) { if (errno == EAGAIN) { usleep(1000); continue; } perror("write"); return 2; }
            off += rc;
        }
        unsigned long long h = 1469598103934665603ULL;
        for (i = 0; i < n; i++) { h ^= (unsigned char)buf[i]; h *= 1099511628211ULL; }
        printf("wrote %d bytes fnv64=%016llx\n", n, h);
        close(fd); return 0;
    }
    if (!strcmp(mode, "r")) {
        int n = argc > 2 ? atoi(argv[2]) : 65536;
        int ms = argc > 3 ? atoi(argv[3]) : 3000;
        char *buf = malloc(n);
        fd = openport(); if (fd < 0) return 1;
        { struct termios t2; tcgetattr(fd, &t2); cfmakeraw(&t2); cfsetspeed(&t2, 115200); tcsetattr(fd, TCSANOW, &t2); }
        int tot = 0;
        double t0 = now();
        while (tot < n && (now() - t0) * 1000 < ms) {
            rc = read(fd, buf + tot, n - tot);
            if (rc > 0) tot += rc;
            else usleep(500);
        }
        printf("read %d bytes:\n", tot);
        for (i = 0; i < tot && i < 64; i++) printf("%02x", (unsigned char)buf[i]);
        printf("\n");
        /* simple pattern check: expect 0..255 cycling if host sent that */
        close(fd); return 0;
    }
    if (!strcmp(mode, "s")) {
        fd = openport(); if (fd < 0) return 1;
        int m = 0;
        rc = ioctl(fd, TIOCMGET, &m);
        printf("TIOCMGET rc=%d modem=0x%x\n", rc, m);
        m = TIOCM_DTR | TIOCM_RTS;
        rc = ioctl(fd, TIOCMSET, &m);
        printf("TIOCMSET(DTR|RTS) rc=%d\n", rc);
        rc = ioctl(fd, TIOCMGET, &m);
        printf("TIOCMGET modem=0x%x\n", m);
        struct termios ti;
        tcgetattr(fd, &ti);
        double t0 = now();
        rc = ioctl(fd, TIOCSBRK);      /* break on */
        usleep(100000);
        rc |= ioctl(fd, TIOCCBRK);     /* break off */
        printf("break on/off rc=%d in %.1fms\n", rc, (now()-t0)*1e3);
        tcgetattr(fd, &ti);
        ioctl(fd, TIOCSDTR);
        ioctl(fd, TIOCCDTR);
        printf("dtr on/off done\n");
        close(fd); return 0;
    }
    if (!strcmp(mode, "bad")) {
        fd = openport(); if (fd < 0) return 1;
        struct termios ti; tcgetattr(fd, &ti);
        int speeds[] = {0, 1, 50, 177, 178, 300, 9600, 57600, 115200, 309278, 309279, 4000000, 12000000};
        for (i = 0; i < (int)(sizeof(speeds)/sizeof(speeds[0])); i++) {
            cfsetspeed(&ti, (speed_t)speeds[i]);
            int r = tcsetattr(fd, TCSANOW, &ti);
            printf("speed %7d -> rc=%d errno=%d (%s)\n", speeds[i], r, errno, r ? strerror(errno) : "ok");
        }
        close(fd); return 0;
    }
    if (!strcmp(mode, "o")) {
        fd = openport(); if (fd < 0) return 1;
        printf("fd=%d open, sleeping 30s\n", fd); fflush(stdout);
        sleep(30);
        char c = 'X';
        rc = write(fd, &c, 1);
        printf("post-sleep write rc=%d errno=%d (%s)\n", rc, errno, strerror(errno));
        rc = read(fd, &c, 1);
        printf("post-sleep read rc=%d errno=%d\n", rc, errno);
        close(fd);
        printf("closed\n");
        return 0;
    }
    fprintf(stderr, "unknown mode\n");
    return 64;
}