1/*- 2 * Copyright (c) 1998 Michael Smith (msmith@freebsd.org) 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h>
| 1/*- 2 * Copyright (c) 1998 Michael Smith (msmith@freebsd.org) 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h>
|
27__FBSDID("$FreeBSD: head/sys/boot/i386/libi386/comconsole.c 229435 2012-01-03 22:36:12Z kib $");
| 27__FBSDID("$FreeBSD: head/sys/boot/i386/libi386/comconsole.c 241300 2012-10-06 20:04:51Z avg $");
|
28 29#include <stand.h> 30#include <bootstrap.h> 31#include <machine/cpufunc.h> 32#include <dev/ic/ns16550.h> 33#include <dev/pci/pcireg.h> 34#include "libi386.h" 35 36#define COMC_FMT 0x3 /* 8N1 */ 37#define COMC_TXWAIT 0x40000 /* transmit timeout */ 38#define COMC_BPS(x) (115200 / (x)) /* speed to DLAB divisor */ 39#define COMC_DIV2BPS(x) (115200 / (x)) /* DLAB divisor to speed */ 40 41#ifndef COMPORT 42#define COMPORT 0x3f8 43#endif 44#ifndef COMSPEED 45#define COMSPEED 9600 46#endif 47 48static void comc_probe(struct console *cp); 49static int comc_init(int arg); 50static void comc_putchar(int c); 51static int comc_getchar(void); 52static int comc_getspeed(void); 53static void set_hw_console_hint(void); 54static int comc_ischar(void); 55static int comc_parseint(const char *string); 56static uint32_t comc_parse_pcidev(const char *string); 57static int comc_pcidev_set(struct env_var *ev, int flags, 58 const void *value); 59static int comc_pcidev_handle(uint32_t locator); 60static int comc_port_set(struct env_var *ev, int flags, 61 const void *value); 62static void comc_setup(int speed, int port); 63static int comc_speed_set(struct env_var *ev, int flags, 64 const void *value); 65
| 28 29#include <stand.h> 30#include <bootstrap.h> 31#include <machine/cpufunc.h> 32#include <dev/ic/ns16550.h> 33#include <dev/pci/pcireg.h> 34#include "libi386.h" 35 36#define COMC_FMT 0x3 /* 8N1 */ 37#define COMC_TXWAIT 0x40000 /* transmit timeout */ 38#define COMC_BPS(x) (115200 / (x)) /* speed to DLAB divisor */ 39#define COMC_DIV2BPS(x) (115200 / (x)) /* DLAB divisor to speed */ 40 41#ifndef COMPORT 42#define COMPORT 0x3f8 43#endif 44#ifndef COMSPEED 45#define COMSPEED 9600 46#endif 47 48static void comc_probe(struct console *cp); 49static int comc_init(int arg); 50static void comc_putchar(int c); 51static int comc_getchar(void); 52static int comc_getspeed(void); 53static void set_hw_console_hint(void); 54static int comc_ischar(void); 55static int comc_parseint(const char *string); 56static uint32_t comc_parse_pcidev(const char *string); 57static int comc_pcidev_set(struct env_var *ev, int flags, 58 const void *value); 59static int comc_pcidev_handle(uint32_t locator); 60static int comc_port_set(struct env_var *ev, int flags, 61 const void *value); 62static void comc_setup(int speed, int port); 63static int comc_speed_set(struct env_var *ev, int flags, 64 const void *value); 65
|
66static int comc_started;
| |
67static int comc_curspeed; 68static int comc_port = COMPORT; 69static uint32_t comc_locator; 70 71struct console comconsole = { 72 "comconsole", 73 "serial port", 74 0, 75 comc_probe, 76 comc_init, 77 comc_putchar, 78 comc_getchar, 79 comc_ischar 80}; 81 82static void 83comc_probe(struct console *cp) 84{ 85 char intbuf[16]; 86 char *cons, *env; 87 int speed, port; 88 uint32_t locator; 89
| 66static int comc_curspeed; 67static int comc_port = COMPORT; 68static uint32_t comc_locator; 69 70struct console comconsole = { 71 "comconsole", 72 "serial port", 73 0, 74 comc_probe, 75 comc_init, 76 comc_putchar, 77 comc_getchar, 78 comc_ischar 79}; 80 81static void 82comc_probe(struct console *cp) 83{ 84 char intbuf[16]; 85 char *cons, *env; 86 int speed, port; 87 uint32_t locator; 88
|
90 /* XXX check the BIOS equipment list? */ 91 cp->c_flags |= (C_PRESENTIN | C_PRESENTOUT); 92
| |
93 if (comc_curspeed == 0) { 94 comc_curspeed = COMSPEED; 95 /* 96 * Assume that the speed was set by an earlier boot loader if 97 * comconsole is already the preferred console. 98 */ 99 cons = getenv("console"); 100 if ((cons != NULL && strcmp(cons, comconsole.c_name) == 0) || 101 getenv("boot_multicons") != NULL) { 102 comc_curspeed = comc_getspeed(); 103 } 104 105 env = getenv("comconsole_speed"); 106 if (env != NULL) { 107 speed = comc_parseint(env); 108 if (speed > 0) 109 comc_curspeed = speed; 110 } 111 112 sprintf(intbuf, "%d", comc_curspeed); 113 unsetenv("comconsole_speed"); 114 env_setenv("comconsole_speed", EV_VOLATILE, intbuf, comc_speed_set, 115 env_nounset); 116 117 env = getenv("comconsole_port"); 118 if (env != NULL) { 119 port = comc_parseint(env); 120 if (port > 0) 121 comc_port = port; 122 } 123 124 sprintf(intbuf, "%d", comc_port); 125 unsetenv("comconsole_port"); 126 env_setenv("comconsole_port", EV_VOLATILE, intbuf, comc_port_set, 127 env_nounset); 128 129 env = getenv("comconsole_pcidev"); 130 if (env != NULL) { 131 locator = comc_parse_pcidev(env); 132 if (locator != 0) 133 comc_pcidev_handle(locator); 134 } 135 136 unsetenv("comconsole_pcidev"); 137 env_setenv("comconsole_pcidev", EV_VOLATILE, env, comc_pcidev_set, 138 env_nounset); 139 }
| 89 if (comc_curspeed == 0) { 90 comc_curspeed = COMSPEED; 91 /* 92 * Assume that the speed was set by an earlier boot loader if 93 * comconsole is already the preferred console. 94 */ 95 cons = getenv("console"); 96 if ((cons != NULL && strcmp(cons, comconsole.c_name) == 0) || 97 getenv("boot_multicons") != NULL) { 98 comc_curspeed = comc_getspeed(); 99 } 100 101 env = getenv("comconsole_speed"); 102 if (env != NULL) { 103 speed = comc_parseint(env); 104 if (speed > 0) 105 comc_curspeed = speed; 106 } 107 108 sprintf(intbuf, "%d", comc_curspeed); 109 unsetenv("comconsole_speed"); 110 env_setenv("comconsole_speed", EV_VOLATILE, intbuf, comc_speed_set, 111 env_nounset); 112 113 env = getenv("comconsole_port"); 114 if (env != NULL) { 115 port = comc_parseint(env); 116 if (port > 0) 117 comc_port = port; 118 } 119 120 sprintf(intbuf, "%d", comc_port); 121 unsetenv("comconsole_port"); 122 env_setenv("comconsole_port", EV_VOLATILE, intbuf, comc_port_set, 123 env_nounset); 124 125 env = getenv("comconsole_pcidev"); 126 if (env != NULL) { 127 locator = comc_parse_pcidev(env); 128 if (locator != 0) 129 comc_pcidev_handle(locator); 130 } 131 132 unsetenv("comconsole_pcidev"); 133 env_setenv("comconsole_pcidev", EV_VOLATILE, env, comc_pcidev_set, 134 env_nounset); 135 }
|
| 136 comc_setup(comc_curspeed, comc_port);
|
140} 141 142static int 143comc_init(int arg) 144{
| 137} 138 139static int 140comc_init(int arg) 141{
|
145 if (comc_started && arg == 0) 146 return 0; 147 comc_started = 1;
| |
148 149 comc_setup(comc_curspeed, comc_port); 150
| 142 143 comc_setup(comc_curspeed, comc_port); 144
|
151 return(0);
| 145 if ((comconsole.c_flags & (C_PRESENTIN | C_PRESENTOUT)) == 146 (C_PRESENTIN | C_PRESENTOUT)) 147 return (CMD_OK); 148 return (CMD_ERROR);
|
152} 153 154static void 155comc_putchar(int c) 156{ 157 int wait; 158 159 for (wait = COMC_TXWAIT; wait > 0; wait--) 160 if (inb(comc_port + com_lsr) & LSR_TXRDY) { 161 outb(comc_port + com_data, (u_char)c); 162 break; 163 } 164} 165 166static int 167comc_getchar(void) 168{
| 149} 150 151static void 152comc_putchar(int c) 153{ 154 int wait; 155 156 for (wait = COMC_TXWAIT; wait > 0; wait--) 157 if (inb(comc_port + com_lsr) & LSR_TXRDY) { 158 outb(comc_port + com_data, (u_char)c); 159 break; 160 } 161} 162 163static int 164comc_getchar(void) 165{
|
169 return(comc_ischar() ? inb(comc_port + com_data) : -1);
| 166 return (comc_ischar() ? inb(comc_port + com_data) : -1);
|
170} 171 172static int 173comc_ischar(void) 174{
| 167} 168 169static int 170comc_ischar(void) 171{
|
175 return(inb(comc_port + com_lsr) & LSR_RXRDY);
| 172 return (inb(comc_port + com_lsr) & LSR_RXRDY);
|
176} 177 178static int 179comc_speed_set(struct env_var *ev, int flags, const void *value) 180{ 181 int speed; 182 183 if (value == NULL || (speed = comc_parseint(value)) <= 0) { 184 printf("Invalid speed\n"); 185 return (CMD_ERROR); 186 } 187
| 173} 174 175static int 176comc_speed_set(struct env_var *ev, int flags, const void *value) 177{ 178 int speed; 179 180 if (value == NULL || (speed = comc_parseint(value)) <= 0) { 181 printf("Invalid speed\n"); 182 return (CMD_ERROR); 183 } 184
|
188 if (comc_started && comc_curspeed != speed)
| 185 if ((comconsole.c_flags & (C_ACTIVEIN | C_ACTIVEOUT)) != 0 && 186 comc_curspeed != speed)
|
189 comc_setup(speed, comc_port); 190 191 env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); 192 193 return (CMD_OK); 194} 195 196static int 197comc_port_set(struct env_var *ev, int flags, const void *value) 198{ 199 int port; 200 201 if (value == NULL || (port = comc_parseint(value)) <= 0) { 202 printf("Invalid port\n"); 203 return (CMD_ERROR); 204 } 205
| 187 comc_setup(speed, comc_port); 188 189 env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); 190 191 return (CMD_OK); 192} 193 194static int 195comc_port_set(struct env_var *ev, int flags, const void *value) 196{ 197 int port; 198 199 if (value == NULL || (port = comc_parseint(value)) <= 0) { 200 printf("Invalid port\n"); 201 return (CMD_ERROR); 202 } 203
|
206 if (comc_started && comc_port != port) {
| 204 if ((comconsole.c_flags & (C_ACTIVEIN | C_ACTIVEOUT)) != 0 && 205 comc_port != port) {
|
207 comc_setup(comc_curspeed, port); 208 set_hw_console_hint(); 209 } 210 211 env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); 212 213 return (CMD_OK); 214} 215 216static void 217set_hw_console_hint(void) 218{ 219 char intbuf[64]; 220 221 unsetenv("hw.uart.console"); 222 sprintf(intbuf, "io:%d,br:%d", comc_port, comc_curspeed); 223 env_setenv("hw.uart.console", EV_VOLATILE, intbuf, 224 env_noset, env_nounset); 225} 226 227/* 228 * Input: bus:dev:func[:bar]. If bar is not specified, it is 0x10. 229 * Output: bar[24:16] bus[15:8] dev[7:3] func[2:0] 230 */ 231static uint32_t 232comc_parse_pcidev(const char *string) 233{ 234 char *p, *p1; 235 uint8_t bus, dev, func, bar; 236 uint32_t locator; 237 int pres; 238 239 pres = strtol(string, &p, 0); 240 if (p == string || *p != ':' || pres < 0 ) 241 return (0); 242 bus = pres; 243 p1 = ++p; 244 245 pres = strtol(p1, &p, 0); 246 if (p == string || *p != ':' || pres < 0 ) 247 return (0); 248 dev = pres; 249 p1 = ++p; 250 251 pres = strtol(p1, &p, 0); 252 if (p == string || (*p != ':' && *p != '\0') || pres < 0 ) 253 return (0); 254 func = pres; 255 256 if (*p == ':') { 257 p1 = ++p; 258 pres = strtol(p1, &p, 0); 259 if (p == string || *p != '\0' || pres <= 0 ) 260 return (0); 261 bar = pres; 262 } else 263 bar = 0x10; 264 265 locator = (bar << 16) | biospci_locator(bus, dev, func); 266 return (locator); 267} 268 269static int 270comc_pcidev_handle(uint32_t locator) 271{ 272 char intbuf[64]; 273 uint32_t port; 274 275 if (biospci_read_config(locator & 0xffff, 276 (locator & 0xff0000) >> 16, 2, &port) == -1) { 277 printf("Cannot read bar at 0x%x\n", locator); 278 return (CMD_ERROR); 279 } 280 if (!PCI_BAR_IO(port)) { 281 printf("Memory bar at 0x%x\n", locator); 282 return (CMD_ERROR); 283 } 284 port &= PCIM_BAR_IO_BASE; 285 286 sprintf(intbuf, "%d", port); 287 unsetenv("comconsole_port"); 288 env_setenv("comconsole_port", EV_VOLATILE, intbuf, 289 comc_port_set, env_nounset); 290 291 comc_setup(comc_curspeed, port); 292 set_hw_console_hint(); 293 comc_locator = locator; 294 295 return (CMD_OK); 296} 297 298static int 299comc_pcidev_set(struct env_var *ev, int flags, const void *value) 300{ 301 uint32_t locator; 302 int error; 303 304 if (value == NULL || (locator = comc_parse_pcidev(value)) <= 0) { 305 printf("Invalid pcidev\n"); 306 return (CMD_ERROR); 307 }
| 206 comc_setup(comc_curspeed, port); 207 set_hw_console_hint(); 208 } 209 210 env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); 211 212 return (CMD_OK); 213} 214 215static void 216set_hw_console_hint(void) 217{ 218 char intbuf[64]; 219 220 unsetenv("hw.uart.console"); 221 sprintf(intbuf, "io:%d,br:%d", comc_port, comc_curspeed); 222 env_setenv("hw.uart.console", EV_VOLATILE, intbuf, 223 env_noset, env_nounset); 224} 225 226/* 227 * Input: bus:dev:func[:bar]. If bar is not specified, it is 0x10. 228 * Output: bar[24:16] bus[15:8] dev[7:3] func[2:0] 229 */ 230static uint32_t 231comc_parse_pcidev(const char *string) 232{ 233 char *p, *p1; 234 uint8_t bus, dev, func, bar; 235 uint32_t locator; 236 int pres; 237 238 pres = strtol(string, &p, 0); 239 if (p == string || *p != ':' || pres < 0 ) 240 return (0); 241 bus = pres; 242 p1 = ++p; 243 244 pres = strtol(p1, &p, 0); 245 if (p == string || *p != ':' || pres < 0 ) 246 return (0); 247 dev = pres; 248 p1 = ++p; 249 250 pres = strtol(p1, &p, 0); 251 if (p == string || (*p != ':' && *p != '\0') || pres < 0 ) 252 return (0); 253 func = pres; 254 255 if (*p == ':') { 256 p1 = ++p; 257 pres = strtol(p1, &p, 0); 258 if (p == string || *p != '\0' || pres <= 0 ) 259 return (0); 260 bar = pres; 261 } else 262 bar = 0x10; 263 264 locator = (bar << 16) | biospci_locator(bus, dev, func); 265 return (locator); 266} 267 268static int 269comc_pcidev_handle(uint32_t locator) 270{ 271 char intbuf[64]; 272 uint32_t port; 273 274 if (biospci_read_config(locator & 0xffff, 275 (locator & 0xff0000) >> 16, 2, &port) == -1) { 276 printf("Cannot read bar at 0x%x\n", locator); 277 return (CMD_ERROR); 278 } 279 if (!PCI_BAR_IO(port)) { 280 printf("Memory bar at 0x%x\n", locator); 281 return (CMD_ERROR); 282 } 283 port &= PCIM_BAR_IO_BASE; 284 285 sprintf(intbuf, "%d", port); 286 unsetenv("comconsole_port"); 287 env_setenv("comconsole_port", EV_VOLATILE, intbuf, 288 comc_port_set, env_nounset); 289 290 comc_setup(comc_curspeed, port); 291 set_hw_console_hint(); 292 comc_locator = locator; 293 294 return (CMD_OK); 295} 296 297static int 298comc_pcidev_set(struct env_var *ev, int flags, const void *value) 299{ 300 uint32_t locator; 301 int error; 302 303 if (value == NULL || (locator = comc_parse_pcidev(value)) <= 0) { 304 printf("Invalid pcidev\n"); 305 return (CMD_ERROR); 306 }
|
308 if (comc_started && comc_locator != locator) {
| 307 if ((comconsole.c_flags & (C_ACTIVEIN | C_ACTIVEOUT)) != 0 && 308 comc_locator != locator) {
|
309 error = comc_pcidev_handle(locator); 310 if (error != CMD_OK) 311 return (error); 312 } 313 env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); 314 return (CMD_OK); 315} 316 317static void 318comc_setup(int speed, int port) 319{
| 309 error = comc_pcidev_handle(locator); 310 if (error != CMD_OK) 311 return (error); 312 } 313 env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); 314 return (CMD_OK); 315} 316 317static void 318comc_setup(int speed, int port) 319{
|
| 320 static int TRY_COUNT = 1000000; 321 int tries;
|
320 321 comc_curspeed = speed; 322 comc_port = port; 323 324 outb(comc_port + com_cfcr, CFCR_DLAB | COMC_FMT); 325 outb(comc_port + com_dlbl, COMC_BPS(speed) & 0xff); 326 outb(comc_port + com_dlbh, COMC_BPS(speed) >> 8); 327 outb(comc_port + com_cfcr, COMC_FMT); 328 outb(comc_port + com_mcr, MCR_RTS | MCR_DTR); 329
| 322 323 comc_curspeed = speed; 324 comc_port = port; 325 326 outb(comc_port + com_cfcr, CFCR_DLAB | COMC_FMT); 327 outb(comc_port + com_dlbl, COMC_BPS(speed) & 0xff); 328 outb(comc_port + com_dlbh, COMC_BPS(speed) >> 8); 329 outb(comc_port + com_cfcr, COMC_FMT); 330 outb(comc_port + com_mcr, MCR_RTS | MCR_DTR); 331
|
| 332 tries = 0;
|
330 do 331 inb(comc_port + com_data);
| 333 do 334 inb(comc_port + com_data);
|
332 while (inb(comc_port + com_lsr) & LSR_RXRDY);
| 335 while (inb(comc_port + com_lsr) & LSR_RXRDY && ++tries < TRY_COUNT); 336 337 if (tries < TRY_COUNT) 338 comconsole.c_flags |= (C_PRESENTIN | C_PRESENTOUT); 339 else 340 comconsole.c_flags &= ~(C_PRESENTIN | C_PRESENTOUT);
|
333} 334 335static int 336comc_parseint(const char *speedstr) 337{ 338 char *p; 339 int speed; 340 341 speed = strtol(speedstr, &p, 0); 342 if (p == speedstr || *p != '\0' || speed <= 0) 343 return (-1); 344 345 return (speed); 346} 347 348static int 349comc_getspeed(void) 350{ 351 u_int divisor; 352 u_char dlbh; 353 u_char dlbl; 354 u_char cfcr; 355 356 cfcr = inb(comc_port + com_cfcr); 357 outb(comc_port + com_cfcr, CFCR_DLAB | cfcr); 358 359 dlbl = inb(comc_port + com_dlbl); 360 dlbh = inb(comc_port + com_dlbh); 361 362 outb(comc_port + com_cfcr, cfcr); 363 364 divisor = dlbh << 8 | dlbl; 365 366 /* XXX there should be more sanity checking. */ 367 if (divisor == 0) 368 return (COMSPEED); 369 return (COMC_DIV2BPS(divisor)); 370}
| 341} 342 343static int 344comc_parseint(const char *speedstr) 345{ 346 char *p; 347 int speed; 348 349 speed = strtol(speedstr, &p, 0); 350 if (p == speedstr || *p != '\0' || speed <= 0) 351 return (-1); 352 353 return (speed); 354} 355 356static int 357comc_getspeed(void) 358{ 359 u_int divisor; 360 u_char dlbh; 361 u_char dlbl; 362 u_char cfcr; 363 364 cfcr = inb(comc_port + com_cfcr); 365 outb(comc_port + com_cfcr, CFCR_DLAB | cfcr); 366 367 dlbl = inb(comc_port + com_dlbl); 368 dlbh = inb(comc_port + com_dlbh); 369 370 outb(comc_port + com_cfcr, cfcr); 371 372 divisor = dlbh << 8 | dlbl; 373 374 /* XXX there should be more sanity checking. */ 375 if (divisor == 0) 376 return (COMSPEED); 377 return (COMC_DIV2BPS(divisor)); 378}
|