/***************************************************************************** Serial (mouse) driver code Chris Giese http://www.execpc.com/~geezer Release date: Oct 13, 2003 This code is public domain (no copyright). You can do whatever you want with it. Updated Dec 27, 2003: - can now use F1 and F2 keys to toggle RTS and DTR NOTE: This code probably won't work inside a Windows DOS box. To do - Watcom C delay() seems slower than Turbo C or DJGPP - detect presence of modem? - maybe write and test a LapLink clone - test in system with 16650+ (32-byte) FIFO *****************************************************************************/ /* define this for serial mouse demo, undefine it for e.g. modem */ #define MOUSE /*---------------------------------------------------------------------------- Portability code for DOS compilers ----------------------------------------------------------------------------*/ /* Turbo C: getvect(), setvect() [in|out]portb(), [peek|poke][b]() DJGPP: [in|out]portb() Watcom C: MK_FP(), dos_getvect(), _dos_setvect() */ #include #define VECTOR_MAGIC 0xB179 /* forward declarations */ int irq_enabled_at_8259(unsigned irq); void enable_irq_at_8259(unsigned irq); void disable_irq_at_8259(unsigned irq); extern const unsigned g_irq_to_vect[]; /********************************* TURBO C **********************************/ #if defined(__TURBOC__) #define peekw(S,O) peek(S,O) #define pokew(S,O,V) poke(S,O,V) #ifdef __cplusplus #define HANDLER_ARGS ... #else #define HANDLER_ARGS void #endif #define HANDLER(X) void interrupt X(HANDLER_ARGS) typedef struct { unsigned irq_num, vect_num, magic; char enabled; void interrupt (*ov)(HANDLER_ARGS); } vector_t; /***************************************************************************** *****************************************************************************/ int hook_irq(vector_t *vector, unsigned irq_num, void interrupt (*handler)(HANDLER_ARGS)) { if(irq_num >= 16) return -1; vector->irq_num = irq_num; vector->vect_num = g_irq_to_vect[irq_num]; vector->enabled = irq_enabled_at_8259(vector->irq_num); vector->ov = getvect(vector->vect_num); setvect(vector->vect_num, handler); enable_irq_at_8259(vector->irq_num); vector->magic = VECTOR_MAGIC; return 0; } /***************************************************************************** *****************************************************************************/ void unhook(vector_t *vector) { if(vector->magic != VECTOR_MAGIC) return; if(!vector->enabled) disable_irq_at_8259(vector->irq_num); setvect(vector->vect_num, vector->ov); } /********************************* DJGPP ************************************/ #elif defined(__DJGPP__) #include /* _farpeekw() */ #include /* _dos_ds, _my_cs() */ #include /* _go32_dpmi..., __dpmi... */ #include /* _crt0_startup_flags, _CRT0_FLAG_LOCK_MEMORY */ #define peekb(S,O) _farpeekb(_dos_ds, 16uL * (S) + (O)) #define pokeb(S,O,V) _farpokeb(_dos_ds, 16uL * (S) + (O), V) #define peekw(S,O) _farpeekw(_dos_ds, 16uL * (S) + (O)) #define pokew(S,O,V) _farpokew(_dos_ds, 16uL * (S) + (O), V) #define HANDLER(X) void X(void) typedef struct { unsigned irq_num, vect_num, magic; char enabled; _go32_dpmi_seginfo ov, nv; } vector_t; /* lock all memory, to prevent it being swapped or paged out */ int _crt0_startup_flags = _CRT0_FLAG_LOCK_MEMORY; /***************************************************************************** *****************************************************************************/ int hook_irq(vector_t *vector, unsigned irq_num, void (*handler)(void)) { if(irq_num >= 16) return -1; vector->irq_num = irq_num; vector->vect_num = g_irq_to_vect[irq_num]; vector->enabled = irq_enabled_at_8259(vector->irq_num); _go32_dpmi_get_protected_mode_interrupt_vector(vector->vect_num, &vector->ov); vector->nv.pm_selector = _my_cs(); vector->nv.pm_offset = (unsigned long)handler; _go32_dpmi_allocate_iret_wrapper(&vector->nv); _go32_dpmi_set_protected_mode_interrupt_vector(vector->vect_num, &vector->nv); enable_irq_at_8259(vector->irq_num); vector->magic = VECTOR_MAGIC; return 0; } /***************************************************************************** *****************************************************************************/ void unhook(vector_t *vector) { if(vector->magic != VECTOR_MAGIC) return; if(!vector->enabled) disable_irq_at_8259(vector->irq_num); _go32_dpmi_set_protected_mode_interrupt_vector(vector->vect_num, &vector->ov); _go32_dpmi_free_iret_wrapper(&vector->nv); } /******************************** WATCOM C **********************************/ #elif defined(__WATCOMC__) #include /* inp(), outp() */ #if defined(__386__) /* CauseWay DOS extender only */ #define peekb(S,O) *(unsigned char *)(16uL * (S) + (O)) #define pokeb(S,O,V) *(unsigned char *)(16uL * (S) + (O)) = (V) #define peekw(S,O) *(unsigned short *)(16uL * (S) + (O)) #define pokew(S,O,V) *(unsigned short *)(16uL * (S) + (O)) = (V) #else #define peekb(S,O) *(unsigned char far *)MK_FP(S,O) #define pokeb(S,O,V) *(unsigned char far *)MK_FP(S,O) = (V) #define peekw(S,O) *(unsigned short far *)MK_FP(S,O) #define pokew(S,O,V) *(unsigned short far *)MK_FP(S,O) = (V) #endif #define inportb(P) inp(P) #define outportb(P,V) outp(P,V) #define HANDLER(X) void __interrupt X(void) typedef struct { unsigned irq_num, vect_num, magic; char enabled; void __interrupt (*ov)(void); } vector_t; /***************************************************************************** *****************************************************************************/ int hook_irq(vector_t *vector, unsigned irq_num, void __interrupt (*handler)(void)) { if(irq_num >= 16) return -1; vector->irq_num = irq_num; vector->vect_num = g_irq_to_vect[irq_num]; vector->enabled = irq_enabled_at_8259(vector->irq_num); vector->ov = _dos_getvect(vector->vect_num); _dos_setvect(vector->vect_num, handler); enable_irq_at_8259(vector->irq_num); vector->magic = VECTOR_MAGIC; return 0; } /***************************************************************************** *****************************************************************************/ void unhook(vector_t *vector) { if(vector->magic != VECTOR_MAGIC) return; if(!vector->enabled) disable_irq_at_8259(vector->irq_num); _dos_setvect(vector->vect_num, vector->ov); } #else #error Not Turbo C, not DJGPP, not Watcom C. Sorry. #endif /* IRQ-to-vector-number mapping programmed into the 8259 chips by the BIOS: */ const unsigned g_irq_to_vect[] = { /* IRQ 0-7 */ 8, 9, 10, 11, 12, 13, 14, 15, /* IRQ 8-15 */ 112, 113, 114, 115, 116, 117, 118, 119 }; /***************************************************************************** *****************************************************************************/ int irq_enabled_at_8259(unsigned irq) { if(irq >= 16) return 0; if(irq >= 8) { if(inportb(0x21) & ~0x04) return 0; irq -= 8; irq = 1 << irq; return (inportb(0xA1) & irq) == 0; } irq = 1 << irq; return (inportb(0x21) & irq) == 0; } /***************************************************************************** *****************************************************************************/ void enable_irq_at_8259(unsigned irq) { if(irq >= 16) return; if(irq >= 8) { outportb(0x21, inportb(0x21) & ~0x04); irq -= 8; irq = 1 << irq; outportb(0xA1, inportb(0xA1) & ~irq); return; } irq = 1 << irq; outportb(0x21, inportb(0x21) & ~irq); } /***************************************************************************** *****************************************************************************/ void disable_irq_at_8259(unsigned irq) { if(irq >= 16) return; if(irq >= 8) { /* outportb(0x21, inportb(0x21) | 0x04); */ irq -= 8; irq = 1 << irq; outportb(0xA1, inportb(0xA1) | irq); return; } irq = 1 << irq; outportb(0x21, inportb(0x21) | irq); } /*---------------------------------------------------------------------------- Circular queues ----------------------------------------------------------------------------*/ typedef struct { unsigned char *buf; unsigned size, in_ptr, out_ptr; } queue_t; /***************************************************************************** *****************************************************************************/ static int inq(queue_t *q, unsigned char data) { unsigned temp; temp = q->in_ptr + 1; if(temp >= q->size) temp = 0; /* if in_ptr reaches out_ptr, the queue is full */ if(temp == q->out_ptr) return -1; q->buf[q->in_ptr] = data; q->in_ptr = temp; return 0; } /***************************************************************************** this function used to look like this: static int deq(queue_t *q, unsigned char *data) but Watcom C produces broken code for such a function. I don't know why. *****************************************************************************/ static int deq(queue_t *q) { int rv; /* if out_ptr reaches in_ptr, the queue is empty */ if(q->out_ptr == q->in_ptr) return -1; rv = q->buf[q->out_ptr]; q->out_ptr++; if(q->out_ptr >= q->size) q->out_ptr = 0; return rv; } /*---------------------------------------------------------------------------- Serial I/O using FIFO and interrupt-driven transmit & receive ----------------------------------------------------------------------------*/ /***************************************************************************** *****************************************************************************/ #include /* memset() */ #include /* kbhit(), getch() */ #include /* putchar(), printf() */ #include /* inportb(), outportb(), getvect(), setvect(), delay() */ typedef struct { queue_t rx, tx; /* number of: interrupts, receive interrupts, transmit interrupts */ unsigned int_count, rx_count, tx_count; /* number of: framing errors, parity errors, overrun errors */ unsigned ferr_count, perr_count, oerr_count; unsigned fifo_size; /* hardware resources */ unsigned io_adr, irq; vector_t vector; } serial_t; /***************************************************************************** Identifies serial chip type (8250, 16550, etc.) Returns FIFO size or 1 if no/defective FIFO. 16650+ detection is UNTESTED. *****************************************************************************/ static unsigned serial_id(unsigned io_adr) { unsigned i, j; /* set EFR = 0 (16650+ chips only) "The EFR can only be accessed after writing [0xBF] to the LCR..." For 16550/A, this code zeroes the FCR instead */ outportb(io_adr + 3, 0xBF); outportb(io_adr + 2, 0); /* set FCR = 1 to enable FIFOs (if any) */ outportb(io_adr + 3, 0); outportb(io_adr + 2, 0x01); /* enabling FIFOs should set bits b7 and b6 in Interrupt ID register */ i = inportb(io_adr + 2) & 0xC0; printf("Serial chip type: "); /* no FIFO -- check if scratch register exists */ if(i == 0) { outportb(io_adr + 7, 0xA5); outportb(0x80, 0xFF); /* prevent bus float returning 0xA5 */ i = inportb(io_adr + 7); outportb(io_adr + 7, 0x5A); outportb(0x80, 0xFF); /* prevent bus float returning 0x5A */ j = inportb(io_adr + 7); /* scratch register 7 exists */ if(i == 0xA5 && j == 0x5A) printf("8250A/16450 (no FIFO)\n"); else /* ALL 8250s (including 8250A) have serious problems... */ printf("ewww, 8250/8250B (no FIFO)\n"); } else if(i == 0x40) printf("UNKNOWN; assuming no FIFO\n"); else if(i == 0x80) printf("16550; defective FIFO disabled\n"); else if(i == 0xC0) { /* for 16650+, should be able to read 0 from EFR else will read 1 from FCR */ outportb(io_adr + 3, 0xBF); if(inportb(io_adr + 2) == 0) { printf("16650+ (32-byte FIFO)\n"); return 32; } else { printf("16550A (16-byte FIFO)\n"); return 16; } } return 1; } /***************************************************************************** Sets bit rate and number of data bits and optionally enables FIFO. Also enables all interrupts except transmit and clears dangling interrupts. *****************************************************************************/ static int serial_init(serial_t *port, unsigned long baud, unsigned bits, char enable_fifo) { unsigned divisor, io_adr, i; if(baud > 115200L || baud < 2) { printf("Bit rate (%lu) must be < 115200 and > 2\n", baud); return -1; } divisor = (unsigned)(115200L / baud); if(bits < 7 || bits > 8) { printf("Number of data bits (%u) must be 7 or 8\n", bits); return -1; } /* set bit rate */ io_adr = port->io_adr; outportb(io_adr + 3, 0x80); outportb(io_adr + 0, divisor); divisor >>= 8; outportb(io_adr + 1, divisor); /* set number of data bits This also sets no parity and 1 stop bit */ outportb(io_adr + 3, (bits == 7) ? 2 : 3); /* enable all interrupts EXCEPT transmit */ outportb(io_adr + 1, 0x0D); /* turn on FIFO, if any */ if(port->fifo_size > 1 && enable_fifo) outportb(io_adr + 2, 0xC7); else outportb(io_adr + 2, 0); /* loopback off, interrupt gate (Out2) on, handshaking lines (RTS, DTR) off */ outportb(io_adr + 4, 0x08); /* clear dangling interrupts */ while(1) { i = inportb(io_adr + 2); if(i & 0x01) break; (void)inportb(io_adr + 0); (void)inportb(io_adr + 5); (void)inportb(io_adr + 6); } return 0; } /***************************************************************************** *****************************************************************************/ static serial_t *g_port; static HANDLER(serial_irq) { /* count number of transmit and receive INTERRUPTS; not number of bytes */ char rx_int = 0, tx_int = 0; unsigned reason; int stat, c, i; serial_t *port; pokeb(0xB800, 0, peekb(0xB800, 0) + 1); port = g_port; port->int_count++; reason = inportb(port->io_adr + 2); /* careful: a loop inside an interrupt handler can cause the system to hang */ while((reason & 0x01) == 0) { reason >>= 1; reason &= 0x07; /* line status interrupt (highest priority) cleared by reading line status register (LSR; register 5) */ if(reason == 3) { stat = inportb(port->io_adr + 5); /* 0x80 == one or more errors in Rx FIFO 0x10 == received BREAK */ if(stat & 0x08) /* framing error */ port->ferr_count++; if(stat & 0x04) /* parity error */ port->perr_count++; if(stat & 0x02) /* overrun error */ port->oerr_count++; } /* receive data interrupt (2nd highest priority) cleared by reading receiver buffer register (register 0) */ else if(reason == 2) { /* count ONE receive interrupt */ if(rx_int == 0) { port->rx_count++; rx_int = 1; } (void)inq(&port->rx, inportb(port->io_adr + 0)); } /* character timeout interrupt (2nd highest priority; FIFO mode only) cleared by receive buffer register */ else if(reason == 6) { /* count ONE receive interrupt */ if(rx_int == 0) { port->rx_count++; rx_int = 1; } (void)inq(&port->rx, inportb(port->io_adr + 0)); } /* transmit holding register empty interrupt (3rd highest priority) cleared by reading the interrupt ID register (IIR; register 2) or by writing into transmit holding register (THR; register 0) */ else if(reason == 1) { /* queue up to port->fifo_size bytes */ for(i = port->fifo_size; i != 0; i--) { c = deq(&port->tx); if(c < 0) { /* empty transmit queue: disable further transmit interrupts */ c = inportb(port->io_adr + 1); if(c & 0x02) outportb(port->io_adr + 1, c & ~0x02); break; } /* count ONE transmit interrupt */ if(tx_int == 0) { port->tx_count++; tx_int = 1; } outportb(port->io_adr + 0, c); } } /* modem status interrupt (4th highest priority) cleared by reading the modem status register (MSR; register 6) */ else if(reason == 0) { (void)inportb(port->io_adr + 6); } reason = inportb(port->io_adr + 2); } outportb(0x20, 0x20); } /***************************************************************************** Serial mouse state machine. Format of serial mouse packet: byte 0: b6 =1 b5 =left button state (1=button pressed) b4 =right button state (1=button pressed) b3:b2 =b7:b6 of Y delta b1:b0 =b7:b6 of X delta byte 1: b6 =0 b5:b0 =b5:b0 of X delta byte 2: b6 =0 b5:b0 =b5:b0 of Y delta byte 3: (3-button mouse only. This byte is sent only when the center button is pressed, released, or held down while some other mouse event occurs.) b6 =0 b5 =center button state (1=button pressed) b4:b0 =0 *****************************************************************************/ static void serial_mouse(unsigned char byte) { static unsigned screen_wd, screen_ht; /* text-mode screen size */ static unsigned char state, buf[4]; static short old_x, old_y; /**/ short new_x, new_y, delta_x, delta_y; unsigned offset; /* get text screen size from BIOS */ if(screen_wd == 0) { screen_wd = peekw(0x40, 0x4A); screen_ht = peekb(0x40, 0x84) + 1; } /* byte with b6 set is first byte in new mouse packet */ if(byte & 0x40) state = 0; /* mouse packets larger than 4 bytes are invalid */ if(state >= 4) return; /* store byte and advance to next state */ buf[state] = byte & 0x3F; state++; /* completed packet? */ if(state == 3) { /* compute new mouse cursor position */ delta_x = buf[0] & 0x03; delta_x <<= 6; delta_x |= (buf[1] & 0x3F); /* sign-extend bytes to signed int/short */ delta_x = (signed char)delta_x; delta_y = buf[0] & 0x0C; delta_y <<= 4; delta_y |= (buf[2] & 0x3F); delta_y = (signed char)delta_y; new_x = old_x + delta_x; new_y = old_y + delta_y; /* clip mouse cursor position against screen size */ if(new_x < 0) new_x = 0; if((unsigned)new_x > screen_wd - 1) new_x = screen_wd - 1; if(new_y < 0) new_y = 0; if((unsigned)new_y > screen_ht - 1) new_y = screen_ht - 1; /* erase old cursor */ offset = (old_y * screen_wd + old_x) * 2 + 1; pokeb(0xB800, offset, peekb(0xB800, offset) ^ 0x60); /* draw new cursor */ offset = (new_y * screen_wd + new_x) * 2 + 1; pokeb(0xB800, offset, peekb(0xB800, offset) ^ 0x60); /* update old pos'n */ old_x = new_x; old_y = new_y; /* draw button state */ if(buf[0] & 0x20) /* left button */ pokeb(0xB800, 0x80, 'L'); else pokeb(0xB800, 0x80, ' '); pokeb(0xB800, 0x81, 0x60); if(buf[0] & 0x10) /* right button */ pokeb(0xB800, 0x88, 'R'); else pokeb(0xB800, 0x88, ' '); pokeb(0xB800, 0x89, 0x60); } /* 4-byte packet indicates 3-button mouse */ else if(state == 4) { if(buf[3] & 0x20) /* center button */ pokeb(0xB800, 0x84, 'C'); else pokeb(0xB800, 0x84, ' '); pokeb(0xB800, 0x85, 0x60); } } /***************************************************************************** *****************************************************************************/ #define BPERL 16 /* byte/line for dump */ static void dump(void *data_p, unsigned count) { unsigned char *data = (unsigned char *)data_p; unsigned byte1, byte2; while(count != 0) { for(byte1 = 0; byte1 < BPERL; byte1++) { if(count == 0) break; printf("%02X ", data[byte1]); count--; } printf("\t"); for(byte2 = 0; byte2 < byte1; byte2++) { if(data[byte2] < ' ') printf("."); else printf("%c", data[byte2]); } printf("\n"); data += BPERL; } } /***************************************************************************** s[n] name size req'd descr ---- ----------- ---- ----- --------- 0 Begin PnP 1 yes begin PnP ID == "(", either 0x28 or 0x08 1-2 PnP Rev 2 yes Plug and Play revision (e.g. 0x00,01) 3-5 EISA ID 3 yes EISA determined unique Mfr Identifier 6-9 Product ID 4 yes Mfr determined unique Product Identifier 10 Extend 1 no "\": either 0x5C or 0x3C. see note below. 11-18 Serial Number 8 no optional device serial number 19 Extend 1 no 20- Class Name <33 no Plug and Play Class Identifier (Annex C) ? Extend 1 no ? Driver ID <41 no Compatible Device IDs ? Extend 1 no ? User Name <41 no human-readable Product Description ? Checksum 2 [*] 8 bit arithmetic checksum of all characters from Begin PnP to End PnP inclusive, exclusive of the checksum bytes themselves, represented as a two character hexadecimal number ? End PnP 1 yes End PnP ID == ")", either 0x29 or 0x09 *****************************************************************************/ static int display_pnp_id(unsigned char *s, unsigned len) { /* s[0] = Begin byte = 0x28 or 0x08 */ for(; *s != '(' && *s != 0x08; s++) { if(len == 0) BAD: { printf("Bad PnP serial ID\n"); return -1; } len--; } if(len < 11) goto BAD; /* s[10] = End byte = 0x29 or 0x09, or Extend byte = 0x5C or 0x3C */ if(s[10] != ')' && s[10] != 0x09 && s[10] != '\\' && s[10] != 0x3C) goto BAD; printf("Serial PnP device: PnP rev %u.%u, ID '%c%c%c%c%c%c%c'\n", /* s[1] ... s[2] = PnP revision */ s[1], s[2], /* s[3] ... s[5] = EISA Vendor ID (e.g. 'LGI' for Logitech) */ '@' + (s[3] & 0x1F), '@' + (s[4] & 0x1F), '@' + (s[5] & 0x1F), /* s[6] ... [s9] = Product ID number */ '0' + (s[6] & 0x0F), '0' + (s[7] & 0x0F), '0' + (s[8] & 0x0F), '0' + (s[9] & 0x0F)); return 0; } /***************************************************************************** do this with ANSI? need these escapes: - Esc[s save current cursor position - Esc[7 save current cursor pos'n and attributes - Esc[u restore old cursor position - Esc[8 restore old cursor pos'n and attributes - Esc[??? set window size and home cursor in new window *****************************************************************************/ static void display_modem_status(unsigned io_adr) { static const char *signal_name[] = { "DCD", "RI", "DSR", "CTS", /* incoming */ "RTS", "DTR" /* outgoing */ }; /**/ unsigned status, csr_pos, i, mask, attrib; const char *s; i = 0; csr_pos = 40; /* incoming */ status = inp(io_adr + 6); for(mask = 0x80; mask > 0x08; mask >>= 1) { if(status & mask) attrib = 0x1F00; /* bright white (F) on blue (1) */ else attrib = 0x7800; /* gray (8) on white (7) */ for(s = signal_name[i]; *s != '\0'; s++) { pokew(0xB800, csr_pos, attrib | *s); csr_pos += 2; } csr_pos += 2; i++; } csr_pos += 8; /* outgoing */ status = inp(io_adr + 4); for(mask = 0x02; mask != 0; mask >>= 1) { if(status & mask) attrib = 0x1F00; /* bright white (F) on blue (1) */ else attrib = 0x7800; /* gray (8) on white (7) */ for(s = signal_name[i]; *s != '\0'; s++) { pokew(0xB800, csr_pos, attrib | *s); csr_pos += 2; } csr_pos += 2; i++; } } /***************************************************************************** *****************************************************************************/ #define MAX_ID 32 #define BUF_SIZE 256 int main(int arg_c, char *arg_v[]) { /* xxx - allocate these from the heap? */ static unsigned char rx_buf[BUF_SIZE], tx_buf[BUF_SIZE]; /**/ unsigned char buf[MAX_ID]; int num_ports, i, j, k; serial_t port; /* there are up to 4 COM port I/O addresses stored in the BIOS data area, at address 400h */ num_ports = 0; for(i = 0; i < 4; i++) { if(peekw(0x40, 0 + 2 * i) == 0) break; num_ports++; } /* check args */ if(arg_c != 2) { printf("Serial mouse driver/demo. Specify a COM port 1-%u\n", num_ports); return 1; } sscanf(arg_v[1], "%u", &i); if(i < 1 || i > num_ports) goto NONE; /* init serial_t struct */ memset(&port, 0, sizeof(port)); port.rx.buf = rx_buf; port.rx.size = BUF_SIZE; port.tx.buf = tx_buf; port.tx.size = BUF_SIZE; port.io_adr = peekw(0x40, 0 + 2 * (i - 1)); if(port.io_adr == 0) NONE: { printf("Sorry, no COM %u on this PC\n", i); return 1; } if(i & 0x01) port.irq = 4; /* COM1 or COM3 */ else port.irq = 3; /* COM2 or COM4 */ /* detect serial chip type and FIFO size */ port.fifo_size = serial_id(port.io_adr); printf("I/O=0x%03X, IRQ=%u, BUF_SIZE=%u\n", port.io_adr, port.irq, BUF_SIZE); g_port = &port; #if defined(MOUSE) /* set 1200 baud, 7N1, FIFO off */ if(serial_init(&port, 1200, 7, 0) != 0) #else /* set 115200 baud, 8N1, FIFO on */ if(serial_init(&port, 115200L, 8, 1) != 0) #endif { printf("Error setting serial port bit rate\n"); return 2; } #if defined(MOUSE) /* serial_init() turned off handshaking lines, cutting power to the mouse. Wait 100 ms, then turn power back on */ delay(100); outportb(port.io_adr + 4, 0x0B); #endif /* hook serial hardware interrupt */ if(hook_irq(&port.vector, port.irq, serial_irq) != 0) { printf("Error hooking IRQ %u\n", port.irq); return 2; } #if defined(MOUSE) /* collect and analyze mouse ID */ i = 0; for(j = 100; j != 0; j--) { k = deq(&port.rx); if(k < 0) { delay(10); continue; } j = 100; /* reset timeout */ buf[i] = k; i++; if(i >= MAX_ID) break; } if(i == 0) { printf("No serial mouse detected\n"); goto END; } /* 'M' */ /*else*/ if(i == 1 && buf[0] == 'M') printf("2-button mouse detected\n"); /* 'M3' */ else if(i == 2 && buf[0] == 'M' && buf[1] == '3') printf("3-button mouse detected\n"); /* PnP mouse */ else if(i >= 13) { if(display_pnp_id(buf, i) != 0) goto END; } /* WTF? */ else { printf("Unknown mouse type; assuming 2-button mouse. " "Dump of ID bytes:\n"); dump(buf, i); } #endif /* main loop */ printf("Press Esc to quit\n"); while(1) { #if !defined(MOUSE) display_modem_status(port.io_adr); #endif i = deq(&port.rx); if(i >= 0) #if defined(MOUSE) serial_mouse(i); #else putch(i); #endif if(!kbhit()) continue; i = getch(); if(i == 0) i = 0x100 | getch(); if(i == 27) break; /* F1 toggles RTS */ if(i == 0x13B) { outportb(port.io_adr + 4, inportb(port.io_adr + 4) ^ 0x02); continue; } /* F2 toggles DTR */ if(i == 0x13C) { outportb(port.io_adr + 4, inportb(port.io_adr + 4) ^ 0x01); continue; } inq(&port.tx, i); /* kick-start transmit by (re)enabling transmit interrupt */ outportb(port.io_adr + 1, inportb(port.io_adr + 1) | 0x02); } END: /* remove interrupt handler */ unhook(&port.vector); /* display statistics */ printf("Total interrupts : %5u\t", port.int_count); printf("Receive interrupts : %5u\n", port.rx_count); printf("Transmit interrupts: %5u\t", port.tx_count); printf("Framing errors : %5u\n", port.ferr_count); printf("Parity errors : %5u\t", port.perr_count); printf("Overrun errors : %5u\n", port.oerr_count); printf("\n\n"); return 0; }