FreeCalypso > hg > freecalypso-sw
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 } |