]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/doscmd/int14.c
This commit was generated by cvs2svn to compensate for changes in r74481,
[FreeBSD/FreeBSD.git] / usr.bin / doscmd / int14.c
1 /*
2  * Copyright (c) 1992, 1993, 1996
3  *      Berkeley Software Design, Inc.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley Software
6  * Design, Inc. by Mark Linoman.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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
19  *      Design, Inc.
20  *
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
31  * SUCH DAMAGE.
32  *
33  *      BSDI int14.c,v 2.2 1996/04/08 19:32:45 bostic Exp
34  *
35  * $FreeBSD$
36  */
37
38 #include "doscmd.h"
39 #include <sys/ioctl.h>
40 #include <termios.h>
41 #include "com.h"
42
43 struct com_data_struct com_data[N_COMS_MAX];
44
45 struct queue *create_queue() { return(0); }
46 int get_char_q() {}
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() {}
52
53 void
54 int14(regcontext_t *REGS)
55 {
56     int reg_num;
57     struct com_data_struct *cdsp;
58     int i;
59     int nbytes;
60     char c;
61
62     debug (D_PORT, "int14: dl = 0x%02X, al = 0x%02X.\n", R_DL, R_AL);
63     if (R_DL >= N_COMS_MAX) {
64         if (vflag)
65             dump_regs(REGS);
66         fatal ("int14: illegal com port COM%d", R_DL + 1);
67     }
68     cdsp = &(com_data[R_DL]);
69
70     switch (R_AH) {
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;
75         R_AL = 0;
76 #endif  0
77         break;
78
79     case 0x01:  /* Write Character */
80         errno = 0;
81         c = R_AL;
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));
85         if (nbytes == 1) {
86                 R_AH = LS_X_SHFT_E | LS_X_HOLD_E;
87                 R_AL = 0;
88         } else {
89                 debug(D_PORT, "int14: lost output character 0x%02x\n",
90                         R_AL);
91                 R_AH = LS_SW_TIME_OUT;
92                 R_AL = 0;
93         }
94         break;
95
96     case 0x02:  /* Read Character */
97         errno = 0;
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) : "");
102         if (nbytes == 1) {
103                 R_AH = LS_X_SHFT_E | LS_X_HOLD_E;
104                 R_AL = c;
105         } else {
106                 R_AH = LS_SW_TIME_OUT;
107                 R_AL = 0x60;
108         }
109         break;
110
111     case 0x03:  /* Status Request */
112         R_AX = (LS_X_SHFT_E | LS_X_HOLD_E) << 8;
113         break;
114
115     case 0x04:  /* Extended Initialization */
116         R_AX = (LS_SW_TIME_OUT) << 8;
117         break;
118
119     case 0x05:  /* Modem Control Register operations */
120         switch (R_AH) {
121         case 0x00:      /* Read Modem Control Register */
122                 R_AX = (LS_SW_TIME_OUT) << 8;
123                 break;
124
125         case 0x01:      /* Write Modem Control Register */
126                 R_AX = (LS_SW_TIME_OUT) << 8;
127                 break;
128
129         default:
130                 unknown_int3(0x14, 0x05, R_AL, REGS);
131                 break;
132         }
133         break;
134     default:
135         unknown_int2(0x14, R_AH, REGS);
136         break;
137     }
138 }
139
140
141 /* called when doscmd initializes a single line */
142 void
143 com_set_line(struct com_data_struct *cdsp, unsigned char port, unsigned char param)
144 {
145     struct termios tty;
146     struct stat stat_buf;
147     int mode = 0;               /* read|write */
148     int speed;
149     int reg_num;
150     int ret_val;
151
152     debug (D_PORT, "com_set_line: cdsp = 0x%08X, port = 0x%04x,"
153                    "param = 0x%04X.\n", cdsp, port, param);
154     if (cdsp->fd > 0) {
155             debug (D_PORT, "Re-initialize serial port com%d\n", port);
156             (void)close(cdsp->fd);
157     } else {
158             debug (D_PORT, "Initialize serial port com%d\n", port);
159     }
160
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)) {
164
165         debug (D_PORT,
166                 "Could not initialize serial port com%d on path '%s'\n",
167                         port, cdsp->path);
168         return;
169     }
170
171     cdsp->flags = 0x00;
172     cdsp->last_char_read = 0x00;
173 #if 0
174     if ((param & PARITY_EVEN) == PARITY_NONE)
175             tty.c_iflag = IGNBRK | IGNPAR | IXON | IXOFF /* | IXANY */;
176     else
177             tty.c_iflag = IGNBRK | IXON | IXOFF /* | IXANY */;
178     tty.c_oflag = 0;           
179     tty.c_lflag = 0;
180     tty.c_cc[VTIME] = 0; 
181     tty.c_cc[VMIN] = 1;
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)
185             tty.c_cflag |= CS8;
186     else
187             tty.c_cflag |= CS7;
188     if ((param & STOPBIT_2) == STOPBIT_2)
189             tty.c_cflag |= CSTOPB;
190     switch (param & PARITY_EVEN) {
191             case (PARITY_ODD):
192                     tty.c_cflag |= (PARENB | PARODD);
193                     break;
194             case (PARITY_EVEN):
195                     tty.c_cflag |= PARENB;
196                     break;
197             case (PARITY_NONE):
198             default:
199                     break;
200     }
201     switch (param & BITRATE_9600) {
202     case (BITRATE_110):
203         speed = B110;
204         break;
205     case (BITRATE_150):
206         speed = B150;
207         break;
208     case (BITRATE_300):
209         speed = B300;
210         break;
211     case (BITRATE_600):
212         speed = B600;
213         break;
214     case (BITRATE_1200):
215         speed = B1200;
216         break;
217     case (BITRATE_2400):
218         speed = B2400;
219         break;
220     case (BITRATE_4800):
221         speed = B4800;
222         break;
223     case (BITRATE_9600):
224         speed = B9600;
225         break;
226     }
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);
229     errno = 0;
230     ret_val = cfsetispeed(&tty, speed);
231     debug (D_PORT, "com_set_line: cfsetispeed returned 0x%X.\n", ret_val);
232     errno = 0;
233     ret_val = cfsetospeed(&tty, speed);
234     debug (D_PORT, "com_set_line: cfsetospeed returned 0x%X.\n", ret_val);
235     errno = 0;
236     ret_val = tcsetattr(cdsp->fd, 0, &tty);
237     debug (D_PORT, "com_set_line: tcsetattr returned 0x%X.\n", ret_val);
238
239     errno = 0;
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);
243     errno = 0;
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);
247 #endif
248     for (reg_num = 0; reg_num < N_OF_COM_REGS; reg_num++) {
249         define_input_port_handler(cdsp->addr + reg_num, 
250                                   com_port_in);
251         define_output_port_handler(cdsp->addr + reg_num,
252                                    com_port_out);
253     }
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);
257 }
258
259
260 /* called when config.c initializes a single line */
261 void
262 init_com(int port, char *path, int addr, unsigned char irq)
263 {
264     struct com_data_struct *cdsp;
265         
266     debug (D_PORT, "init_com: port = 0x%04x, addr = 0x%04X, irq = %d.\n",
267            port, addr, irq);
268     cdsp = &(com_data[port]);
269     cdsp->path = path;  /* XXX DEBUG strcpy? */
270     cdsp->addr = addr;
271     cdsp->irq = irq;
272     cdsp->fd = -1;
273     com_set_line(cdsp, port + 1, TXLEN_8BITS | BITRATE_9600);
274 }
275
276
277 /* called when DOS wants to read directly from a physical port */
278 unsigned char
279 com_port_in(int port)
280 {
281     struct com_data_struct *cdsp;
282     unsigned char rs;
283     unsigned char i;
284     int nbytes;
285
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]);
290             break;
291         }
292     }
293     if (i == N_COMS_MAX) {
294         debug (D_PORT, "com port 0x%04x not found\n", port);
295         return 0xff;
296     }
297
298     switch (port - cdsp->addr) {
299         /* 0x03F8 - (receive buffer) or (divisor latch LO) */
300     case 0:
301         if (cdsp->line_ctrl & LC_DIV_ACC)
302             rs = cdsp->div_latch[DIV_LATCH_LOW];
303         else {
304 #if     0
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) {
310                     debug(D_PORT,
311                           "com_port_in: setting irq %d because bytes yet to be read.\n",
312                           cdsp->irq);
313                     set_irq_request(cdsp->irq);
314                 }
315             } else
316 #else
317                 errno = 0;
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);
321             if (nbytes != 1)
322 #endif
323                 rs = cdsp->last_char_read;
324         }
325         break;
326
327         /* 0x03F9 - (interrupt enable) or (divisor latch HI) */
328     case 1:    
329         if (cdsp->line_ctrl & LC_DIV_ACC)
330             rs = cdsp->div_latch[DIV_LATCH_HIGH];
331         else
332             rs = cdsp->int_enable;
333
334         /* 0x03FA - interrupt identification register */
335     case 2:
336         /* rs = cdsp->int_id;   * XXX DEBUG not initialized */
337         rs = 0;
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)
342             rs |= II_FIFOS_EN;
343         break;
344
345         /* 0x03FB - line control register */
346     case 3:
347         rs = cdsp->line_ctrl;
348         break;
349
350         /* 0x03FC - modem control register */
351     case 4:
352         rs = cdsp->modem_ctrl;
353         break;
354
355         /* 0x03FD - line status register */
356     case 5:
357         rs = LS_X_SHFT_E | LS_X_HOLD_E;
358         /* if (queue_not_empty(cdsp->com_queue)) */
359         ioctl(cdsp->fd, FIONREAD, &nbytes);
360         if (nbytes > 0);
361         rs |= LS_RCV_DATA_RD;
362         break;
363
364         /* 0x03FE - modem status register */
365     case 6:
366         rs = cdsp->modem_stat | MS_DCD | MS_DSR | MS_CTS;
367         break;
368
369         /* 0x03FF - spare register */
370     case 7:
371         rs = cdsp->uart_spare;
372         break;
373
374     default:
375         debug(D_PORT, "com_port_in: illegal port index 0x%04x - 0x%04x\n",
376               port, cdsp->addr);
377         break;
378     }
379     return rs;
380 }
381
382
383 /* called when DOS wants to write directly to a physical port */
384 void
385 com_port_out(int port, unsigned char val)
386 {
387     struct com_data_struct *cdsp;
388     int nbytes;
389     int i;
390
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]);
395             break;
396         }
397     }
398     if (i == N_COMS_MAX) {
399         debug (D_PORT, "com port 0x%04x not found\n", port);
400         return;
401     }
402
403     switch (port - cdsp->addr) {
404         /* 0x03F8 - (transmit buffer) or (divisor latch LO) */
405     case 0:
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);
410         } else {
411             errno = 0;
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);
415             if (nbytes != 1)
416                 debug(D_PORT,
417                       "int14: lost output character 0x%02x\n",
418                       val);
419         }
420         break;
421
422         /* 0x03F9 - (interrupt enable) or (divisor latch HI) */
423     case 1:
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);
428         } else {
429             cdsp->int_enable = val;
430             if ((val & IE_RCV_DATA) == 0) {
431                 reset_irq_request(cdsp->irq);
432             } else {
433                 if (queue_not_empty(cdsp->com_queue)) {
434                     set_irq_request(cdsp->irq);
435                 }
436             }
437         }
438         break;
439         
440         /* 0x03FA - FIFO control register */
441     case 2:
442         cdsp->fifo_ctrl = val;
443         break;
444         
445         /* 0x03FB - line control register */
446     case 3:
447         cdsp->line_ctrl = val;
448         break;
449
450         /* 0x03FC - modem control register */
451     case 4:
452         cdsp->modem_ctrl = val;
453         break;
454
455         /* 0x03FD - line status register */
456     case 5:
457         cdsp->line_stat = val;
458         break;
459
460         /* 0x03FE - modem status register */
461     case 6:
462         cdsp->modem_stat = val;
463         break;
464
465         /* 0x03FF - spare register */
466     case 7:
467         cdsp->uart_spare = val;
468         break;
469
470     default:
471         debug(D_PORT, "com_port_out: illegal port index 0x%04x - 0x%04x\n",
472               port, cdsp->addr);
473         break;
474     }
475 }
476
477 #if     0
478 /*
479  * called when BSD has bytes ready (as discovered via select) for DOS
480  */
481 static void do_com_input(int fd)
482 {
483     struct com_data_struct *cdsp;
484     unsigned char buffer[BUFSIZE];
485     int i, nbytes;
486     
487     dp = search_com_device_by_fd(fd);
488     if (dp == NULL)
489         return;
490     do {
491         nbytes = read(cdsp->fd, buffer, BUFSIZE);
492         if (nbytes > 0) {
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) {
498                     debug(D_PORT, "\n");
499                     debug(D_PORT, "do_com_input: setting irq %d because %d bytes read.\n",
500                           dp->irq, nbytes);
501                     debug(D_PORT, "do_com_input: ");
502                     set_irq_request(dp->irq);
503                 }
504                 debug(D_PORT, "%02x ", buffer[i]);
505             }
506             debug(D_PORT, "\n");
507         }
508     } while (nbytes == BUFSIZE);
509 }
510 #endif  0