|
|
1.1 root 1: /* (-lgl
2: * COHERENT Driver Kit Version 1.1.0
3: * Copyright (c) 1982, 1990 by Mark Williams Company.
4: * All rights reserved. May not be copied without permission.
5: -lgl) */
6: /*
7: * Raw Serial Device Driver.
8: *
9: * Provides fast, efficiently buffered serial i/o to COM1 & COM2.
10: * Supports an extreme subset of System V (termio) parameters.
11: * c_iflag: ISTRIP, IXON, IXANY, IGNBRK, INPCK, PARMRK, IGNPAR.
12: * c_oflag: OPOST, ONLCR, ONLRET, TAB3.
13: * c_cflag: *.
14: *
15: */
16:
17: #include <sys/coherent.h>
18: #include <sys/ins8250.h>
19: #include <sys/proc.h>
20: #include <sys/uproc.h>
21: #include <sys/con.h>
22: #include <sys/devices.h>
23: #include <sys/sched.h>
24: #include <sys/stat.h>
25: #include <termio.h>
26: #include <errno.h>
27:
28: #define COM1VEC 4 /* interrupt vector for COM1 */
29: #define COM2VEC 3 /* interrupt vector for COM2 */
30:
31: #define COM1PORT 0x3F8 /* i/o port address for COM1 */
32: #define COM2PORT 0x2F8 /* i/o port address for COM2 */
33:
34: #ifdef RS1
35: # define CFLAG RS1CFLAG
36: # define MAJ AL1_MAJOR /* major device for /dev/rs1 */
37: # define rscon rs1con /* configuration table for " */
38: # define rstty rs1tty
39: # define IVEC COM2VEC /* interrupt vector for rs1 */
40: # define PORT COM2PORT /* i/o port address for rs1 */
41: #else
42: # define CFLAG RS0CFLAG
43: # define MAJ AL0_MAJOR /* major device for /dev/rs0 */
44: # define rscon rs0con /* configuration table for " */
45: # define rstty rs0tty
46: # define IVEC COM1VEC /* interrupt vector for rs0 */
47: # define PORT COM1PORT /* i/o port address for rs0 */
48: #endif
49:
50: #define CTRLS '\023'
51: #define CTRLQ '\021'
52:
53: /*
54: * Functions.
55: */
56:
57: int rsload();
58: int rsunload();
59: int rsopen();
60: int rsclose();
61: int rsread();
62: int rswrite();
63: int rsioctl();
64: int rspoll();
65: int nulldev();
66: int nonedev();
67:
68: int rsintr();
69: int rsparam();
70:
71: /*
72: * Configuration table.
73: */
74:
75: CON rscon ={
76: DFCHR|DFPOL, /* Flags */
77: MAJ, /* Major index */
78: rsopen, /* Open */
79: rsclose, /* Close */
80: nulldev, /* Block */
81: rsread, /* Read */
82: rswrite, /* Write */
83: rsioctl, /* Ioctl */
84: nulldev, /* Powerfail */
85: nulldev, /* Timeout */
86: rsload, /* Load */
87: rsunload, /* Unload */
88: rspoll /* Poll */
89: };
90:
91: /*
92: * Terminal structure.
93: */
94:
95: #define RAWSZ (2048-1)
96: #define OUTSZ (2048-1)
97:
98: #define NRAWC ((rsrawq.rq_ix - rsrawq.rq_ox) & RAWSZ)
99: #define NOUTC ((rsoutq.rq_ix - rsoutq.rq_ox) & OUTSZ)
100:
101: #define TTSTOP 00001
102: #define TTSBRK 00002
103: #define CARRIER 00004
104:
105: typedef
106: struct rawtty_s {
107: unsigned rt_state; /* terminal state */
108: int rt_group; /* controlling process group */
109: unsigned rt_ticks; /* send break 1/10 sec counter */
110: unsigned rt_iflag; /* termio input flags */
111: unsigned rt_oflag; /* termio output flags */
112: unsigned rt_cflag; /* termio control flags */
113: unsigned char rt_col; /* current output column */
114: unsigned char rt_refc; /* # procs accessing the port */
115: unsigned char rt_irefc; /* # procs waiting for input */
116: unsigned char rt_orefc; /* # procs waitint for output */
117: unsigned char rt_crefc; /* # procs waiting for carrier */
118: unsigned char rt_drefc; /* # procs waiting for drain */
119: event_t rt_ipolls; /* Procs polling on input queue */
120: event_t rt_opolls; /* Procs polling on output que */
121: } RAWTTY;
122:
123: typedef
124: struct iring_s {
125: unsigned short rq_mask;
126: unsigned short rq_ix;
127: unsigned short rq_ox;
128: unsigned char rq_cc[RAWSZ+1];
129: } IRING;
130:
131: typedef
132: struct oring_s {
133: unsigned short rq_mask;
134: unsigned short rq_ix;
135: unsigned short rq_ox;
136: unsigned char rq_cc[OUTSZ+1];
137: } ORING;
138:
139: /*
140: * Local variables.
141: */
142: unsigned CFLAG = CLOCAL | CREAD | B1200 | CS8 | HUPCL;
143: RAWTTY rstty;
144: static ORING rsoutq;
145: static IRING rsrawq;
146: static TIM rstim;
147:
148: /*
149: * Time constant table.
150: * Indexed by ioctl baud rate.
151: */
152: static
153: int timeconst[] = {
154: 0, /* 0 */
155: 2304, /* 50 */
156: 1536, /* 75 */
157: 1047, /* 110 */
158: 857, /* 134.5 */
159: 768, /* 150 */
160: 576, /* 200 */
161: 384, /* 300 */
162: 192, /* 600 */
163: 96, /* 1200 */
164: 64, /* 1800 */
165: 48, /* 2400 */
166: 24, /* 4800 */
167: 12, /* 9600 */
168: 6, /* 19200/EXTA */
169: 6 /* 19200/EXTB */
170: };
171:
172: /*
173: * Rsload() -- Raw Serial Load Routine.
174: *
175: * Action: Define terminal parameters.
176: * Initialize terminal hardware.
177: * If serial port exists, seize its interrupt vector.
178: *
179: * Return: None.
180: */
181:
182: static
183: rsload()
184: {
185: /*
186: * Initialize terminal parameters.
187: */
188: rsoutq.rq_mask = OUTSZ;
189: rsrawq.rq_mask = RAWSZ;
190:
191: /*
192: * Initialize terminal hardware.
193: */
194: rsparam();
195:
196: /*
197: * If serial port exists, initialize interrupt vector.
198: */
199: if ( inb(PORT+IER) == 0 ) {
200: setivec( IVEC, rsintr);
201: rscycle();
202: }
203: }
204:
205: /*
206: * Rsunload() -- Raw Serial unload Routine.
207: */
208:
209: static
210: rsunload()
211: {
212: timeout( &rstim, 0, NULL, 0 ); /* cancel timed function */
213: clrivec( IVEC ); /* release interrupt vector */
214: outb(PORT+IER, 0); /* disable port interrupts */
215: outb(PORT+MCR, MC_OUT2); /* hangup port */
216: }
217:
218: /*
219: * Rsopen -- Open Routine.
220: *
221: * Input: dev = device to open.
222: * If high bit (0x80) set in minor, modem control is requested.
223: *
224: * Action: Validate minor device.
225: * Increment reference count.
226: * If first reference and parameters are not initialized,
227: * set default parameters and initialize hardware.
228: *
229: * Return: None.
230: */
231:
232: static
233: rsopen( dev, mode )
234:
235: dev_t dev;
236:
237: {
238: register PROC *pp = SELF;
239:
240: /*
241: * Validate minor device.
242: */
243: if (minor(dev) & ~0x80) {
244: u.u_error = ENODEV;
245: return;
246: }
247:
248: /*
249: * Validate hardware.
250: */
251: if (inb(PORT+IER) & ~(IE_RxI|IE_TxI|IE_LSI)) {
252: u.u_error = ENXIO;
253: return;
254: }
255:
256: /*
257: * Ensure controlling terminal and group fields initialized.
258: */
259: if (pp->p_ttdev == NODEV)
260: pp->p_ttdev = dev;
261: if (pp->p_group == 0)
262: pp->p_group = pp->p_pid;
263:
264: /*
265: * Check for first open.
266: */
267: if (++rstty.rt_refc == 1) {
268:
269: if (pp->p_group == pp->p_pid)
270: rstty.rt_group = pp->p_group;
271:
272: if ((rstty.rt_cflag & CBAUD) == B0) {
273:
274: /*
275: * Define terminal parameters.
276: */
277: rstty.rt_state = 0;
278: rstty.rt_col = 0;
279: rstty.rt_iflag = ISTRIP | IXON;
280: rstty.rt_oflag = OPOST | ONLCR | TAB3;
281: rstty.rt_cflag = CFLAG;
282: if ( minor(dev) & 0x80 )
283: rstty.rt_cflag &= ~CLOCAL;
284:
285: /*
286: * Initialize terminal hardware.
287: */
288: rsparam();
289: }
290:
291: /*
292: * Discard input data.
293: */
294: rsrawq.rq_ox = rsrawq.rq_ix;
295: }
296:
297: /*
298: * If modem control is requested, check carrier.
299: */
300: if ( minor(dev) & 0x80 ) {
301:
302: /*
303: * Delay until carrier is present.
304: */
305: while ( (rstty.rt_state & CARRIER) == 0 ) {
306:
307: /*
308: * Sleep on carrier.
309: */
310: ++rstty.rt_crefc;
311: sleep( &rstty.rt_crefc,
312: CVTTOUT, IVTTOUT, SVTTOUT);
313: --rstty.rt_crefc;
314:
315: /*
316: * Abort if non-ignored signal is received.
317: */
318: if (SELF->p_ssig && nondsig()) {
319:
320: if (--rstty.rt_refc == 0) {
321: rstty.rt_group = 0;
322: rstty.rt_cflag = 0;
323: rsparam();
324: }
325: u.u_error = EINTR;
326: return;
327: }
328: }
329: }
330: }
331:
332: /*
333: * Rsclose -- Close Routine.
334: *
335: * Action: Decrement reference count.
336: * If serial port is no longer referenced,
337: * and the hangup on last close bit is set in rt_cflag,
338: * clear terminal parameters, and initialize hardware.
339: *
340: * Return: None.
341: *
342: * Note: This routine does not wait for the output queue to empty.
343: */
344:
345: static
346: rsclose( dev )
347:
348: dev_t dev;
349:
350: {
351: /*
352: * Check for last close and hangup on close.
353: */
354: if ((rstty.rt_refc == 1) && (rstty.rt_cflag & HUPCL)) {
355:
356: /*
357: * Wait for output to drain.
358: */
359: while ( rsoutq.rq_ox != rsoutq.rq_ix ) {
360:
361: ++rstty.rt_drefc;
362: sleep( &rstty.rt_drefc, CVTTOUT, IVTTOUT, SVTTOUT );
363: --rstty.rt_drefc;
364:
365: if (rstty.rt_refc != 1) {
366: rstty.rt_refc--;
367: return;
368: }
369:
370: if (SELF->p_ssig && nondsig())
371: break;
372: }
373:
374: /*
375: * Initialize terminal hardware.
376: */
377: rstty.rt_group = 0;
378: rstty.rt_cflag = 0;
379: rsparam();
380:
381: /*
382: * Flush input and output queues.
383: */
384: rsrawq.rq_ix =
385: rsrawq.rq_ox =
386: rsoutq.rq_ox =
387: rsoutq.rq_ix = 0;
388: }
389: --rstty.rt_refc;
390: }
391:
392: /*
393: * Rsread -- Read Routine.
394: *
395: * Input: iop = pointer to structure containing i/o parameters.
396: *
397: * Action: Attempt to read data from input buffer until at least
398: * one character has been read, or a signal is received
399: * by the current process.
400: * Update the parameters in the io structure.
401: * If a signal is received, set errno to EINTR.
402: *
403: * Return: None.
404: */
405:
406: static
407: rsread( dev, iop )
408:
409: dev_t dev;
410: register IO *iop;
411:
412: {
413: register int sioc;
414:
415: /*
416: * Remember original char count.
417: */
418: sioc = iop->io_ioc;
419:
420: do {
421: /*
422: * Transfer data until done or input buffer empty.
423: */
424: rsin( &rsrawq, iop );
425:
426: /*
427: * Return if some data was transferred.
428: */
429: if (sioc != iop->io_ioc)
430: return;
431:
432: /*
433: * Non-blocking reads.
434: */
435: if ( iop->io_flag & IONDLY ) {
436: u.u_error = EAGAIN;
437: return;
438: }
439:
440: /*
441: * Sleep waiting for a signal or input data.
442: */
443: ++rstty.rt_irefc;
444: sleep( &rstty.rt_irefc, CVTTOUT, IVTTOUT, SVTTOUT );
445: --rstty.rt_irefc;
446:
447: /*
448: * Abort if a non-ignored signal was received.
449: */
450: if (SELF->p_ssig && nondsig()) {
451: u.u_error = EINTR;
452: return;
453: }
454:
455: } while (1);
456: }
457:
458: /*
459: * Rswrite -- Write Routine.
460: */
461:
462: static
463: rswrite( dev, iop )
464:
465: dev_t dev;
466: register IO *iop;
467:
468: {
469: register int n;
470:
471: /*
472: * Non-blocking write.
473: */
474: if ( iop->io_flag & IONDLY ) {
475:
476: /*
477: * Calculate free slots.
478: */
479: n = rsoutq.rq_mask - rsoutq.rq_ix + rsoutq.rq_ox;
480: n &= rsoutq.rq_mask;
481:
482: /*
483: * Insufficient space.
484: */
485: if ( n <= iop->io_ioc ) {
486: u.u_error = EAGAIN;
487: return;
488: }
489: }
490:
491: do {
492: /*
493: * Transfer data until done or output queue full.
494: */
495: rsout( &rsoutq, iop );
496:
497: /*
498: * Make sure the transmitter is operating.
499: */
500: rsstart();
501:
502: /*
503: * Return if all data was transferred.
504: */
505: if ( iop->io_ioc == 0 )
506: return;
507:
508: /*
509: * Sleep waiting for a signal or room in the output queue.
510: */
511: ++rstty.rt_orefc;
512: sleep( &rstty.rt_orefc, CVTTOUT, IVTTOUT, SVTTOUT );
513: --rstty.rt_orefc;
514:
515: /*
516: * Abort if a non-ignored signal was received.
517: */
518: if ( SELF->p_ssig && nondsig() ) {
519: u.u_error = EINTR;
520: return;
521: }
522:
523: } while (1);
524: }
525:
526: /*
527: * Rspoll -- Polling Routine.
528: */
529: static int
530: rspoll( dev, ev, msec )
531: dev_t dev;
532: register int ev;
533: int msec;
534: {
535: /*
536: * No priority reports.
537: */
538: ev &= ~POLLPRI;
539:
540: /*
541: * Input poll with empty input ring.
542: */
543: if ( (ev & POLLIN) && (rsrawq.rq_ix == rsrawq.rq_ox) ) {
544:
545: /*
546: * Blocking input poll.
547: */
548: if ( msec != 0 )
549: pollopen( &rstty.rt_ipolls );
550:
551: /*
552: * Second look and clear input report.
553: */
554: if ( rsrawq.rq_ix == rsrawq.rq_ox )
555: ev &= ~POLLIN;
556: }
557:
558: /*
559: * Output poll with non-empty output ring.
560: */
561: if ( (ev & POLLOUT) && (rsoutq.rq_ix != rsrawq.rq_ox) ) {
562:
563: /*
564: * Blocking output poll.
565: */
566: if ( msec != 0 )
567: pollopen( &rstty.rt_opolls );
568:
569: /*
570: * Second look and clear output report.
571: */
572: if ( rsoutq.rq_ix != rsoutq.rq_ox )
573: ev &= ~POLLOUT;
574: }
575:
576: return ev;
577: }
578:
579: /*
580: * Cyclic [1 sec] Routine.
581: */
582: static
583: rscycle()
584: {
585: register PROC *pp;
586: register int b;
587:
588: /*
589: * Check for carrier transitions.
590: */
591: if ( inb( PORT + MSR ) & MS_RLSD ) {
592:
593: /*
594: * Have carrier. Wake processes waiting for carrier.
595: */
596: rstty.rt_state |= CARRIER;
597:
598: if ( rstty.rt_crefc )
599: wakeup( &rstty.rt_crefc );
600: }
601: else if ((rstty.rt_state & CARRIER) && (rstty.rt_cflag&CLOCAL) == 0) {
602:
603: /*
604: * Lost carrier. Signal attached processes.
605: */
606: rstty.rt_state &= ~CARRIER;
607:
608: if (rstty.rt_refc && (b = rstty.rt_group))
609: for (pp=procq.p_nforw; pp != &procq; pp=pp->p_nforw)
610: if ( pp->p_group == b )
611: sendsig( SIGHUP, pp );
612: }
613:
614: /*
615: * Wakeup processes waiting to read if input data present.
616: */
617: if ( rsrawq.rq_ix != rsrawq.rq_ox ) {
618: if ( rstty.rt_irefc )
619: wakeup( &rstty.rt_irefc );
620: if ( rstty.rt_ipolls.e_procp )
621: pollwake( &rstty.rt_ipolls );
622: }
623:
624: /*
625: * Check for break being sent.
626: */
627: if ( rstty.rt_ticks != 0 ) {
628:
629: if ( --rstty.rt_ticks == 0 ) {
630:
631: b = inb( PORT + LCR );
632: outb( PORT + LCR, b & ~LC_SBRK );
633: rstty.rt_state &= ~TTSBRK;
634: }
635: }
636:
637: /*
638: * Can check output if not sending break.
639: */
640: if ( rstty.rt_ticks == 0 ) {
641:
642: /*
643: * Restart output if necessary.
644: */
645: if ( rsoutq.rq_ox != rsoutq.rq_ix )
646: rsstart();
647:
648: /*
649: * Wakeup processes waiting for drain if output queue empty.
650: */
651: if ( rstty.rt_drefc ) {
652: if ( rsoutq.rq_ix == rsoutq.rq_ox )
653: wakeup( &rstty.rt_drefc );
654: }
655:
656: /*
657: * Wakeup processes waiting to write if 512 slots are free.
658: */
659: else if ( NOUTC < OUTSZ-512 ) {
660: if ( rstty.rt_orefc )
661: wakeup( &rstty.rt_orefc );
662: if ( rstty.rt_opolls.e_procp )
663: pollwake( &rstty.rt_opolls );
664: }
665: }
666:
667: timeout( &rstim, HZ/10, rscycle, 0 );
668: }
669:
670: /*
671: * Rsintr -- Serial Interrupt Handler.
672: *
673: * Action: Process all pending interrupt service requests
674: * on the serial port.
675: *
676: * Return: None.
677: *
678: * Notes: This routine must loop until all requests are serviced
679: * because of the edge sensitive nature of the programmable
680: * interrupt controller.
681: */
682:
683: static
684: rsintr()
685: {
686: register int b;
687:
688: /*
689: * Service serial port interrupt requests, highest to lowest priority.
690: */
691: rescan:
692: b = inb( PORT + IIR );
693:
694: switch ( b ) {
695:
696: case LS_INTR:
697: /*
698: * Get line status (clear interrupt).
699: */
700: b = inb( PORT + LSR );
701:
702: /*
703: * Check for received break.
704: */
705: if (b & LS_BREAK) {
706:
707: /*
708: * Read the break char ('\0').
709: */
710: rsrawq.rq_cc[ rsrawq.rq_ix ] = inb( PORT + DREG );
711:
712: /*
713: * Clear output stops.
714: */
715: rstty.rt_state &= ~TTSTOP;
716:
717: /*
718: * Update input index if not ignoring break.
719: */
720: if ((rstty.rt_iflag & IGNBRK) == 0) {
721: rsrawq.rq_ix ++;
722: rsrawq.rq_ix &= RAWSZ;
723: }
724: }
725:
726: /*
727: * Special handling if frame/parity error and checking enabled.
728: */
729: if ((b & (LS_FRAME|LS_PARITY)) && (rstty.rt_iflag & INPCK)) {
730:
731: /*
732: * Ignore next input char if IGNPAR set.
733: */
734: if (rstty.rt_iflag & IGNPAR)
735: inb( PORT + DREG );
736: /*
737: * Change next input char into 0377,0,ch if PARMRK set.
738: */
739: else if (rstty.rt_iflag & PARMRK) {
740:
741: b = rsrawq.rq_ix;
742: rsrawq.rq_cc[ b++ ] = 0377;
743: b &= RAWSZ;
744: rsrawq.rq_cc[ b++ ] = '\0';
745: b &= RAWSZ;
746: rsrawq.rq_cc[ b++ ] = inb( PORT + DREG );
747: b &= RAWSZ;
748: rsrawq.rq_ix = b;
749: }
750:
751: /*
752: * Otherwise change next input char into null.
753: */
754: else {
755: inb( PORT + DREG );
756: rsrawq.rq_cc[ rsrawq.rq_ix++ ] = '\0';
757: rsrawq.rq_ix &= RAWSZ;
758: }
759: }
760: goto rescan;
761:
762: case Rx_INTR:
763: /*
764: * Read character from receive buffer.
765: */
766: b = inb( PORT + DREG );
767:
768: /*
769: * Discard high bit if ISTRIP set.
770: */
771: if ( rstty.rt_iflag & ISTRIP )
772: b &= 0177;
773:
774: /*
775: * Check for output flow control if IXON set.
776: */
777: if ( rstty.rt_iflag & IXON ) {
778:
779: /*
780: * Stop output if Ctl-S.
781: */
782: if ( b == CTRLS ) {
783: rstty.rt_state |= TTSTOP;
784: goto rescan;
785: }
786:
787: /*
788: * Resume output if Ctl-Q.
789: */
790: if ( b == CTRLQ ) {
791: rstty.rt_state &= ~TTSTOP;
792: goto rescan;
793: }
794:
795: /*
796: * Enable output if IXANY set.
797: */
798: if ( rstty.rt_iflag & IXANY )
799: rstty.rt_state &= ~TTSTOP;
800: }
801:
802: /*
803: * Save the character in the input queue.
804: */
805: rsrawq.rq_cc[ rsrawq.rq_ix++ ] = b;
806: rsrawq.rq_ix &= RAWSZ;
807:
808: /*
809: * Save again if 0377 and parity marking enabled.
810: */
811: if ((b == 0377)
812: && ((rstty.rt_iflag & (INPCK|PARMRK)) == (INPCK|PARMRK))) {
813:
814: rsrawq.rq_cc[ rsrawq.rq_ix++ ] = b;
815: rsrawq.rq_ix &= RAWSZ;
816: }
817:
818: goto rescan;
819:
820: case Tx_INTR:
821: rsstart();
822: goto rescan;
823: }
824: }
825:
826: /*
827: * Rsstart()
828: *
829: * Action: While output data is available, and the transmitter buffer
830: * is empty, transfer one character from the output queue to the
831: * transmit buffer.
832: *
833: * Return: None.
834: */
835:
836: static
837: rsstart()
838: {
839: register int b;
840: register int s;
841:
842: /*
843: * Can't transmit if output stopped or sending break.
844: */
845: if ( rstty.rt_state & (TTSTOP|TTSBRK) )
846: return;
847:
848: /*
849: * Can't transmit if modem control enabled without CTS present.
850: */
851: if ( (rstty.rt_cflag & CLOCAL) == 0 )
852: if ( (inb(PORT+MSR) & MS_CTS) == 0 )
853: return;
854:
855: /*
856: * Disable interrupts to avoid critical race.
857: */
858: s = sphi();
859:
860: /*
861: * Can transmit if output data available and transmit buffer empty.
862: */
863: if ( (rsoutq.rq_ix != rsoutq.rq_ox)
864: && (inb(PORT+LSR) & LS_TxRDY) ) {
865:
866: /*
867: * Get next char from output queue.
868: */
869: b = rsoutq.rq_cc [ rsoutq.rq_ox ];
870:
871: if (rstty.rt_oflag & OPOST) {
872:
873: /*
874: * Printable characters increment the column.
875: */
876: if (b >= ' ') {
877: rstty.rt_col++;
878: }
879: /*
880: * Carriage return resets the column.
881: */
882: else if (b == '\r') {
883: rstty.rt_col = 0;
884: if (rstty.rt_oflag & OCRNL)
885: b = '\n';
886: }
887: /*
888: * New-line may also generate a carriage return.
889: */
890: else if (b == '\n') {
891: if (rstty.rt_oflag & ONLCR) {
892: if (rstty.rt_col) {
893: rstty.rt_col = 0;
894: rsoutq.rq_ox--;
895: b = '\r';
896: }
897: }
898: else if (rstty.rt_oflag & ONLRET)
899: rstty.rt_col = 0;
900: }
901: /*
902: * Backspace decrements the column.
903: */
904: else if (b == '\b') {
905: if (rstty.rt_col)
906: --rstty.rt_col;
907: }
908: /*
909: * Tabs may generate spaces, always move to tab stop.
910: */
911: else if (b == '\t') {
912: if ((rstty.rt_oflag & TABDLY) == TAB3) {
913: b = ' ';
914: if (++rstty.rt_col & 7)
915: rsoutq.rq_ox--;
916: }
917: else {
918: rstty.rt_col |= 7;
919: rstty.rt_col++;
920: }
921: }
922: }
923: rsoutq.rq_ox++;
924: rsoutq.rq_ox &= OUTSZ;
925:
926: /*
927: * Transmit next char.
928: */
929: outb( PORT+DREG, b );
930: }
931:
932: spl(s);
933: }
934:
935: /*
936: * Ioctl Routine.
937: */
938:
939: static
940: rsioctl( dev, com, vec )
941:
942: dev_t dev;
943: int com;
944: struct termio *vec;
945:
946: {
947: register int b;
948: struct termio tb;
949:
950: switch (com) {
951:
952: case TCSETAW: /* Set attributes after waiting for output to clear */
953: case TCSETAF: /* ditto, but also flush input queue */
954: case TCSBRK: /* wait for output to clear, send break */
955:
956: /*
957: * Delay until output queue is empty.
958: */
959: while ( rsoutq.rq_ox != rsoutq.rq_ix ) {
960:
961: /*
962: * Sleep waiting for empty output queue.
963: */
964: ++rstty.rt_drefc;
965: sleep( &rstty.rt_drefc, CVTTOUT, IVTTOUT, SVTTOUT);
966: --rstty.rt_drefc;
967:
968: /*
969: * Abort if a non-ignored signal was received.
970: */
971: if ( SELF->p_ssig && nondsig() ) {
972: u.u_error = EINTR;
973: return;
974: }
975: }
976:
977: if ( com == TCSBRK ) {
978:
979: b = inb( PORT + LCR );
980:
981: if ( vec == 0 ) {
982: rstty.rt_ticks = 3; /* 0.2 to 0.3 sec */
983: rstty.rt_state |= TTSBRK;
984: b |= LC_SBRK;
985: }
986: else {
987: rstty.rt_ticks = 0;
988: rstty.rt_state &= ~TTSBRK;
989: b &= ~LC_SBRK;
990: }
991:
992: outb( PORT + LCR, b );
993: return;
994: }
995: /* no break */
996:
997: case TCSETA:
998: /*
999: * Get new terminal attributes.
1000: */
1001: ukcopy( vec, &tb, sizeof(tb) );
1002: if ( u.u_error )
1003: return;
1004:
1005: /*
1006: * Set terminal attributes and hardware.
1007: */
1008: rstty.rt_iflag = tb.c_iflag;
1009: rstty.rt_oflag = tb.c_oflag;
1010: if (rstty.rt_cflag != tb.c_cflag) {
1011: rstty.rt_cflag = tb.c_cflag;
1012: rsparam();
1013: }
1014:
1015: if ((rstty.rt_iflag & IXON) == 0)
1016: rstty.rt_state &= ~TTSTOP;
1017:
1018: /*
1019: * Flush input queue if command was TCSETAF.
1020: */
1021: if ( com == TCSETAF )
1022: rsrawq.rq_ox = rsrawq.rq_ix;
1023: break;
1024:
1025: case TCGETA: /* Get terminal attributes */
1026:
1027: memset( &tb, 0, sizeof(tb) );
1028: tb.c_cflag = rstty.rt_cflag;
1029: tb.c_iflag = rstty.rt_iflag;
1030: tb.c_oflag = rstty.rt_oflag;
1031:
1032: /*
1033: * Transfer terminal attributes to user space.
1034: */
1035: kucopy( &tb, vec, sizeof(tb) );
1036: break;
1037:
1038: case TCFLSH:
1039: switch ((int) vec) {
1040: case 0:
1041: /* flush input queue */
1042: rsrawq.rq_ox = rsrawq.rq_ix;
1043: break;
1044: case 1:
1045: /* flush output queue */
1046: rsoutq.rq_ox = rsoutq.rq_ix;
1047: break;
1048: case 2:
1049: /* flush both input and output queues */
1050: rsrawq.rq_ox = rsrawq.rq_ix;
1051: rsoutq.rq_ox = rsoutq.rq_ix;
1052: break;
1053: default:
1054: u.u_error = EINVAL;
1055: }
1056: break;
1057:
1058: case TCXONC:
1059: switch ( (int) vec ) {
1060: case 0:
1061: /* stop output */
1062: rstty.rt_state |= TTSTOP;
1063: break;
1064: case 1:
1065: /* restart output */
1066: rstty.rt_state &= ~TTSTOP;
1067: rsstart();
1068: break;
1069: default:
1070: u.u_error = EINVAL;
1071: }
1072: break;
1073:
1074: default:
1075: u.u_error = EINVAL;
1076: }
1077: }
1078:
1079: /*
1080: * Rsparam -- Setup hardware parameters.
1081: */
1082:
1083: static
1084: rsparam()
1085: {
1086: register int b;
1087: register int s;
1088:
1089: /*
1090: * Disable interrupts.
1091: */
1092: s = sphi();
1093:
1094: /*
1095: * Assert required modem control lines (DTR, RTS).
1096: */
1097: if ((rstty.rt_cflag & CBAUD) == B0)
1098: outb( PORT+MCR, MC_OUT2 );
1099: else if ((rstty.rt_refc == 0) && (rstty.rt_cflag & HUPCL))
1100: outb( PORT+MCR, MC_OUT2 );
1101: else
1102: outb( PORT+MCR, MC_OUT2+MC_DTR+MC_RTS );
1103:
1104: /*
1105: * Program baud rate.
1106: */
1107: if (b = timeconst[ rstty.rt_cflag & CBAUD ]) {
1108: outb( PORT+LCR, LC_DLAB );
1109: outb( PORT+DLL, b );
1110: outb( PORT+DLH, b >> 8 );
1111: }
1112:
1113: /*
1114: * Program character size, parity, and stop bits.
1115: */
1116: switch (rstty.rt_cflag & CSIZE) {
1117: case CS5: b = LC_CS5; break;
1118: case CS6: b = LC_CS6; break;
1119: case CS7: b = LC_CS7; break;
1120: case CS8: b = LC_CS8; break;
1121: }
1122:
1123: switch (rstty.rt_cflag & (PARENB|PARODD)) {
1124: case PARENB: b |= LC_PARENB|LC_PAREVEN; break;
1125: case PARENB|PARODD: b |= LC_PARENB; break;
1126: }
1127:
1128: if (rstty.rt_cflag & CSTOPB)
1129: b |= LC_STOPB;
1130:
1131: if (rstty.rt_state & TTSBRK)
1132: b |= LC_SBRK;
1133:
1134: outb( PORT+LCR, b );
1135:
1136: /*
1137: * Enable desired interrupts.
1138: */
1139: b = 0;
1140: if (rstty.rt_cflag & CBAUD) {
1141: b = IE_TxI | IE_LSI;
1142: if (rstty.rt_cflag & CREAD)
1143: b |= IE_RxI;
1144: }
1145: outb( PORT+IER, b );
1146:
1147: /*
1148: * Enable interrupts.
1149: */
1150: spl( s );
1151: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.