]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/si/si.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / dev / si / si.c
1 /*-
2  * Device driver for Specialix range (SI/XIO) of serial line multiplexors.
3  *
4  * Copyright (C) 1990, 1992, 1998 Specialix International,
5  * Copyright (C) 1993, Andy Rutter <andy@acronym.co.uk>
6  * Copyright (C) 2000, Peter Wemm <peter@netplex.com.au>
7  *
8  * Originally derived from:     SunOS 4.x version
9  * Ported from BSDI version to FreeBSD by Peter Wemm.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notices, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notices, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *      This product includes software developed by Andy Rutter of
22  *      Advanced Methods and Tools Ltd. based on original information
23  *      from Specialix International.
24  * 4. Neither the name of Advanced Methods and Tools, nor Specialix
25  *    International may be used to endorse or promote products derived from
26  *    this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
29  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
31  * NO EVENT SHALL THE AUTHORS BE LIABLE.
32  *
33  */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 #ifndef lint
39 static const char si_copyright1[] =  "@(#) Copyright (C) Specialix International, 1990,1992,1998",
40                   si_copyright2[] =  "@(#) Copyright (C) Andy Rutter 1993",
41                   si_copyright3[] =  "@(#) Copyright (C) Peter Wemm 2000";
42 #endif  /* not lint */
43
44 #include "opt_compat.h"
45 #include "opt_debug_si.h"
46 #include "opt_eisa.h"
47 #include "opt_tty.h"
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/serial.h>
52 #include <sys/tty.h>
53 #include <sys/conf.h>
54 #include <sys/fcntl.h>
55 #include <sys/kernel.h>
56 #include <sys/malloc.h>
57 #include <sys/priv.h>
58 #include <sys/sysctl.h>
59 #include <sys/bus.h>
60 #include <machine/bus.h>
61 #include <sys/rman.h>
62 #include <machine/resource.h>
63
64
65 #include <vm/vm.h>
66 #include <vm/pmap.h>
67
68 #include <machine/stdarg.h>
69
70 #include <dev/si/sireg.h>
71 #include <dev/si/sivar.h>
72 #include <dev/si/si.h>
73
74 /*
75  * This device driver is designed to interface the Specialix International
76  * SI, XIO and SX range of serial multiplexor cards to FreeBSD on an ISA,
77  * EISA or PCI bus machine.
78  *
79  * The controller is interfaced to the host via dual port RAM
80  * and an interrupt.
81  *
82  * The code for the Host 1 (very old ISA cards) has not been tested.
83  */
84
85 #define POLL            /* turn on poller to scan for lost interrupts */
86 #define REALPOLL        /* on each poll, scan for work regardless */
87 #define POLLHZ  (hz/10) /* 10 times per second */
88 #define SI_I_HIGH_WATER (TTYHOG - 2 * SI_BUFFERSIZE)
89 #define INT_COUNT 25000         /* max of 125 ints per second */
90 #define JET_INT_COUNT 100       /* max of 100 ints per second */
91 #define RXINT_COUNT 1   /* one rxint per 10 milliseconds */
92
93 static void si_command(struct si_port *, int, int);
94 static int si_Sioctl(struct cdev *, u_long, caddr_t, int, struct thread *);
95 static void si_start(struct tty *);
96 static void si_stop(struct tty *, int);
97 static timeout_t si_lstart;
98
99 static t_break_t sibreak;
100 static t_close_t siclose;
101 static t_modem_t simodem;
102 static t_open_t siopen;
103
104 static int      siparam(struct tty *, struct termios *);
105
106 static void     si_modem_state(struct si_port *pp, struct tty *tp, int hi_ip);
107 static char *   si_modulename(int host_type, int uart_type);
108
109 static struct cdevsw si_Scdevsw = {
110         .d_version =    D_VERSION,
111         .d_ioctl =      si_Sioctl,
112         .d_name =       "si",
113         .d_flags =      D_TTY | D_NEEDGIANT,
114 };
115
116 static int si_Nports;
117 static int si_Nmodules;
118 static int si_debug = 0;        /* data, not bss, so it's patchable */
119
120 SYSCTL_INT(_machdep, OID_AUTO, si_debug, CTLFLAG_RW, &si_debug, 0, "");
121 TUNABLE_INT("machdep.si_debug", &si_debug);
122
123 static int si_numunits;
124
125 devclass_t si_devclass;
126
127 #ifndef B2000   /* not standard, but the hardware knows it. */
128 # define B2000 2000
129 #endif
130 static struct speedtab bdrates[] = {
131         { B75,          CLK75, },       /* 0x0 */
132         { B110,         CLK110, },      /* 0x1 */
133         { B150,         CLK150, },      /* 0x3 */
134         { B300,         CLK300, },      /* 0x4 */
135         { B600,         CLK600, },      /* 0x5 */
136         { B1200,        CLK1200, },     /* 0x6 */
137         { B2000,        CLK2000, },     /* 0x7 */
138         { B2400,        CLK2400, },     /* 0x8 */
139         { B4800,        CLK4800, },     /* 0x9 */
140         { B9600,        CLK9600, },     /* 0xb */
141         { B19200,       CLK19200, },    /* 0xc */
142         { B38400,       CLK38400, },    /* 0x2 (out of order!) */
143         { B57600,       CLK57600, },    /* 0xd */
144         { B115200,      CLK110, },      /* 0x1 (dupe!, 110 baud on "si") */
145         { -1,           -1 },
146 };
147
148
149 /* populated with approx character/sec rates - translated at card
150  * initialisation time to chars per tick of the clock */
151 static int done_chartimes = 0;
152 static struct speedtab chartimes[] = {
153         { B75,          8, },
154         { B110,         11, },
155         { B150,         15, },
156         { B300,         30, },
157         { B600,         60, },
158         { B1200,        120, },
159         { B2000,        200, },
160         { B2400,        240, },
161         { B4800,        480, },
162         { B9600,        960, },
163         { B19200,       1920, },
164         { B38400,       3840, },
165         { B57600,       5760, },
166         { B115200,      11520, },
167         { -1,           -1 },
168 };
169 static volatile int in_intr = 0;        /* Inside interrupt handler? */
170
171 #ifdef POLL
172 static int si_pollrate;                 /* in addition to irq */
173 static int si_realpoll = 0;             /* poll HW on timer */
174
175 SYSCTL_INT(_machdep, OID_AUTO, si_pollrate, CTLFLAG_RW, &si_pollrate, 0, "");
176 SYSCTL_INT(_machdep, OID_AUTO, si_realpoll, CTLFLAG_RW, &si_realpoll, 0, "");
177
178 static int init_finished = 0;
179 static void si_poll(void *);
180 #endif
181
182 /*
183  * Array of adapter types and the corresponding RAM size. The order of
184  * entries here MUST match the ordinal of the adapter type.
185  */
186 static const char *si_type[] = {
187         "EMPTY",
188         "SIHOST",
189         "SIMCA",                /* FreeBSD does not support Microchannel */
190         "SIHOST2",
191         "SIEISA",
192         "SIPCI",
193         "SXPCI",
194         "SXISA",
195 };
196
197 /*
198  * We have to make an 8 bit version of bcopy, since some cards can't
199  * deal with 32 bit I/O
200  */
201 static void __inline
202 si_bcopy(const void *src, void *dst, size_t len)
203 {
204         u_char *d;
205         const u_char *s;
206
207         d = dst;
208         s = src;
209         while (len--)
210                 *d++ = *s++;
211 }
212 static void __inline
213 si_vbcopy(const volatile void *src, void *dst, size_t len)
214 {
215         u_char *d;
216         const volatile u_char *s;
217
218         d = dst;
219         s = src;
220         while (len--)
221                 *d++ = *s++;
222 }
223 static void __inline
224 si_bcopyv(const void *src, volatile void *dst, size_t len)
225 {
226         volatile u_char *d;
227         const u_char *s;
228
229         d = dst;
230         s = src;
231         while (len--)
232                 *d++ = *s++;
233 }
234
235 /*
236  * Attach the device.  Initialize the card.
237  */
238 int
239 siattach(device_t dev)
240 {
241         int unit;
242         struct si_softc *sc;
243         struct si_port *pp;
244         struct tty *tp;
245         volatile struct si_channel *ccbp;
246         volatile struct si_reg *regp;
247         volatile caddr_t maddr;
248         struct si_module *modp;
249         struct speedtab *spt;
250         int nmodule, nport, x, y;
251         int uart_type;
252
253         sc = device_get_softc(dev);
254         unit = device_get_unit(dev);
255
256         sc->sc_typename = si_type[sc->sc_type];
257         if (si_numunits < unit + 1)
258                 si_numunits = unit + 1;
259
260         DPRINT((0, DBG_AUTOBOOT, "si%d: siattach\n", unit));
261
262 #ifdef POLL
263         if (si_pollrate == 0) {
264                 si_pollrate = POLLHZ;           /* in addition to irq */
265 #ifdef REALPOLL
266                 si_realpoll = 1;                /* scan always */
267 #endif
268         }
269 #endif
270
271         DPRINT((0, DBG_AUTOBOOT, "si%d: type: %s paddr: %x maddr: %x\n", unit,
272                 sc->sc_typename, sc->sc_paddr, sc->sc_maddr));
273
274         sc->sc_ports = NULL;                    /* mark as uninitialised */
275
276         maddr = sc->sc_maddr;
277
278         /* Stop the CPU first so it won't stomp around while we load */
279
280         switch (sc->sc_type) {
281 #ifdef DEV_EISA
282                 case SIEISA:
283                         outb(sc->sc_iobase + 2, sc->sc_irq << 4);
284 #endif
285                 break;
286                 case SIPCI:
287                         *(maddr+SIPCIRESET) = 0;
288                 break;
289                 case SIJETPCI: /* fall through to JET ISA */
290                 case SIJETISA:
291                         *(maddr+SIJETCONFIG) = 0;
292                 break;
293                 case SIHOST2:
294                         *(maddr+SIPLRESET) = 0;
295                 break;
296                 case SIHOST:
297                         *(maddr+SIRESET) = 0;
298                 break;
299                 default: /* this should never happen */
300                         printf("si%d: unsupported configuration\n", unit);
301                         return EINVAL;
302                 break;
303         }
304
305         /* OK, now lets download the download code */
306
307         if (SI_ISJET(sc->sc_type)) {
308                 DPRINT((0, DBG_DOWNLOAD, "si%d: jet_download: nbytes %d\n",
309                         unit, si3_t225_dsize));
310                 si_bcopy(si3_t225_download, maddr + si3_t225_downloadaddr,
311                         si3_t225_dsize);
312                 DPRINT((0, DBG_DOWNLOAD,
313                         "si%d: jet_bootstrap: nbytes %d -> %x\n",
314                         unit, si3_t225_bsize, si3_t225_bootloadaddr));
315                 si_bcopy(si3_t225_bootstrap, maddr + si3_t225_bootloadaddr,
316                         si3_t225_bsize);
317         } else {
318                 DPRINT((0, DBG_DOWNLOAD, "si%d: si_download: nbytes %d\n",
319                         unit, si2_z280_dsize));
320                 si_bcopy(si2_z280_download, maddr + si2_z280_downloadaddr,
321                         si2_z280_dsize);
322         }
323
324         /* Now start the CPU */
325
326         switch (sc->sc_type) {
327 #ifdef DEV_EISA
328         case SIEISA:
329                 /* modify the download code to tell it that it's on an EISA */
330                 *(maddr + 0x42) = 1;
331                 outb(sc->sc_iobase + 2, (sc->sc_irq << 4) | 4);
332                 (void)inb(sc->sc_iobase + 3); /* reset interrupt */
333                 break;
334 #endif
335         case SIPCI:
336                 /* modify the download code to tell it that it's on a PCI */
337                 *(maddr+0x42) = 1;
338                 *(maddr+SIPCIRESET) = 1;
339                 *(maddr+SIPCIINTCL) = 0;
340                 break;
341         case SIJETPCI:
342                 *(maddr+SIJETRESET) = 0;
343                 *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN;
344                 break;
345         case SIJETISA:
346                 *(maddr+SIJETRESET) = 0;
347                 switch (sc->sc_irq) {
348                 case 9:
349                         *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0x90;
350                         break;
351                 case 10:
352                         *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xa0;
353                         break;
354                 case 11:
355                         *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xb0;
356                         break;
357                 case 12:
358                         *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xc0;
359                         break;
360                 case 15:
361                         *(maddr+SIJETCONFIG) = SIJETBUSEN|SIJETIRQEN|0xf0;
362                         break;
363                 }
364                 break;
365         case SIHOST:
366                 *(maddr+SIRESET_CL) = 0;
367                 *(maddr+SIINTCL_CL) = 0;
368                 break;
369         case SIHOST2:
370                 *(maddr+SIPLRESET) = 0x10;
371                 switch (sc->sc_irq) {
372                 case 11:
373                         *(maddr+SIPLIRQ11) = 0x10;
374                         break;
375                 case 12:
376                         *(maddr+SIPLIRQ12) = 0x10;
377                         break;
378                 case 15:
379                         *(maddr+SIPLIRQ15) = 0x10;
380                         break;
381                 }
382                 *(maddr+SIPLIRQCLR) = 0x10;
383                 break;
384         default: /* this should _REALLY_ never happen */
385                 printf("si%d: Uh, it was supported a second ago...\n", unit);
386                 return EINVAL;
387         }
388
389         DELAY(1000000);                 /* wait around for a second */
390
391         regp = (struct si_reg *)maddr;
392         y = 0;
393                                         /* wait max of 5 sec for init OK */
394         while (regp->initstat == 0 && y++ < 10) {
395                 DELAY(500000);
396         }
397         switch (regp->initstat) {
398         case 0:
399                 printf("si%d: startup timeout - aborting\n", unit);
400                 sc->sc_type = SIEMPTY;
401                 return EINVAL;
402         case 1:
403                 if (SI_ISJET(sc->sc_type)) {
404                         /* set throttle to 100 times per second */
405                         regp->int_count = JET_INT_COUNT;
406                         /* rx_intr_count is a NOP in Jet */
407                 } else {
408                         /* set throttle to 125 times per second */
409                         regp->int_count = INT_COUNT;
410                         /* rx intr max of 25 times per second */
411                         regp->rx_int_count = RXINT_COUNT;
412                 }
413                 regp->int_pending = 0;          /* no intr pending */
414                 regp->int_scounter = 0; /* reset counter */
415                 break;
416         case 0xff:
417                 /*
418                  * No modules found, so give up on this one.
419                  */
420                 printf("si%d: %s - no ports found\n", unit,
421                         si_type[sc->sc_type]);
422                 return 0;
423         default:
424                 printf("si%d: download code version error - initstat %x\n",
425                         unit, regp->initstat);
426                 return EINVAL;
427         }
428
429         /*
430          * First time around the ports just count them in order
431          * to allocate some memory.
432          */
433         nport = 0;
434         modp = (struct si_module *)(maddr + 0x80);
435         for (;;) {
436                 DPRINT((0, DBG_DOWNLOAD, "si%d: ccb addr 0x%x\n", unit, modp));
437                 switch (modp->sm_type) {
438                 case TA4:
439                         DPRINT((0, DBG_DOWNLOAD,
440                                 "si%d: Found old TA4 module, 4 ports\n",
441                                 unit));
442                         x = 4;
443                         break;
444                 case TA8:
445                         DPRINT((0, DBG_DOWNLOAD,
446                                 "si%d: Found old TA8 module, 8 ports\n",
447                                 unit));
448                         x = 8;
449                         break;
450                 case TA4_ASIC:
451                         DPRINT((0, DBG_DOWNLOAD,
452                                 "si%d: Found ASIC TA4 module, 4 ports\n",
453                                 unit));
454                         x = 4;
455                         break;
456                 case TA8_ASIC:
457                         DPRINT((0, DBG_DOWNLOAD,
458                                 "si%d: Found ASIC TA8 module, 8 ports\n",
459                                 unit));
460                         x = 8;
461                         break;
462                 case MTA:
463                         DPRINT((0, DBG_DOWNLOAD,
464                                 "si%d: Found CD1400 module, 8 ports\n",
465                                 unit));
466                         x = 8;
467                         break;
468                 case SXDC:
469                         DPRINT((0, DBG_DOWNLOAD,
470                                 "si%d: Found SXDC module, 8 ports\n",
471                                 unit));
472                         x = 8;
473                         break;
474                 default:
475                         printf("si%d: unknown module type %d\n",
476                                 unit, modp->sm_type);
477                         goto try_next;
478                 }
479
480                 /* this was limited in firmware and is also a driver issue */
481                 if ((nport + x) > SI_MAXPORTPERCARD) {
482                         printf("si%d: extra ports ignored\n", unit);
483                         goto try_next;
484                 }
485
486                 nport += x;
487                 si_Nports += x;
488                 si_Nmodules++;
489
490 try_next:
491                 if (modp->sm_next == 0)
492                         break;
493                 modp = (struct si_module *)
494                         (maddr + (unsigned)(modp->sm_next & 0x7fff));
495         }
496         sc->sc_ports = (struct si_port *)malloc(sizeof(struct si_port) * nport,
497                 M_DEVBUF, M_NOWAIT | M_ZERO);
498         if (sc->sc_ports == 0) {
499                 printf("si%d: fail to malloc memory for port structs\n",
500                         unit);
501                 return EINVAL;
502         }
503         sc->sc_nport = nport;
504
505         /*
506          * Scan round the ports again, this time initialising.
507          */
508         pp = sc->sc_ports;
509         nmodule = 0;
510         modp = (struct si_module *)(maddr + 0x80);
511         uart_type = 1000;       /* arbitary, > uchar_max */
512         for (;;) {
513                 switch (modp->sm_type) {
514                 case TA4:
515                         nport = 4;
516                         break;
517                 case TA8:
518                         nport = 8;
519                         break;
520                 case TA4_ASIC:
521                         nport = 4;
522                         break;
523                 case TA8_ASIC:
524                         nport = 8;
525                         break;
526                 case MTA:
527                         nport = 8;
528                         break;
529                 case SXDC:
530                         nport = 8;
531                         break;
532                 default:
533                         goto try_next2;
534                 }
535                 nmodule++;
536                 ccbp = (struct si_channel *)((char *)modp + 0x100);
537                 if (uart_type == 1000)
538                         uart_type = ccbp->type;
539                 else if (uart_type != ccbp->type)
540                         printf("si%d: Warning: module %d mismatch! (%d%s != %d%s)\n",
541                             unit, nmodule,
542                             ccbp->type, si_modulename(sc->sc_type, ccbp->type),
543                             uart_type, si_modulename(sc->sc_type, uart_type));
544
545                 for (x = 0; x < nport; x++, pp++, ccbp++) {
546                         pp->sp_ccb = ccbp;      /* save the address */
547                         pp->sp_pend = IDLE_CLOSE;
548                         pp->sp_state = 0;       /* internal flag */
549 #ifdef SI_DEBUG
550                         sprintf(pp->sp_name, "si%r%r", unit,
551                             (int)(pp - sc->sc_ports));
552 #endif
553                         tp = pp->sp_tty = ttyalloc();
554                         tp->t_sc = pp;
555                         tp->t_break = sibreak;
556                         tp->t_close = siclose;
557                         tp->t_modem = simodem;
558                         tp->t_open = siopen;
559                         tp->t_oproc = si_start;
560                         tp->t_param = siparam;
561                         tp->t_stop = si_stop;
562                         ttycreate(tp, TS_CALLOUT, "A%r%r", unit,
563                             (int)(pp - sc->sc_ports));
564                 }
565 try_next2:
566                 if (modp->sm_next == 0) {
567                         printf("si%d: card: %s, ports: %d, modules: %d, type: %d%s\n",
568                                 unit,
569                                 sc->sc_typename,
570                                 sc->sc_nport,
571                                 nmodule,
572                                 uart_type,
573                                 si_modulename(sc->sc_type, uart_type));
574                         break;
575                 }
576                 modp = (struct si_module *)
577                         (maddr + (unsigned)(modp->sm_next & 0x7fff));
578         }
579         if (done_chartimes == 0) {
580                 for (spt = chartimes ; spt->sp_speed != -1; spt++) {
581                         if ((spt->sp_code /= hz) == 0)
582                                 spt->sp_code = 1;
583                 }
584                 done_chartimes = 1;
585         }
586
587         if (unit == 0)
588                 make_dev(&si_Scdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
589                     "si_control");
590         return (0);
591 }
592
593 static  int
594 siopen(struct tty *tp, struct cdev *dev)
595 {
596
597 #ifdef  POLL
598         /*
599          * We've now got a device, so start the poller.
600          */
601         if (init_finished == 0) {
602                 timeout(si_poll, (caddr_t)0L, si_pollrate);
603                 init_finished = 1;
604         }
605 #endif
606         return(0);
607 }
608
609 static void
610 siclose(struct tty *tp)
611 {
612         struct si_port *pp;
613
614         pp = tp->t_sc;
615         (void) si_command(pp, FCLOSE, SI_NOWAIT);
616 }
617
618 static void
619 sibreak(struct tty *tp, int sig)
620 {
621         struct si_port *pp;
622
623         pp = tp->t_sc;
624         if (sig)
625                 si_command(pp, SBREAK, SI_WAIT);
626         else
627                 si_command(pp, EBREAK, SI_WAIT);
628 }
629
630
631 /*
632  * Handle the Specialix ioctls on the control dev.
633  */
634 static int
635 si_Sioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
636 {
637         struct si_softc *xsc;
638         struct si_port *xpp;
639         volatile struct si_reg *regp;
640         struct si_tcsi *dp;
641         struct si_pstat *sps;
642         int *ip, error = 0;
643         int oldspl;
644         int card, port;
645
646         DPRINT((0, DBG_ENTRY|DBG_IOCTL, "si_Sioctl(%s,%lx,%x,%x)\n",
647                 devtoname(dev), cmd, data, flag));
648
649 #if 1
650         DPRINT((0, DBG_IOCTL, "TCSI_PORT=%x\n", TCSI_PORT));
651         DPRINT((0, DBG_IOCTL, "TCSI_CCB=%x\n", TCSI_CCB));
652         DPRINT((0, DBG_IOCTL, "TCSI_TTY=%x\n", TCSI_TTY));
653 #endif
654
655         oldspl = spltty();      /* better safe than sorry */
656
657         ip = (int *)data;
658
659 #define SUCHECK if ((error = priv_check(td, PRIV_DRIVER))) goto out
660
661         switch (cmd) {
662         case TCSIPORTS:
663                 *ip = si_Nports;
664                 goto out;
665         case TCSIMODULES:
666                 *ip = si_Nmodules;
667                 goto out;
668         case TCSISDBG_ALL:
669                 SUCHECK;
670                 si_debug = *ip;
671                 goto out;
672         case TCSIGDBG_ALL:
673                 *ip = si_debug;
674                 goto out;
675         default:
676                 /*
677                  * Check that a controller for this port exists
678                  */
679
680                 /* may also be a struct si_pstat, a superset of si_tcsi */
681
682                 dp = (struct si_tcsi *)data;
683                 sps = (struct si_pstat *)data;
684                 card = dp->tc_card;
685                 xsc = devclass_get_softc(si_devclass, card);    /* check.. */
686                 if (xsc == NULL || xsc->sc_type == SIEMPTY) {
687                         error = ENOENT;
688                         goto out;
689                 }
690                 /*
691                  * And check that a port exists
692                  */
693                 port = dp->tc_port;
694                 if (port < 0 || port >= xsc->sc_nport) {
695                         error = ENOENT;
696                         goto out;
697                 }
698                 xpp = xsc->sc_ports + port;
699                 regp = (struct si_reg *)xsc->sc_maddr;
700         }
701
702         switch (cmd) {
703         case TCSIDEBUG:
704 #ifdef  SI_DEBUG
705                 SUCHECK;
706                 if (xpp->sp_debug)
707                         xpp->sp_debug = 0;
708                 else {
709                         xpp->sp_debug = DBG_ALL;
710                         DPRINT((xpp, DBG_IOCTL, "debug toggled %s\n",
711                                 (xpp->sp_debug&DBG_ALL)?"ON":"OFF"));
712                 }
713                 break;
714 #else
715                 error = ENODEV;
716                 goto out;
717 #endif
718         case TCSISDBG_LEVEL:
719         case TCSIGDBG_LEVEL:
720 #ifdef  SI_DEBUG
721                 if (cmd == TCSIGDBG_LEVEL) {
722                         dp->tc_dbglvl = xpp->sp_debug;
723                 } else {
724                         SUCHECK;
725                         xpp->sp_debug = dp->tc_dbglvl;
726                 }
727                 break;
728 #else
729                 error = ENODEV;
730                 goto out;
731 #endif
732         case TCSIGRXIT:
733                 dp->tc_int = regp->rx_int_count;
734                 break;
735         case TCSIRXIT:
736                 SUCHECK;
737                 regp->rx_int_count = dp->tc_int;
738                 break;
739         case TCSIGIT:
740                 dp->tc_int = regp->int_count;
741                 break;
742         case TCSIIT:
743                 SUCHECK;
744                 regp->int_count = dp->tc_int;
745                 break;
746         case TCSISTATE:
747                 dp->tc_int = xpp->sp_ccb->hi_ip;
748                 break;
749         /* these next three use a different structure */
750         case TCSI_PORT:
751                 SUCHECK;
752                 si_bcopy(xpp, &sps->tc_siport, sizeof(sps->tc_siport));
753                 break;
754         case TCSI_CCB:
755                 SUCHECK;
756                 si_vbcopy(xpp->sp_ccb, &sps->tc_ccb, sizeof(sps->tc_ccb));
757                 break;
758         case TCSI_TTY:
759                 SUCHECK;
760                 si_bcopy(xpp->sp_tty, &sps->tc_tty, sizeof(sps->tc_tty));
761                 break;
762         default:
763                 error = EINVAL;
764                 goto out;
765         }
766 out:
767         splx(oldspl);
768         return(error);          /* success */
769 }
770
771 /*
772  *      siparam()       : Configure line params
773  *      called at spltty();
774  *      this may sleep, does not flush, nor wait for drain, nor block writes
775  *      caller must arrange this if it's important..
776  */
777 static int
778 siparam(struct tty *tp, struct termios *t)
779 {
780         struct si_port *pp = tp->t_sc;
781         volatile struct si_channel *ccbp;
782         int oldspl, cflag, iflag, oflag, lflag;
783         int error = 0;          /* shutup gcc */
784         int ispeed = 0;         /* shutup gcc */
785         int ospeed = 0;         /* shutup gcc */
786         BYTE val;
787
788         DPRINT((pp, DBG_ENTRY|DBG_PARAM, "siparam(%x,%x)\n", tp, t));
789         cflag = t->c_cflag;
790         iflag = t->c_iflag;
791         oflag = t->c_oflag;
792         lflag = t->c_lflag;
793         DPRINT((pp, DBG_PARAM, "OFLAG 0x%x CFLAG 0x%x IFLAG 0x%x LFLAG 0x%x\n",
794                 oflag, cflag, iflag, lflag));
795
796         /* XXX - if Jet host and SXDC module, use extended baud rates */
797
798         /* if not hung up.. */
799         if (t->c_ospeed != 0) {
800                 /* translate baud rate to firmware values */
801                 ospeed = ttspeedtab(t->c_ospeed, bdrates);
802                 ispeed = t->c_ispeed ?
803                          ttspeedtab(t->c_ispeed, bdrates) : ospeed;
804
805                 /* enforce legit baud rate */
806                 if (ospeed < 0 || ispeed < 0)
807                         return (EINVAL);
808         }
809
810         oldspl = spltty();
811
812         ccbp = pp->sp_ccb;
813
814         /* ========== set hi_break ========== */
815         val = 0;
816         if (iflag & IGNBRK)             /* Breaks */
817                 val |= BR_IGN;
818         if (iflag & BRKINT)             /* Interrupt on break? */
819                 val |= BR_INT;
820         if (iflag & PARMRK)             /* Parity mark? */
821                 val |= BR_PARMRK;
822         if (iflag & IGNPAR)             /* Ignore chars with parity errors? */
823                 val |= BR_PARIGN;
824         ccbp->hi_break = val;
825
826         /* ========== set hi_csr ========== */
827         /* if not hung up.. */
828         if (t->c_ospeed != 0) {
829                 /* Set I/O speeds */
830                  val = (ispeed << 4) | ospeed;
831         }
832         ccbp->hi_csr = val;
833
834         /* ========== set hi_mr2 ========== */
835         val = 0;
836         if (cflag & CSTOPB)                             /* Stop bits */
837                 val |= MR2_2_STOP;
838         else
839                 val |= MR2_1_STOP;
840         /*
841          * Enable H/W RTS/CTS handshaking. The default TA/MTA is
842          * a DCE, hence the reverse sense of RTS and CTS
843          */
844         /* Output Flow - RTS must be raised before data can be sent */
845         if (cflag & CCTS_OFLOW)
846                 val |= MR2_RTSCONT;
847
848         ccbp->hi_mr2 = val;
849
850         /* ========== set hi_mr1 ========== */
851         val = 0;
852         if (!(cflag & PARENB))                          /* Parity */
853                 val |= MR1_NONE;
854         else
855                 val |= MR1_WITH;
856         if (cflag & PARODD)
857                 val |= MR1_ODD;
858
859         if ((cflag & CS8) == CS8) {                     /* 8 data bits? */
860                 val |= MR1_8_BITS;
861         } else if ((cflag & CS7) == CS7) {              /* 7 data bits? */
862                 val |= MR1_7_BITS;
863         } else if ((cflag & CS6) == CS6) {              /* 6 data bits? */
864                 val |= MR1_6_BITS;
865         } else {                                        /* Must be 5 */
866                 val |= MR1_5_BITS;
867         }
868         /*
869          * Enable H/W RTS/CTS handshaking. The default TA/MTA is
870          * a DCE, hence the reverse sense of RTS and CTS
871          */
872         /* Input Flow - CTS is raised when port is ready to receive data */
873         if (cflag & CRTS_IFLOW)
874                 val |= MR1_CTSCONT;
875
876         ccbp->hi_mr1 = val;
877
878         /* ========== set hi_mask ========== */
879         val = 0xff;
880         if ((cflag & CS8) == CS8) {                     /* 8 data bits? */
881                 val &= 0xFF;
882         } else if ((cflag & CS7) == CS7) {              /* 7 data bits? */
883                 val &= 0x7F;
884         } else if ((cflag & CS6) == CS6) {              /* 6 data bits? */
885                 val &= 0x3F;
886         } else {                                        /* Must be 5 */
887                 val &= 0x1F;
888         }
889         if (iflag & ISTRIP)
890                 val &= 0x7F;
891
892         ccbp->hi_mask = val;
893
894         /* ========== set hi_prtcl ========== */
895         val = SP_DCEN;          /* Monitor DCD always, or TIOCMGET misses it */
896         if (iflag & IXANY)
897                 val |= SP_TANY;
898         if (iflag & IXON)
899                 val |= SP_TXEN;
900         if (iflag & IXOFF)
901                 val |= SP_RXEN;
902         if (iflag & INPCK)
903                 val |= SP_PAEN;
904
905         ccbp->hi_prtcl = val;
906
907
908         /* ========== set hi_{rx|tx}{on|off} ========== */
909         /* XXX: the card TOTALLY shields us from the flow control... */
910         ccbp->hi_txon = t->c_cc[VSTART];
911         ccbp->hi_txoff = t->c_cc[VSTOP];
912
913         ccbp->hi_rxon = t->c_cc[VSTART];
914         ccbp->hi_rxoff = t->c_cc[VSTOP];
915
916         /* ========== send settings to the card ========== */
917         /* potential sleep here */
918         if (ccbp->hi_stat == IDLE_CLOSE)                /* Not yet open */
919                 si_command(pp, LOPEN, SI_WAIT);         /* open it */
920         else
921                 si_command(pp, CONFIG, SI_WAIT);        /* change params */
922
923         /* ========== set DTR etc ========== */
924         /* Hangup if ospeed == 0 */
925         if (t->c_ospeed == 0) {
926                 (void) simodem(tp, 0, SER_DTR | SER_RTS);
927         } else {
928                 /*
929                  * If the previous speed was 0, may need to re-enable
930                  * the modem signals
931                  */
932                 (void) simodem(tp, SER_DTR | SER_RTS, 0);
933         }
934
935         DPRINT((pp, DBG_PARAM, "siparam, complete: MR1 %x MR2 %x HI_MASK %x PRTCL %x HI_BREAK %x\n",
936                 ccbp->hi_mr1, ccbp->hi_mr2, ccbp->hi_mask, ccbp->hi_prtcl, ccbp->hi_break));
937
938         splx(oldspl);
939         return(error);
940 }
941
942 /*
943  * Set/Get state of modem control lines.
944  * Due to DCE-like behaviour of the adapter, some signals need translation:
945  *      TIOCM_DTR       DSR
946  *      TIOCM_RTS       CTS
947  */
948 static int
949 simodem(struct tty *tp, int sigon, int sigoff)
950 {
951         struct si_port *pp;
952         volatile struct si_channel *ccbp;
953         int x;
954
955         pp = tp->t_sc;
956         DPRINT((pp, DBG_ENTRY|DBG_MODEM, "simodem(%x,%x)\n", sigon, sigoff));
957         ccbp = pp->sp_ccb;              /* Find channel address */
958         if (sigon == 0 && sigoff == 0) {
959                 x = ccbp->hi_ip;
960                 /*
961                  * XXX: not sure this is correct, should it be CTS&DSR ?
962                  * XXX: or do we (just) miss CTS & DSR ?
963                  */
964                 if (x & IP_DCD)         sigon |= SER_DCD;
965                 if (x & IP_DTR)         sigon |= SER_DTR;
966                 if (x & IP_RTS)         sigon |= SER_RTS;
967                 if (x & IP_RI)          sigon |= SER_RI;
968                 return (sigon);
969         }
970
971         x = ccbp->hi_op;
972         if (sigon & SER_DTR)
973                 x |= OP_DSR;
974         if (sigoff & SER_DTR)
975                 x &= ~OP_DSR;
976         if (sigon & SER_RTS)
977                 x |= OP_CTS;
978         if (sigoff & SER_RTS)
979                 x &= ~OP_CTS;
980         ccbp->hi_op = x;
981         return 0;
982 }
983
984 /*
985  * Handle change of modem state
986  */
987 static void
988 si_modem_state(struct si_port *pp, struct tty *tp, int hi_ip)
989 {
990                                                         /* if a modem dev */
991         if (hi_ip & IP_DCD) {
992                 if (!(pp->sp_last_hi_ip & IP_DCD)) {
993                         DPRINT((pp, DBG_INTR, "modem carr on t_line %d\n",
994                                 tp->t_line));
995                         (void)ttyld_modem(tp, 1);
996                 }
997         } else {
998                 if (pp->sp_last_hi_ip & IP_DCD) {
999                         DPRINT((pp, DBG_INTR, "modem carr off\n"));
1000                         if (ttyld_modem(tp, 0))
1001                                 (void) simodem(tp, 0, SER_DTR | SER_RTS);
1002                 }
1003         }
1004         pp->sp_last_hi_ip = hi_ip;
1005
1006 }
1007
1008 /*
1009  * Poller to catch missed interrupts.
1010  *
1011  * Note that the SYSV Specialix drivers poll at 100 times per second to get
1012  * better response.  We could really use a "periodic" version timeout(). :-)
1013  */
1014 #ifdef POLL
1015 static void
1016 si_poll(void *nothing)
1017 {
1018         struct si_softc *sc;
1019         int i;
1020         volatile struct si_reg *regp;
1021         struct si_port *pp;
1022         int lost, oldspl, port;
1023
1024         DPRINT((0, DBG_POLL, "si_poll()\n"));
1025         oldspl = spltty();
1026         if (in_intr)
1027                 goto out;
1028         lost = 0;
1029         for (i = 0; i < si_numunits; i++) {
1030                 sc = devclass_get_softc(si_devclass, i);
1031                 if (sc == NULL || sc->sc_type == SIEMPTY)
1032                         continue;
1033                 regp = (struct si_reg *)sc->sc_maddr;
1034
1035                 /*
1036                  * See if there has been a pending interrupt for 2 seconds
1037                  * or so. The test (int_scounter >= 200) won't correspond
1038                  * to 2 seconds if int_count gets changed.
1039                  */
1040                 if (regp->int_pending != 0) {
1041                         if (regp->int_scounter >= 200 &&
1042                             regp->initstat == 1) {
1043                                 printf("si%d: lost intr\n", i);
1044                                 lost++;
1045                         }
1046                 } else {
1047                         regp->int_scounter = 0;
1048                 }
1049
1050                 /*
1051                  * gripe about no input flow control..
1052                  */
1053                 pp = sc->sc_ports;
1054                 for (port = 0; port < sc->sc_nport; pp++, port++) {
1055                         if (pp->sp_delta_overflows > 0) {
1056                                 printf("si%d: %d tty level buffer overflows\n",
1057                                         i, pp->sp_delta_overflows);
1058                                 pp->sp_delta_overflows = 0;
1059                         }
1060                 }
1061         }
1062         if (lost || si_realpoll)
1063                 si_intr(NULL);  /* call intr with fake vector */
1064 out:
1065         splx(oldspl);
1066
1067         timeout(si_poll, (caddr_t)0L, si_pollrate);
1068 }
1069 #endif  /* ifdef POLL */
1070
1071 /*
1072  * The interrupt handler polls ALL ports on ALL adapters each time
1073  * it is called.
1074  */
1075
1076 static BYTE si_rxbuf[SI_BUFFERSIZE];    /* input staging area */
1077 static BYTE si_txbuf[SI_BUFFERSIZE];    /* output staging area */
1078
1079 void
1080 si_intr(void *arg)
1081 {
1082         struct si_softc *sc;
1083         struct si_port *pp;
1084         volatile struct si_channel *ccbp;
1085         struct tty *tp;
1086         volatile caddr_t maddr;
1087         BYTE op, ip;
1088         int x, card, port, n, i, isopen;
1089         volatile BYTE *z;
1090         BYTE c;
1091
1092         sc = arg;
1093
1094         DPRINT((0, arg == NULL ? DBG_POLL:DBG_INTR, "si_intr\n"));
1095         if (in_intr)
1096                 return;
1097         in_intr = 1;
1098
1099         /*
1100          * When we get an int we poll all the channels and do ALL pending
1101          * work, not just the first one we find. This allows all cards to
1102          * share the same vector.
1103          *
1104          * XXX - But if we're sharing the vector with something that's NOT
1105          * a SI/XIO/SX card, we may be making more work for ourselves.
1106          */
1107         for (card = 0; card < si_numunits; card++) {
1108                 sc = devclass_get_softc(si_devclass, card);
1109                 if (sc == NULL || sc->sc_type == SIEMPTY)
1110                         continue;
1111
1112                 /*
1113                  * First, clear the interrupt
1114                  */
1115                 switch(sc->sc_type) {
1116                 case SIHOST:
1117                         maddr = sc->sc_maddr;
1118                         ((volatile struct si_reg *)maddr)->int_pending = 0;
1119                                                         /* flag nothing pending */
1120                         *(maddr+SIINTCL) = 0x00;        /* Set IRQ clear */
1121                         *(maddr+SIINTCL_CL) = 0x00;     /* Clear IRQ clear */
1122                         break;
1123                 case SIHOST2:
1124                         maddr = sc->sc_maddr;
1125                         ((volatile struct si_reg *)maddr)->int_pending = 0;
1126                         *(maddr+SIPLIRQCLR) = 0x00;
1127                         *(maddr+SIPLIRQCLR) = 0x10;
1128                         break;
1129                 case SIPCI:
1130                         maddr = sc->sc_maddr;
1131                         ((volatile struct si_reg *)maddr)->int_pending = 0;
1132                         *(maddr+SIPCIINTCL) = 0x0;
1133                         break;
1134                 case SIJETPCI:  /* fall through to JETISA case */
1135                 case SIJETISA:
1136                         maddr = sc->sc_maddr;
1137                         ((volatile struct si_reg *)maddr)->int_pending = 0;
1138                         *(maddr+SIJETINTCL) = 0x0;
1139                         break;
1140 #ifdef DEV_EISA
1141                 case SIEISA:
1142                         maddr = sc->sc_maddr;
1143                         ((volatile struct si_reg *)maddr)->int_pending = 0;
1144                         (void)inb(sc->sc_iobase + 3);
1145                         break;
1146 #endif
1147                 case SIEMPTY:
1148                 default:
1149                         continue;
1150                 }
1151                 ((volatile struct si_reg *)maddr)->int_scounter = 0;
1152
1153                 /*
1154                  * check each port
1155                  */
1156                 for (pp = sc->sc_ports, port = 0; port < sc->sc_nport;
1157                      pp++, port++) {
1158                         ccbp = pp->sp_ccb;
1159                         tp = pp->sp_tty;
1160
1161                         /*
1162                          * See if a command has completed ?
1163                          */
1164                         if (ccbp->hi_stat != pp->sp_pend) {
1165                                 DPRINT((pp, DBG_INTR,
1166                                         "si_intr hi_stat = 0x%x, pend = %d\n",
1167                                         ccbp->hi_stat, pp->sp_pend));
1168                                 switch(pp->sp_pend) {
1169                                 case LOPEN:
1170                                 case MPEND:
1171                                 case MOPEN:
1172                                 case CONFIG:
1173                                 case SBREAK:
1174                                 case EBREAK:
1175                                         pp->sp_pend = ccbp->hi_stat;
1176                                                 /* sleeping in si_command */
1177                                         wakeup(&pp->sp_state);
1178                                         break;
1179                                 default:
1180                                         pp->sp_pend = ccbp->hi_stat;
1181                                 }
1182                         }
1183
1184                         /*
1185                          * Continue on if it's closed
1186                          */
1187                         if (ccbp->hi_stat == IDLE_CLOSE) {
1188                                 continue;
1189                         }
1190
1191                         /*
1192                          * Do modem state change if not a local device
1193                          */
1194                         si_modem_state(pp, tp, ccbp->hi_ip);
1195
1196                         /*
1197                          * Check to see if we should 'receive' characters.
1198                          */
1199                         if (tp->t_state & TS_CONNECTED &&
1200                             tp->t_state & TS_ISOPEN)
1201                                 isopen = 1;
1202                         else
1203                                 isopen = 0;
1204
1205                         /*
1206                          * Do input break processing
1207                          */
1208                         if (ccbp->hi_state & ST_BREAK) {
1209                                 if (isopen) {
1210                                     ttyld_rint(tp, TTY_BI);
1211                                 }
1212                                 ccbp->hi_state &= ~ST_BREAK;   /* A Bit iffy this */
1213                                 DPRINT((pp, DBG_INTR, "si_intr break\n"));
1214                         }
1215
1216                         /*
1217                          * Do RX stuff - if not open then dump any characters.
1218                          * XXX: This is VERY messy and needs to be cleaned up.
1219                          *
1220                          * XXX: can we leave data in the host adapter buffer
1221                          * when the clists are full?  That may be dangerous
1222                          * if the user cannot get an interrupt signal through.
1223                          */
1224
1225         more_rx:        /* XXX Sorry. the nesting was driving me bats! :-( */
1226
1227                         if (!isopen) {
1228                                 ccbp->hi_rxopos = ccbp->hi_rxipos;
1229                                 goto end_rx;
1230                         }
1231
1232                         /*
1233                          * If the tty input buffers are blocked, stop emptying
1234                          * the incoming buffers and let the auto flow control
1235                          * assert..
1236                          */
1237                         if (tp->t_state & TS_TBLOCK) {
1238                                 goto end_rx;
1239                         }
1240
1241                         /*
1242                          * Process read characters if not skipped above
1243                          */
1244                         op = ccbp->hi_rxopos;
1245                         ip = ccbp->hi_rxipos;
1246                         c = ip - op;
1247                         if (c == 0) {
1248                                 goto end_rx;
1249                         }
1250
1251                         n = c & 0xff;
1252                         if (n > 250)
1253                                 n = 250;
1254
1255                         DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n",
1256                                                 n, op, ip));
1257
1258                         /*
1259                          * Suck characters out of host card buffer into the
1260                          * "input staging buffer" - so that we dont leave the
1261                          * host card in limbo while we're possibly echoing
1262                          * characters and possibly flushing input inside the
1263                          * ldisc l_rint() routine.
1264                          */
1265                         if (n <= SI_BUFFERSIZE - op) {
1266
1267                                 DPRINT((pp, DBG_INTR, "\tsingle copy\n"));
1268                                 z = ccbp->hi_rxbuf + op;
1269                                 si_vbcopy(z, si_rxbuf, n);
1270
1271                                 op += n;
1272                         } else {
1273                                 x = SI_BUFFERSIZE - op;
1274
1275                                 DPRINT((pp, DBG_INTR, "\tdouble part 1 %d\n", x));
1276                                 z = ccbp->hi_rxbuf + op;
1277                                 si_vbcopy(z, si_rxbuf, x);
1278
1279                                 DPRINT((pp, DBG_INTR, "\tdouble part 2 %d\n",
1280                                         n - x));
1281                                 z = ccbp->hi_rxbuf;
1282                                 si_vbcopy(z, si_rxbuf + x, n - x);
1283
1284                                 op += n;
1285                         }
1286
1287                         /* clear collected characters from buffer */
1288                         ccbp->hi_rxopos = op;
1289
1290                         DPRINT((pp, DBG_INTR, "n = %d, op = %d, ip = %d\n",
1291                                                 n, op, ip));
1292
1293                         /*
1294                          * at this point...
1295                          * n = number of chars placed in si_rxbuf
1296                          */
1297
1298                         /*
1299                          * Avoid the grotesquely inefficient lineswitch
1300                          * routine (ttyinput) in "raw" mode. It usually
1301                          * takes about 450 instructions (that's without
1302                          * canonical processing or echo!). slinput is
1303                          * reasonably fast (usually 40 instructions
1304                          * plus call overhead).
1305                          */
1306                         if (tp->t_state & TS_CAN_BYPASS_L_RINT) {
1307
1308                                 /* block if the driver supports it */
1309                                 if (tp->t_rawq.c_cc + n >= SI_I_HIGH_WATER &&
1310                                     (tp->t_cflag & CRTS_IFLOW ||
1311                                      tp->t_iflag & IXOFF) &&
1312                                     !(tp->t_state & TS_TBLOCK))
1313                                         ttyblock(tp);
1314
1315                                 tk_nin += n;
1316                                 tk_rawcc += n;
1317                                 tp->t_rawcc += n;
1318
1319                                 pp->sp_delta_overflows +=
1320                                     b_to_q((char *)si_rxbuf, n, &tp->t_rawq);
1321
1322                                 ttwakeup(tp);
1323                                 if (tp->t_state & TS_TTSTOP &&
1324                                     (tp->t_iflag & IXANY ||
1325                                      tp->t_cc[VSTART] == tp->t_cc[VSTOP])) {
1326                                         tp->t_state &= ~TS_TTSTOP;
1327                                         tp->t_lflag &= ~FLUSHO;
1328                                         si_start(tp);
1329                                 }
1330                         } else {
1331                                 /*
1332                                  * It'd be nice to not have to go through the
1333                                  * function call overhead for each char here.
1334                                  * It'd be nice to block input it, saving a
1335                                  * loop here and the call/return overhead.
1336                                  */
1337                                 for(x = 0; x < n; x++) {
1338                                         i = si_rxbuf[x];
1339                                         if (ttyld_rint(tp, i)
1340                                              == -1) {
1341                                                 pp->sp_delta_overflows++;
1342                                         }
1343                                 }
1344                         }
1345                         goto more_rx;   /* try for more until RXbuf is empty */
1346
1347         end_rx:         /* XXX: Again, sorry about the gotos.. :-) */
1348
1349                         /*
1350                          * Do TX stuff
1351                          */
1352                         ttyld_start(tp);
1353
1354                 } /* end of for (all ports on this controller) */
1355         } /* end of for (all controllers) */
1356
1357         in_intr = 0;
1358         DPRINT((0, arg == NULL ? DBG_POLL:DBG_INTR, "end si_intr\n"));
1359 }
1360
1361 /*
1362  * Nudge the transmitter...
1363  *
1364  * XXX: I inherited some funny code here.  It implies the host card only
1365  * interrupts when the transmit buffer reaches the low-water-mark, and does
1366  * not interrupt when it's actually hits empty.  In some cases, we have
1367  * processes waiting for complete drain, and we need to simulate an interrupt
1368  * about when we think the buffer is going to be empty (and retry if not).
1369  * I really am not certain about this...  I *need* the hardware manuals.
1370  */
1371 static void
1372 si_start(struct tty *tp)
1373 {
1374         struct si_port *pp;
1375         volatile struct si_channel *ccbp;
1376         struct clist *qp;
1377         BYTE ipos;
1378         int nchar;
1379         int oldspl, count, n, amount, buffer_full;
1380
1381         oldspl = spltty();
1382
1383         qp = &tp->t_outq;
1384         pp = tp->t_sc;
1385
1386         DPRINT((pp, DBG_ENTRY|DBG_START,
1387                 "si_start(%x) t_state %x sp_state %x t_outq.c_cc %d\n",
1388                 tp, tp->t_state, pp->sp_state, qp->c_cc));
1389
1390         if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
1391                 goto out;
1392
1393         buffer_full = 0;
1394         ccbp = pp->sp_ccb;
1395
1396         count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
1397         DPRINT((pp, DBG_START, "count %d\n", (BYTE)count));
1398
1399         while ((nchar = qp->c_cc) > 0) {
1400                 if ((BYTE)count >= 255) {
1401                         buffer_full++;
1402                         break;
1403                 }
1404                 amount = min(nchar, (255 - (BYTE)count));
1405                 ipos = (unsigned int)ccbp->hi_txipos;
1406                 n = q_to_b(&tp->t_outq, si_txbuf, amount);
1407                 /* will it fit in one lump? */
1408                 if ((SI_BUFFERSIZE - ipos) >= n) {
1409                         si_bcopyv(si_txbuf, &ccbp->hi_txbuf[ipos], n);
1410                 } else {
1411                         si_bcopyv(si_txbuf, &ccbp->hi_txbuf[ipos],
1412                                 SI_BUFFERSIZE - ipos);
1413                         si_bcopyv(si_txbuf + (SI_BUFFERSIZE - ipos),
1414                                 &ccbp->hi_txbuf[0], n - (SI_BUFFERSIZE - ipos));
1415                 }
1416                 ccbp->hi_txipos += n;
1417                 count = (int)ccbp->hi_txipos - (int)ccbp->hi_txopos;
1418         }
1419
1420         if (count != 0 && nchar == 0) {
1421                 tp->t_state |= TS_BUSY;
1422         } else {
1423                 tp->t_state &= ~TS_BUSY;
1424         }
1425
1426         /* wakeup time? */
1427         ttwwakeup(tp);
1428
1429         DPRINT((pp, DBG_START, "count %d, nchar %d, tp->t_state 0x%x\n",
1430                 (BYTE)count, nchar, tp->t_state));
1431
1432         if (tp->t_state & TS_BUSY)
1433         {
1434                 int time;
1435
1436                 time = ttspeedtab(tp->t_ospeed, chartimes);
1437
1438                 if (time > 0) {
1439                         if (time < nchar)
1440                                 time = nchar / time;
1441                         else
1442                                 time = 2;
1443                 } else {
1444                         DPRINT((pp, DBG_START,
1445                                 "bad char time value! %d\n", time));
1446                         time = hz/10;
1447                 }
1448
1449                 if ((pp->sp_state & (SS_LSTART|SS_INLSTART)) == SS_LSTART) {
1450                         untimeout(si_lstart, (caddr_t)pp, pp->lstart_ch);
1451                 } else {
1452                         pp->sp_state |= SS_LSTART;
1453                 }
1454                 DPRINT((pp, DBG_START, "arming lstart, time=%d\n", time));
1455                 pp->lstart_ch = timeout(si_lstart, (caddr_t)pp, time);
1456         }
1457
1458 out:
1459         splx(oldspl);
1460         DPRINT((pp, DBG_EXIT|DBG_START, "leave si_start()\n"));
1461 }
1462
1463 /*
1464  * Note: called at splsoftclock from the timeout code
1465  * This has to deal with two things...  cause wakeups while waiting for
1466  * tty drains on last process exit, and call l_start at about the right
1467  * time for protocols like ppp.
1468  */
1469 static void
1470 si_lstart(void *arg)
1471 {
1472         struct si_port *pp = arg;
1473         struct tty *tp;
1474         int oldspl;
1475
1476         DPRINT((pp, DBG_ENTRY|DBG_LSTART, "si_lstart(%x) sp_state %x\n",
1477                 pp, pp->sp_state));
1478
1479         oldspl = spltty();
1480         tp = pp->sp_tty;
1481
1482         if ((tp->t_state & TS_ISOPEN) == 0 ||
1483             (pp->sp_state & SS_LSTART) == 0) {
1484                 splx(oldspl);
1485                 return;
1486         }
1487         pp->sp_state &= ~SS_LSTART;
1488         pp->sp_state |= SS_INLSTART;
1489
1490
1491         /* deal with the process exit case */
1492         ttwwakeup(tp);
1493
1494         /* nudge protocols - eg: ppp */
1495         ttyld_start(tp);
1496
1497         pp->sp_state &= ~SS_INLSTART;
1498         splx(oldspl);
1499 }
1500
1501 /*
1502  * Stop output on a line. called at spltty();
1503  */
1504 static void
1505 si_stop(struct tty *tp, int rw)
1506 {
1507         volatile struct si_channel *ccbp;
1508         struct si_port *pp;
1509
1510         pp = tp->t_sc;
1511         ccbp = pp->sp_ccb;
1512
1513         DPRINT((pp, DBG_ENTRY|DBG_STOP, "si_stop(%x,%x)\n", tp, rw));
1514
1515         /* XXX: must check (rw & FWRITE | FREAD) etc flushing... */
1516         if (rw & FWRITE) {
1517                 /* what level are we meant to be flushing anyway? */
1518                 if (tp->t_state & TS_BUSY) {
1519                         si_command(pp, WFLUSH, SI_NOWAIT);
1520                         tp->t_state &= ~TS_BUSY;
1521                         ttwwakeup(tp);  /* Bruce???? */
1522                 }
1523         }
1524 #if 1   /* XXX: this doesn't work right yet.. */
1525         /* XXX: this may have been failing because we used to call l_rint()
1526          * while we were looping based on these two counters. Now, we collect
1527          * the data and then loop stuffing it into l_rint(), making this
1528          * useless.  Should we cause this to blow away the staging buffer?
1529          */
1530         if (rw & FREAD) {
1531                 ccbp->hi_rxopos = ccbp->hi_rxipos;
1532         }
1533 #endif
1534 }
1535
1536 /*
1537  * Issue a command to the host card CPU.
1538  */
1539
1540 static void
1541 si_command(struct si_port *pp, int cmd, int waitflag)
1542 {
1543         int oldspl;
1544         volatile struct si_channel *ccbp = pp->sp_ccb;
1545         int x;
1546
1547         DPRINT((pp, DBG_ENTRY|DBG_PARAM, "si_command(%x,%x,%d): hi_stat 0x%x\n",
1548                 pp, cmd, waitflag, ccbp->hi_stat));
1549
1550         oldspl = spltty();              /* Keep others out */
1551
1552         /* wait until it's finished what it was doing.. */
1553         /* XXX: sits in IDLE_BREAK until something disturbs it or break
1554          * is turned off. */
1555         while((x = ccbp->hi_stat) != IDLE_OPEN &&
1556                         x != IDLE_CLOSE &&
1557                         x != IDLE_BREAK &&
1558                         x != cmd) {
1559                 if (in_intr) {                  /* Prevent sleep in intr */
1560                         DPRINT((pp, DBG_PARAM,
1561                                 "cmd intr collision - completing %d\trequested %d\n",
1562                                 x, cmd));
1563                         splx(oldspl);
1564                         return;
1565                 } else if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
1566                                 "sicmd1", 1)) {
1567                         splx(oldspl);
1568                         return;
1569                 }
1570         }
1571         /* it should now be in IDLE_{OPEN|CLOSE|BREAK}, or "cmd" */
1572
1573         /* if there was a pending command, cause a state-change wakeup */
1574         switch(pp->sp_pend) {
1575         case LOPEN:
1576         case MPEND:
1577         case MOPEN:
1578         case CONFIG:
1579         case SBREAK:
1580         case EBREAK:
1581                 wakeup(&pp->sp_state);
1582                 break;
1583         default:
1584                 break;
1585         }
1586
1587         pp->sp_pend = cmd;              /* New command pending */
1588         ccbp->hi_stat = cmd;            /* Post it */
1589
1590         if (waitflag) {
1591                 if (in_intr) {          /* If in interrupt handler */
1592                         DPRINT((pp, DBG_PARAM,
1593                                 "attempt to sleep in si_intr - cmd req %d\n",
1594                                 cmd));
1595                         splx(oldspl);
1596                         return;
1597                 } else while(ccbp->hi_stat != IDLE_OPEN &&
1598                              ccbp->hi_stat != IDLE_BREAK) {
1599                         if (ttysleep(pp->sp_tty, (caddr_t)&pp->sp_state, TTIPRI|PCATCH,
1600                             "sicmd2", 0))
1601                                 break;
1602                 }
1603         }
1604         splx(oldspl);
1605 }
1606
1607
1608 #ifdef  SI_DEBUG
1609
1610 void
1611 si_dprintf(struct si_port *pp, int flags, const char *fmt, ...)
1612 {
1613         va_list ap;
1614
1615         if ((pp == NULL && (si_debug&flags)) ||
1616             (pp != NULL && ((pp->sp_debug&flags) || (si_debug&flags)))) {
1617                 if (pp != NULL)
1618                         printf("%s: ", pp->sp_name);
1619                 va_start(ap, fmt);
1620                 vprintf(fmt, ap);
1621                 va_end(ap);
1622         }
1623 }
1624
1625 #endif  /* DEBUG */
1626
1627 static char *
1628 si_modulename(int host_type, int uart_type)
1629 {
1630         switch (host_type) {
1631         /* Z280 based cards */
1632 #ifdef DEV_EISA
1633         case SIEISA:
1634 #endif
1635         case SIHOST2:
1636         case SIHOST:
1637         case SIPCI:
1638                 switch (uart_type) {
1639                 case 0:
1640                         return(" (XIO)");
1641                 case 1:
1642                         return(" (SI)");
1643                 }
1644                 break;
1645         /* T225 based hosts */
1646         case SIJETPCI:
1647         case SIJETISA:
1648                 switch (uart_type) {
1649                 case 0:
1650                         return(" (SI)");
1651                 case 40:
1652                         return(" (XIO)");
1653                 case 72:
1654                         return(" (SXDC)");
1655                 }
1656                 break;
1657         }
1658         return("");
1659 }