|
|
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: static int iocbaud[MAX_HSNUM];
114: static char ioclcr[MAX_HSNUM];
115:
116: /*
117: * Time constant table.
118: * Indexed by ioctl baud rate.
119: */
120: static
121: int timeconst[] = {
122: 0, /* 0 */
123: 2304, /* 50 */
124: 1536, /* 75 */
125: 1047, /* 110 */
126: 857, /* 134.5 */
127: 768, /* 150 */
128: 576, /* 200 */
129: 384, /* 300 */
130: 192, /* 600 */
131: 96, /* 1200 */
132: 64, /* 1800 */
133: 58, /* 2000 */
134: 48, /* 2400 */
135: 32, /* 3600 */
136: 24, /* 4800 */
137: 16, /* 7200 */
138: 12, /* 9600 */
139: 6, /* 19200 */
140: 6, /* EXTA */
141: 6 /* EXTB */
142: };
143:
144: /*
145: * poll_hz[] is tied to timeconst[] - it gives the minimum polling
146: * rate for the corresponding port speed; it must be a multiple
147: * of 100 (system clock Hz) and >= baud/6
148: */
149: int poll_hz[] ={
150: 0, /* 0 */
151: 1*HZ, /* 50 */
152: 1*HZ, /* 75 */
153: 1*HZ, /* 110 */
154: 1*HZ, /* 134.5 */
155: 1*HZ, /* 150 */
156: 1*HZ, /* 200 */
157: 1*HZ, /* 300 */
158: 1*HZ, /* 600 */
159: 2*HZ, /* 1200 */
160: 3*HZ, /* 1800 */
161: 4*HZ, /* 2000 */
162: 4*HZ, /* 2400 */
163: 6*HZ, /* 3600 */
164: 8*HZ, /* 4800 */
165: 12*HZ, /* 7200 */
166: 16*HZ, /* 9600 */
167: 0, /* 19200 */
168: 0, /* EXTA */
169: 0 /* EXTB */
170: };
171:
172: /*
173: * Load Routine.
174: */
175: static hsload()
176: {
177: register TTY * tp;
178: register int port;
179: int i, b;
180:
181: if ((hstty = (TTY *)kalloc(HSNUM*sizeof(TTY))) == 0) {
182: printf("hsload: can't allocate tty's\n");
183: return;
184: }
185: kclear(hstty, HSNUM*sizeof(TTY));
186:
187: for (i = 0; i < HSNUM; i++) {
188: port = HS_PORTS[i].addr;
189: tp = hstty + i;
190:
191: outb(port+MCR, 0);
192: outb(port+IER, 0);
193:
194: if (inb(port+IER))
195: break;
196:
197: tp->t_cs_sel = cs_sel();
198: tp->t_start = hsstart;
199: tp->t_param = hsparam;
200: tp->t_sgttyb.sg_ospeed = tp->t_sgttyb.sg_ispeed =
201: tp->t_dispeed = tp->t_dospeed = HS_PORTS[i].speed;
202: tp->t_ddp = port;
203:
204: b = timeconst[ tp->t_sgttyb.sg_ospeed ];
205: outb(port+LCR, LC_DLAB);
206: outb(port+DLL, b);
207: outb(port+DLH, b >> 8);
208: outb(port+LCR, LC_CS8);
209:
210: hslimtty = tp;
211: }
212: }
213:
214: static hsunload()
215: {
216: if (hstty != (TTY *)0)
217: kfree(hstty);
218: }
219:
220: /*
221: * Open Routine.
222: */
223: hsopen(dev, mode)
224: dev_t dev;
225: {
226: register TTY * tp = &hstty[ dev & 15 ];
227: register int b;
228: int s;
229:
230: /*
231: * Verify hardware exists.
232: */
233: if ((PORT == 0) || (inb(PORT+IER) & ~IE_TxI)) {
234: u.u_error = ENXIO;
235: return;
236: }
237:
238: /*
239: * Can't open if another driver is using polling
240: */
241: if (poll_owner & ~ POLL_HS) {
242: u.u_error = EDBUSY;
243: return;
244: }
245:
246: /*
247: * Initialize if not already open.
248: */
249: if (++tp->t_open == 1) {
250: ttopen(tp);
251:
252: if (dev & 0x80) {
253: s = sphi();
254: b = inb(PORT+MSR);
255: tp->t_flags |= T_MODC + T_STOP;
256: if (b & MS_CTS)
257: tp->t_flags &= ~T_STOP;
258: if (b & MS_DSR)
259: tp->t_flags |= T_CARR;
260: spl(s);
261: } else {
262: tp->t_flags &= ~T_MODC;
263: tp->t_flags |= T_CARR;
264: }
265: hscycle(tp);
266: }
267: ttsetgrp(tp, dev);
268: set_poll_rate();
269: }
270:
271: /*
272: * Close Routine.
273: */
274: hsclose(dev)
275: dev_t dev;
276: {
277: register TTY * tp = &hstty[ dev & 15 ];
278:
279: /*
280: * Reset if last close.
281: */
282: if (tp->t_open == 1) {
283: int state;
284:
285: ttclose(tp);
286: /*
287: * ttclose() only emptied the output queue tp->t_oq;
288: * now wait 0.1 sec for the silo tp->rawout to empty
289: * and allow a delay for the UART on-chip xmit buffer to empty
290: *
291: * state 2: waiting for silo to empty
292: * state 1: stalling so UART can empty xmit buffer
293: * state 0: done!
294: */
295: state = 2;
296: while (state) {
297: timeout(&hstim, 10, wakeup, (int)&hstim);
298: sleep((char *)&hstim, CVTTOUT, IVTTOUT, SVTTOUT);
299: if (tp->t_rawout.si_ix == tp->t_rawout.si_ox && state)
300: state--;
301: }
302: }
303:
304: --tp->t_open;
305: set_poll_rate();
306: }
307:
308: /*
309: * Read Routine.
310: */
311: hsread(dev, iop)
312: dev_t dev;
313: register IO * iop;
314: {
315: ttread(&hstty[ dev & 15 ], iop);
316: }
317:
318: /*
319: * Write Routine.
320: */
321: hswrite(dev, iop)
322: dev_t dev;
323: register IO * iop;
324: {
325: ttwrite(&hstty[ dev & 15 ], iop);
326: }
327:
328: /*
329: * Ioctl Routine.
330: */
331: hsioctl(dev, com, vec)
332: dev_t dev;
333: int com;
334: struct sgttyb * vec;
335: {
336: ttioctl(&hstty[ dev & 15 ], com, vec);
337: }
338:
339: /*
340: * Polling Routine.
341: */
342: hspoll(dev, ev, msec)
343: dev_t dev;
344: int ev;
345: int msec;
346: {
347: return ttpoll(&hstty[ dev & 15 ], ev, msec);
348: }
349:
350: /*
351: * Cyclic routine - invoked every clock tick to perform raw input/output.
352: *
353: * Notes: Invoked 10 times per second.
354: */
355: hscycle(tp)
356: register TTY * tp;
357: {
358: register int resid;
359: register int c;
360:
361: /*
362: * Process rawin buf.
363: */
364: while (tp->t_rawin.si_ix != tp->t_rawin.si_ox) {
365:
366: ttin(tp, tp->t_rawin.si_buf[ tp->t_rawin.si_ox ]);
367:
368: if (tp->t_rawin.si_ox >= sizeof(tp->t_rawin.si_buf) - 1)
369: tp->t_rawin.si_ox = 0;
370: else
371: tp->t_rawin.si_ox++;
372: }
373:
374: /*
375: * Calculate free output slot count.
376: */
377: resid = sizeof(tp->t_rawout.si_buf) - 1;
378: resid += tp->t_rawout.si_ox - tp->t_rawout.si_ix;
379: resid %= sizeof(tp->t_rawout.si_buf);
380:
381: /*
382: * Fill raw output buffer.
383: */
384: while ((--resid >= 0) && ((c = ttout(tp)) >= 0)) {
385:
386: tp->t_rawout.si_buf[ tp->t_rawout.si_ix ] = c;
387:
388: if (tp->t_rawout.si_ix >= sizeof(tp->t_rawout.si_buf) - 1)
389: tp->t_rawout.si_ix = 0;
390: else
391: tp->t_rawout.si_ix++;
392: }
393:
394: /*
395: * (Re)start output, waking processes waiting to output, etc.
396: */
397: ttstart(tp);
398:
399: /*
400: * Schedule next cycle.
401: */
402: if (tp->t_open != 0)
403: timeout(&tp->t_rawtim, HZ/10, hscycle, tp);
404: }
405:
406: /*
407: * Clock Interrupt driven Polling routine.
408: */
409: hsintr()
410: {
411: register TTY * tp = &hstty[0];
412: register int b;
413:
414: do {
415: if (tp->t_open == 0)
416: continue;
417:
418: /*
419: * Check modem status if modem control is enabled.
420: */
421: if (tp->t_flags & T_MODC) {
422:
423: b = inb(PORT+MSR);
424:
425: if (b & (MS_DCTS|MS_DDSR)) {
426:
427: if (b & MS_DCTS) {
428: if (b & MS_CTS)
429: tp->t_flags &= ~T_STOP;
430: else
431: tp->t_flags |= T_STOP;
432: }
433: if (b & MS_DDSR) {
434: if (b & MS_DSR)
435: tp->t_flags |= T_CARR;
436: else {
437: tp->t_flags &= ~T_CARR;
438: tthup(tp);
439: }
440: }
441: }
442: }
443:
444: b = inb(PORT+LSR);
445:
446: if ((b & LS_BREAK) && (tp->t_flags & T_CARR))
447: ttsignal(tp, SIGINT);
448:
449: /*
450: * Receive ready.
451: */
452: if (b & LS_RxRDY) {
453:
454: tp->t_rawin.si_buf[tp->t_rawin.si_ix] = inb(PORT+DREG);
455:
456: if (tp->t_flags & T_CARR) {
457:
458: if (++(tp->t_rawin.si_ix) >=
459: sizeof(tp->t_rawin.si_buf))
460: tp->t_rawin.si_ix = 0;
461: }
462: }
463:
464: /*
465: * Transmit ready and raw output data exists.
466: */
467: if ((b & LS_TxRDY) && ((tp->t_flags & T_STOP) == 0)
468: && (tp->t_rawout.si_ix != tp->t_rawout.si_ox)) {
469:
470: outb( PORT+DREG,
471: tp->t_rawout.si_buf[ tp->t_rawout.si_ox ]);
472:
473: if (++(tp->t_rawout.si_ox) >=
474: sizeof(tp->t_rawout.si_buf))
475: tp->t_rawout.si_ox = 0;
476: }
477:
478: } while (++tp <= hslimtty);
479: }
480:
481: /*
482: * Set hardware parameters.
483: */
484: hsparam(tp)
485: register TTY * tp;
486: {
487: register int b;
488: int s;
489: int hnum;
490: int newbaud;
491: char newlcr;
492: int write_baud = 1, write_lcr = 1;
493:
494: newbaud = timeconst[tp->t_sgttyb.sg_ospeed];
495:
496: switch (tp->t_sgttyb.sg_flags & (EVENP|ODDP|RAW)) {
497: case ODDP:
498: newlcr = LC_CS7|LC_PARENB;
499: break;
500: case EVENP:
501: newlcr = LC_CS7|LC_PARENB|LC_PAREVEN;
502: break;
503: default:
504: newlcr = LC_CS8;
505: break;
506: }
507:
508: hnum = tp - hstty;
509: if (hnum >= 0 && hnum < HSNUM) {
510: if (newbaud == iocbaud[hnum]) {
511: write_baud = 0;
512: if (newlcr == ioclcr[hnum]) {
513: write_lcr = 0;
514: }
515: }
516: iocbaud[hnum] = newbaud;
517: ioclcr[hnum] = newlcr;
518: }
519:
520: s = sphi();
521: /*
522: * Assert required modem control lines (DTR, RTS).
523: */
524: if (tp->t_sgttyb.sg_ospeed == B0) {
525: outb(PORT+MCR, 0);
526: } else {
527: outb(PORT+MCR, MC_DTR | MC_RTS);
528: }
529:
530: /*
531: * Program baud rate.
532: */
533: if (write_baud) {
534: outb(PORT+LCR, LC_DLAB);
535: outb(PORT+DLL, newbaud);
536: outb(PORT+DLH, newbaud >> 8);
537: }
538:
539: /*
540: * Program character size, parity.
541: */
542: if (write_lcr)
543: outb(PORT+LCR, newlcr);
544:
545: /*
546: * Enable Transmit Buffer Empty Interrupts.
547: */
548: outb(PORT+IER, IE_TxI);
549:
550: spl(s);
551: set_poll_rate();
552: }
553:
554: /*
555: * Start Routine.
556: */
557: hsstart(tp)
558: register TTY * tp;
559: {
560: register int s;
561:
562: /*
563: * Transmit buffer is empty, and raw output buffer is not.
564: */
565: s = sphi();
566: if ((inb(PORT+LSR) & LS_TxRDY)
567: && (tp->t_rawout.si_ix != tp->t_rawout.si_ox)) {
568:
569: /*
570: * Send next char from raw output buffer.
571: */
572: outb(PORT+DREG, tp->t_rawout.si_buf[ tp->t_rawout.si_ox ]);
573:
574: if (++tp->t_rawout.si_ox >= sizeof(tp->t_rawout.si_buf))
575: tp->t_rawout.si_ox = 0;
576: }
577: spl(s);
578: }
579:
580: /*
581: * hsclk will be called every time T0 interrupts - if it returns 0,
582: * the usual system timer interrupt stuff is done
583: */
584: static int hsclk()
585: {
586: static int count;
587:
588: hsintr();
589: count++;
590: if (count >= poll_divisor)
591: count = 0;
592: return count;
593: }
594:
595: /*
596: * set_poll_rate is called when a port is opened or closed or changes speed
597: * it sets the polling rate only as fast as needed, and shuts off polling
598: * whenever possible
599: */
600: static set_poll_rate()
601: {
602: int port_num, max_rate, port_rate;
603:
604: /*
605: * If another driver has the polling clock, do nothing.
606: */
607: if (poll_owner & ~ POLL_HS)
608: return;
609:
610: /*
611: * find highest valid polling rate in units of HZ/10
612: */
613: max_rate = 0;
614: for (port_num = 0; port_num < HSNUM; port_num++) {
615: if (hstty[port_num].t_open) {
616: port_rate = poll_hz[hstty[port_num].t_sgttyb.sg_ispeed];
617: if (max_rate < port_rate)
618: max_rate = port_rate;
619: }
620: }
621: /*
622: * if max_rate is not current rate, adjust the system clock
623: */
624: if (max_rate != poll_rate) {
625: poll_rate = max_rate;
626: poll_divisor = poll_rate/HZ; /* used in hsclk() */
627: altclk_out(); /* stop previous polling */
628: poll_owner &= ~POLL_HS;
629: if (max_rate) { /* resume polling at new rate if needed */
630: altclk_in(poll_rate, hsclk);
631: poll_owner |= POLL_HS;
632: }
633: }
634: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.