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