3 * 8250/16450/16550/16750 serial port UART test program.
4 * (C) 2009-2012 Jonathan Campbell.
5 * Hackipedia DOS library.
7 * This code is licensed under the LGPL.
8 * <insert LGPL legal text here>
10 * Compiles for intended target environments:
11 * - MS-DOS [pure DOS mode, or Windows or OS/2 DOS Box] */
13 /* TODO: - Can you transform the IRQ buffering code into some kind of C object that the program can allocate as needed (including what size buffer) so that
14 * such IRQ enabled code is easily usable in other programming projects?
15 * - See how well this works on that Saber laptop where the trackball is a serial device on COM2.
16 * - Add code to show you the state of the line and modem status registers, and twiddle them too.
17 * - Does this program actually work on... say... the IBM PC/XT you have sitting in the corner?
18 * - How about that ancient 286 laptop you have? The 386 one? The Compaq elite? */
20 /* Warnings regarding this code: The order of operations involved in enabling interrupts is
21 * very important! The 8250/16450/16550A/etc UARTs in PC hardware are just so goddamn finicky
22 * about getting interrupts to fire like they're supposed to that if you change the order of
23 * I/O port operations (even if to a more intuitive order) you will probably break UART
24 * interrupt support on many configurations.
26 * I must explain why the code enables interrupts the way it does in the specific order:
27 * 1. At the very start, the IRQ is unmasked ahead of time (prior to main loop)
28 * 2. The user hits '6' to enable interrupts
29 * 3. The code sends a specific EOI to the programmable interrupt controller. If we don't do this,
30 * the Programmable Interrupt Controller may fail to send interrupts in the event the UART
31 * was already holding the IRQ line high and interrupts will not happen
32 * 4. We set all lower 4 bits of the Interrupt Enable register of the UART so that we're notified
33 * when (1) data is available (2) the trasmitter buffer is empty (and waiting for more)
34 * (3 & 4) any change in the line or modem status registers
35 * 5. Experience tells me that if for any reason the UART had events pending, but was interrupted
36 * for any reason, it might not fire any futher interrupts until someone reads the IIR and
37 * services each register appropriately. So the UART is never serviced because the IRQ is never
38 * fired, and the IRQ is never fired because the UART is never serviced. Forcibly read and discard
39 * all "events" from the UART to clear out that queue and get the UART firing off interrupts once
42 * Again: if you change the order of operations there, you will produce code that for one reason or
43 * another fail to enable UART interrupts on some computers, and will happen to work on other
44 * computers. Follow the above order strictly, and interrupts will fire like they are supposed to. */
48 * DB-9 port = Device is a UART with an externally visible 9-pin D-shell connector
49 * DB-25 port= Device is a UART with an externally visible 25-pin D-shell connector
50 * Int modem = Device is an internal modem emulating a UART
51 * IRDA = Device is an infared port pretending to be a UART
52 * Emulated = If platform involves an emulator, the UART is emulated by the software
53 * If the platform is actual hardware, then the BIOS or host OS traps I/O to emulate a UART
55 * Scenario I/O works Bi-dir Up to UART loop Type Notes
56 * Poll Interrupt ectional baud Poll Interrupt
57 * --------------------------------------------------------------------------------------------------
58 * Microsoft Virtual PC 2007
59 * - real & protected mode Y Y Y 115200 N N Emulated Everything works, except loopback is improperly
60 * emulated. What is actually received is the last byte
61 * received, not the one we sent out.
62 * * Actual transfer speed is limited by the mechanism used to emulate. If using NT pipes like \\.\pipe\dostest the fake UART
63 * will stall until that pipe can be written by Virtual PC.
64 * * Works with both traditional and ISA Plug & Play versions of the test program.
65 * * Prior versions of these comments complained about the Real-mode copy running erratically and crashing.
66 * It was discovered the CPU detection code was calling a far routine as if near and the incorrect stack
67 * return caused the erratic behavior (as well as solid hangs on other configurations). Since the fix was
68 * applied VirtualBox now runs our code flawlessly.
70 * Oracle VirtualBox 4.0.4
71 * - real & protected ver Y Y Y 115200 Y Y Emulated Everything works fine. VirtualBox's UART emulation
72 * is very tolerant of errors, perhaps even deceptively
73 * tolerant compared to actual hardware.
74 * * Works with traditional program. VirtualBox does not emulate ISA Plug & Play.
76 * Toshiba Satellite Pro 465CDX laptop
77 * - With COM1 (0x3F8) Y Y Y 115200 Y ? DB-9 port Works fine.
78 * - With COM2 (0x2F8) Y Y ? ? Y ? Int modem Communication works at any baud, Hayes compatible
79 * - With COM3 (0x3E8) Y Y N 115200 Y ? IRDA Toshiba's BIOS puts this on IRQ 9. The port and IRQ
80 * will only be detected properly by the ISA PnP version.
81 * The traditional version will mis-detect the port IRQ
84 * Bidirectional communications are impossible over IRDA.
85 * If both ends transmit one byte simultaneously the
86 * bits collide and each end receives gibberish.
87 * Perfect transmission is only possible if each end
88 * takes turns transmitting and receiving.
89 * * DOS extender problem (dos32a): When we enable and hook the UART IRQ the DOS extender
90 * crashes back to DOS with "Invalid TSS" exception (INT 0x0A). This makes the 32-bit
91 * protected mode version unusable on Toshiba hardware unless polling is involved.
92 * For interrupt-enabled testing, you must use the real-mode version.
94 * Toshiba Libretto laptop
95 * - With COM1 (0x3F8) Y Y Y 115200 Y ? DB-9 port Actual communication not verified. The port is only
96 * available through the docking station, which I do not
98 * - With COM2 (0x2F8) Y Y N 115200 Y ? IRDA Bidirectional communications are not possible. Each end
99 * must take turns transmitting and receiving, or else
100 * data becomes corrupt in transmission.
101 * * DOS extender problem (dos32a): When we enable and hook the UART IRQ the DOS extender
102 * crashes back to DOS with "Invalid TSS" exception (INT 0x0A). This makes the 32-bit
103 * protected mode version unusable on Toshiba hardware unless polling is involved.
104 * For interrupt-enabled testing, you must use the real-mode version.
106 * Compaq Elite laptop
107 * - With COM1 (0x3F8) Y Y Y 115200 Y ? DB-9 port
111 #include <conio.h> /* this is where Open Watcom hides the outp() etc. functions */
119 #include <hw/cpu/cpu.h>
120 #include <hw/dos/dos.h>
121 #include <hw/8254/8254.h>
122 #include <hw/8259/8259.h>
123 #include <hw/8250/8250.h>
124 #include <hw/dos/doswin.h>
127 #include <hw/8250/8250pnp.h>
128 #include <hw/isapnp/isapnp.h>
131 /* global variable: the uart object */
132 static struct info_8250 *uart = NULL;
134 /* IRQ transfer buffers. Used by interrupt handler to store incoming data. Non-interrupt code should disable interrupts before accessing */
135 #define IRQ_BUFFER_SIZE 512
137 static unsigned char irq_buffer[IRQ_BUFFER_SIZE];
138 static unsigned int irq_buffer_i=0,irq_buffer_o=0;
140 static unsigned char irq_bufferout[IRQ_BUFFER_SIZE];
141 static unsigned int irq_bufferout_i=0,irq_bufferout_o=0;
143 static void irq_buffer_reset() {
145 irq_buffer_i = irq_buffer_o = 0;
146 irq_bufferout_i = irq_bufferout_o = 0;
150 /* take any IRQ buffered output and send it.
151 * must be called with interrupts disabled.
152 * may be called from the IRQ handler. */
153 static void irq_uart_xmit_bufferout(struct info_8250 *uart) {
156 if (irq_bufferout_o != irq_bufferout_i) {
158 while (uart_8250_can_write(uart) && irq_bufferout_o != irq_bufferout_i) {
159 c = irq_bufferout[irq_bufferout_o++];
160 if (irq_bufferout_o >= IRQ_BUFFER_SIZE) irq_bufferout_o = 0;
161 outp(uart->port+PORT_8250_IO,c);
166 static void irq_uart_recv_buffer(struct info_8250 *uart) {
169 while (uart_8250_can_read(uart)) {
170 c = inp(uart->port+PORT_8250_IO);
171 if ((irq_buffer_i+1)%IRQ_BUFFER_SIZE != irq_buffer_o) {
172 irq_buffer[irq_buffer_i++] = c;
173 if (irq_buffer_i >= IRQ_BUFFER_SIZE) irq_buffer_i = 0;
178 static int irq_bufferout_count() {
179 int x = irq_bufferout_i - irq_bufferout_o;
180 if (x < 0) x += IRQ_BUFFER_SIZE;
184 /* NOTE: You're supposed to call this function with interrupts disabled,
185 * or from within an interrupt handler in response to the UART's IRQ signal. */
186 static void irq_uart_handle_iir(struct info_8250 *uart) {
187 unsigned char reason,c,patience = 8;
189 #if TARGET_MSDOS == 32
190 (*((unsigned short*)0xB8010))++;
192 (*((unsigned short far*)MK_FP(0xB800,0x0010)))++;
195 /* why the interrupt? */
196 /* NOTE: we loop a maximum of 8 times in case the UART we're talking to happens
197 * to be some cheap knockoff chipset that never clears the IIR register
198 * when all events are read */
199 /* if there was actually an interrupt, then handle it. loop until all interrupt conditions are depleted */
200 while (((reason=inp(uart->port+PORT_8250_IIR)&7)&1) == 0) {
202 #if TARGET_MSDOS == 32
203 (*((unsigned short*)0xB8000))++;
205 (*((unsigned short far*)MK_FP(0xB800,0x0000)))++;
208 if (reason == 3) { /* line status */
209 #if TARGET_MSDOS == 32
210 (*((unsigned short*)0xB8008))++;
212 (*((unsigned short far*)MK_FP(0xB800,0x0008)))++;
215 c = inp(uart->port+PORT_8250_LSR);
216 /* do what you will with this info */
218 else if (reason == 0) { /* modem status */
219 #if TARGET_MSDOS == 32
220 (*((unsigned short*)0xB8006))++;
222 (*((unsigned short far*)MK_FP(0xB800,0x0006)))++;
225 c = inp(uart->port+PORT_8250_MSR);
226 /* do what you will with this info */
228 else if (reason == 2) { /* data avail */
229 #if TARGET_MSDOS == 32
230 (*((unsigned short*)0xB8002))++;
232 (*((unsigned short far*)MK_FP(0xB800,0x0002)))++;
235 irq_uart_recv_buffer(uart);
237 else if (reason == 1) { /* transmit empty */
238 #if TARGET_MSDOS == 32
239 (*((unsigned short*)0xB8004))++;
241 (*((unsigned short far*)MK_FP(0xB800,0x0004)))++;
244 irq_uart_xmit_bufferout(uart);
247 if (--patience == 0) {
248 #if TARGET_MSDOS == 32
249 (*((unsigned short*)0xB800A))++;
251 (*((unsigned short far*)MK_FP(0xB800,0x000A)))++;
258 static void (interrupt *old_irq)() = NULL;
259 static void interrupt uart_irq() {
260 /* clear interrupts, just in case. NTS: the nature of interrupt handlers
261 * on the x86 platform (IF in EFLAGS) ensures interrupts will be reenabled on exit */
263 irq_uart_handle_iir(uart);
266 if (uart->irq >= 8) p8259_OCW2(8,P8259_OCW2_NON_SPECIFIC_EOI);
267 p8259_OCW2(0,P8259_OCW2_NON_SPECIFIC_EOI);
270 static void change_config(struct info_8250 *uart) {
276 unsigned long baud=0;
277 unsigned char bits=0,stop_bits=0,parity=0;
278 uart_8250_get_config(uart,&baud,&bits,&stop_bits,&parity);
279 printf("State: %lu baud %u-bit %u stop bits %s\n",baud,bits,stop_bits,type_8250_parity(parity));
280 printf("1/!. Baud rate inc/dec 2/@. Bits inc/dec 3. Stop bits 4. Parity\n");
281 printf("? "); fflush(stdout);
290 else if (c == '1' || c == '!') {
291 unsigned long rate = 9600;
292 printf("new rate? "); fflush(stdout);
294 uart_8250_set_baudrate(uart,uart_8250_baud_to_divisor(uart,rate));
296 else if (c == '2' || c == '@') {
297 by = inp(uart->port+PORT_8250_LCR);
298 if (c == '2') by = (by & (~3)) | (((by & 3) + 3) & 3);
299 else by = (by & (~3)) | (((by & 3) + 1) & 3);
300 outp(uart->port+PORT_8250_LCR,by);
302 else if (c == '3' || c == '#') {
303 by = inp(uart->port+PORT_8250_LCR);
305 outp(uart->port+PORT_8250_LCR,by);
307 else if (c == '4' || c == '$') {
308 by = inp(uart->port+PORT_8250_LCR);
311 else if (t2 == 1) t2 = 3;
312 else if (t2 >= 3) t2 += 2;
316 outp(uart->port+PORT_8250_LCR,by);
321 static void config_fifo(struct info_8250 *uart) {
325 if (uart->type <= TYPE_8250_IS_16550) {
326 printf("Your UART (as far as I know) does not have a FIFO\n");
331 printf("FCR: Enable=%u mode=%u 64byte=%u recv_trigger_level=%u\n",
336 printf("1. Flush & enable/disable 2. Mode 3. 64byte 4. Level\n");
337 printf("? "); fflush(stdout);
347 uart_8250_set_FIFO(uart,fcr);
351 uart_8250_set_FIFO(uart,fcr);
355 uart_8250_set_FIFO(uart,fcr);
359 uart_8250_set_FIFO(uart,fcr);
364 void irq_bufferout_write(unsigned char c) {
366 while (((irq_bufferout_i+1)%IRQ_BUFFER_SIZE) == irq_bufferout_o) {
367 /* try to force transmit interrupt that gets the character out the door */
368 uart_toggle_xmit_ien(uart);
370 /* IODELAY during interrupt enable. Give the UART's interrupt a chance to interrupt the CPU */
371 inp(uart->port+PORT_8250_MCR); /* iodelay */
372 inp(uart->port+PORT_8250_MCR); /* iodelay */
373 inp(uart->port+PORT_8250_MCR); /* iodelay */
374 inp(uart->port+PORT_8250_MCR); /* iodelay */
378 /* put it in the buffer */
379 irq_bufferout[irq_bufferout_i++] = c;
380 if (irq_bufferout_i >= IRQ_BUFFER_SIZE) irq_bufferout_i = 0;
381 if (irq_bufferout_count() == 1) uart_toggle_xmit_ien(uart);
385 static void show_console(struct info_8250 *uart) {
386 static const char *msg = "Testing testing 1... 2... 3... 01234567890123456789.\r\n"
387 "The big dog jumped the shark or something like that.\r\n";
388 unsigned char pc=0,seqmatch=0,xmitseq=0,xmitbyte=0;
389 const size_t msg_len = strlen(msg);
390 unsigned int patience;
394 printf("Incoming data will be printed out, and data you type will xmit (port=%X)\n",uart->port);
395 printf("Tap ESC twice to exit. '~' = type out a predefined message.\n");
396 printf("SHIFT + ~ to rapidly transmit the message.\n");
397 printf("Type CTRL+A to initiate sequential byte test.\n");
399 if (use_8250_int) irq_buffer_reset();
409 stuck_xmit = !stuck_xmit;
411 else if (c == 1) { /* CTRL+S */
419 irq_bufferout_write(c);
422 while (!uart_8250_can_write(uart));
423 uart_8250_write(uart,(uint8_t)c);
429 irq_bufferout_write(13);
430 irq_bufferout_write(10);
433 while (!uart_8250_can_write(uart));
434 uart_8250_write(uart,13);
435 while (!uart_8250_can_write(uart));
436 uart_8250_write(uart,10);
445 irq_bufferout_write(c);
448 while (!uart_8250_can_write(uart));
449 uart_8250_write(uart,(uint8_t)c);
451 fwrite(&c,1,1,stdout); fflush(stdout);
457 /* the interrupt handler takes care of reading the data in (in bursts, if necessary).
458 * our job is to follow the buffer. Note we have a "patience" parameter to break out
459 * of the loop in cases where fast continious transmission prevents us from ever
460 * emptying the buffer entirely. */
463 while (patience-- != 0 && irq_buffer_o != irq_buffer_i) {
464 c = irq_buffer[irq_buffer_o++];
465 if (irq_buffer_o >= IRQ_BUFFER_SIZE) irq_buffer_o = 0;
468 if (seqmatch >= 16) {
469 if (((pc+1)&0xFF) != c) {
471 printf("Sequential byte error %u -> %u\n",pc,c);
474 printf(":)"); fflush(stdout);
482 fwrite(&c,1,1,stdout); fflush(stdout);
486 if (((pc+1)&0xFF) == c) {
487 if (seqmatch < 255) seqmatch++;
489 else if (seqmatch > 0) {
497 while (uart_8250_can_read(uart)) {
498 c = uart_8250_read(uart);
499 if (seqmatch >= 16) {
500 if (((pc+1)&0xFF) != c) {
501 printf("Sequential byte error %u -> %u\n",pc,c);
504 printf(":)"); fflush(stdout);
512 fwrite(&c,1,1,stdout); fflush(stdout);
517 if (((pc+1)&0xFF) == c) {
518 if (seqmatch < 255) seqmatch++;
520 else if (seqmatch > 0) {
529 for (c=0;c < 0x40;c++) {
531 irq_bufferout_write(xmitbyte++);
534 if (!uart_8250_can_write(uart)) break;
535 uart_8250_write(uart,xmitbyte++);
539 else if (stuck_xmit) {
544 irq_bufferout_write(c);
547 while (!uart_8250_can_write(uart));
548 uart_8250_write(uart,(uint8_t)c);
558 static unsigned char devnode_raw[4096];
560 void pnp_serial_scan() {
561 /* most of the time the serial ports are BIOS controlled and on the motherboard.
562 * they usually don't even show up in a PnP isolation scan. so we have to use
563 * the "get device nodes" functions of the PnP BIOS. */
565 struct isa_pnp_device_node far *devn;
566 unsigned int ret_ax,nodesize=0xFFFF;
567 unsigned char numnodes=0xFF;
568 struct isapnp_tag tag;
571 printf("Enumerating PnP system device nodes...\n");
573 ret_ax = isa_pnp_bios_number_of_sysdev_nodes(&numnodes,&nodesize);
574 if (ret_ax == 0 && numnodes != 0xFF && nodesize < sizeof(devnode_raw)) {
575 /* NTS: How nodes are enumerated in the PnP BIOS: set node = 0, pass address of node
576 * to BIOS. BIOS, if it returns node information, will also overwrite node with
577 * the node number of the next node, or with 0xFF if this is the last one.
578 * On the last one, stop enumerating. */
579 for (node=0;node != 0xFF;) {
580 unsigned char far *rsc;
584 /* apparently, start with 0. call updates node to
585 * next node number, or 0xFF to signify end */
586 ret_ax = isa_pnp_bios_get_sysdev_node(&node,devnode_raw,
587 ISA_PNP_BIOS_GET_SYSDEV_NODE_CTRL_NOW);
592 devn = (struct isa_pnp_device_node far*)devnode_raw;
593 if (!is_rs232_or_compat_pnp_device(devn))
596 /* there are three config blocks, one after the other.
600 * since we're not a configuration utility, we only care about the first one */
601 rsc = devnode_raw + sizeof(*devn);
602 if (isapnp_read_tag(&rsc,devnode_raw + devn->size,&tag)) {
604 if (tag.tag == ISAPNP_TAG_END) /* end tag */
608 /*---------------------------------------------------------------------------------*/
609 case ISAPNP_TAG_IRQ_FORMAT: {
610 struct isapnp_tag_irq_format far *x = (struct isapnp_tag_irq_format far*)tag.data;
612 for (i=0;i < 16 && irq < 0;i++) {
613 if (x->irq_mask & (1U << (unsigned int)i))
617 case ISAPNP_TAG_IO_PORT: {
618 struct isapnp_tag_io_port far *x = (struct isapnp_tag_io_port far*)tag.data;
619 if (x->length >= 8 && port < 0) port = x->min_range;
621 case ISAPNP_TAG_FIXED_IO_PORT: {
622 struct isapnp_tag_fixed_io_port far *x = (struct isapnp_tag_fixed_io_port far*)tag.data;
623 if (x->length >= 8 && port < 0) port = x->base;
625 /*---------------------------------------------------------------------------------*/
627 } while (isapnp_read_tag(&rsc,devnode_raw + devn->size,&tag));
633 if (add_pnp_8250(port,irq))
634 printf("Found PnP port @ 0x%03x IRQ %d\n",port,irq);
642 unsigned char msr_redraw = 1;
643 unsigned char redraw = 1;
644 unsigned char p_msr = 0;
647 printf("8250/16450/16550 test program\n");
649 printf("ISA Plug & Play version\n");
652 cpu_probe(); /* ..for the DOS probe routine */
653 probe_dos(); /* ..for the Windows detection code */
654 detect_windows(); /* Windows virtualizes the COM ports, and we don't want probing to occur to avoid any disruption */
657 printf("8254 not found (I need this for time-sensitive portions of the driver)\n");
662 printf("8259 not found (I need this for portions of the test involving serial interrupts)\n");
667 printf("Cannot init 8250 library\n");
672 if (!init_isa_pnp_bios()) {
673 printf("Cannot init ISA PnP\n");
676 if (find_isa_pnp_bios()) {
680 printf("Warning, ISA PnP BIOS not found\n");
683 printf("%u BIOS I/O ports listed\nThey are: ",(unsigned int)bios_8250_ports);
684 for (i=0;i < (int)bios_8250_ports;i++) printf("0x%04x ",get_8250_bios_port(i));
687 printf("Now probing ports: "); fflush(stdout);
688 for (i=0;!base_8250_full() && i < (int)bios_8250_ports;i++) {
689 const uint16_t port = get_8250_bios_port(i);
690 if (port == 0) continue;
691 printf("0x%03X ",port); fflush(stdout);
692 if (probe_8250(port)) printf("[OK] ");
694 if (windows_mode == WINDOWS_NONE || windows_mode == WINDOWS_REAL) {
695 /* if we're running under Windows it's likely the kernel is virtualizing the ports. play it safe and
696 * stick to the "BIOS" ports that Windows and it's virtualization likely added to the data area */
697 for (i=0;!base_8250_full() && i < (int)(sizeof(standard_8250_ports)/sizeof(standard_8250_ports[0]));i++) {
698 const uint16_t port = standard_8250_ports[i];
699 if (port == 0) continue;
700 printf("0x%03X ",port); fflush(stdout);
701 if (probe_8250(port)) printf("[OK] ");
707 for (i=0;i < base_8250_ports;i++) {
708 struct info_8250 *inf = &info_8250_port[i];
709 printf("[%u] @ %03X (type %s IRQ %d)\n",i+1,inf->port,type_8250_to_str(inf->type),inf->irq);
711 printf("Choice? "); fflush(stdout);
715 if (choice < 0 || choice >= base_8250_ports) return 0;
716 uart = &info_8250_port[choice];
718 if (uart->irq != -1) {
719 old_irq = _dos_getvect(irq2int(uart->irq));
720 _dos_setvect(irq2int(uart->irq),uart_irq);
721 if (uart->irq >= 0) {
722 p8259_unmask(uart->irq);
723 if (uart->irq >= 8) p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (uart->irq&7));
724 p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | (uart->irq&7));
728 uart_8250_enable_interrupt(uart,0); /* disable interrupts (set IER=0) */
729 uart_8250_disable_FIFO(uart);
730 uart_8250_set_MCR(uart,3); /* turn on RTS and DTS */
731 uart_8250_set_line_control(uart,UART_8250_LCR_8BIT | UART_8250_LCR_PARITY); /* 8 bit 1 stop bit odd parity */
732 uart_8250_set_baudrate(uart,uart_8250_baud_to_divisor(uart,9600));
734 for (die=0;die == 0;) {
735 unsigned char msr = uart_8250_read_MSR(uart);
738 unsigned long baud=0;
739 unsigned char bits=0,stop_bits=0,parity=0;
740 unsigned char mcr = uart_8250_read_MCR(uart);
745 uart_8250_get_config(uart,&baud,&bits,&stop_bits,&parity);
747 printf("State: %lu baud %u-bit %u stop bits %s DTR=%u RTS=%u LOOP=%u\n",baud,bits,stop_bits,type_8250_parity(parity),
748 (mcr & 1) ? 1 : 0/*DTR*/,
749 (mcr & 2) ? 1 : 0/*RTS*/,
750 (mcr & 16) ? 1 : 0/*LOOP*/);
751 printf("1. Change config 2. Toggle DTR 3. Toggle RTS 4. Show on console\n");
752 printf("5. Config FIFO ");
753 if (use_8250_int) printf("6. To poll IO ");
754 else printf("6. To int IO ");
755 printf("7. Toggle LOOP ");
759 if ((msr ^ p_msr) & 0xF0) msr_redraw = 1;
765 "CTS=%u DSR=%u RI=%u CD=%u ? ",
769 (msr & 128) ? 1 : 0);
779 else if (choice == '1') {
783 else if (choice == '2') {
784 uart_8250_set_MCR(uart,uart_8250_read_MCR(uart) ^ 1);
787 else if (choice == '3') {
788 uart_8250_set_MCR(uart,uart_8250_read_MCR(uart) ^ 2);
791 else if (choice == '7') {
792 uart_8250_set_MCR(uart,uart_8250_read_MCR(uart) ^ 16);
795 else if (choice == '4') {
799 else if (choice == '5') {
803 else if (choice == '6') {
804 /* NTS: Apparently a lot of hardware has problems with just turning on interrupts.
805 * So do everything we can to fucking whip the UART into shape. Drain & reset
806 * it's FIFO. Clear all interrupt events. Unmask the IRQ. Enable all interrupt
807 * events. What ever it fucking takes */
810 /* ACK the IRQ to ensure the PIC will send more. Doing this resolves a bug on
811 * a Toshiba 465CDX and IBM NetVista where enabling interrupts would seem to
812 * "hang" the machine (when in fact it was just the PIC not firing interrupts
813 * and therefore preventing the keyboard and timer from having their interrupts
815 if (uart->irq >= 8) p8259_OCW2(8,P8259_OCW2_SPECIFIC_EOI | (uart->irq&7));
816 p8259_OCW2(0,P8259_OCW2_SPECIFIC_EOI | (uart->irq&7));
819 use_8250_int = !use_8250_int;
820 if (use_8250_int) uart_8250_enable_interrupt(uart,0xF);
821 else uart_8250_enable_interrupt(uart,0x0);
822 for (i=0;i < 256 && (inp(uart->port+PORT_8250_IIR) & 1) == 0;i++) {
824 inp(uart->port+PORT_8250_MSR);
825 inp(uart->port+PORT_8250_MCR);
826 inp(uart->port+PORT_8250_LSR);
827 inp(uart->port+PORT_8250_IIR);
828 inp(uart->port+PORT_8250_IER);
830 if (i == 256) printf("Warning: Unable to clear UART interrupt conditions\n");
836 uart_8250_enable_interrupt(uart,0); /* disable interrupts (set IER=0) */
837 uart_8250_set_MCR(uart,0); /* RTS/DTR and aux lines off */
838 uart_8250_disable_FIFO(uart);
839 uart_8250_set_line_control(uart,UART_8250_LCR_8BIT | UART_8250_LCR_PARITY); /* 8 bit 1 stop bit odd parity */
840 uart_8250_set_baudrate(uart,uart_8250_baud_to_divisor(uart,9600));
842 if (uart->irq != -1) {
843 _dos_setvect(irq2int(uart->irq),old_irq);
844 if (uart->irq >= 0) p8259_mask(uart->irq);