2 * Copyright (c) 1992, 1993, 1996
3 * Berkeley Software Design, Inc. All rights reserved.
5 * This code is derived from software contributed to Berkeley Software
6 * Design, Inc. by Mark Linoman.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Berkeley Software
21 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * BSDI int14.c,v 2.2 1996/04/08 19:32:45 bostic Exp
35 * $Id: int14.c,v 1.3 1996/09/22 15:42:53 miff Exp $
39 #include <sys/ioctl.h>
43 struct com_data_struct com_data[N_COMS_MAX];
45 struct queue *create_queue() { return(0); }
47 int queue_not_empty() {}
48 int reset_irq_request() {}
49 int set_irq_request() {}
50 int test_irq_request() {}
51 int write_div_latches() {}
54 int14(regcontext_t *REGS)
57 struct com_data_struct *cdsp;
62 debug (D_PORT, "int14: dl = 0x%02X, al = 0x%02X.\n", R_DL, R_AL);
63 if (R_DL >= N_COMS_MAX) {
66 fatal ("int14: illegal com port COM%d", R_DL + 1);
68 cdsp = &(com_data[R_DL]);
71 case 0x00: /* Initialize Serial Port */
72 #if 0 /* hold off: try to defeat stupid DOS defaults */
73 com_set_line(cdsp, R_DL + 1, R_AL);
74 R_AH = LS_X_SHFT_E | LS_X_HOLD_E;
79 case 0x01: /* Write Character */
82 nbytes = write(cdsp->fd, &c, 1);
83 debug (D_PORT, "write of 0x%02x to fd %d on '%s' returned %d %s\n",
84 R_AL, cdsp->fd, cdsp->path, nbytes, strerror(errno));
86 R_AH = LS_X_SHFT_E | LS_X_HOLD_E;
89 debug(D_PORT, "int14: lost output character 0x%02x\n",
91 R_AH = LS_SW_TIME_OUT;
96 case 0x02: /* Read Character */
98 nbytes = read(cdsp->fd, &c, 1);
99 debug (D_PORT, "read of fd %d on '%s' returned %d byte 0x%02x %s\n",
100 cdsp->fd, cdsp->path, nbytes, c,
101 errno ? strerror(errno) : "");
103 R_AH = LS_X_SHFT_E | LS_X_HOLD_E;
106 R_AH = LS_SW_TIME_OUT;
111 case 0x03: /* Status Request */
112 R_AX = (LS_X_SHFT_E | LS_X_HOLD_E) << 8;
115 case 0x04: /* Extended Initialization */
116 R_AX = (LS_SW_TIME_OUT) << 8;
119 case 0x05: /* Modem Control Register operations */
121 case 0x00: /* Read Modem Control Register */
122 R_AX = (LS_SW_TIME_OUT) << 8;
125 case 0x01: /* Write Modem Control Register */
126 R_AX = (LS_SW_TIME_OUT) << 8;
130 unknown_int3(0x14, 0x05, R_AL, REGS);
135 unknown_int2(0x14, R_AH, REGS);
141 /* called when doscmd initializes a single line */
143 com_set_line(struct com_data_struct *cdsp, unsigned char port, unsigned char param)
146 struct stat stat_buf;
147 int mode = 0; /* read|write */
152 debug (D_PORT, "com_set_line: cdsp = 0x%08X, port = 0x%04x,"
153 "param = 0x%04X.\n", cdsp, port, param);
155 debug (D_PORT, "Re-initialize serial port com%d\n", port);
156 (void)close(cdsp->fd);
158 debug (D_PORT, "Initialize serial port com%d\n", port);
161 stat(cdsp->path, &stat_buf);
162 if (!S_ISCHR(stat_buf.st_mode) ||
163 ((cdsp->fd = open(cdsp->path, O_RDWR | O_NONBLOCK, 0666)) == -1)) {
166 "Could not initialize serial port com%d on path '%s'\n",
172 cdsp->last_char_read = 0x00;
174 if ((param & PARITY_EVEN) == PARITY_NONE)
175 tty.c_iflag = IGNBRK | IGNPAR | IXON | IXOFF /* | IXANY */;
177 tty.c_iflag = IGNBRK | IXON | IXOFF /* | IXANY */;
182 tty.c_cflag = CREAD | CLOCAL | HUPCL;
183 /* MCL WHY CLOCAL ??????; but, gets errno EIO on writes, else */
184 if ((param & TXLEN_8BITS) == TXLEN_8BITS)
188 if ((param & STOPBIT_2) == STOPBIT_2)
189 tty.c_cflag |= CSTOPB;
190 switch (param & PARITY_EVEN) {
192 tty.c_cflag |= (PARENB | PARODD);
195 tty.c_cflag |= PARENB;
201 switch (param & BITRATE_9600) {
227 debug (D_PORT, "com_set_line: going with cflag 0x%X iflag 0x%X speed %d.\n",
228 tty.c_cflag, tty.c_iflag, speed);
230 ret_val = cfsetispeed(&tty, speed);
231 debug (D_PORT, "com_set_line: cfsetispeed returned 0x%X.\n", ret_val);
233 ret_val = cfsetospeed(&tty, speed);
234 debug (D_PORT, "com_set_line: cfsetospeed returned 0x%X.\n", ret_val);
236 ret_val = tcsetattr(cdsp->fd, 0, &tty);
237 debug (D_PORT, "com_set_line: tcsetattr returned 0x%X.\n", ret_val);
240 ret_val = fcntl(cdsp->fd, F_SETFL, O_NDELAY);
241 debug (D_PORT, "fcntl of 0x%X, 0x%X to fd %d returned %d errno %d\n",
242 F_SETFL, O_NDELAY, cdsp->fd, ret_val, errno);
244 ret_val = ioctl(cdsp->fd, TIOCFLUSH, &mode);
245 debug (D_PORT, "ioctl of 0x%02x to fd %d on 0x%X returned %d errno %d\n",
246 TIOCFLUSH, cdsp->fd, mode, ret_val, errno);
248 for (reg_num = 0; reg_num < N_OF_COM_REGS; reg_num++) {
249 define_input_port_handler(cdsp->addr + reg_num,
251 define_output_port_handler(cdsp->addr + reg_num,
254 cdsp->com_queue = create_queue(cdsp->irq);
255 debug(D_PORT, "com%d: attached '%s' at addr 0x%04x irq %d\n",
256 port, cdsp->path, cdsp->addr, cdsp->irq);
260 /* called when config.c initializes a single line */
262 init_com(int port, char *path, int addr, unsigned char irq)
264 struct com_data_struct *cdsp;
266 debug (D_PORT, "init_com: port = 0x%04x, addr = 0x%04X, irq = %d.\n",
268 cdsp = &(com_data[port]);
269 cdsp->path = path; /* XXX DEBUG strcpy? */
273 com_set_line(cdsp, port + 1, TXLEN_8BITS | BITRATE_9600);
277 /* called when DOS wants to read directly from a physical port */
279 com_port_in(int port)
281 struct com_data_struct *cdsp;
286 /* search for a valid COM ???or MOUSE??? port */
287 for (i = 0; i < N_COMS_MAX; i++) {
288 if (com_data[i].addr == ((unsigned short)port & 0xfff8)) {
289 cdsp = &(com_data[i]);
293 if (i == N_COMS_MAX) {
294 debug (D_PORT, "com port 0x%04x not found\n", port);
298 switch (port - cdsp->addr) {
299 /* 0x03F8 - (receive buffer) or (divisor latch LO) */
301 if (cdsp->line_ctrl & LC_DIV_ACC)
302 rs = cdsp->div_latch[DIV_LATCH_LOW];
305 if (queue_not_empty(cdsp->com_queue)) {
306 rs = get_char_q(cdsp->com_queue);
307 cdsp->last_char_read = rs;
308 if (queue_not_empty(cdsp->com_queue) &&
309 (cdsp->int_enable & IE_RCV_DATA) != 0) {
311 "com_port_in: setting irq %d because bytes yet to be read.\n",
313 set_irq_request(cdsp->irq);
318 nbytes = read(cdsp->fd, &rs, 1);
319 debug (D_PORT, "read of fd %d on '%s' returned %d byte 0x%02x errno %d\n",
320 cdsp->fd, cdsp->path, nbytes, rs, errno);
323 rs = cdsp->last_char_read;
327 /* 0x03F9 - (interrupt enable) or (divisor latch HI) */
329 if (cdsp->line_ctrl & LC_DIV_ACC)
330 rs = cdsp->div_latch[DIV_LATCH_HIGH];
332 rs = cdsp->int_enable;
334 /* 0x03FA - interrupt identification register */
336 /* rs = cdsp->int_id; * XXX DEBUG not initialized */
338 if ((queue_not_empty(cdsp->com_queue))
339 && (test_irq_request(cdsp->irq) != 0))
340 rs |= II_PEND_INT | II_RCV_DATA;
341 if ((cdsp->fifo_ctrl & FC_FIFO_EN) == FC_FIFO_EN)
345 /* 0x03FB - line control register */
347 rs = cdsp->line_ctrl;
350 /* 0x03FC - modem control register */
352 rs = cdsp->modem_ctrl;
355 /* 0x03FD - line status register */
357 rs = LS_X_SHFT_E | LS_X_HOLD_E;
358 /* if (queue_not_empty(cdsp->com_queue)) */
359 ioctl(cdsp->fd, FIONREAD, &nbytes);
361 rs |= LS_RCV_DATA_RD;
364 /* 0x03FE - modem status register */
366 rs = cdsp->modem_stat | MS_DCD | MS_DSR | MS_CTS;
369 /* 0x03FF - spare register */
371 rs = cdsp->uart_spare;
375 debug(D_PORT, "com_port_in: illegal port index 0x%04x - 0x%04x\n",
383 /* called when DOS wants to write directly to a physical port */
385 com_port_out(int port, unsigned char val)
387 struct com_data_struct *cdsp;
391 /* search for a valid COM ???or MOUSE??? port */
392 for (i = 0; i < N_COMS_MAX; i++) {
393 if (com_data[i].addr == ((unsigned short)port & 0xfff8)) {
394 cdsp = &(com_data[i]);
398 if (i == N_COMS_MAX) {
399 debug (D_PORT, "com port 0x%04x not found\n", port);
403 switch (port - cdsp->addr) {
404 /* 0x03F8 - (transmit buffer) or (divisor latch LO) */
406 if (cdsp->line_ctrl & LC_DIV_ACC) {
407 cdsp->div_latch[DIV_LATCH_LOW] = val;
408 cdsp->flags |= DIV_LATCH_LOW_WRITTEN;
409 write_div_latches(cdsp);
412 nbytes = write(cdsp->fd, val, 1);
413 debug (D_PORT, "write of 0x%02x to fd %d on '%s' returned %d errno %d\n",
414 val, cdsp->fd, cdsp->path, nbytes, errno);
417 "int14: lost output character 0x%02x\n",
422 /* 0x03F9 - (interrupt enable) or (divisor latch HI) */
424 if (cdsp->line_ctrl & LC_DIV_ACC) {
425 cdsp->div_latch[DIV_LATCH_HIGH] = val;
426 cdsp->flags |= DIV_LATCH_HIGH_WRITTEN;
427 write_div_latches(cdsp);
429 cdsp->int_enable = val;
430 if ((val & IE_RCV_DATA) == 0) {
431 reset_irq_request(cdsp->irq);
433 if (queue_not_empty(cdsp->com_queue)) {
434 set_irq_request(cdsp->irq);
440 /* 0x03FA - FIFO control register */
442 cdsp->fifo_ctrl = val;
445 /* 0x03FB - line control register */
447 cdsp->line_ctrl = val;
450 /* 0x03FC - modem control register */
452 cdsp->modem_ctrl = val;
455 /* 0x03FD - line status register */
457 cdsp->line_stat = val;
460 /* 0x03FE - modem status register */
462 cdsp->modem_stat = val;
465 /* 0x03FF - spare register */
467 cdsp->uart_spare = val;
471 debug(D_PORT, "com_port_out: illegal port index 0x%04x - 0x%04x\n",
479 * called when BSD has bytes ready (as discovered via select) for DOS
481 static void do_com_input(int fd)
483 struct com_data_struct *cdsp;
484 unsigned char buffer[BUFSIZE];
487 dp = search_com_device_by_fd(fd);
491 nbytes = read(cdsp->fd, buffer, BUFSIZE);
493 debug(D_PORT, "do_com_input: read %d bytes from fd %d (aka %d): ",
494 nbytes, fd, cdsp->fd);
495 for (i = 0; i < nbytes; i++) {
496 put_char_q(cdsp->com_queue, buffer[i]);
497 if (cdsp->int_enable & IE_RCV_DATA) {
499 debug(D_PORT, "do_com_input: setting irq %d because %d bytes read.\n",
501 debug(D_PORT, "do_com_input: ");
502 set_irq_request(dp->irq);
504 debug(D_PORT, "%02x ", buffer[i]);
508 } while (nbytes == BUFSIZE);