FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/sio.c
1 /*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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 * from: @(#)com.c 7.5 (Berkeley) 5/16/91
34 * $FreeBSD: src/sys/i386/isa/sio.c,v 1.147.2.17 1999/09/05 08:13:30 peter Exp $
35 */
36
37 #include "opt_comconsole.h"
38 #include "opt_ddb.h"
39 #include "opt_sio.h"
40 #include "sio.h"
41 #include "pnp.h"
42
43 #ifndef EXTRA_SIO
44 #if NPNP > 0
45 #define EXTRA_SIO 2
46 #else
47 #define EXTRA_SIO 0
48 #endif
49 #endif
50
51 #define NSIOTOT (NSIO + EXTRA_SIO)
52
53 /*
54 * Serial driver, based on 386BSD-0.1 com driver.
55 * Mostly rewritten to use pseudo-DMA.
56 * Works for National Semiconductor NS8250-NS16550AF UARTs.
57 * COM driver, based on HP dca driver.
58 *
59 * Changes for PC-Card integration:
60 * - Added PC-Card driver table and handlers
61 */
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/reboot.h>
65 #include <sys/ioctl.h>
66 #include <sys/tty.h>
67 #include <sys/proc.h>
68 #include <sys/conf.h>
69 #include <sys/dkstat.h>
70 #include <sys/file.h>
71 #include <sys/uio.h>
72 #include <sys/kernel.h>
73 #include <sys/malloc.h>
74 #include <sys/syslog.h>
75 #ifdef DEVFS
76 #include <sys/devfsext.h>
77 #endif
78
79 #include <machine/clock.h>
80
81 #include <i386/isa/isa.h>
82 #include <i386/isa/isa_device.h>
83 #include <i386/isa/sioreg.h>
84
85 #ifdef COM_ESP
86 #include <i386/isa/ic/esp.h>
87 #endif
88 #include <i386/isa/ic/ns16550.h>
89
90 #include "card.h"
91 #if NCARD > 0
92 #include <pccard/cardinfo.h>
93 #include <pccard/driver.h>
94 #include <pccard/slot.h>
95 #endif
96
97 #if NPNP > 0
98 #include <i386/isa/pnp.h>
99 #endif
100
101 #define LOTS_OF_EVENTS 64 /* helps separate urgent events from input */
102 #define RB_I_HIGH_WATER (TTYHOG - 2 * RS_IBUFSIZE)
103 #define RS_IBUFSIZE 256
104
105 #define CALLOUT_MASK 0x80
106 #define CONTROL_MASK 0x60
107 #define CONTROL_INIT_STATE 0x20
108 #define CONTROL_LOCK_STATE 0x40
109 #define DEV_TO_UNIT(dev) (MINOR_TO_UNIT(minor(dev)))
110 #define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
111 #define MINOR_TO_UNIT(mynor) ((mynor) & ~MINOR_MAGIC_MASK)
112
113 #ifdef COM_MULTIPORT
114 /* checks in flags for multiport and which is multiport "master chip"
115 * for a given card
116 */
117 #define COM_ISMULTIPORT(dev) ((dev)->id_flags & 0x01)
118 #define COM_MPMASTER(dev) (((dev)->id_flags >> 8) & 0x0ff)
119 #define COM_NOTAST4(dev) ((dev)->id_flags & 0x04)
120 #endif /* COM_MULTIPORT */
121
122 #define COM_LOSESOUTINTS(dev) ((dev)->id_flags & 0x08)
123 #define COM_NOFIFO(dev) ((dev)->id_flags & 0x02)
124
125 #define com_scr 7 /* scratch register for 16450-16550 (R/W) */
126
127 /*
128 * Input buffer watermarks.
129 * The external device is asked to stop sending when the buffer exactly reaches
130 * high water, or when the high level requests it.
131 * The high level is notified immediately (rather than at a later clock tick)
132 * when this watermark is reached.
133 * The buffer size is chosen so the watermark should almost never be reached.
134 * The low watermark is invisibly 0 since the buffer is always emptied all at
135 * once.
136 */
137 #define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
138
139 /*
140 * com state bits.
141 * (CS_BUSY | CS_TTGO) and (CS_BUSY | CS_TTGO | CS_ODEVREADY) must be higher
142 * than the other bits so that they can be tested as a group without masking
143 * off the low bits.
144 *
145 * The following com and tty flags correspond closely:
146 * CS_BUSY = TS_BUSY (maintained by comstart(), siopoll() and
147 * siostop())
148 * CS_TTGO = ~TS_TTSTOP (maintained by comparam() and comstart())
149 * CS_CTS_OFLOW = CCTS_OFLOW (maintained by comparam())
150 * CS_RTS_IFLOW = CRTS_IFLOW (maintained by comparam())
151 * TS_FLUSH is not used.
152 * XXX I think TIOCSETA doesn't clear TS_TTSTOP when it clears IXON.
153 * XXX CS_*FLOW should be CF_*FLOW in com->flags (control flags not state).
154 */
155 #define CS_BUSY 0x80 /* output in progress */
156 #define CS_TTGO 0x40 /* output not stopped by XOFF */
157 #define CS_ODEVREADY 0x20 /* external device h/w ready (CTS) */
158 #define CS_CHECKMSR 1 /* check of MSR scheduled */
159 #define CS_CTS_OFLOW 2 /* use CTS output flow control */
160 #define CS_DTR_OFF 0x10 /* DTR held off */
161 #define CS_ODONE 4 /* output completed */
162 #define CS_RTS_IFLOW 8 /* use RTS input flow control */
163 #define CSE_BUSYCHECK 1 /* siobusycheck() scheduled */
164
165 static char const * const error_desc[] = {
166 #define CE_OVERRUN 0
167 "silo overflow",
168 #define CE_INTERRUPT_BUF_OVERFLOW 1
169 "interrupt-level buffer overflow",
170 #define CE_TTY_BUF_OVERFLOW 2
171 "tty-level buffer overflow",
172 };
173
174 #define CE_NTYPES 3
175 #define CE_RECORD(com, errnum) (++(com)->delta_error_counts[errnum])
176
177 /* types. XXX - should be elsewhere */
178 typedef u_int Port_t; /* hardware port */
179 typedef u_char bool_t; /* boolean */
180
181 /* queue of linear buffers */
182 struct lbq {
183 u_char *l_head; /* next char to process */
184 u_char *l_tail; /* one past the last char to process */
185 struct lbq *l_next; /* next in queue */
186 bool_t l_queued; /* nonzero if queued */
187 };
188
189 /* com device structure */
190 struct com_s {
191 u_char state; /* miscellaneous flag bits */
192 bool_t active_out; /* nonzero if the callout device is open */
193 u_char cfcr_image; /* copy of value written to CFCR */
194 #ifdef COM_ESP
195 bool_t esp; /* is this unit a hayes esp board? */
196 #endif
197 u_char extra_state; /* more flag bits, separate for order trick */
198 u_char fifo_image; /* copy of value written to FIFO */
199 bool_t hasfifo; /* nonzero for 16550 UARTs */
200 bool_t loses_outints; /* nonzero if device loses output interrupts */
201 u_char mcr_image; /* copy of value written to MCR */
202 #ifdef COM_MULTIPORT
203 bool_t multiport; /* is this unit part of a multiport device? */
204 #endif /* COM_MULTIPORT */
205 bool_t no_irq; /* nonzero if irq is not attached */
206 bool_t gone; /* hardware disappeared */
207 bool_t poll; /* nonzero if polling is required */
208 bool_t poll_output; /* nonzero if polling for output is required */
209 int unit; /* unit number */
210 int dtr_wait; /* time to hold DTR down on close (* 1/hz) */
211 u_int tx_fifo_size;
212 u_int wopeners; /* # processes waiting for DCD in open() */
213
214 /*
215 * The high level of the driver never reads status registers directly
216 * because there would be too many side effects to handle conveniently.
217 * Instead, it reads copies of the registers stored here by the
218 * interrupt handler.
219 */
220 u_char last_modem_status; /* last MSR read by intr handler */
221 u_char prev_modem_status; /* last MSR handled by high level */
222
223 u_char hotchar; /* ldisc-specific char to be handled ASAP */
224 u_char *ibuf; /* start of input buffer */
225 u_char *ibufend; /* end of input buffer */
226 u_char *ihighwater; /* threshold in input buffer */
227 u_char *iptr; /* next free spot in input buffer */
228
229 struct lbq obufq; /* head of queue of output buffers */
230 struct lbq obufs[2]; /* output buffers */
231
232 Port_t data_port; /* i/o ports */
233 #ifdef COM_ESP
234 Port_t esp_port;
235 #endif
236 Port_t int_id_port;
237 Port_t iobase;
238 Port_t modem_ctl_port;
239 Port_t line_status_port;
240 Port_t modem_status_port;
241
242 struct tty *tp; /* cross reference */
243
244 /* Initial state. */
245 struct termios it_in; /* should be in struct tty */
246 struct termios it_out;
247
248 /* Lock state. */
249 struct termios lt_in; /* should be in struct tty */
250 struct termios lt_out;
251
252 bool_t do_timestamp;
253 bool_t do_dcd_timestamp;
254 struct timeval timestamp;
255 struct timeval dcd_timestamp;
256
257 u_long bytes_in; /* statistics */
258 u_long bytes_out;
259 u_int delta_error_counts[CE_NTYPES];
260 u_long error_counts[CE_NTYPES];
261
262 /*
263 * Ping-pong input buffers. The extra factor of 2 in the sizes is
264 * to allow for an error byte for each input byte.
265 */
266 #define CE_INPUT_OFFSET RS_IBUFSIZE
267 u_char ibuf1[2 * RS_IBUFSIZE];
268 u_char ibuf2[2 * RS_IBUFSIZE];
269
270 /*
271 * Data area for output buffers. Someday we should build the output
272 * buffer queue without copying data.
273 */
274 u_char obuf1[256];
275 u_char obuf2[256];
276 #ifdef DEVFS
277 void *devfs_token_ttyd;
278 void *devfs_token_ttyl;
279 void *devfs_token_ttyi;
280 void *devfs_token_cuaa;
281 void *devfs_token_cual;
282 void *devfs_token_cuai;
283 #endif
284 };
285
286 /*
287 * XXX public functions in drivers should be declared in headers produced
288 * by `config', not here.
289 */
290
291 /* Interrupt handling entry point. */
292 void siopoll __P((void));
293
294 /* Device switch entry points. */
295 #define sioreset noreset
296 #define siommap nommap
297 #define siostrategy nostrategy
298
299 #ifdef COM_ESP
300 static int espattach __P((struct isa_device *isdp, struct com_s *com,
301 Port_t esp_port));
302 #endif
303 static int sioattach __P((struct isa_device *dev));
304 static timeout_t siobusycheck;
305 static timeout_t siodtrwakeup;
306 static void comhardclose __P((struct com_s *com));
307 static void siointr1 __P((struct com_s *com));
308 static int commctl __P((struct com_s *com, int bits, int how));
309 static int comparam __P((struct tty *tp, struct termios *t));
310 static int sioprobe __P((struct isa_device *dev));
311 static void siosettimeout __P((void));
312 static void comstart __P((struct tty *tp));
313 static timeout_t comwakeup;
314 static void disc_optim __P((struct tty *tp, struct termios *t,
315 struct com_s *com));
316
317 #ifdef DSI_SOFT_MODEM
318 static int LoadSoftModem __P((int unit,int base_io, u_long size, u_char *ptr));
319 #endif /* DSI_SOFT_MODEM */
320
321 static char driver_name[] = "sio";
322
323 /* table and macro for fast conversion from a unit number to its com struct */
324 static struct com_s *p_com_addr[NSIOTOT];
325 #define com_addr(unit) (p_com_addr[unit])
326
327 struct isa_driver siodriver = {
328 sioprobe, sioattach, driver_name
329 };
330
331 static d_open_t sioopen;
332 static d_close_t sioclose;
333 static d_read_t sioread;
334 static d_write_t siowrite;
335 static d_ioctl_t sioioctl;
336 static d_stop_t siostop;
337 static d_devtotty_t siodevtotty;
338
339 #define CDEV_MAJOR 28
340 static struct cdevsw sio_cdevsw = {
341 sioopen, sioclose, sioread, siowrite,
342 sioioctl, siostop, noreset, siodevtotty,
343 ttselect, nommap, NULL, driver_name,
344 NULL, -1,
345 };
346
347 static int comconsole = -1;
348 static speed_t comdefaultrate = CONSPEED;
349 static u_int com_events; /* input chars + weighted output completions */
350 static Port_t siocniobase;
351 static int sio_timeout;
352 static int sio_timeouts_until_log;
353 #if 0 /* XXX */
354 static struct tty *sio_tty[NSIOTOT];
355 #else
356 static struct tty sio_tty[NSIOTOT];
357 #endif
358 static const int nsio_tty = NSIOTOT;
359
360 static struct speedtab comspeedtab[] = {
361 { 0, 0 },
362 { 50, COMBRD(50) },
363 { 75, COMBRD(75) },
364 { 110, COMBRD(110) },
365 { 134, COMBRD(134) },
366 { 150, COMBRD(150) },
367 { 200, COMBRD(200) },
368 { 300, COMBRD(300) },
369 { 600, COMBRD(600) },
370 { 1200, COMBRD(1200) },
371 { 1800, COMBRD(1800) },
372 { 2400, COMBRD(2400) },
373 { 4800, COMBRD(4800) },
374 { 9600, COMBRD(9600) },
375 { 19200, COMBRD(19200) },
376 { 38400, COMBRD(38400) },
377 { 57600, COMBRD(57600) },
378 { 115200, COMBRD(115200) },
379 { -1, -1 }
380 };
381
382 #ifdef COM_ESP
383 /* XXX configure this properly. */
384 static Port_t likely_com_ports[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, };
385 static Port_t likely_esp_ports[] = { 0x140, 0x180, 0x280, 0 };
386 #endif
387
388 #if NCARD > 0
389 /*
390 * PC-Card (PCMCIA) specific code.
391 */
392 static int sioinit(struct pccard_devinfo *); /* init device */
393 static void siounload(struct pccard_devinfo *); /* Disable driver */
394 static int card_intr(struct pccard_devinfo *); /* Interrupt handler */
395
396 static struct pccard_device sio_info = {
397 driver_name,
398 sioinit,
399 siounload,
400 card_intr,
401 0, /* Attributes - presently unused */
402 &tty_imask /* Interrupt mask for device */
403 /* XXX - Should this also include net_imask? */
404 };
405
406 DATA_SET(pccarddrv_set, sio_info);
407
408 /*
409 * Initialize the device - called from Slot manager.
410 */
411 int
412 sioinit(struct pccard_devinfo *devi)
413 {
414
415 /* validate unit number. */
416 if (devi->isahd.id_unit >= (NSIOTOT))
417 return(ENODEV);
418 /* Make sure it isn't already probed. */
419 if (com_addr(devi->isahd.id_unit))
420 return(EBUSY);
421 /*
422 * Probe the device. If a value is returned, the
423 * device was found at the location.
424 */
425 if (sioprobe(&devi->isahd) == 0)
426 return(ENXIO);
427 if (sioattach(&devi->isahd) == 0)
428 return(ENXIO);
429
430 return(0);
431 }
432
433 /*
434 * siounload - unload the driver and clear the table.
435 * XXX TODO:
436 * This is usually called when the card is ejected, but
437 * can be caused by a modunload of a controller driver.
438 * The idea is to reset the driver's view of the device
439 * and ensure that any driver entry points such as
440 * read and write do not hang.
441 */
442 static void
443 siounload(struct pccard_devinfo *devi)
444 {
445 struct com_s *com;
446
447 com = com_addr(devi->isahd.id_unit);
448 if (!com->iobase) {
449 printf("sio%d already unloaded!\n",devi->isahd.id_unit);
450 return;
451 }
452 if (com->tp && (com->tp->t_state & TS_ISOPEN)) {
453 com->gone = 1;
454 printf("sio%d: unload\n", devi->isahd.id_unit);
455 com->tp->t_gen++;
456 ttyclose(com->tp);
457 ttwakeup(com->tp);
458 ttwwakeup(com->tp);
459 } else {
460 com_addr(com->unit) = NULL;
461 bzero(com, sizeof *com);
462 free(com,M_TTYS);
463 printf("sio%d: unload,gone\n", devi->isahd.id_unit);
464 }
465 }
466
467 /*
468 * card_intr - Shared interrupt called from
469 * front end of PC-Card handler.
470 */
471 static int
472 card_intr(struct pccard_devinfo *devi)
473 {
474 struct com_s *com;
475
476 com = com_addr(devi->isahd.id_unit);
477 if (com && !com->gone)
478 siointr1(com_addr(devi->isahd.id_unit));
479 return(1);
480 }
481 #endif /* NCARD > 0 */
482
483 static int
484 sioprobe(dev)
485 struct isa_device *dev;
486 {
487 static bool_t already_init;
488 bool_t failures[10];
489 int fn;
490 struct isa_device *idev;
491 Port_t iobase;
492 u_int irqmap[4];
493 u_int irqs;
494 u_char mcr_image;
495 int result;
496 struct isa_device *xdev;
497
498 if (!already_init) {
499 /*
500 * Turn off MCR_IENABLE for all likely serial ports. An unused
501 * port with its MCR_IENABLE gate open will inhibit interrupts
502 * from any used port that shares the interrupt vector.
503 * XXX the gate enable is elsewhere for some multiports.
504 */
505 for (xdev = isa_devtab_tty; xdev->id_driver != NULL; xdev++)
506 if (xdev->id_driver == &siodriver && xdev->id_enabled)
507 outb(xdev->id_iobase + com_mcr, 0);
508 already_init = TRUE;
509 }
510
511 /*
512 * If the device is on a multiport card and has an AST/4
513 * compatible interrupt control register, initialize this
514 * register and prepare to leave MCR_IENABLE clear in the mcr.
515 * Otherwise, prepare to set MCR_IENABLE in the mcr.
516 * Point idev to the device struct giving the correct id_irq.
517 * This is the struct for the master device if there is one.
518 */
519 idev = dev;
520 mcr_image = MCR_IENABLE;
521 #ifdef COM_MULTIPORT
522 if (COM_ISMULTIPORT(dev)) {
523 idev = find_isadev(isa_devtab_tty, &siodriver,
524 COM_MPMASTER(dev));
525 if (idev == NULL) {
526 printf("sio%d: master device %d not configured\n",
527 dev->id_unit, COM_MPMASTER(dev));
528 dev->id_irq = 0;
529 idev = dev;
530 }
531 if (!COM_NOTAST4(dev)) {
532 outb(idev->id_iobase + com_scr,
533 idev->id_irq ? 0x80 : 0);
534 mcr_image = 0;
535 }
536 }
537 #endif /* COM_MULTIPORT */
538 if (idev->id_irq == 0)
539 mcr_image = 0;
540
541 bzero(failures, sizeof failures);
542 iobase = dev->id_iobase;
543
544 /*
545 * We don't want to get actual interrupts, just masked ones.
546 * Interrupts from this line should already be masked in the ICU,
547 * but mask them in the processor as well in case there are some
548 * (misconfigured) shared interrupts.
549 */
550 disable_intr();
551 /* EXTRA DELAY? */
552
553 /*
554 * Initialize the speed and the word size and wait long enough to
555 * drain the maximum of 16 bytes of junk in device output queues.
556 * The speed is undefined after a master reset and must be set
557 * before relying on anything related to output. There may be
558 * junk after a (very fast) soft reboot and (apparently) after
559 * master reset.
560 * XXX what about the UART bug avoided by waiting in comparam()?
561 * We don't want to to wait long enough to drain at 2 bps.
562 */
563 outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
564 outb(iobase + com_dlbl, COMBRD(9600) & 0xff);
565 outb(iobase + com_dlbh, (u_int) COMBRD(9600) >> 8);
566 outb(iobase + com_cfcr, CFCR_8BITS);
567 DELAY((16 + 1) * 1000000 / (9600 / 10));
568
569 /*
570 * Enable the interrupt gate and disable device interupts. This
571 * should leave the device driving the interrupt line low and
572 * guarantee an edge trigger if an interrupt can be generated.
573 */
574 /* EXTRA DELAY? */
575 outb(iobase + com_mcr, mcr_image);
576 outb(iobase + com_ier, 0);
577 DELAY(1000); /* XXX */
578 irqmap[0] = isa_irq_pending();
579
580 /*
581 * Attempt to set loopback mode so that we can send a null byte
582 * without annoying any external device.
583 */
584 /* EXTRA DELAY? */
585 outb(iobase + com_mcr, mcr_image | MCR_LOOPBACK);
586
587 /*
588 * Attempt to generate an output interrupt. On 8250's, setting
589 * IER_ETXRDY generates an interrupt independent of the current
590 * setting and independent of whether the THR is empty. On 16450's,
591 * setting IER_ETXRDY generates an interrupt independent of the
592 * current setting. On 16550A's, setting IER_ETXRDY only
593 * generates an interrupt when IER_ETXRDY is not already set.
594 */
595 outb(iobase + com_ier, IER_ETXRDY);
596
597 /*
598 * On some 16x50 incompatibles, setting IER_ETXRDY doesn't generate
599 * an interrupt. They'd better generate one for actually doing
600 * output. Loopback may be broken on the same incompatibles but
601 * it's unlikely to do more than allow the null byte out.
602 */
603 outb(iobase + com_data, 0);
604 DELAY((1 + 2) * 1000000 / (9600 / 10));
605
606 /*
607 * Turn off loopback mode so that the interrupt gate works again
608 * (MCR_IENABLE was hidden). This should leave the device driving
609 * an interrupt line high. It doesn't matter if the interrupt
610 * line oscillates while we are not looking at it, since interrupts
611 * are disabled.
612 */
613 /* EXTRA DELAY? */
614 outb(iobase + com_mcr, mcr_image);
615
616 /*
617 * Check that
618 * o the CFCR, IER and MCR in UART hold the values written to them
619 * (the values happen to be all distinct - this is good for
620 * avoiding false positive tests from bus echoes).
621 * o an output interrupt is generated and its vector is correct.
622 * o the interrupt goes away when the IIR in the UART is read.
623 */
624 /* EXTRA DELAY? */
625 failures[0] = inb(iobase + com_cfcr) - CFCR_8BITS;
626 failures[1] = inb(iobase + com_ier) - IER_ETXRDY;
627 failures[2] = inb(iobase + com_mcr) - mcr_image;
628 DELAY(10000); /* Some internal modems need this time */
629 irqmap[1] = isa_irq_pending();
630 failures[4] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_TXRDY;
631 DELAY(1000); /* XXX */
632 irqmap[2] = isa_irq_pending();
633 failures[6] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
634
635 /*
636 * Turn off all device interrupts and check that they go off properly.
637 * Leave MCR_IENABLE alone. For ports without a master port, it gates
638 * the OUT2 output of the UART to
639 * the ICU input. Closing the gate would give a floating ICU input
640 * (unless there is another device driving at) and spurious interrupts.
641 * (On the system that this was first tested on, the input floats high
642 * and gives a (masked) interrupt as soon as the gate is closed.)
643 */
644 outb(iobase + com_ier, 0);
645 outb(iobase + com_cfcr, CFCR_8BITS); /* dummy to avoid bus echo */
646 failures[7] = inb(iobase + com_ier);
647 DELAY(1000); /* XXX */
648 irqmap[3] = isa_irq_pending();
649 failures[9] = (inb(iobase + com_iir) & IIR_IMASK) - IIR_NOPEND;
650
651 enable_intr();
652
653 irqs = irqmap[1] & ~irqmap[0];
654 if (idev->id_irq != 0 && (idev->id_irq & irqs) == 0)
655 printf(
656 "sio%d: configured irq %d not in bitmap of probed irqs %#x\n",
657 dev->id_unit, ffs(idev->id_irq) - 1, irqs);
658 if (bootverbose)
659 printf("sio%d: irq maps: %#x %#x %#x %#x\n",
660 dev->id_unit, irqmap[0], irqmap[1], irqmap[2], irqmap[3]);
661
662 result = IO_COMSIZE;
663 for (fn = 0; fn < sizeof failures; ++fn)
664 if (failures[fn]) {
665 outb(iobase + com_mcr, 0);
666 result = 0;
667 if (bootverbose) {
668 printf("sio%d: probe failed test(s):",
669 dev->id_unit);
670 for (fn = 0; fn < sizeof failures; ++fn)
671 if (failures[fn])
672 printf(" %d", fn);
673 printf("\n");
674 }
675 break;
676 }
677 return (iobase == siocniobase ? IO_COMSIZE : result);
678 }
679
680 #ifdef COM_ESP
681 static int
682 espattach(isdp, com, esp_port)
683 struct isa_device *isdp;
684 struct com_s *com;
685 Port_t esp_port;
686 {
687 u_char dips;
688 u_char val;
689
690 /*
691 * Check the ESP-specific I/O port to see if we're an ESP
692 * card. If not, return failure immediately.
693 */
694 if ((inb(esp_port) & 0xf3) == 0) {
695 printf(" port 0x%x is not an ESP board?\n", esp_port);
696 return (0);
697 }
698
699 /*
700 * We've got something that claims to be a Hayes ESP card.
701 * Let's hope so.
702 */
703
704 /* Get the dip-switch configuration */
705 outb(esp_port + ESP_CMD1, ESP_GETDIPS);
706 dips = inb(esp_port + ESP_STATUS1);
707
708 /*
709 * Bits 0,1 of dips say which COM port we are.
710 */
711 if (com->iobase == likely_com_ports[dips & 0x03])
712 printf(" : ESP");
713 else {
714 printf(" esp_port has com %d\n", dips & 0x03);
715 return (0);
716 }
717
718 /*
719 * Check for ESP version 2.0 or later: bits 4,5,6 = 010.
720 */
721 outb(esp_port + ESP_CMD1, ESP_GETTEST);
722 val = inb(esp_port + ESP_STATUS1); /* clear reg 1 */
723 val = inb(esp_port + ESP_STATUS2);
724 if ((val & 0x70) < 0x20) {
725 printf("-old (%o)", val & 0x70);
726 return (0);
727 }
728
729 /*
730 * Check for ability to emulate 16550: bit 7 == 1
731 */
732 if ((dips & 0x80) == 0) {
733 printf(" slave");
734 return (0);
735 }
736
737 /*
738 * Okay, we seem to be a Hayes ESP card. Whee.
739 */
740 com->esp = TRUE;
741 com->esp_port = esp_port;
742 return (1);
743 }
744 #endif /* COM_ESP */
745
746 static int
747 sioattach(isdp)
748 struct isa_device *isdp;
749 {
750 struct com_s *com;
751 dev_t dev;
752 #ifdef COM_ESP
753 Port_t *espp;
754 #endif
755 Port_t iobase;
756 int s;
757 int unit;
758
759 isdp->id_ri_flags |= RI_FAST;
760 iobase = isdp->id_iobase;
761 unit = isdp->id_unit;
762 com = malloc(sizeof *com, M_TTYS, M_NOWAIT);
763 if (com == NULL)
764 return (0);
765
766 /*
767 * sioprobe() has initialized the device registers as follows:
768 * o cfcr = CFCR_8BITS.
769 * It is most important that CFCR_DLAB is off, so that the
770 * data port is not hidden when we enable interrupts.
771 * o ier = 0.
772 * Interrupts are only enabled when the line is open.
773 * o mcr = MCR_IENABLE, or 0 if the port has AST/4 compatible
774 * interrupt control register or the config specifies no irq.
775 * Keeping MCR_DTR and MCR_RTS off might stop the external
776 * device from sending before we are ready.
777 */
778 bzero(com, sizeof *com);
779 com->unit = unit;
780 com->cfcr_image = CFCR_8BITS;
781 com->dtr_wait = 3 * hz;
782 com->loses_outints = COM_LOSESOUTINTS(isdp) != 0;
783 com->no_irq = isdp->id_irq == 0;
784 com->tx_fifo_size = 1;
785 com->iptr = com->ibuf = com->ibuf1;
786 com->ibufend = com->ibuf1 + RS_IBUFSIZE;
787 com->ihighwater = com->ibuf1 + RS_IHIGHWATER;
788 com->obufs[0].l_head = com->obuf1;
789 com->obufs[1].l_head = com->obuf2;
790
791 com->iobase = iobase;
792 com->data_port = iobase + com_data;
793 com->int_id_port = iobase + com_iir;
794 com->modem_ctl_port = iobase + com_mcr;
795 com->mcr_image = inb(com->modem_ctl_port);
796 com->line_status_port = iobase + com_lsr;
797 com->modem_status_port = iobase + com_msr;
798
799 /*
800 * We don't use all the flags from <sys/ttydefaults.h> since they
801 * are only relevant for logins. It's important to have echo off
802 * initially so that the line doesn't start blathering before the
803 * echo flag can be turned off.
804 */
805 com->it_in.c_iflag = 0;
806 com->it_in.c_oflag = 0;
807 com->it_in.c_cflag = TTYDEF_CFLAG;
808 com->it_in.c_lflag = 0;
809 if (unit == comconsole) {
810 com->it_in.c_iflag = TTYDEF_IFLAG;
811 com->it_in.c_oflag = TTYDEF_OFLAG;
812 com->it_in.c_cflag = TTYDEF_CFLAG | CLOCAL;
813 com->it_in.c_lflag = TTYDEF_LFLAG;
814 com->lt_out.c_cflag = com->lt_in.c_cflag = CLOCAL;
815 com->it_in.c_ispeed = com->it_in.c_ospeed = comdefaultrate;
816 } else
817 com->it_in.c_ispeed = com->it_in.c_ospeed = TTYDEF_SPEED;
818 termioschars(&com->it_in);
819 com->it_out = com->it_in;
820
821 /* attempt to determine UART type */
822 printf("sio%d: type", unit);
823
824 #ifdef DSI_SOFT_MODEM
825 if((inb(iobase+7) ^ inb(iobase+7)) & 0x80) {
826 printf(" Digicom Systems, Inc. SoftModem");
827 goto determined_type;
828 }
829 #endif /* DSI_SOFT_MODEM */
830
831 #ifdef COM_MULTIPORT
832 if (!COM_ISMULTIPORT(isdp))
833 #endif
834 {
835 u_char scr;
836 u_char scr1;
837 u_char scr2;
838
839 scr = inb(iobase + com_scr);
840 outb(iobase + com_scr, 0xa5);
841 scr1 = inb(iobase + com_scr);
842 outb(iobase + com_scr, 0x5a);
843 scr2 = inb(iobase + com_scr);
844 outb(iobase + com_scr, scr);
845 if (scr1 != 0xa5 || scr2 != 0x5a) {
846 printf(" 8250");
847 goto determined_type;
848 }
849 }
850 outb(iobase + com_fifo, FIFO_ENABLE | FIFO_RX_HIGH);
851 DELAY(100);
852 switch (inb(com->int_id_port) & IIR_FIFO_MASK) {
853 case FIFO_RX_LOW:
854 printf(" 16450");
855 break;
856 case FIFO_RX_MEDL:
857 printf(" 16450?");
858 break;
859 case FIFO_RX_MEDH:
860 printf(" 16550?");
861 break;
862 case FIFO_RX_HIGH:
863 printf(" 16550A");
864 if (COM_NOFIFO(isdp)) {
865 printf(" fifo disabled");
866 } else {
867 com->hasfifo = TRUE;
868 com->tx_fifo_size = 16;
869 #ifdef COM_ESP
870 for (espp = likely_esp_ports; *espp != 0; espp++)
871 if (espattach(isdp, com, *espp)) {
872 com->tx_fifo_size = 1024;
873 break;
874 }
875 #endif
876 }
877 #if 0
878 /*
879 * Check for the Startech ST16C650 chip.
880 * it has a shadow register under the com_iir,
881 * which can only be accessed when cfcr == 0xff
882 */
883 {
884 u_char i, j;
885
886 i = inb(iobase + com_iir);
887 outb(iobase + com_cfcr, 0xff);
888 outb(iobase + com_iir, 0x0);
889 outb(iobase + com_cfcr, CFCR_8BITS);
890 j = inb(iobase + com_iir);
891 outb(iobase + com_iir, i);
892 if (i != j) {
893 printf(" 16550A");
894 } else {
895 com->tx_fifo_size = 32;
896 printf(" 16650");
897 }
898 if (!com->tx_fifo_size)
899 printf(" fifo disabled");
900 }
901 #endif
902 break;
903 }
904 #ifdef COM_ESP
905 if (com->esp) {
906 /*
907 * Set 16550 compatibility mode.
908 * We don't use the ESP_MODE_SCALE bit to increase the
909 * fifo trigger levels because we can't handle large
910 * bursts of input.
911 * XXX flow control should be set in comparam(), not here.
912 */
913 outb(com->esp_port + ESP_CMD1, ESP_SETMODE);
914 outb(com->esp_port + ESP_CMD2, ESP_MODE_RTS | ESP_MODE_FIFO);
915
916 /* Set RTS/CTS flow control. */
917 outb(com->esp_port + ESP_CMD1, ESP_SETFLOWTYPE);
918 outb(com->esp_port + ESP_CMD2, ESP_FLOW_RTS);
919 outb(com->esp_port + ESP_CMD2, ESP_FLOW_CTS);
920
921 /* Set flow-control levels. */
922 outb(com->esp_port + ESP_CMD1, ESP_SETRXFLOW);
923 outb(com->esp_port + ESP_CMD2, HIBYTE(768));
924 outb(com->esp_port + ESP_CMD2, LOBYTE(768));
925 outb(com->esp_port + ESP_CMD2, HIBYTE(512));
926 outb(com->esp_port + ESP_CMD2, LOBYTE(512));
927 }
928 #endif /* COM_ESP */
929 outb(iobase + com_fifo, 0);
930 determined_type: ;
931
932 #ifdef COM_MULTIPORT
933 if (COM_ISMULTIPORT(isdp)) {
934 com->multiport = TRUE;
935 printf(" (multiport");
936 if (unit == COM_MPMASTER(isdp))
937 printf(" master");
938 printf(")");
939 com->no_irq = find_isadev(isa_devtab_tty, &siodriver,
940 COM_MPMASTER(isdp))->id_irq == 0;
941 }
942 #endif /* COM_MULTIPORT */
943 printf("\n");
944
945 s = spltty();
946 com_addr(unit) = com;
947 splx(s);
948
949 dev = makedev(CDEV_MAJOR, 0);
950 cdevsw_add(&dev, &sio_cdevsw, NULL);
951 #ifdef DEVFS
952 com->devfs_token_ttyd = devfs_add_devswf(&sio_cdevsw,
953 unit, DV_CHR,
954 UID_ROOT, GID_WHEEL, 0600, "ttyd%n", unit);
955 com->devfs_token_ttyi = devfs_add_devswf(&sio_cdevsw,
956 unit | CONTROL_INIT_STATE, DV_CHR,
957 UID_ROOT, GID_WHEEL, 0600, "ttyid%n", unit);
958 com->devfs_token_ttyl = devfs_add_devswf(&sio_cdevsw,
959 unit | CONTROL_LOCK_STATE, DV_CHR,
960 UID_ROOT, GID_WHEEL, 0600, "ttyld%n", unit);
961 com->devfs_token_cuaa = devfs_add_devswf(&sio_cdevsw,
962 unit | CALLOUT_MASK, DV_CHR,
963 UID_UUCP, GID_DIALER, 0660, "cuaa%n", unit);
964 com->devfs_token_cuai = devfs_add_devswf(&sio_cdevsw,
965 unit | CALLOUT_MASK | CONTROL_INIT_STATE, DV_CHR,
966 UID_UUCP, GID_DIALER, 0660, "cuaia%n", unit);
967 com->devfs_token_cual = devfs_add_devswf(&sio_cdevsw,
968 unit | CALLOUT_MASK | CONTROL_LOCK_STATE, DV_CHR,
969 UID_UUCP, GID_DIALER, 0660, "cuala%n", unit);
970 #endif
971 return (1);
972 }
973
974 static int
975 sioopen(dev, flag, mode, p)
976 dev_t dev;
977 int flag;
978 int mode;
979 struct proc *p;
980 {
981 struct com_s *com;
982 int error;
983 Port_t iobase;
984 int mynor;
985 int s;
986 struct tty *tp;
987 int unit;
988
989 mynor = minor(dev);
990 unit = MINOR_TO_UNIT(mynor);
991 if ((u_int) unit >= NSIOTOT || (com = com_addr(unit)) == NULL)
992 return (ENXIO);
993 if (com->gone)
994 return (ENXIO);
995 if (mynor & CONTROL_MASK)
996 return (0);
997 #if 0 /* XXX */
998 tp = com->tp = sio_tty[unit] = ttymalloc(sio_tty[unit]);
999 #else
1000 tp = com->tp = &sio_tty[unit];
1001 #endif
1002 s = spltty();
1003 /*
1004 * We jump to this label after all non-interrupted sleeps to pick
1005 * up any changes of the device state.
1006 */
1007 open_top:
1008 while (com->state & CS_DTR_OFF) {
1009 error = tsleep(&com->dtr_wait, TTIPRI | PCATCH, "siodtr", 0);
1010 if (com_addr(unit) == NULL)
1011 return (ENXIO);
1012 if (error != 0 || com->gone)
1013 goto out;
1014 }
1015 if (tp->t_state & TS_ISOPEN) {
1016 /*
1017 * The device is open, so everything has been initialized.
1018 * Handle conflicts.
1019 */
1020 if (mynor & CALLOUT_MASK) {
1021 if (!com->active_out) {
1022 error = EBUSY;
1023 goto out;
1024 }
1025 } else {
1026 if (com->active_out) {
1027 if (flag & O_NONBLOCK) {
1028 error = EBUSY;
1029 goto out;
1030 }
1031 error = tsleep(&com->active_out,
1032 TTIPRI | PCATCH, "siobi", 0);
1033 if (com_addr(unit) == NULL)
1034 return (ENXIO);
1035 if (error != 0 || com->gone)
1036 goto out;
1037 goto open_top;
1038 }
1039 }
1040 if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) {
1041 error = EBUSY;
1042 goto out;
1043 }
1044 } else {
1045 /*
1046 * The device isn't open, so there are no conflicts.
1047 * Initialize it. Initialization is done twice in many
1048 * cases: to preempt sleeping callin opens if we are
1049 * callout, and to complete a callin open after DCD rises.
1050 */
1051 tp->t_oproc = comstart;
1052 tp->t_param = comparam;
1053 tp->t_dev = dev;
1054 tp->t_termios = mynor & CALLOUT_MASK
1055 ? com->it_out : com->it_in;
1056 (void)commctl(com, TIOCM_DTR | TIOCM_RTS, DMSET);
1057 com->poll = com->no_irq;
1058 com->poll_output = com->loses_outints;
1059 ++com->wopeners;
1060 error = comparam(tp, &tp->t_termios);
1061 --com->wopeners;
1062 if (error != 0)
1063 goto out;
1064 /*
1065 * XXX we should goto open_top if comparam() slept.
1066 */
1067 ttsetwater(tp);
1068 iobase = com->iobase;
1069 if (com->hasfifo) {
1070 /*
1071 * (Re)enable and drain fifos.
1072 *
1073 * Certain SMC chips cause problems if the fifos
1074 * are enabled while input is ready. Turn off the
1075 * fifo if necessary to clear the input. We test
1076 * the input ready bit after enabling the fifos
1077 * since we've already enabled them in comparam()
1078 * and to handle races between enabling and fresh
1079 * input.
1080 */
1081 while (TRUE) {
1082 outb(iobase + com_fifo,
1083 FIFO_RCV_RST | FIFO_XMT_RST
1084 | com->fifo_image);
1085 /*
1086 * XXX the delays are for superstitious
1087 * historical reasons. It must be less than
1088 * the character time at the maximum
1089 * supported speed (87 usec at 115200 bps
1090 * 8N1). Otherwise we might loop endlessly
1091 * if data is streaming in. We used to use
1092 * delays of 100. That usually worked
1093 * because DELAY(100) used to usually delay
1094 * for about 85 usec instead of 100.
1095 */
1096 DELAY(50);
1097 if (!(inb(com->line_status_port) & LSR_RXRDY))
1098 break;
1099 outb(iobase + com_fifo, 0);
1100 DELAY(50);
1101 (void) inb(com->data_port);
1102 }
1103 }
1104
1105 disable_intr();
1106 (void) inb(com->line_status_port);
1107 (void) inb(com->data_port);
1108 com->prev_modem_status = com->last_modem_status
1109 = inb(com->modem_status_port);
1110 outb(iobase + com_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS
1111 | IER_EMSC);
1112 enable_intr();
1113 /*
1114 * Handle initial DCD. Callout devices get a fake initial
1115 * DCD (trapdoor DCD). If we are callout, then any sleeping
1116 * callin opens get woken up and resume sleeping on "siobi"
1117 * instead of "siodcd".
1118 */
1119 /*
1120 * XXX `mynor & CALLOUT_MASK' should be
1121 * `tp->t_cflag & (SOFT_CARRIER | TRAPDOOR_CARRIER) where
1122 * TRAPDOOR_CARRIER is the default initial state for callout
1123 * devices and SOFT_CARRIER is like CLOCAL except it hides
1124 * the true carrier.
1125 */
1126 if (com->prev_modem_status & MSR_DCD || mynor & CALLOUT_MASK)
1127 (*linesw[tp->t_line].l_modem)(tp, 1);
1128 }
1129 /*
1130 * Wait for DCD if necessary.
1131 */
1132 if (!(tp->t_state & TS_CARR_ON) && !(mynor & CALLOUT_MASK)
1133 && !(tp->t_cflag & CLOCAL) && !(flag & O_NONBLOCK)) {
1134 ++com->wopeners;
1135 error = tsleep(TSA_CARR_ON(tp), TTIPRI | PCATCH, "siodcd", 0);
1136 if (com_addr(unit) == NULL)
1137 return (ENXIO);
1138 --com->wopeners;
1139 if (error != 0 || com->gone)
1140 goto out;
1141 goto open_top;
1142 }
1143 error = (*linesw[tp->t_line].l_open)(dev, tp);
1144 disc_optim(tp, &tp->t_termios, com);
1145 if (tp->t_state & TS_ISOPEN && mynor & CALLOUT_MASK)
1146 com->active_out = TRUE;
1147 siosettimeout();
1148 out:
1149 splx(s);
1150 if (!(tp->t_state & TS_ISOPEN) && com->wopeners == 0)
1151 comhardclose(com);
1152 return (error);
1153 }
1154
1155 static int
1156 sioclose(dev, flag, mode, p)
1157 dev_t dev;
1158 int flag;
1159 int mode;
1160 struct proc *p;
1161 {
1162 struct com_s *com;
1163 int mynor;
1164 int s;
1165 struct tty *tp;
1166
1167 mynor = minor(dev);
1168 if (mynor & CONTROL_MASK)
1169 return (0);
1170 com = com_addr(MINOR_TO_UNIT(mynor));
1171 tp = com->tp;
1172 s = spltty();
1173 (*linesw[tp->t_line].l_close)(tp, flag);
1174 disc_optim(tp, &tp->t_termios, com);
1175 siostop(tp, FREAD | FWRITE);
1176 comhardclose(com);
1177 ttyclose(tp);
1178 siosettimeout();
1179 splx(s);
1180 if (com->gone) {
1181 printf("sio%d: gone\n", com->unit);
1182 s = spltty();
1183 com_addr(com->unit) = 0;
1184 bzero(tp,sizeof *tp);
1185 bzero(com,sizeof *com);
1186 free(com,M_TTYS);
1187 splx(s);
1188 }
1189 return (0);
1190 }
1191
1192 static void
1193 comhardclose(com)
1194 struct com_s *com;
1195 {
1196 Port_t iobase;
1197 int s;
1198 struct tty *tp;
1199 int unit;
1200
1201 unit = com->unit;
1202 iobase = com->iobase;
1203 s = spltty();
1204 com->poll = FALSE;
1205 com->poll_output = FALSE;
1206 com->do_timestamp = FALSE;
1207 com->do_dcd_timestamp = FALSE;
1208 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
1209 {
1210 outb(iobase + com_ier, 0);
1211 tp = com->tp;
1212 if (tp->t_cflag & HUPCL
1213 /*
1214 * XXX we will miss any carrier drop between here and the
1215 * next open. Perhaps we should watch DCD even when the
1216 * port is closed; it is not sufficient to check it at
1217 * the next open because it might go up and down while
1218 * we're not watching.
1219 */
1220 || !com->active_out
1221 && !(com->prev_modem_status & MSR_DCD)
1222 && !(com->it_in.c_cflag & CLOCAL)
1223 || !(tp->t_state & TS_ISOPEN)) {
1224 (void)commctl(com, TIOCM_DTR, DMBIC);
1225 if (com->dtr_wait != 0 && !(com->state & CS_DTR_OFF)) {
1226 timeout(siodtrwakeup, com, com->dtr_wait);
1227 com->state |= CS_DTR_OFF;
1228 }
1229 }
1230 }
1231 if (com->hasfifo) {
1232 /*
1233 * Disable fifos so that they are off after controlled
1234 * reboots. Some BIOSes fail to detect 16550s when the
1235 * fifos are enabled.
1236 */
1237 outb(iobase + com_fifo, 0);
1238 }
1239 com->active_out = FALSE;
1240 wakeup(&com->active_out);
1241 wakeup(TSA_CARR_ON(tp)); /* restart any wopeners */
1242 splx(s);
1243 }
1244
1245 static int
1246 sioread(dev, uio, flag)
1247 dev_t dev;
1248 struct uio *uio;
1249 int flag;
1250 {
1251 int mynor;
1252 int unit;
1253 struct tty *tp;
1254
1255 mynor = minor(dev);
1256 if (mynor & CONTROL_MASK)
1257 return (ENODEV);
1258 unit = MINOR_TO_UNIT(mynor);
1259 if (com_addr(unit)->gone)
1260 return (ENODEV);
1261 tp = com_addr(unit)->tp;
1262 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
1263 }
1264
1265 static int
1266 siowrite(dev, uio, flag)
1267 dev_t dev;
1268 struct uio *uio;
1269 int flag;
1270 {
1271 int mynor;
1272 struct tty *tp;
1273 int unit;
1274
1275 mynor = minor(dev);
1276 if (mynor & CONTROL_MASK)
1277 return (ENODEV);
1278
1279 unit = MINOR_TO_UNIT(mynor);
1280 if (com_addr(unit)->gone)
1281 return (ENODEV);
1282 tp = com_addr(unit)->tp;
1283 /*
1284 * (XXX) We disallow virtual consoles if the physical console is
1285 * a serial port. This is in case there is a display attached that
1286 * is not the console. In that situation we don't need/want the X
1287 * server taking over the console.
1288 */
1289 if (constty != NULL && unit == comconsole)
1290 constty = NULL;
1291 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
1292 }
1293
1294 static void
1295 siobusycheck(chan)
1296 void *chan;
1297 {
1298 struct com_s *com;
1299 int s;
1300
1301 com = (struct com_s *)chan;
1302
1303 /*
1304 * Clear TS_BUSY if low-level output is complete.
1305 * spl locking is sufficient because siointr1() does not set CS_BUSY.
1306 * If siointr1() clears CS_BUSY after we look at it, then we'll get
1307 * called again. Reading the line status port outside of siointr1()
1308 * is safe because CS_BUSY is clear so there are no output interrupts
1309 * to lose.
1310 */
1311 s = spltty();
1312 if (com->state & CS_BUSY)
1313 com->extra_state &= ~CSE_BUSYCHECK; /* False alarm. */
1314 else if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
1315 == (LSR_TSRE | LSR_TXRDY)) {
1316 com->tp->t_state &= ~TS_BUSY;
1317 ttwwakeup(com->tp);
1318 com->extra_state &= ~CSE_BUSYCHECK;
1319 } else
1320 timeout(siobusycheck, com, hz / 100);
1321 splx(s);
1322 }
1323
1324 static void
1325 siodtrwakeup(chan)
1326 void *chan;
1327 {
1328 struct com_s *com;
1329
1330 com = (struct com_s *)chan;
1331 com->state &= ~CS_DTR_OFF;
1332 wakeup(&com->dtr_wait);
1333 }
1334
1335 void
1336 siointr(unit)
1337 int unit;
1338 {
1339 #ifndef COM_MULTIPORT
1340 siointr1(com_addr(unit));
1341 #else /* COM_MULTIPORT */
1342 struct com_s *com;
1343 bool_t possibly_more_intrs;
1344
1345 /*
1346 * Loop until there is no activity on any port. This is necessary
1347 * to get an interrupt edge more than to avoid another interrupt.
1348 * If the IRQ signal is just an OR of the IRQ signals from several
1349 * devices, then the edge from one may be lost because another is
1350 * on.
1351 */
1352 do {
1353 possibly_more_intrs = FALSE;
1354 for (unit = 0; unit < NSIOTOT; ++unit) {
1355 com = com_addr(unit);
1356 if (com != NULL
1357 && !com->gone
1358 && (inb(com->int_id_port) & IIR_IMASK)
1359 != IIR_NOPEND) {
1360 siointr1(com);
1361 possibly_more_intrs = TRUE;
1362 }
1363 }
1364 } while (possibly_more_intrs);
1365 #endif /* COM_MULTIPORT */
1366 }
1367
1368 static void
1369 siointr1(com)
1370 struct com_s *com;
1371 {
1372 u_char line_status;
1373 u_char modem_status;
1374 u_char *ioptr;
1375 u_char recv_data;
1376
1377 while (TRUE) {
1378 line_status = inb(com->line_status_port);
1379
1380 /* input event? (check first to help avoid overruns) */
1381 while (line_status & LSR_RCV_MASK) {
1382 /* break/unnattached error bits or real input? */
1383 if (!(line_status & LSR_RXRDY))
1384 recv_data = 0;
1385 else
1386 recv_data = inb(com->data_port);
1387 if (line_status & (LSR_BI | LSR_FE | LSR_PE)) {
1388 /*
1389 * Don't store BI if IGNBRK or FE/PE if IGNPAR.
1390 * Otherwise, push the work to a higher level
1391 * (to handle PARMRK) if we're bypassing.
1392 * Otherwise, convert BI/FE and PE+INPCK to 0.
1393 *
1394 * This makes bypassing work right in the
1395 * usual "raw" case (IGNBRK set, and IGNPAR
1396 * and INPCK clear).
1397 *
1398 * Note: BI together with FE/PE means just BI.
1399 */
1400 if (line_status & LSR_BI) {
1401 #if defined(DDB) && defined(BREAK_TO_DEBUGGER)
1402 if (com->unit == comconsole) {
1403 breakpoint();
1404 goto cont;
1405 }
1406 #endif
1407 if (com->tp == NULL
1408 || com->tp->t_iflag & IGNBRK)
1409 goto cont;
1410 } else {
1411 if (com->tp == NULL
1412 || com->tp->t_iflag & IGNPAR)
1413 goto cont;
1414 }
1415 if (com->tp->t_state & TS_CAN_BYPASS_L_RINT
1416 && (line_status & (LSR_BI | LSR_FE)
1417 || com->tp->t_iflag & INPCK))
1418 recv_data = 0;
1419 }
1420 ++com->bytes_in;
1421 if (com->hotchar != 0 && recv_data == com->hotchar)
1422 setsofttty();
1423 ioptr = com->iptr;
1424 if (ioptr >= com->ibufend)
1425 CE_RECORD(com, CE_INTERRUPT_BUF_OVERFLOW);
1426 else {
1427 if (com->do_timestamp)
1428 microtime(&com->timestamp);
1429 ++com_events;
1430 schedsofttty();
1431 #if 0 /* for testing input latency vs efficiency */
1432 if (com->iptr - com->ibuf == 8)
1433 setsofttty();
1434 #endif
1435 ioptr[0] = recv_data;
1436 ioptr[CE_INPUT_OFFSET] = line_status;
1437 com->iptr = ++ioptr;
1438 if (ioptr == com->ihighwater
1439 && com->state & CS_RTS_IFLOW)
1440 outb(com->modem_ctl_port,
1441 com->mcr_image &= ~MCR_RTS);
1442 if (line_status & LSR_OE)
1443 CE_RECORD(com, CE_OVERRUN);
1444 }
1445 cont:
1446 /*
1447 * "& 0x7F" is to avoid the gcc-1.40 generating a slow
1448 * jump from the top of the loop to here
1449 */
1450 line_status = inb(com->line_status_port) & 0x7F;
1451 }
1452
1453 /* modem status change? (always check before doing output) */
1454 modem_status = inb(com->modem_status_port);
1455 if (modem_status != com->last_modem_status) {
1456 if (com->do_dcd_timestamp
1457 && !(com->last_modem_status & MSR_DCD)
1458 && modem_status & MSR_DCD)
1459 microtime(&com->dcd_timestamp);
1460
1461 /*
1462 * Schedule high level to handle DCD changes. Note
1463 * that we don't use the delta bits anywhere. Some
1464 * UARTs mess them up, and it's easy to remember the
1465 * previous bits and calculate the delta.
1466 */
1467 com->last_modem_status = modem_status;
1468 if (!(com->state & CS_CHECKMSR)) {
1469 com_events += LOTS_OF_EVENTS;
1470 com->state |= CS_CHECKMSR;
1471 setsofttty();
1472 }
1473
1474 /* handle CTS change immediately for crisp flow ctl */
1475 if (com->state & CS_CTS_OFLOW) {
1476 if (modem_status & MSR_CTS)
1477 com->state |= CS_ODEVREADY;
1478 else
1479 com->state &= ~CS_ODEVREADY;
1480 }
1481 }
1482
1483 /* output queued and everything ready? */
1484 if (line_status & LSR_TXRDY
1485 && com->state >= (CS_BUSY | CS_TTGO | CS_ODEVREADY)) {
1486 ioptr = com->obufq.l_head;
1487 if (com->tx_fifo_size > 1) {
1488 u_int ocount;
1489
1490 ocount = com->obufq.l_tail - ioptr;
1491 if (ocount > com->tx_fifo_size)
1492 ocount = com->tx_fifo_size;
1493 com->bytes_out += ocount;
1494 do
1495 outb(com->data_port, *ioptr++);
1496 while (--ocount != 0);
1497 } else {
1498 outb(com->data_port, *ioptr++);
1499 ++com->bytes_out;
1500 }
1501 com->obufq.l_head = ioptr;
1502 if (ioptr >= com->obufq.l_tail) {
1503 struct lbq *qp;
1504
1505 qp = com->obufq.l_next;
1506 qp->l_queued = FALSE;
1507 qp = qp->l_next;
1508 if (qp != NULL) {
1509 com->obufq.l_head = qp->l_head;
1510 com->obufq.l_tail = qp->l_tail;
1511 com->obufq.l_next = qp;
1512 } else {
1513 /* output just completed */
1514 com->state &= ~CS_BUSY;
1515 }
1516 if (!(com->state & CS_ODONE)) {
1517 com_events += LOTS_OF_EVENTS;
1518 com->state |= CS_ODONE;
1519 setsofttty(); /* handle at high level ASAP */
1520 }
1521 }
1522 }
1523
1524 /* finished? */
1525 #ifndef COM_MULTIPORT
1526 if ((inb(com->int_id_port) & IIR_IMASK) == IIR_NOPEND)
1527 #endif /* COM_MULTIPORT */
1528 return;
1529 }
1530 }
1531
1532 static int
1533 sioioctl(dev, cmd, data, flag, p)
1534 dev_t dev;
1535 int cmd;
1536 caddr_t data;
1537 int flag;
1538 struct proc *p;
1539 {
1540 struct com_s *com;
1541 int error;
1542 Port_t iobase;
1543 int mynor;
1544 int s;
1545 struct tty *tp;
1546 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1547 int oldcmd;
1548 struct termios term;
1549 #endif
1550
1551 mynor = minor(dev);
1552 com = com_addr(MINOR_TO_UNIT(mynor));
1553 if (com->gone)
1554 return (ENODEV);
1555 iobase = com->iobase;
1556 if (mynor & CONTROL_MASK) {
1557 struct termios *ct;
1558
1559 switch (mynor & CONTROL_MASK) {
1560 case CONTROL_INIT_STATE:
1561 ct = mynor & CALLOUT_MASK ? &com->it_out : &com->it_in;
1562 break;
1563 case CONTROL_LOCK_STATE:
1564 ct = mynor & CALLOUT_MASK ? &com->lt_out : &com->lt_in;
1565 break;
1566 default:
1567 return (ENODEV); /* /dev/nodev */
1568 }
1569 switch (cmd) {
1570 case TIOCSETA:
1571 error = suser(p->p_ucred, &p->p_acflag);
1572 if (error != 0)
1573 return (error);
1574 *ct = *(struct termios *)data;
1575 return (0);
1576 case TIOCGETA:
1577 *(struct termios *)data = *ct;
1578 return (0);
1579 case TIOCGETD:
1580 *(int *)data = TTYDISC;
1581 return (0);
1582 case TIOCGWINSZ:
1583 bzero(data, sizeof(struct winsize));
1584 return (0);
1585 #ifdef DSI_SOFT_MODEM
1586 /*
1587 * Download micro-code to Digicom modem.
1588 */
1589 case TIOCDSIMICROCODE:
1590 {
1591 u_long l;
1592 u_char *p,*pi;
1593
1594 pi = (u_char*)(*(caddr_t*)data);
1595 error = copyin(pi,&l,sizeof l);
1596 if(error)
1597 {return error;};
1598 pi += sizeof l;
1599
1600 p = malloc(l,M_TEMP,M_NOWAIT);
1601 if(!p)
1602 {return ENOBUFS;}
1603 error = copyin(pi,p,l);
1604 if(error)
1605 {free(p,M_TEMP); return error;};
1606 if(error = LoadSoftModem(
1607 MINOR_TO_UNIT(mynor),iobase,l,p))
1608 {free(p,M_TEMP); return error;}
1609 free(p,M_TEMP);
1610 return(0);
1611 }
1612 #endif /* DSI_SOFT_MODEM */
1613 default:
1614 return (ENOTTY);
1615 }
1616 }
1617 tp = com->tp;
1618 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1619 term = tp->t_termios;
1620 oldcmd = cmd;
1621 error = ttsetcompat(tp, &cmd, data, &term);
1622 if (error != 0)
1623 return (error);
1624 if (cmd != oldcmd)
1625 data = (caddr_t)&term;
1626 #endif
1627 if (cmd == TIOCSETA || cmd == TIOCSETAW || cmd == TIOCSETAF) {
1628 int cc;
1629 struct termios *dt = (struct termios *)data;
1630 struct termios *lt = mynor & CALLOUT_MASK
1631 ? &com->lt_out : &com->lt_in;
1632
1633 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1634 | (dt->c_iflag & ~lt->c_iflag);
1635 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1636 | (dt->c_oflag & ~lt->c_oflag);
1637 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1638 | (dt->c_cflag & ~lt->c_cflag);
1639 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1640 | (dt->c_lflag & ~lt->c_lflag);
1641 for (cc = 0; cc < NCCS; ++cc)
1642 if (lt->c_cc[cc] != 0)
1643 dt->c_cc[cc] = tp->t_cc[cc];
1644 if (lt->c_ispeed != 0)
1645 dt->c_ispeed = tp->t_ispeed;
1646 if (lt->c_ospeed != 0)
1647 dt->c_ospeed = tp->t_ospeed;
1648 }
1649 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
1650 if (error >= 0)
1651 return (error);
1652 s = spltty();
1653 error = ttioctl(tp, cmd, data, flag);
1654 disc_optim(tp, &tp->t_termios, com);
1655 if (error >= 0) {
1656 splx(s);
1657 return (error);
1658 }
1659 switch (cmd) {
1660 case TIOCSBRK:
1661 outb(iobase + com_cfcr, com->cfcr_image |= CFCR_SBREAK);
1662 break;
1663 case TIOCCBRK:
1664 outb(iobase + com_cfcr, com->cfcr_image &= ~CFCR_SBREAK);
1665 break;
1666 case TIOCSDTR:
1667 (void)commctl(com, TIOCM_DTR, DMBIS);
1668 break;
1669 case TIOCCDTR:
1670 (void)commctl(com, TIOCM_DTR, DMBIC);
1671 break;
1672 /*
1673 * XXX should disallow changing MCR_RTS if CS_RTS_IFLOW is set. The
1674 * changes get undone on the next call to comparam().
1675 */
1676 case TIOCMSET:
1677 (void)commctl(com, *(int *)data, DMSET);
1678 break;
1679 case TIOCMBIS:
1680 (void)commctl(com, *(int *)data, DMBIS);
1681 break;
1682 case TIOCMBIC:
1683 (void)commctl(com, *(int *)data, DMBIC);
1684 break;
1685 case TIOCMGET:
1686 *(int *)data = commctl(com, 0, DMGET);
1687 break;
1688 case TIOCMSDTRWAIT:
1689 /* must be root since the wait applies to following logins */
1690 error = suser(p->p_ucred, &p->p_acflag);
1691 if (error != 0) {
1692 splx(s);
1693 return (error);
1694 }
1695 com->dtr_wait = *(int *)data * hz / 100;
1696 break;
1697 case TIOCMGDTRWAIT:
1698 *(int *)data = com->dtr_wait * 100 / hz;
1699 break;
1700 case TIOCTIMESTAMP:
1701 com->do_timestamp = TRUE;
1702 *(struct timeval *)data = com->timestamp;
1703 break;
1704 case TIOCDCDTIMESTAMP:
1705 com->do_dcd_timestamp = TRUE;
1706 *(struct timeval *)data = com->dcd_timestamp;
1707 break;
1708 default:
1709 splx(s);
1710 return (ENOTTY);
1711 }
1712 splx(s);
1713 return (0);
1714 }
1715
1716 void
1717 siopoll()
1718 {
1719 int unit;
1720
1721 if (com_events == 0)
1722 return;
1723 repeat:
1724 for (unit = 0; unit < NSIOTOT; ++unit) {
1725 u_char *buf;
1726 struct com_s *com;
1727 u_char *ibuf;
1728 int incc;
1729 struct tty *tp;
1730
1731 com = com_addr(unit);
1732 if (com == NULL)
1733 continue;
1734 tp = com->tp;
1735 if (tp == NULL || com->gone) {
1736 /*
1737 * Discard any events related to never-opened or
1738 * going-away devices.
1739 */
1740 disable_intr();
1741 incc = com->iptr - com->ibuf;
1742 com->iptr = com->ibuf;
1743 if (com->state & CS_CHECKMSR) {
1744 incc += LOTS_OF_EVENTS;
1745 com->state &= ~CS_CHECKMSR;
1746 }
1747 com_events -= incc;
1748 enable_intr();
1749 continue;
1750 }
1751
1752 /* switch the role of the low-level input buffers */
1753 if (com->iptr == (ibuf = com->ibuf)) {
1754 buf = NULL; /* not used, but compiler can't tell */
1755 incc = 0;
1756 } else {
1757 buf = ibuf;
1758 disable_intr();
1759 incc = com->iptr - buf;
1760 com_events -= incc;
1761 if (ibuf == com->ibuf1)
1762 ibuf = com->ibuf2;
1763 else
1764 ibuf = com->ibuf1;
1765 com->ibufend = ibuf + RS_IBUFSIZE;
1766 com->ihighwater = ibuf + RS_IHIGHWATER;
1767 com->iptr = ibuf;
1768
1769 /*
1770 * There is now room for another low-level buffer full
1771 * of input, so enable RTS if it is now disabled and
1772 * there is room in the high-level buffer.
1773 */
1774 if ((com->state & CS_RTS_IFLOW)
1775 && !(com->mcr_image & MCR_RTS)
1776 && !(tp->t_state & TS_TBLOCK))
1777 outb(com->modem_ctl_port,
1778 com->mcr_image |= MCR_RTS);
1779 enable_intr();
1780 com->ibuf = ibuf;
1781 }
1782
1783 if (com->state & CS_CHECKMSR) {
1784 u_char delta_modem_status;
1785
1786 disable_intr();
1787 delta_modem_status = com->last_modem_status
1788 ^ com->prev_modem_status;
1789 com->prev_modem_status = com->last_modem_status;
1790 com_events -= LOTS_OF_EVENTS;
1791 com->state &= ~CS_CHECKMSR;
1792 enable_intr();
1793 if (delta_modem_status & MSR_DCD)
1794 (*linesw[tp->t_line].l_modem)
1795 (tp, com->prev_modem_status & MSR_DCD);
1796 }
1797 if (com->state & CS_ODONE) {
1798 disable_intr();
1799 com_events -= LOTS_OF_EVENTS;
1800 com->state &= ~CS_ODONE;
1801 enable_intr();
1802 if (!(com->state & CS_BUSY)
1803 && !(com->extra_state & CSE_BUSYCHECK)) {
1804 timeout(siobusycheck, com, hz / 100);
1805 com->extra_state |= CSE_BUSYCHECK;
1806 }
1807 (*linesw[tp->t_line].l_start)(tp);
1808 }
1809 if (incc <= 0 || !(tp->t_state & TS_ISOPEN) ||
1810 !(tp->t_cflag & CREAD))
1811 continue;
1812 /*
1813 * Avoid the grotesquely inefficient lineswitch routine
1814 * (ttyinput) in "raw" mode. It usually takes about 450
1815 * instructions (that's without canonical processing or echo!).
1816 * slinput is reasonably fast (usually 40 instructions plus
1817 * call overhead).
1818 */
1819 if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1820 if (tp->t_rawq.c_cc + incc >= RB_I_HIGH_WATER
1821 && (com->state & CS_RTS_IFLOW
1822 || tp->t_iflag & IXOFF)
1823 && !(tp->t_state & TS_TBLOCK))
1824 ttyblock(tp);
1825 tk_nin += incc;
1826 tk_rawcc += incc;
1827 tp->t_rawcc += incc;
1828 com->delta_error_counts[CE_TTY_BUF_OVERFLOW]
1829 += b_to_q((char *)buf, incc, &tp->t_rawq);
1830 ttwakeup(tp);
1831 if (tp->t_state & TS_TTSTOP
1832 && (tp->t_iflag & IXANY
1833 || tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
1834 tp->t_state &= ~TS_TTSTOP;
1835 tp->t_lflag &= ~FLUSHO;
1836 comstart(tp);
1837 }
1838 } else {
1839 do {
1840 u_char line_status;
1841 int recv_data;
1842
1843 line_status = (u_char) buf[CE_INPUT_OFFSET];
1844 recv_data = (u_char) *buf++;
1845 if (line_status
1846 & (LSR_BI | LSR_FE | LSR_OE | LSR_PE)) {
1847 if (line_status & LSR_BI)
1848 recv_data |= TTY_BI;
1849 if (line_status & LSR_FE)
1850 recv_data |= TTY_FE;
1851 if (line_status & LSR_OE)
1852 recv_data |= TTY_OE;
1853 if (line_status & LSR_PE)
1854 recv_data |= TTY_PE;
1855 }
1856 (*linesw[tp->t_line].l_rint)(recv_data, tp);
1857 } while (--incc > 0);
1858 }
1859 if (com_events == 0)
1860 break;
1861 }
1862 if (com_events >= LOTS_OF_EVENTS)
1863 goto repeat;
1864 }
1865
1866 static int
1867 comparam(tp, t)
1868 struct tty *tp;
1869 struct termios *t;
1870 {
1871 u_int cfcr;
1872 int cflag;
1873 struct com_s *com;
1874 int divisor;
1875 u_char dlbh;
1876 u_char dlbl;
1877 int error;
1878 Port_t iobase;
1879 int s;
1880 int unit;
1881 int txtimeout;
1882
1883 /* do historical conversions */
1884 if (t->c_ispeed == 0)
1885 t->c_ispeed = t->c_ospeed;
1886
1887 /* check requested parameters */
1888 divisor = ttspeedtab(t->c_ospeed, comspeedtab);
1889 if (divisor < 0 || divisor > 0 && t->c_ispeed != t->c_ospeed)
1890 return (EINVAL);
1891
1892 /* parameters are OK, convert them to the com struct and the device */
1893 unit = DEV_TO_UNIT(tp->t_dev);
1894 com = com_addr(unit);
1895 iobase = com->iobase;
1896 s = spltty();
1897 if (divisor == 0)
1898 (void)commctl(com, TIOCM_DTR, DMBIC); /* hang up line */
1899 else
1900 (void)commctl(com, TIOCM_DTR, DMBIS);
1901 cflag = t->c_cflag;
1902 switch (cflag & CSIZE) {
1903 case CS5:
1904 cfcr = CFCR_5BITS;
1905 break;
1906 case CS6:
1907 cfcr = CFCR_6BITS;
1908 break;
1909 case CS7:
1910 cfcr = CFCR_7BITS;
1911 break;
1912 default:
1913 cfcr = CFCR_8BITS;
1914 break;
1915 }
1916 if (cflag & PARENB) {
1917 cfcr |= CFCR_PENAB;
1918 if (!(cflag & PARODD))
1919 cfcr |= CFCR_PEVEN;
1920 }
1921 if (cflag & CSTOPB)
1922 cfcr |= CFCR_STOPB;
1923
1924 if (com->hasfifo && divisor != 0) {
1925 /*
1926 * Use a fifo trigger level low enough so that the input
1927 * latency from the fifo is less than about 16 msec and
1928 * the total latency is less than about 30 msec. These
1929 * latencies are reasonable for humans. Serial comms
1930 * protocols shouldn't expect anything better since modem
1931 * latencies are larger.
1932 */
1933 com->fifo_image = t->c_ospeed <= 4800
1934 ? FIFO_ENABLE : FIFO_ENABLE | FIFO_RX_HIGH;
1935 #ifdef COM_ESP
1936 /*
1937 * The Hayes ESP card needs the fifo DMA mode bit set
1938 * in compatibility mode. If not, it will interrupt
1939 * for each character received.
1940 */
1941 if (com->esp)
1942 com->fifo_image |= FIFO_DMA_MODE;
1943 #endif
1944 outb(iobase + com_fifo, com->fifo_image);
1945 }
1946
1947 /*
1948 * Some UARTs lock up if the divisor latch registers are selected
1949 * while the UART is doing output (they refuse to transmit anything
1950 * more until given a hard reset). Fix this by stopping filling
1951 * the device buffers and waiting for them to drain. Reading the
1952 * line status port outside of siointr1() might lose some receiver
1953 * error bits, but that is acceptable here.
1954 */
1955 disable_intr();
1956 retry:
1957 com->state &= ~CS_TTGO;
1958 txtimeout = tp->t_timeout;
1959 enable_intr();
1960 while ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
1961 != (LSR_TSRE | LSR_TXRDY)) {
1962 tp->t_state |= TS_SO_OCOMPLETE;
1963 error = ttysleep(tp, TSA_OCOMPLETE(tp), TTIPRI | PCATCH,
1964 "siotx", hz / 100);
1965 if ( txtimeout != 0
1966 && (!error || error == EAGAIN)
1967 && (txtimeout -= hz / 100) <= 0
1968 )
1969 error = EIO;
1970 if (com->gone)
1971 error = ENODEV;
1972 if (error != 0 && error != EAGAIN) {
1973 if (!(tp->t_state & TS_TTSTOP)) {
1974 disable_intr();
1975 com->state |= CS_TTGO;
1976 enable_intr();
1977 }
1978 splx(s);
1979 return (error);
1980 }
1981 }
1982
1983 disable_intr(); /* very important while com_data is hidden */
1984
1985 /*
1986 * XXX - clearing CS_TTGO is not sufficient to stop further output,
1987 * because siopoll() calls comstart() which usually sets it again
1988 * because TS_TTSTOP is clear. Setting TS_TTSTOP would not be
1989 * sufficient, for similar reasons.
1990 */
1991 if ((inb(com->line_status_port) & (LSR_TSRE | LSR_TXRDY))
1992 != (LSR_TSRE | LSR_TXRDY))
1993 goto retry;
1994
1995 if (divisor != 0) {
1996 outb(iobase + com_cfcr, cfcr | CFCR_DLAB);
1997 /*
1998 * Only set the divisor registers if they would change,
1999 * since on some 16550 incompatibles (UMC8669F), setting
2000 * them while input is arriving them loses sync until
2001 * data stops arriving.
2002 */
2003 dlbl = divisor & 0xFF;
2004 if (inb(iobase + com_dlbl) != dlbl)
2005 outb(iobase + com_dlbl, dlbl);
2006 dlbh = (u_int) divisor >> 8;
2007 if (inb(iobase + com_dlbh) != dlbh)
2008 outb(iobase + com_dlbh, dlbh);
2009 }
2010 outb(iobase + com_cfcr, com->cfcr_image = cfcr);
2011 if (!(tp->t_state & TS_TTSTOP))
2012 com->state |= CS_TTGO;
2013 if (cflag & CRTS_IFLOW) {
2014 com->state |= CS_RTS_IFLOW;
2015 /*
2016 * If CS_RTS_IFLOW just changed from off to on, the change
2017 * needs to be propagated to MCR_RTS. This isn't urgent,
2018 * so do it later by calling comstart() instead of repeating
2019 * a lot of code from comstart() here.
2020 */
2021 } else if (com->state & CS_RTS_IFLOW) {
2022 com->state &= ~CS_RTS_IFLOW;
2023 /*
2024 * CS_RTS_IFLOW just changed from on to off. Force MCR_RTS
2025 * on here, since comstart() won't do it later.
2026 */
2027 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2028 }
2029
2030 /*
2031 * Set up state to handle output flow control.
2032 * XXX - worth handling MDMBUF (DCD) flow control at the lowest level?
2033 * Now has 10+ msec latency, while CTS flow has 50- usec latency.
2034 */
2035 com->state |= CS_ODEVREADY;
2036 com->state &= ~CS_CTS_OFLOW;
2037 if (cflag & CCTS_OFLOW) {
2038 com->state |= CS_CTS_OFLOW;
2039 if (!(com->last_modem_status & MSR_CTS))
2040 com->state &= ~CS_ODEVREADY;
2041 }
2042 /* XXX shouldn't call functions while intrs are disabled. */
2043 disc_optim(tp, t, com);
2044 /*
2045 * Recover from fiddling with CS_TTGO. We used to call siointr1()
2046 * unconditionally, but that defeated the careful discarding of
2047 * stale input in sioopen().
2048 */
2049 if (com->state >= (CS_BUSY | CS_TTGO))
2050 siointr1(com);
2051
2052 enable_intr();
2053 splx(s);
2054 comstart(tp);
2055 return (0);
2056 }
2057
2058 static void
2059 comstart(tp)
2060 struct tty *tp;
2061 {
2062 struct com_s *com;
2063 int s;
2064 int unit;
2065
2066 unit = DEV_TO_UNIT(tp->t_dev);
2067 com = com_addr(unit);
2068 s = spltty();
2069 disable_intr();
2070 if (tp->t_state & TS_TTSTOP)
2071 com->state &= ~CS_TTGO;
2072 else
2073 com->state |= CS_TTGO;
2074 if (tp->t_state & TS_TBLOCK) {
2075 if (com->mcr_image & MCR_RTS && com->state & CS_RTS_IFLOW)
2076 outb(com->modem_ctl_port, com->mcr_image &= ~MCR_RTS);
2077 } else {
2078 if (!(com->mcr_image & MCR_RTS) && com->iptr < com->ihighwater
2079 && com->state & CS_RTS_IFLOW)
2080 outb(com->modem_ctl_port, com->mcr_image |= MCR_RTS);
2081 }
2082 enable_intr();
2083 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
2084 splx(s);
2085 return;
2086 }
2087 if (tp->t_outq.c_cc != 0) {
2088 struct lbq *qp;
2089 struct lbq *next;
2090
2091 if (!com->obufs[0].l_queued) {
2092 com->obufs[0].l_tail
2093 = com->obuf1 + q_to_b(&tp->t_outq, com->obuf1,
2094 sizeof com->obuf1);
2095 com->obufs[0].l_next = NULL;
2096 com->obufs[0].l_queued = TRUE;
2097 disable_intr();
2098 if (com->state & CS_BUSY) {
2099 qp = com->obufq.l_next;
2100 while ((next = qp->l_next) != NULL)
2101 qp = next;
2102 qp->l_next = &com->obufs[0];
2103 } else {
2104 com->obufq.l_head = com->obufs[0].l_head;
2105 com->obufq.l_tail = com->obufs[0].l_tail;
2106 com->obufq.l_next = &com->obufs[0];
2107 com->state |= CS_BUSY;
2108 }
2109 enable_intr();
2110 }
2111 if (tp->t_outq.c_cc != 0 && !com->obufs[1].l_queued) {
2112 com->obufs[1].l_tail
2113 = com->obuf2 + q_to_b(&tp->t_outq, com->obuf2,
2114 sizeof com->obuf2);
2115 com->obufs[1].l_next = NULL;
2116 com->obufs[1].l_queued = TRUE;
2117 disable_intr();
2118 if (com->state & CS_BUSY) {
2119 qp = com->obufq.l_next;
2120 while ((next = qp->l_next) != NULL)
2121 qp = next;
2122 qp->l_next = &com->obufs[1];
2123 } else {
2124 com->obufq.l_head = com->obufs[1].l_head;
2125 com->obufq.l_tail = com->obufs[1].l_tail;
2126 com->obufq.l_next = &com->obufs[1];
2127 com->state |= CS_BUSY;
2128 }
2129 enable_intr();
2130 }
2131 tp->t_state |= TS_BUSY;
2132 }
2133 disable_intr();
2134 if (com->state >= (CS_BUSY | CS_TTGO))
2135 siointr1(com); /* fake interrupt to start output */
2136 enable_intr();
2137 ttwwakeup(tp);
2138 splx(s);
2139 }
2140
2141 static void
2142 siostop(tp, rw)
2143 struct tty *tp;
2144 int rw;
2145 {
2146 struct com_s *com;
2147
2148 com = com_addr(DEV_TO_UNIT(tp->t_dev));
2149 if (com->gone)
2150 return;
2151 disable_intr();
2152 if (rw & FWRITE) {
2153 #ifdef COM_ESP_BUG_FIXED
2154 if (com->hasfifo)
2155 #ifdef COM_ESP
2156 /* XXX avoid h/w bug. */
2157 if (!com->esp)
2158 #endif
2159 /* XXX does this flush everything? */
2160 outb(com->iobase + com_fifo,
2161 FIFO_XMT_RST | com->fifo_image);
2162 #endif
2163 com->obufs[0].l_queued = FALSE;
2164 com->obufs[1].l_queued = FALSE;
2165 if (com->state & CS_ODONE)
2166 com_events -= LOTS_OF_EVENTS;
2167 com->state &= ~(CS_ODONE | CS_BUSY);
2168 com->tp->t_state &= ~TS_BUSY;
2169 }
2170 if (rw & FREAD) {
2171 #ifdef COM_ESP_BUG_FIXED
2172 if (com->hasfifo)
2173 #ifdef COM_ESP
2174 /* XXX avoid h/w bug. */
2175 if (!com->esp)
2176 #endif
2177 /* XXX does this flush everything? */
2178 outb(com->iobase + com_fifo,
2179 FIFO_RCV_RST | com->fifo_image);
2180 #endif
2181 com_events -= (com->iptr - com->ibuf);
2182 com->iptr = com->ibuf;
2183 }
2184 enable_intr();
2185 comstart(tp);
2186 }
2187
2188 static struct tty *
2189 siodevtotty(dev)
2190 dev_t dev;
2191 {
2192 int mynor;
2193 int unit;
2194
2195 mynor = minor(dev);
2196 if (mynor & CONTROL_MASK)
2197 return (NULL);
2198 unit = MINOR_TO_UNIT(mynor);
2199 if ((u_int) unit >= NSIOTOT)
2200 return (NULL);
2201 return (&sio_tty[unit]);
2202 }
2203
2204 static int
2205 commctl(com, bits, how)
2206 struct com_s *com;
2207 int bits;
2208 int how;
2209 {
2210 int mcr;
2211 int msr;
2212
2213 if (how == DMGET) {
2214 bits = TIOCM_LE; /* XXX - always enabled while open */
2215 mcr = com->mcr_image;
2216 if (mcr & MCR_DTR)
2217 bits |= TIOCM_DTR;
2218 if (mcr & MCR_RTS)
2219 bits |= TIOCM_RTS;
2220 msr = com->prev_modem_status;
2221 if (msr & MSR_CTS)
2222 bits |= TIOCM_CTS;
2223 if (msr & MSR_DCD)
2224 bits |= TIOCM_CD;
2225 if (msr & MSR_DSR)
2226 bits |= TIOCM_DSR;
2227 /*
2228 * XXX - MSR_RI is naturally volatile, and we make MSR_TERI
2229 * more volatile by reading the modem status a lot. Perhaps
2230 * we should latch both bits until the status is read here.
2231 */
2232 if (msr & (MSR_RI | MSR_TERI))
2233 bits |= TIOCM_RI;
2234 return (bits);
2235 }
2236 mcr = 0;
2237 if (bits & TIOCM_DTR)
2238 mcr |= MCR_DTR;
2239 if (bits & TIOCM_RTS)
2240 mcr |= MCR_RTS;
2241 if (com->gone)
2242 return(0);
2243 disable_intr();
2244 switch (how) {
2245 case DMSET:
2246 outb(com->modem_ctl_port,
2247 com->mcr_image = mcr | (com->mcr_image & MCR_IENABLE));
2248 break;
2249 case DMBIS:
2250 outb(com->modem_ctl_port, com->mcr_image |= mcr);
2251 break;
2252 case DMBIC:
2253 outb(com->modem_ctl_port, com->mcr_image &= ~mcr);
2254 break;
2255 }
2256 enable_intr();
2257 return (0);
2258 }
2259
2260 static void
2261 siosettimeout()
2262 {
2263 struct com_s *com;
2264 bool_t someopen;
2265 int unit;
2266
2267 /*
2268 * Set our timeout period to 1 second if no polled devices are open.
2269 * Otherwise set it to max(1/200, 1/hz).
2270 * Enable timeouts iff some device is open.
2271 */
2272 untimeout(comwakeup, (void *)NULL);
2273 sio_timeout = hz;
2274 someopen = FALSE;
2275 for (unit = 0; unit < NSIOTOT; ++unit) {
2276 com = com_addr(unit);
2277 if (com != NULL && com->tp != NULL
2278 && com->tp->t_state & TS_ISOPEN && !com->gone) {
2279 someopen = TRUE;
2280 if (com->poll || com->poll_output) {
2281 sio_timeout = hz > 200 ? hz / 200 : 1;
2282 break;
2283 }
2284 }
2285 }
2286 if (someopen) {
2287 sio_timeouts_until_log = hz / sio_timeout;
2288 timeout(comwakeup, (void *)NULL, sio_timeout);
2289 } else {
2290 /* Flush error messages, if any. */
2291 sio_timeouts_until_log = 1;
2292 comwakeup((void *)NULL);
2293 untimeout(comwakeup, (void *)NULL);
2294 }
2295 }
2296
2297 static void
2298 comwakeup(chan)
2299 void *chan;
2300 {
2301 struct com_s *com;
2302 int unit;
2303
2304 timeout(comwakeup, (void *)NULL, sio_timeout);
2305
2306 /*
2307 * Recover from lost output interrupts.
2308 * Poll any lines that don't use interrupts.
2309 */
2310 for (unit = 0; unit < NSIOTOT; ++unit) {
2311 com = com_addr(unit);
2312 if (com != NULL && !com->gone
2313 && (com->state >= (CS_BUSY | CS_TTGO) || com->poll)) {
2314 disable_intr();
2315 siointr1(com);
2316 enable_intr();
2317 }
2318 }
2319
2320 /*
2321 * Check for and log errors, but not too often.
2322 */
2323 if (--sio_timeouts_until_log > 0)
2324 return;
2325 sio_timeouts_until_log = hz / sio_timeout;
2326 for (unit = 0; unit < NSIOTOT; ++unit) {
2327 int errnum;
2328
2329 com = com_addr(unit);
2330 if (com == NULL)
2331 continue;
2332 if (com->gone)
2333 continue;
2334 for (errnum = 0; errnum < CE_NTYPES; ++errnum) {
2335 u_int delta;
2336 u_long total;
2337
2338 disable_intr();
2339 delta = com->delta_error_counts[errnum];
2340 com->delta_error_counts[errnum] = 0;
2341 enable_intr();
2342 if (delta == 0)
2343 continue;
2344 total = com->error_counts[errnum] += delta;
2345 log(LOG_ERR, "sio%d: %u more %s%s (total %lu)\n",
2346 unit, delta, error_desc[errnum],
2347 delta == 1 ? "" : "s", total);
2348 }
2349 }
2350 }
2351
2352 static void
2353 disc_optim(tp, t, com)
2354 struct tty *tp;
2355 struct termios *t;
2356 struct com_s *com;
2357 {
2358 if (!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
2359 && (!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
2360 && (!(t->c_iflag & PARMRK)
2361 || (t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
2362 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
2363 && linesw[tp->t_line].l_rint == ttyinput)
2364 tp->t_state |= TS_CAN_BYPASS_L_RINT;
2365 else
2366 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
2367 /*
2368 * Prepare to reduce input latency for packet
2369 * discplines with a end of packet character.
2370 */
2371 if (tp->t_line == SLIPDISC)
2372 com->hotchar = 0xc0;
2373 else if (tp->t_line == PPPDISC)
2374 com->hotchar = 0x7e;
2375 else
2376 com->hotchar = 0;
2377 }
2378
2379 /*
2380 * Following are all routines needed for SIO to act as console
2381 */
2382 #include <machine/cons.h>
2383
2384 struct siocnstate {
2385 u_char dlbl;
2386 u_char dlbh;
2387 u_char ier;
2388 u_char cfcr;
2389 u_char mcr;
2390 };
2391
2392 static void siocnclose __P((struct siocnstate *sp));
2393 static void siocnopen __P((struct siocnstate *sp));
2394 static void siocntxwait __P((void));
2395
2396 static void
2397 siocntxwait()
2398 {
2399 int timo;
2400
2401 /*
2402 * Wait for any pending transmission to finish. Required to avoid
2403 * the UART lockup bug when the speed is changed, and for normal
2404 * transmits.
2405 */
2406 timo = 100000;
2407 while ((inb(siocniobase + com_lsr) & (LSR_TSRE | LSR_TXRDY))
2408 != (LSR_TSRE | LSR_TXRDY) && --timo != 0)
2409 ;
2410 }
2411
2412 static void
2413 siocnopen(sp)
2414 struct siocnstate *sp;
2415 {
2416 int divisor;
2417 u_char dlbh;
2418 u_char dlbl;
2419 Port_t iobase;
2420
2421 /*
2422 * Save all the device control registers except the fifo register
2423 * and set our default ones (cs8 -parenb speed=comdefaultrate).
2424 * We can't save the fifo register since it is read-only.
2425 */
2426 iobase = siocniobase;
2427 sp->ier = inb(iobase + com_ier);
2428 outb(iobase + com_ier, 0); /* spltty() doesn't stop siointr() */
2429 siocntxwait();
2430 sp->cfcr = inb(iobase + com_cfcr);
2431 outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
2432 sp->dlbl = inb(iobase + com_dlbl);
2433 sp->dlbh = inb(iobase + com_dlbh);
2434 /*
2435 * Only set the divisor registers if they would change, since on
2436 * some 16550 incompatibles (Startech), setting them clears the
2437 * data input register. This also reduces the effects of the
2438 * UMC8669F bug.
2439 */
2440 divisor = ttspeedtab(comdefaultrate, comspeedtab);
2441 dlbl = divisor & 0xFF;
2442 if (sp->dlbl != dlbl)
2443 outb(iobase + com_dlbl, dlbl);
2444 dlbh = (u_int) divisor >> 8;
2445 if (sp->dlbh != dlbh)
2446 outb(iobase + com_dlbh, dlbh);
2447 outb(iobase + com_cfcr, CFCR_8BITS);
2448 sp->mcr = inb(iobase + com_mcr);
2449 /*
2450 * We don't want interrupts, but must be careful not to "disable"
2451 * them by clearing the MCR_IENABLE bit, since that might cause
2452 * an interrupt by floating the IRQ line.
2453 */
2454 outb(iobase + com_mcr, (sp->mcr & MCR_IENABLE) | MCR_DTR | MCR_RTS);
2455 }
2456
2457 static void
2458 siocnclose(sp)
2459 struct siocnstate *sp;
2460 {
2461 Port_t iobase;
2462
2463 /*
2464 * Restore the device control registers.
2465 */
2466 siocntxwait();
2467 iobase = siocniobase;
2468 outb(iobase + com_cfcr, CFCR_DLAB | CFCR_8BITS);
2469 if (sp->dlbl != inb(iobase + com_dlbl))
2470 outb(iobase + com_dlbl, sp->dlbl);
2471 if (sp->dlbh != inb(iobase + com_dlbh))
2472 outb(iobase + com_dlbh, sp->dlbh);
2473 outb(iobase + com_cfcr, sp->cfcr);
2474 /*
2475 * XXX damp oscillations of MCR_DTR and MCR_RTS by not restoring them.
2476 */
2477 outb(iobase + com_mcr, sp->mcr | MCR_DTR | MCR_RTS);
2478 outb(iobase + com_ier, sp->ier);
2479 }
2480
2481 void
2482 siocnprobe(cp)
2483 struct consdev *cp;
2484 {
2485 int unit;
2486
2487 /* XXX: ick */
2488 unit = DEV_TO_UNIT(CONUNIT);
2489 siocniobase = CONADDR;
2490
2491 /* make sure hardware exists? XXX */
2492
2493 /* initialize required fields */
2494 cp->cn_dev = makedev(CDEV_MAJOR, unit);
2495 #ifdef COMCONSOLE
2496 cp->cn_pri = CN_REMOTE; /* Force a serial port console */
2497 #else
2498 cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL;
2499 #endif
2500 }
2501
2502 void
2503 siocninit(cp)
2504 struct consdev *cp;
2505 {
2506 comconsole = DEV_TO_UNIT(cp->cn_dev);
2507 }
2508
2509 int
2510 siocncheckc(dev)
2511 dev_t dev;
2512 {
2513 int c;
2514 Port_t iobase;
2515 int s;
2516 struct siocnstate sp;
2517
2518 iobase = siocniobase;
2519 s = spltty();
2520 siocnopen(&sp);
2521 if (inb(iobase + com_lsr) & LSR_RXRDY)
2522 c = inb(iobase + com_data);
2523 else
2524 c = -1;
2525 siocnclose(&sp);
2526 splx(s);
2527 return (c);
2528 }
2529
2530
2531 int
2532 siocngetc(dev)
2533 dev_t dev;
2534 {
2535 int c;
2536 Port_t iobase;
2537 int s;
2538 struct siocnstate sp;
2539
2540 iobase = siocniobase;
2541 s = spltty();
2542 siocnopen(&sp);
2543 while (!(inb(iobase + com_lsr) & LSR_RXRDY))
2544 ;
2545 c = inb(iobase + com_data);
2546 siocnclose(&sp);
2547 splx(s);
2548 return (c);
2549 }
2550
2551 void
2552 siocnputc(dev, c)
2553 dev_t dev;
2554 int c;
2555 {
2556 int s;
2557 struct siocnstate sp;
2558
2559 s = spltty();
2560 siocnopen(&sp);
2561 siocntxwait();
2562 outb(siocniobase + com_data, c);
2563 siocnclose(&sp);
2564 splx(s);
2565 }
2566
2567 #ifdef DSI_SOFT_MODEM
2568 /*
2569 * The magic code to download microcode to a "Connection 14.4+Fax"
2570 * modem from Digicom Systems Inc. Very magic.
2571 */
2572
2573 #define DSI_ERROR(str) { ptr = str; goto error; }
2574 static int
2575 LoadSoftModem(int unit, int base_io, u_long size, u_char *ptr)
2576 {
2577 int int_c,int_k;
2578 int data_0188, data_0187;
2579
2580 /*
2581 * First see if it is a DSI SoftModem
2582 */
2583 if(!((inb(base_io+7) ^ inb(base_io+7) & 0x80)))
2584 return ENODEV;
2585
2586 data_0188 = inb(base_io+4);
2587 data_0187 = inb(base_io+3);
2588 outb(base_io+3,0x80);
2589 outb(base_io+4,0x0C);
2590 outb(base_io+0,0x31);
2591 outb(base_io+1,0x8C);
2592 outb(base_io+7,0x10);
2593 outb(base_io+7,0x19);
2594
2595 if(0x18 != (inb(base_io+7) & 0x1A))
2596 DSI_ERROR("dsp bus not granted");
2597
2598 if(0x01 != (inb(base_io+7) & 0x01)) {
2599 outb(base_io+7,0x18);
2600 outb(base_io+7,0x19);
2601 if(0x01 != (inb(base_io+7) & 0x01))
2602 DSI_ERROR("program mem not granted");
2603 }
2604
2605 int_c = 0;
2606
2607 while(1) {
2608 if(int_c >= 7 || size <= 0x1800)
2609 break;
2610
2611 for(int_k = 0 ; int_k < 0x800; int_k++) {
2612 outb(base_io+0,*ptr++);
2613 outb(base_io+1,*ptr++);
2614 outb(base_io+2,*ptr++);
2615 }
2616
2617 size -= 0x1800;
2618 int_c++;
2619 }
2620
2621 if(size > 0x1800) {
2622 outb(base_io+7,0x18);
2623 outb(base_io+7,0x19);
2624 if(0x00 != (inb(base_io+7) & 0x01))
2625 DSI_ERROR("program data not granted");
2626
2627 for(int_k = 0 ; int_k < 0x800; int_k++) {
2628 outb(base_io+1,*ptr++);
2629 outb(base_io+2,0);
2630 outb(base_io+1,*ptr++);
2631 outb(base_io+2,*ptr++);
2632 }
2633
2634 size -= 0x1800;
2635
2636 while(size > 0x1800) {
2637 for(int_k = 0 ; int_k < 0xC00; int_k++) {
2638 outb(base_io+1,*ptr++);
2639 outb(base_io+2,*ptr++);
2640 }
2641 size -= 0x1800;
2642 }
2643
2644 if(size < 0x1800) {
2645 for(int_k=0;int_k<size/2;int_k++) {
2646 outb(base_io+1,*ptr++);
2647 outb(base_io+2,*ptr++);
2648 }
2649 }
2650
2651 } else if (size > 0) {
2652 if(int_c == 7) {
2653 outb(base_io+7,0x18);
2654 outb(base_io+7,0x19);
2655 if(0x00 != (inb(base_io+7) & 0x01))
2656 DSI_ERROR("program data not granted");
2657 for(int_k = 0 ; int_k < size/3; int_k++) {
2658 outb(base_io+1,*ptr++);
2659 outb(base_io+2,0);
2660 outb(base_io+1,*ptr++);
2661 outb(base_io+2,*ptr++);
2662 }
2663 } else {
2664 for(int_k = 0 ; int_k < size/3; int_k++) {
2665 outb(base_io+0,*ptr++);
2666 outb(base_io+1,*ptr++);
2667 outb(base_io+2,*ptr++);
2668 }
2669 }
2670 }
2671 outb(base_io+7,0x11);
2672 outb(base_io+7,3);
2673
2674 outb(base_io+4,data_0188 & 0xfb);
2675
2676 outb(base_io+3,data_0187);
2677
2678 return 0;
2679 error:
2680 printf("sio%d: DSI SoftModem microcode load failed: <%s>\n",unit,ptr);
2681 outb(base_io+7,0x00); \
2682 outb(base_io+3,data_0187); \
2683 outb(base_io+4,data_0188); \
2684 return EIO;
2685 }
2686 #endif /* DSI_SOFT_MODEM */
2687
2688 /*
2689 * support PnP cards if we are using 'em
2690 */
2691
2692 #if NPNP > 0
2693
2694 static struct siopnp_ids {
2695 u_long vend_id;
2696 char *id_str;
2697 } siopnp_ids[] = {
2698 { 0x8113b04e, "Supra1381"},
2699 { 0x9012b04e, "Supra1290"},
2700 { 0x11007256, "USR0011"},
2701 { 0 }
2702 };
2703
2704 static char *siopnp_probe(u_long csn, u_long vend_id);
2705 static void siopnp_attach(u_long csn, u_long vend_id, char *name,
2706 struct isa_device *dev);
2707 static u_long nsiopnp = NSIO;
2708
2709 static struct pnp_device siopnp = {
2710 "siopnp",
2711 siopnp_probe,
2712 siopnp_attach,
2713 &nsiopnp,
2714 &tty_imask
2715 };
2716 DATA_SET (pnpdevice_set, siopnp);
2717
2718 static char *
2719 siopnp_probe(u_long csn, u_long vend_id)
2720 {
2721 struct siopnp_ids *ids;
2722 char *s = NULL;
2723
2724 for(ids = siopnp_ids; ids->vend_id != 0; ids++) {
2725 if (vend_id == ids->vend_id) {
2726 s = ids->id_str;
2727 break;
2728 }
2729 }
2730
2731 if (s) {
2732 struct pnp_cinfo d;
2733 read_pnp_parms(&d, 0);
2734 if (d.enable == 0 || d.flags & 1) {
2735 printf("CSN %d is disabled.\n", csn);
2736 return (NULL);
2737 }
2738
2739 }
2740
2741 return (s);
2742 }
2743
2744 static void
2745 siopnp_attach(u_long csn, u_long vend_id, char *name, struct isa_device *dev)
2746 {
2747 struct pnp_cinfo d;
2748 struct isa_device *dvp;
2749
2750 if (dev->id_unit >= NSIOTOT)
2751 return;
2752
2753 if (read_pnp_parms(&d, 0) == 0) {
2754 printf("failed to read pnp parms\n");
2755 return;
2756 }
2757
2758 write_pnp_parms(&d, 0);
2759
2760 enable_pnp_card();
2761
2762 dev->id_iobase = d.port[0];
2763 dev->id_irq = (1 << d.irq[0]);
2764 dev->id_intr = siointr;
2765 dev->id_ri_flags = RI_FAST;
2766 dev->id_drq = -1;
2767
2768 if (dev->id_driver == NULL) {
2769 dev->id_driver = &siodriver;
2770 dvp = find_isadev(isa_devtab_tty, &siodriver, 0);
2771 if (dvp != NULL)
2772 dev->id_id = dvp->id_id;
2773 }
2774
2775 if ((dev->id_alive = sioprobe(dev)) != 0)
2776 sioattach(dev);
2777 else
2778 printf("sio%d: probe failed\n", dev->id_unit);
2779 }
2780 #endif
Cache object: a646d7c934e69c70bfdafb7ff1dcf5c3
|