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