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