⬢ DragonFlyBSD Kernel Audit
DF-5422 / uftdi_probe2.c
← back to finding ↓ download raw
/* uftdi_probe2.c — TX drain instrumentation (DF-5422 pack)
 * Opens cuaU0 raw 115200, queues n bytes NONBLOCKING, then polls
 * TIOCOUTQ (outq size) + TIOCMGET every 100ms for 5s.
 */
#include <sys/ioctl.h>
#include <termios.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/time.h>

int main(int argc, char **argv) {
    int n = argc > 1 ? atoi(argv[1]) : 65;
    int dev = argc > 2 ? atoi(argv[2]) : 0; /* 0=cuaU0 1=ttyU0 */
    int block = argc > 3 ? atoi(argv[3]) : 0; /* keep O_NONBLOCK clear during write */
    int poll = argc > 4 ? atoi(argv[4]) : 1; /* poll ioctls */
    int clocal = argc > 5 ? atoi(argv[5]) : 1;
    const char *name = dev ? "/dev/ttyU0" : "/dev/cuaU0";
    int fd = open(name, O_RDWR | O_NONBLOCK);
    if (fd < 0) { perror("open"); return 1; }
    struct termios t;
    tcgetattr(fd, &t);
    cfmakeraw(&t);
    if (clocal) t.c_cflag |= CLOCAL;
    cfsetspeed(&t, 115200);
    tcsetattr(fd, TCSANOW, &t);

    char *buf = malloc(n);
    for (int i = 0; i < n; i++) buf[i] = 'A' + (i % 26);
    int off = 0;
    if (block) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK);
    while (off < n) {
        int rc = write(fd, buf + off, n - off);
        if (rc < 0) {
            if (errno == EAGAIN) { printf("write EAGAIN at %d\n", off); break; }
            perror("write"); return 2;
        }
        off += rc;
    }
    printf("queued %d bytes\n", off);
    if (!poll) { usleep(2000000); int q=-1; ioctl(fd, TIOCOUTQ, &q); printf("nopoll outq=%d\n", q); fflush(stdout); }
    for (int i = 0; i < 50; i++) {
        if (!poll) { usleep(100000); continue; }
        int outq = -1, modem = -1;
        ioctl(fd, TIOCOUTQ, &outq);
        ioctl(fd, TIOCMGET, &modem);
        int c_cc_flag = 0;
        printf("t=%dms outq=%d modem=0x%x\n", i * 100, outq, modem);
        fflush(stdout);
        if (outq == 0) { printf("DRAINED\n"); break; }
        usleep(100000);
    }
    printf("closing...\n"); fflush(stdout);
    double t0, t1;
    struct timeval tv;
    gettimeofday(&tv, 0); t0 = tv.tv_sec + tv.tv_usec / 1e6;
    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK);
    close(fd);
    gettimeofday(&tv, 0); t1 = tv.tv_sec + tv.tv_usec / 1e6;
    printf("closed in %.0fms\n", (t1 - t0) * 1e3);
    return 0;
}