at v2.6.24-rc2 216 lines 4.5 kB view raw
1/* suncore.c 2 * 3 * Common SUN serial routines. Based entirely 4 * upon drivers/sbus/char/sunserial.c which is: 5 * 6 * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) 7 * 8 * Adaptation to new UART layer is: 9 * 10 * Copyright (C) 2002 David S. Miller (davem@redhat.com) 11 */ 12 13#include <linux/module.h> 14#include <linux/kernel.h> 15#include <linux/console.h> 16#include <linux/tty.h> 17#include <linux/errno.h> 18#include <linux/string.h> 19#include <linux/serial_core.h> 20#include <linux/init.h> 21 22#include <asm/prom.h> 23 24#include "suncore.h" 25 26int sunserial_current_minor = 64; 27 28EXPORT_SYMBOL(sunserial_current_minor); 29 30int sunserial_console_match(struct console *con, struct device_node *dp, 31 struct uart_driver *drv, int line) 32{ 33 int off; 34 35 if (!con || of_console_device != dp) 36 return 0; 37 38 off = 0; 39 if (of_console_options && 40 *of_console_options == 'b') 41 off = 1; 42 43 if ((line & 1) != off) 44 return 0; 45 46 con->index = line; 47 drv->cons = con; 48 add_preferred_console(con->name, line, NULL); 49 50 return 1; 51} 52EXPORT_SYMBOL(sunserial_console_match); 53 54void 55sunserial_console_termios(struct console *con) 56{ 57 struct device_node *dp; 58 const char *od, *mode, *s; 59 char mode_prop[] = "ttyX-mode"; 60 int baud, bits, stop, cflag; 61 char parity; 62 63 dp = of_find_node_by_path("/options"); 64 od = of_get_property(dp, "output-device", NULL); 65 if (!strcmp(od, "rsc")) { 66 mode = of_get_property(of_console_device, 67 "ssp-console-modes", NULL); 68 if (!mode) 69 mode = "115200,8,n,1,-"; 70 } else { 71 char c; 72 73 c = 'a'; 74 if (of_console_options) 75 c = *of_console_options; 76 77 mode_prop[3] = c; 78 79 mode = of_get_property(dp, mode_prop, NULL); 80 if (!mode) 81 mode = "9600,8,n,1,-"; 82 } 83 84 cflag = CREAD | HUPCL | CLOCAL; 85 86 s = mode; 87 baud = simple_strtoul(s, NULL, 0); 88 s = strchr(s, ','); 89 bits = simple_strtoul(++s, NULL, 0); 90 s = strchr(s, ','); 91 parity = *(++s); 92 s = strchr(s, ','); 93 stop = simple_strtoul(++s, NULL, 0); 94 s = strchr(s, ','); 95 /* XXX handshake is not handled here. */ 96 97 switch (baud) { 98 case 150: cflag |= B150; break; 99 case 300: cflag |= B300; break; 100 case 600: cflag |= B600; break; 101 case 1200: cflag |= B1200; break; 102 case 2400: cflag |= B2400; break; 103 case 4800: cflag |= B4800; break; 104 case 9600: cflag |= B9600; break; 105 case 19200: cflag |= B19200; break; 106 case 38400: cflag |= B38400; break; 107 case 57600: cflag |= B57600; break; 108 case 115200: cflag |= B115200; break; 109 case 230400: cflag |= B230400; break; 110 case 460800: cflag |= B460800; break; 111 default: baud = 9600; cflag |= B9600; break; 112 } 113 114 switch (bits) { 115 case 5: cflag |= CS5; break; 116 case 6: cflag |= CS6; break; 117 case 7: cflag |= CS7; break; 118 case 8: cflag |= CS8; break; 119 default: cflag |= CS8; break; 120 } 121 122 switch (parity) { 123 case 'o': cflag |= (PARENB | PARODD); break; 124 case 'e': cflag |= PARENB; break; 125 case 'n': default: break; 126 } 127 128 switch (stop) { 129 case 2: cflag |= CSTOPB; break; 130 case 1: default: break; 131 } 132 133 con->cflag = cflag; 134} 135 136EXPORT_SYMBOL(sunserial_console_termios); 137 138/* Sun serial MOUSE auto baud rate detection. */ 139static struct mouse_baud_cflag { 140 int baud; 141 unsigned int cflag; 142} mouse_baud_table[] = { 143 { 1200, B1200 }, 144 { 2400, B2400 }, 145 { 4800, B4800 }, 146 { 9600, B9600 }, 147 { -1, ~0 }, 148 { -1, ~0 }, 149}; 150 151unsigned int suncore_mouse_baud_cflag_next(unsigned int cflag, int *new_baud) 152{ 153 int i; 154 155 for (i = 0; mouse_baud_table[i].baud != -1; i++) 156 if (mouse_baud_table[i].cflag == (cflag & CBAUD)) 157 break; 158 159 i += 1; 160 if (mouse_baud_table[i].baud == -1) 161 i = 0; 162 163 *new_baud = mouse_baud_table[i].baud; 164 return mouse_baud_table[i].cflag; 165} 166 167EXPORT_SYMBOL(suncore_mouse_baud_cflag_next); 168 169/* Basically, when the baud rate is wrong the mouse spits out 170 * breaks to us. 171 */ 172int suncore_mouse_baud_detection(unsigned char ch, int is_break) 173{ 174 static int mouse_got_break = 0; 175 static int ctr = 0; 176 177 if (is_break) { 178 /* Let a few normal bytes go by before we jump the gun 179 * and say we need to try another baud rate. 180 */ 181 if (mouse_got_break && ctr < 8) 182 return 1; 183 184 /* Ok, we need to try another baud. */ 185 ctr = 0; 186 mouse_got_break = 1; 187 return 2; 188 } 189 if (mouse_got_break) { 190 ctr++; 191 if (ch == 0x87) { 192 /* Correct baud rate determined. */ 193 mouse_got_break = 0; 194 } 195 return 1; 196 } 197 return 0; 198} 199 200EXPORT_SYMBOL(suncore_mouse_baud_detection); 201 202static int __init suncore_init(void) 203{ 204 return 0; 205} 206 207static void __exit suncore_exit(void) 208{ 209} 210 211module_init(suncore_init); 212module_exit(suncore_exit); 213 214MODULE_AUTHOR("Eddie C. Dost, David S. Miller"); 215MODULE_DESCRIPTION("Sun serial common layer"); 216MODULE_LICENSE("GPL");