|
|
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: * Polled Serial Port Device Driver.
8: * - supports version 7 compatible ioctl
9: */
10:
11: #include <sys/coherent.h>
12: #include <sys/ins8250.h>
13: #include <sys/stat.h>
14: #include <sys/uproc.h>
15: #include <sys/proc.h>
16: #include <sys/tty.h> /* indirectly includes sgtty.h */
17: #include <sys/con.h>
18: #include <sys/devices.h>
19: #include <errno.h>
20: #include <sys/sched.h> /* CVTTOUT, IVTTOUT, SVTTOUT */
21: #include <sys/poll_clk.h>
22:
23: /*
24: * Definitions.
25: *
26: * HSBAUD is the highest baud rate supported by this driver
27: * HS_HZ is the polling rate, i.e. the number of times per second
28: * at which all open ports are checked for input, output, and
29: * line status changes
30: * MAX_HSNUM is the maximum number of devices that can be polled
31: * using this driver and can be revised up or down
32: * PORT is a convenience macro for the base address of a port
33: * port_config is the structure of the initial configuration for each
34: * polled port; note that "speed" is NOT the actual baud rate, but
35: * the value of the symbol for that baud rate as defined in
36: * /usr/include/sgtty.h
37: */
38: #define HSBAUD 9600
39: #define HS_HZ (HSBAUD/6)
40: #define MAX_HSNUM 8
41: #define PORT ((int)(tp->t_ddp))
42: struct port_config {
43: int addr; /* base address of the 8250-family UART */
44: int speed; /* B0..B19200 */
45: };
46:
47: /*
48: * Export Variables - these can be patched without recompiling and linking
49: *
50: * HSNUM is the actual number of polled serial ports, and should be
51: * less than or equal to MAX_HSNUM
52: * HS_PORTS is an array of address/speed pairs, one for each port
53: */
54: int HSNUM = 4;
55: struct port_config HS_PORTS[MAX_HSNUM] = {
56: { 0x3F8, B9600 },
57: { 0x2F8, B9600 },
58: { 0x3E8, B9600 },
59: { 0x2E8, B9600 }
60: };
61:
62: /*
63: * Export Functions.
64: */
65: int hsload();
66: int hsopen();
67: int hsclose();
68: int hsread();
69: int hswrite();
70: int hsioctl();
71: int hsunload();
72: int hspoll();
73:
74: int hscycle();
75: int hsintr();
76: int hsparam();
77: int hsstart();
78: int hsclk();
79: int set_poll_rate();
80:
81: /*
82: * Import Functions
83: */
84: int nulldev();
85: int nonedev();
86:
87: /*
88: * Configuration table.
89: */
90: CON hscon ={
91: DFCHR|DFPOL, /* Flags */
92: HS_MAJOR, /* Major index */
93: hsopen, /* Open */
94: hsclose, /* Close */
95: nulldev, /* Block */
96: hsread, /* Read */
97: hswrite, /* Write */
98: hsioctl, /* Ioctl */
99: nulldev, /* Powerfail */
100: nulldev, /* Timeout */
101: hsload, /* Load */
102: hsunload, /* Unload */
103: hspoll /* Poll */
104: };
105:
106: /*
107: * Local variables.
108: */
109: static TTY *hstty;
110: static TTY *hslimtty;
111: static TIM hstim;
112: static int poll_divisor; /* used in hsclk() and set_poll_rate() */
113:
114: /*
115: * Time constant table.
116: * Indexed by ioctl baud rate.
117: */
118: static
119: int timeconst[] = {
120: 0, /* 0 */
121: 2304, /* 50 */
122: 1536, /* 75 */
123: 1047, /* 110 */
124: 857, /* 134.5 */
125: 768, /* 150 */
126: 576, /* 200 */
127: 384, /* 300 */
128: 192, /* 600 */
129: 96, /* 1200 */
130: 64, /* 1800 */
131: 58, /* 2000 */
132: 48, /* 2400 */
133: 32, /* 3600 */
134: 24, /* 4800 */
135: 16, /* 7200 */
136: 12, /* 9600 */
137: 6, /* 19200 */
138: 6, /* EXTA */
139: 6 /* EXTB */
140: };
141:
142: /*
143: * poll_hz[] is tied to timeconst[] - it gives the minimum polling
144: * rate for the corresponding port speed; it must be a multiple
145: * of 100 (system clock Hz) and >= baud/6
146: */
147: int poll_hz[] ={
148: 0, /* 0 */
149: 1*HZ, /* 50 */
150: 1*HZ, /* 75 */
151: 1*HZ, /* 110 */
152: 1*HZ, /* 134.5 */
153: 1*HZ, /* 150 */
154: 1*HZ, /* 200 */
155: 1*HZ, /* 300 */
156: 1*HZ, /* 600 */
157: 2*HZ, /* 1200 */
158: 3*HZ, /* 1800 */
159: 4*HZ, /* 2000 */
160: 4*HZ, /* 2400 */
161: 6*HZ, /* 3600 */
162: 8*HZ, /* 4800 */
163: 12*HZ, /* 7200 */
164: 16*HZ, /* 9600 */
165: 0, /* 19200 */
166: 0, /* EXTA */
167: 0 /* EXTB */
168: };
169:
170: /*
171: * Load Routine.
172: */
173: static hsload()
174: {
175: register TTY * tp;
176: register int port;
177: int i, b;
178:
179: if ((hstty = (TTY *)kalloc(HSNUM*sizeof(TTY))) == 0) {
180: printf("hsload: can't allocate tty's\n");
181: return;
182: }
183: kclear(hstty, HSNUM*sizeof(TTY));
184:
185: for (i = 0; i < HSNUM; i++) {
186: port = HS_PORTS[i].addr;
187: tp = hstty + i;
188:
189: outb( port+MCR, 0 );
190: outb( port+IER, 0 );
191:
192: if ( inb( port+IER ) )
193: break;
194:
195: tp->t_cs_sel = cs_sel();
196: tp->t_start = hsstart;
197: tp->t_param = hsparam;
198: tp->t_sgttyb.sg_ospeed = tp->t_sgttyb.sg_ispeed =
199: tp->t_dispeed = tp->t_dospeed = HS_PORTS[i].speed;
200: tp->t_ddp = port;
201:
202: b = timeconst[ tp->t_sgttyb.sg_ospeed ];
203: outb( port+LCR, LC_DLAB );
204: outb( port+DLL, b );
205: outb( port+DLH, b >> 8);
206: outb( port+LCR, LC_CS8);
207:
208: hslimtty = tp;
209: }
210: }
211:
212: static hsunload()
213: {
214: if (hstty != (TTY *)0)
215: kfree(hstty);
216: }
217:
218: /*
219: * Open Routine.
220: */
221: hsopen( dev, mode )
222: dev_t dev;
223: {
224: register TTY * tp = &hstty[ dev & 15 ];
225: register int b;
226: int s;
227:
228: /*
229: * Verify hardware exists.
230: */
231: if ( (PORT == 0) || (inb(PORT+IER) & ~IE_TxI) ) {
232: u.u_error = ENXIO;
233: return;
234: }
235:
236: /*
237: * Can't open if another driver is using polling
238: */
239: if (poll_owner & ~ POLL_HS) {
240: u.u_error = EDBUSY;
241: return;
242: }
243:
244: /*
245: * Initialize if not already open.
246: */
247: if ( ++tp->t_open == 1 ) {
248: ttopen( tp );
249:
250: if ( dev & 0x80 ) {
251: s = sphi();
252: b = inb(PORT+MSR);
253: tp->t_flags |= T_MODC + T_STOP;
254: if ( b & MS_CTS )
255: tp->t_flags &= ~T_STOP;
256: if ( b & MS_DSR )
257: tp->t_flags |= T_CARR;
258: spl( s );
259: } else {
260: tp->t_flags &= ~T_MODC;
261: tp->t_flags |= T_CARR;
262: }
263: hscycle( tp );
264: }
265: ttsetgrp( tp, dev );
266: set_poll_rate();
267: }
268:
269: /*
270: * Close Routine.
271: */
272: hsclose( dev )
273: dev_t dev;
274: {
275: register TTY * tp = &hstty[ dev & 15 ];
276:
277: /*
278: * Reset if last close.
279: */
280: if ( tp->t_open == 1 ) {
281: int state;
282:
283: ttclose( tp );
284: /*
285: * ttclose() only emptied the output queue tp->t_oq;
286: * now wait 0.1 sec for the silo tp->rawout to empty
287: * and allow a delay for the UART on-chip xmit buffer to empty
288: *
289: * state 2: waiting for silo to empty
290: * state 1: stalling so UART can empty xmit buffer
291: * state 0: done!
292: */
293: state = 2;
294: while (state) {
295: timeout(&hstim, 10, wakeup, (int)&hstim);
296: sleep((char *)&hstim, CVTTOUT, IVTTOUT, SVTTOUT);
297: if (tp->t_rawout.si_ix == tp->t_rawout.si_ox && state)
298: state--;
299: }
300: }
301:
302: --tp->t_open;
303: set_poll_rate();
304: }
305:
306: /*
307: * Read Routine.
308: */
309: hsread( dev, iop )
310: dev_t dev;
311: register IO * iop;
312: {
313: ttread( &hstty[ dev & 15 ], iop, 0 );
314: }
315:
316: /*
317: * Write Routine.
318: */
319: hswrite( dev, iop )
320: dev_t dev;
321: register IO * iop;
322: {
323: ttwrite( &hstty[ dev & 15 ], iop, 0 );
324: }
325:
326: /*
327: * Ioctl Routine.
328: */
329: hsioctl( dev, com, vec )
330: dev_t dev;
331: int com;
332: struct sgttyb * vec;
333: {
334: ttioctl( &hstty[ dev & 15 ], com, vec );
335: }
336:
337: /*
338: * Polling Routine.
339: */
340: hspoll( dev, ev, msec )
341: dev_t dev;
342: int ev;
343: int msec;
344: {
345: return ttpoll( &hstty[ dev & 15 ], ev, msec );
346: }
347:
348: /*
349: * Cyclic routine - invoked every clock tick to perform raw input/output.
350: *
351: * Notes: Invoked 10 times per second.
352: */
353: hscycle( tp )
354: register TTY * tp;
355: {
356: register int resid;
357: register int c;
358:
359: /*
360: * Process rawin buf.
361: */
362: while ( tp->t_rawin.si_ix != tp->t_rawin.si_ox ) {
363:
364: ttin( tp, tp->t_rawin.si_buf[ tp->t_rawin.si_ox ] );
365:
366: if ( tp->t_rawin.si_ox >= sizeof(tp->t_rawin.si_buf) - 1 )
367: tp->t_rawin.si_ox = 0;
368: else
369: tp->t_rawin.si_ox++;
370: }
371:
372: /*
373: * Calculate free output slot count.
374: */
375: resid = sizeof(tp->t_rawout.si_buf) - 1;
376: resid += tp->t_rawout.si_ox - tp->t_rawout.si_ix;
377: resid %= sizeof(tp->t_rawout.si_buf);
378:
379: /*
380: * Fill raw output buffer.
381: */
382: while ( (--resid >= 0) && ((c = ttout(tp)) >= 0) ) {
383:
384: tp->t_rawout.si_buf[ tp->t_rawout.si_ix ] = c;
385:
386: if ( tp->t_rawout.si_ix >= sizeof(tp->t_rawout.si_buf) - 1 )
387: tp->t_rawout.si_ix = 0;
388: else
389: tp->t_rawout.si_ix++;
390: }
391:
392: /*
393: * (Re)start output, waking processes waiting to output, etc.
394: */
395: ttstart( tp );
396:
397: /*
398: * Schedule next cycle.
399: */
400: if ( tp->t_open != 0 )
401: timeout( &tp->t_rawtim, HZ/10, hscycle, tp );
402: }
403:
404: /*
405: * Clock Interrupt driven Polling routine.
406: */
407: hsintr()
408: {
409: register TTY * tp = &hstty[0];
410: register int b;
411:
412: do {
413: if ( tp->t_open == 0 )
414: continue;
415:
416: /*
417: * Check modem status if modem control is enabled.
418: */
419: if ( tp->t_flags & T_MODC ) {
420:
421: b = inb( PORT+MSR );
422:
423: if ( b & (MS_DCTS|MS_DDSR) ) {
424:
425: if ( b & MS_DCTS ) {
426: if ( b & MS_CTS )
427: tp->t_flags &= ~T_STOP;
428: else
429: tp->t_flags |= T_STOP;
430: }
431: if ( b & MS_DDSR ) {
432: if ( b & MS_DSR )
433: tp->t_flags |= T_CARR;
434: else {
435: tp->t_flags &= ~T_CARR;
436: tthup( tp );
437: }
438: }
439: }
440: }
441:
442: b = inb( PORT+LSR );
443:
444: if ( (b & LS_BREAK) && (tp->t_flags & T_CARR) )
445: ttsignal( tp, SIGINT );
446:
447: /*
448: * Receive ready.
449: */
450: if ( b & LS_RxRDY ) {
451:
452: tp->t_rawin.si_buf[tp->t_rawin.si_ix] = inb(PORT+DREG);
453:
454: if ( tp->t_flags & T_CARR ) {
455:
456: if ( ++(tp->t_rawin.si_ix) >=
457: sizeof(tp->t_rawin.si_buf) )
458: tp->t_rawin.si_ix = 0;
459: }
460: }
461:
462: /*
463: * Transmit ready and raw output data exists.
464: */
465: if ( (b & LS_TxRDY) && ((tp->t_flags & T_STOP) == 0)
466: && (tp->t_rawout.si_ix != tp->t_rawout.si_ox) ) {
467:
468: outb( PORT+DREG,
469: tp->t_rawout.si_buf[ tp->t_rawout.si_ox ] );
470:
471: if ( ++(tp->t_rawout.si_ox) >=
472: sizeof(tp->t_rawout.si_buf) )
473: tp->t_rawout.si_ox = 0;
474: }
475:
476: } while ( ++tp <= hslimtty );
477: }
478:
479: /*
480: * Set hardware parameters.
481: */
482: hsparam( tp )
483: register TTY * tp;
484: {
485: register int b;
486: int s;
487:
488: s = sphi();
489: /*
490: * Assert required modem control lines (DTR, RTS).
491: */
492: b = 0;
493: if ( tp->t_sgttyb.sg_ospeed != B0 )
494: b |= MC_DTR | MC_RTS;
495: outb( PORT+MCR, b );
496:
497: /*
498: * Program baud rate.
499: */
500: if (b = timeconst[ tp->t_sgttyb.sg_ospeed ]) {
501: outb( PORT+LCR, LC_DLAB );
502: outb( PORT+DLL, b );
503: outb( PORT+DLH, b >> 8 );
504: }
505:
506: /*
507: * Program character size, parity.
508: */
509: switch ( tp->t_sgttyb.sg_flags & (EVENP|ODDP|RAW) ) {
510: case ODDP: b = LC_CS7|LC_PARENB; break;
511: case EVENP: b = LC_CS7|LC_PARENB|LC_PAREVEN; break;
512: default: b = LC_CS8; break;
513: }
514: outb( PORT+LCR, b );
515:
516: /*
517: * Enable Transmit Buffer Empty Interrupts.
518: */
519: outb( PORT+IER, IE_TxI );
520:
521: spl(s);
522: set_poll_rate();
523: }
524:
525: /*
526: * Start Routine.
527: */
528: hsstart( tp )
529: register TTY * tp;
530: {
531: register int s;
532:
533: /*
534: * Transmit buffer is empty, and raw output buffer is not.
535: */
536: s = sphi();
537: if ( (inb( PORT+LSR ) & LS_TxRDY)
538: && (tp->t_rawout.si_ix != tp->t_rawout.si_ox) ) {
539:
540: /*
541: * Send next char from raw output buffer.
542: */
543: outb( PORT+DREG, tp->t_rawout.si_buf[ tp->t_rawout.si_ox ] );
544:
545: if ( ++tp->t_rawout.si_ox >= sizeof(tp->t_rawout.si_buf) )
546: tp->t_rawout.si_ox = 0;
547: }
548: spl( s );
549: }
550:
551: /*
552: * hsclk will be called every time T0 interrupts - if it returns 0,
553: * the usual system timer interrupt stuff is done
554: */
555: static int hsclk()
556: {
557: static int count;
558:
559: hsintr();
560: count++;
561: if (count >= poll_divisor)
562: count = 0;
563: return count;
564: }
565:
566: /*
567: * set_poll_rate is called when a port is opened or closed or changes speed
568: * it sets the polling rate only as fast as needed, and shuts off polling
569: * whenever possible
570: */
571: static set_poll_rate()
572: {
573: int port_num, max_rate, port_rate;
574:
575: /*
576: * If another driver has the polling clock, do nothing.
577: */
578: if (poll_owner & ~ POLL_HS)
579: return;
580:
581: /*
582: * find highest valid polling rate in units of HZ/10
583: */
584: max_rate = 0;
585: for (port_num = 0; port_num < HSNUM; port_num++) {
586: if (hstty[port_num].t_open) {
587: port_rate = poll_hz[hstty[port_num].t_sgttyb.sg_ispeed];
588: if (max_rate < port_rate)
589: max_rate = port_rate;
590: }
591: }
592: /*
593: * if max_rate is not current rate, adjust the system clock
594: */
595: if (max_rate != poll_rate) {
596: poll_rate = max_rate;
597: poll_divisor = poll_rate/HZ; /* used in hsclk() */
598: altclk_out(); /* stop previous polling */
599: poll_owner &= ~POLL_HS;
600: if (max_rate) { /* resume polling at new rate if needed */
601: altclk_in(poll_rate, hsclk);
602: poll_owner |= POLL_HS;
603: }
604: }
605: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.