comparison target-utils/libcommon/cmd_baud_switch.c @ 37:437f9365249c

loadagent: baud rate switching implemented
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Mon, 13 May 2013 06:56:54 +0000
parents
children
comparison
equal deleted inserted replaced
36:65111e6eee9e 37:437f9365249c
1 /*
2 * Baud rate switching command
3 */
4
5 #include <stdlib.h>
6 #include "types.h"
7 #include "ns16550.h"
8
9 extern struct ns16550_regs *uart_base;
10 extern int serial_in_poll();
11
12 static const struct tab {
13 int baud;
14 int divisor;
15 } rate_table[] = {
16 /*
17 * First support the rates and divisors implemented by the
18 * Calypso boot ROM. Dividing 13 MHz by 7 gives an approximation
19 * of 115200 (x16); the divisors used by the boot ROM code for
20 * the slower baud rates are all 7x the usual PC value.
21 */
22 {115200, 7},
23 {57600, 7 * 2},
24 {38400, 7 * 3},
25 {28800, 7 * 4},
26 {19200, 7 * 6},
27 /*
28 * Going faster than ~115200 baud means using a divisor
29 * less than 7, resulting in a non-standard baud rate.
30 * The /1, /2 and /4 seem like reasonable choices.
31 */
32 {812500, 1},
33 {406250, 2},
34 {203125, 4},
35 /* that's all we really need to support */
36 {0, 0}
37 };
38
39 /*
40 * The following helper function actually switches the UART
41 * baud rate divisor. Call serial_flush() first. It returns the
42 * old divisor value.
43 *
44 * Note the u8 type for both the new and old divisor values.
45 * All supported divisors are well below 255, so we don't bother
46 * with the upper byte.
47 */
48 static u8
49 actually_switch_baud(newdiv)
50 u8 newdiv;
51 {
52 volatile struct ns16550_regs *regs;
53 u8 save_lcr, save_old_baud;
54
55 regs = uart_base;
56 save_lcr = regs->lcr;
57 regs->lcr = save_lcr | NS16550_LCR_DLAB;
58 save_old_baud = regs->datareg;
59 regs->datareg = newdiv;
60 regs->lcr = save_lcr;
61 return(save_old_baud);
62 }
63
64 void
65 cmd_baud_switch(argbulk)
66 char *argbulk;
67 {
68 char *argv[2];
69 int baudarg;
70 struct tab *tp;
71 u8 save_old_baud;
72 int c;
73
74 if (parse_args(argbulk, 1, 1, argv, 0) < 0)
75 return;
76 baudarg = atoi(argv[0]);
77 for (tp = rate_table; tp->baud; tp++)
78 if (tp->baud == baudarg)
79 break;
80 if (!tp->baud) {
81 printf("ERROR: invalid/unimplemented baud rate argument\n");
82 return;
83 }
84
85 /* do it */
86 serial_flush();
87 save_old_baud = actually_switch_baud(tp->divisor);
88
89 /*
90 * After getting the echo of this command at the old baud rate
91 * (see the serial flush call just before switching the divisor),
92 * the line will go silent from the user's perspective.
93 * The user should wait just a little bit, then send us a 0x55 ('U')
94 * at the new baud rate - we should be in the below loop waiting
95 * for this character by then. Receiving that character
96 * correctly (0x55 was chosen for the bit pattern - unlikely to
97 * be received if the sender is sending at a wrong baud rate)
98 * will cause us to conclude this command and return a new '='
99 * prompt at the new baud rate.
100 *
101 * If we get something else, we assume that someone messed up,
102 * switch back to the old baud rate, scribble an error message
103 * and return.
104 */
105 do
106 c = serial_in_poll();
107 while (c < 0);
108 if (c != 0x55) {
109 actually_switch_baud(save_old_baud);
110 printf("ERROR: no \'U\' received, switched back to old baud rate\n");
111 }
112 }