FreeCalypso > hg > freecalypso-reveng
view fluid-mnf/serial.c @ 348:37b5f94de802
fluid-mnf: sensible target tty specification
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 13 Mar 2020 06:41:44 +0000 |
parents | 2bd27d940023 |
children | 49fe64a5e207 |
line wrap: on
line source
/****************************************************************************** * FLUID (Flash Loader Utility Independent of Device) * * Copyright Texas Instruments, 2001. * Mads Meisner-Jensen, mmj@ti.com. * * Serial/UART driver * * $Id: serial.c 1.23 Fri, 18 Oct 2002 08:53:12 +0200 mmj $ * * This serial interface handling architecture has been majorly redesigned * by Mychaela N. Falconia for the present fluid-mnf Linux port. * * Because FLUID supports Calypso high baud rates of 203125, 406250 and 812500 * bps, as well as D-Sample XXO (eXternal Xtal Oscillator) baud rates of * 230400, 460800 and 912600 bps, the present fluid-mnf port had to be made * quite Linux-specific, using the same raw ioctl approach as is used in * freecalypso-tools/libserial-linux. * ******************************************************************************/ #include "fluid.h" #include "serial.h" #include "trace.h" #include <sys/types.h> #include <sys/file.h> #include <sys/time.h> #include <sys/ioctl.h> #include <asm/ioctls.h> #include <asm/termbits.h> #include <sys/errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> extern int errno; /****************************************************************************** * Linux Driver ******************************************************************************/ static int target_fd; static struct termios2 target_termios; static void fill_termios(int bps) { int termios_baud_code; switch (bps) { case 9600: termios_baud_code = B9600; break; case 19200: termios_baud_code = B19200; break; case 38400: termios_baud_code = B38400; break; case 57600: termios_baud_code = B57600; break; case 115200: termios_baud_code = B115200; break; case 230400: termios_baud_code = B230400; break; case 460800: termios_baud_code = B460800; break; case 921600: termios_baud_code = B921600; break; default: termios_baud_code = BOTHER; } target_termios.c_iflag = IGNBRK; target_termios.c_oflag = 0; target_termios.c_cflag = termios_baud_code | CLOCAL|HUPCL|CREAD|CS8; target_termios.c_lflag = 0; target_termios.c_cc[VMIN] = 1; target_termios.c_cc[VTIME] = 0; target_termios.c_ispeed = bps; target_termios.c_ospeed = bps; } int serial_init(char *ttyport, int bps) { static int zero = 0; if (!ttyport) { ttyport = getenv("FLUID_PORT"); if (!ttyport) { fprintf(stderr, "fluid-mnf error: target tty port must be specified with -p or FLUID_PORT=\n"); exit(-E_BADARG); } } target_fd = open(ttyport, O_RDWR|O_NONBLOCK); if (target_fd < 0) return E_OS + E_UART_INIT; ioctl(target_fd, TIOCEXCL); fill_termios(bps); if (ioctl(target_fd, TCSETSF2, &target_termios) < 0) return E_OS + E_UART_INIT; ioctl(target_fd, FIONBIO, &zero); if (arg_uart_level_convert) { /* * Powering TI's serial level converter * with DTR = +12V and RTS = -12V */ serial_dtr(1); serial_rts(0); } serial_reset(); return 0; } int serial_is_baudrate(int bps) { int i; const struct rate_s { int bps; int baudrate; } rates[] = { { 9600, 9600 }, { 9, 9600 }, { 14400, 14400 }, { 14, 14400 }, { 19200, 19200 }, { 19, 19200 }, { 38400, 38400 }, { 38, 38400 }, { 57600, 57600 }, { 57, 57600 }, { 115200, 115200 }, { 115, 115200 }, { 203125, 203125 }, { 203, 203125 }, // 13MHz clock { 230400, 230400 }, { 230, 230400 }, { 406250, 406250 }, { 406, 406250 }, // 13MHz clock { 460800, 460800 }, { 460, 460800 }, { 812500, 812500 }, { 812, 812500 }, // 13MHz clock { 921600, 921600 }, { 921, 921600 }, { 0, 0 } // terminator }; for (i = 0; i < sizeof(rates) / sizeof(struct rate_s) - 1; i++) if (rates[i].bps == bps) break; tr(TrTargetDrv, "serial_is_baudrate(%d) %d\n", bps, rates[i].baudrate); return rates[i].baudrate; } int serial_baudrate_set(int bps) { bps = serial_is_baudrate(bps); if (bps == 0) return E_OS + E_UART_PARAM; fill_termios(bps); if (ioctl(target_fd, TCSETSF2, &target_termios) < 0) return E_OS + E_UART_PARAM; return bps; } int serial_baudrate_get(void) { return target_termios.c_ospeed; } void serial_exit(void) { serial_reset(); close(target_fd); } // Clear buffers and transactions. void serial_reset(void) { ioctl(target_fd, TCFLSH, TCIOFLUSH); } // Return the number of milli-seconds it takes to transfer <n> bytes. int serial_transfer_time(int size) { return 1000 * 10 * size / serial_baudrate_get(); } /*************************************** * Send ***************************************/ int serial_send(char *buf, int size) { int cc; cc = write(target_fd, buf, size); if (cc < 0) cc = E_OS + E_UART_DRV_SEND; return cc; } /*************************************** * Receive ***************************************/ void serial_recv_reset(void) { ioctl(target_fd, TCFLSH, TCIFLUSH); } int serial_recv(char *buf, int size, int timeout) { fd_set fds; struct timeval tv; int cc; for (;;) { FD_ZERO(&fds); FD_SET(target_fd, &fds); tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; cc = select(target_fd+1, &fds, NULL, NULL, &tv); if (cc < 0) { if (errno == EINTR) continue; return E_OS + E_UART_DRV_RECV; } break; } if (cc == 0) return cc; cc = read(target_fd, buf, size); if (cc <= 0) cc = E_OS + E_UART_DRV_RECV; return cc; } /****************************************************************************** * Control of Delta cable special outputs ******************************************************************************/ void serial_rts(char state) { int rts_arg = TIOCM_RTS; if (state) ioctl(target_fd, TIOCMBIS, &rts_arg); else ioctl(target_fd, TIOCMBIC, &rts_arg); } void serial_dtr(char state) { int dtr_arg = TIOCM_DTR; if (state) ioctl(target_fd, TIOCMBIS, &dtr_arg); else ioctl(target_fd, TIOCMBIC, &dtr_arg); } void serial_break(char state) { if (state) ioctl(target_fd, TIOCSBRK); else ioctl(target_fd, TIOCCBRK); }