FreeCalypso > hg > freecalypso-sw
view target-utils/libcommon/cmd_baud_switch.c @ 484:c617a6adcb69
top level README: status update
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Sun, 29 Jun 2014 19:05:52 +0000 |
parents | 437f9365249c |
children |
line wrap: on
line source
/* * Baud rate switching command */ #include <stdlib.h> #include "types.h" #include "ns16550.h" extern struct ns16550_regs *uart_base; extern int serial_in_poll(); static const struct tab { int baud; int divisor; } rate_table[] = { /* * First support the rates and divisors implemented by the * Calypso boot ROM. Dividing 13 MHz by 7 gives an approximation * of 115200 (x16); the divisors used by the boot ROM code for * the slower baud rates are all 7x the usual PC value. */ {115200, 7}, {57600, 7 * 2}, {38400, 7 * 3}, {28800, 7 * 4}, {19200, 7 * 6}, /* * Going faster than ~115200 baud means using a divisor * less than 7, resulting in a non-standard baud rate. * The /1, /2 and /4 seem like reasonable choices. */ {812500, 1}, {406250, 2}, {203125, 4}, /* that's all we really need to support */ {0, 0} }; /* * The following helper function actually switches the UART * baud rate divisor. Call serial_flush() first. It returns the * old divisor value. * * Note the u8 type for both the new and old divisor values. * All supported divisors are well below 255, so we don't bother * with the upper byte. */ static u8 actually_switch_baud(newdiv) u8 newdiv; { volatile struct ns16550_regs *regs; u8 save_lcr, save_old_baud; regs = uart_base; save_lcr = regs->lcr; regs->lcr = save_lcr | NS16550_LCR_DLAB; save_old_baud = regs->datareg; regs->datareg = newdiv; regs->lcr = save_lcr; return(save_old_baud); } void cmd_baud_switch(argbulk) char *argbulk; { char *argv[2]; int baudarg; struct tab *tp; u8 save_old_baud; int c; if (parse_args(argbulk, 1, 1, argv, 0) < 0) return; baudarg = atoi(argv[0]); for (tp = rate_table; tp->baud; tp++) if (tp->baud == baudarg) break; if (!tp->baud) { printf("ERROR: invalid/unimplemented baud rate argument\n"); return; } /* do it */ serial_flush(); save_old_baud = actually_switch_baud(tp->divisor); /* * After getting the echo of this command at the old baud rate * (see the serial flush call just before switching the divisor), * the line will go silent from the user's perspective. * The user should wait just a little bit, then send us a 0x55 ('U') * at the new baud rate - we should be in the below loop waiting * for this character by then. Receiving that character * correctly (0x55 was chosen for the bit pattern - unlikely to * be received if the sender is sending at a wrong baud rate) * will cause us to conclude this command and return a new '=' * prompt at the new baud rate. * * If we get something else, we assume that someone messed up, * switch back to the old baud rate, scribble an error message * and return. */ do c = serial_in_poll(); while (c < 0); if (c != 0x55) { actually_switch_baud(save_old_baud); printf("ERROR: no \'U\' received, switched back to old baud rate\n"); } }