|
|
1.1 root 1: /*
2: * Interrupt Driver Multi-Port Device Driver.
3: * - supports version 7 compatible ioctl
4: */
5:
6: #include "coherent.h"
7: #include "ins8250.h"
8: #include <sys/stat.h>
9: #include <sys/proc.h>
10: #include <sys/tty.h> /* indirectly includes sgtty.h */
11: #include <sys/con.h>
12: #include <errno.h>
13: #include <sys/timeout.h> /* TIM */
14: #include <sched.h> /* CVTTOUT, IVTTOUT, SVTTOUT */
15: #include <poll_clk.h>
16:
17: /*
18: * Definitions.
19: *
20: * MAX_GCNUM is the maximum number of devices that can be polled
21: * using this driver and can be revised up or down
22: * PORT is a convenience macro for the base address of a port
23: * port_config is the structure of the initial configuration for each
24: * polled port; note that "speed" is NOT the actual baud rate, but
25: * the value of the symbol for that baud rate as defined in
26: * /usr/include/sgtty.h
27: * GCINT is the IRQ number for the interrupt belonging to the board.
28: * On the AT, IRQ2 is mapped to the same vector as IRQ9.
29: */
30: #define MAX_GCNUM 8
31: #define PORT ((int)(tp->t_ddp))
32: struct port_config {
33: int addr; /* base address of the 8250-family UART */
34: int speed; /* B0..B19200 */
35: };
36: #define GCINT 2
37:
38: /*
39: * Export Variables - these can be patched without recompiling and linking
40: *
41: * GCNUM is the actual number of polled serial ports, and should be
42: * less than or equal to MAX_GCNUM
43: * GCIRPT is the I/O address of the multiport interrupt register;
44: * a value of 0 in bit 0..3 means a pending interrupt for port 0..3
45: * GC_PORTS is an array of address/speed pairs, one for each port
46: */
47: int GCNUM = 4;
48: int GCIRPT = 0x2BF;
49: /*
50: * Defaults are for PC COM4, Enhanced Mode, High Address.
51: */
52: struct port_config GC_PORTS[MAX_GCNUM] = {
53: { 0x2A0, B9600 },
54: { 0x2A8, B9600 },
55: { 0x2B0, B9600 },
56: { 0x2B8, B9600 }
57: };
58:
59: /*
60: * Export Functions.
61: */
62: int gcload();
63: int gcopen();
64: int gcclose();
65: int gcread();
66: int gcwrite();
67: int gcioctl();
68: int gcunload();
69: int gcpoll();
70:
71: int gccycle();
72: int gcintr();
73: int gcparam();
74: int gcstart();
75:
76: /*
77: * Import Functions
78: */
79: int nulldev();
80: int nonedev();
81:
82: /*
83: * Configuration table.
84: */
85: CON gccon ={
86: DFCHR|DFPOL, /* Flags */
87: GCINT, /* Major index */
88: gcopen, /* Open */
89: gcclose, /* Close */
90: nulldev, /* Block */
91: gcread, /* Read */
92: gcwrite, /* Write */
93: gcioctl, /* Ioctl */
94: nulldev, /* Powerfail */
95: nulldev, /* Timeout */
96: gcload, /* Load */
97: gcunload, /* Unload */
98: gcpoll /* Poll */
99: };
100:
101: /*
102: * Local variables.
103: */
104: static TTY *hstty;
105: static TTY *hslimtty;
106: static TIM hstim;
107:
108: /*
109: * Time constant table.
110: * Indexed by ioctl baud rate.
111: */
112: static
113: int timeconst[] = {
114: 0, /* 0 */
115: 2304, /* 50 */
116: 1536, /* 75 */
117: 1047, /* 110 */
118: 857, /* 134.5 */
119: 768, /* 150 */
120: 576, /* 200 */
121: 384, /* 300 */
122: 192, /* 600 */
123: 96, /* 1200 */
124: 64, /* 1800 */
125: 58, /* 2000 */
126: 48, /* 2400 */
127: 32, /* 3600 */
128: 24, /* 4800 */
129: 16, /* 7200 */
130: 12, /* 9600 */
131: 6, /* 19200 */
132: 6, /* EXTA */
133: 6 /* EXTB */
134: };
135:
136: /*
137: * Load Routine.
138: */
139: static gcload()
140: {
141: register TTY * tp;
142: register int port;
143: int i, b, s;
144:
145: if ((hstty = (TTY *)kalloc(GCNUM*sizeof(TTY))) == 0) {
146: printf("gcload: can't allocate tty's\n");
147: return;
148: }
149: kclear(hstty, GCNUM*sizeof(TTY));
150:
151: s = sphi();
152: for (i = 0; i < GCNUM; i++) {
153: port = GC_PORTS[i].addr;
154: tp = hstty + i;
155:
156: outb( port+MCR, 0 );
157: outb( port+IER, 0 );
158:
159: if ( inb( port+IER ) )
160: break;
161:
162: tp->t_cs_sel = cs_sel();
163: tp->t_start = gcstart;
164: tp->t_param = gcparam;
165: tp->t_sgttyb.sg_ospeed = tp->t_sgttyb.sg_ispeed =
166: tp->t_dispeed = tp->t_dospeed = GC_PORTS[i].speed;
167: tp->t_ddp = port;
168:
169: b = timeconst[ tp->t_sgttyb.sg_ospeed ];
170: outb( port+LCR, LC_DLAB );
171: outb( port+DLL, b );
172: outb( port+DLH, b >> 8);
173: outb( port+LCR, LC_CS8);
174:
175: hslimtty = tp;
176: }
177: setivec(GCINT, gcintr);
178: spl(s);
179: }
180:
181: static gcunload()
182: {
183: clrivec(GCINT);
184: kfree(hstty);
185: }
186:
187: /*
188: * Open Routine.
189: */
190: gcopen( dev, mode )
191: dev_t dev;
192: {
193: register TTY * tp = &hstty[ dev & 15 ];
194: register int b;
195: int s;
196:
197: /*
198: * Verify hardware exists.
199: */
200: if ( (PORT == 0) || (inb(PORT+IER) & ~IE_TxI) ) {
201: u.u_error = ENXIO;
202: return;
203: }
204:
205: /*
206: * Initialize if not already open.
207: */
208: if ( ++tp->t_open == 1 ) {
209: ttopen( tp );
210:
211: if ( dev & 0x80 ) {
212: s = sphi();
213: b = inb(PORT+MSR);
214: tp->t_flags |= T_MODC + T_STOP;
215: if ( b & MS_CTS )
216: tp->t_flags &= ~T_STOP;
217: if ( b & MS_DSR )
218: tp->t_flags |= T_CARR;
219: spl( s );
220: } else {
221: tp->t_flags &= ~T_MODC;
222: tp->t_flags |= T_CARR;
223: }
224: gccycle( tp );
225: }
226: ttsetgrp( tp, dev );
227: }
228:
229: /*
230: * Close Routine.
231: */
232: gcclose( dev )
233: dev_t dev;
234: {
235: register TTY * tp = &hstty[ dev & 15 ];
236:
237: /*
238: * Reset if last close.
239: */
240: if ( tp->t_open == 1 ) {
241: int state;
242:
243: ttclose( tp );
244: /*
245: * ttclose() only emptied the output queue tp->t_oq;
246: * now wait 0.1 sec for the silo tp->rawout to empty
247: * and allow a delay for the UART on-chip xmit buffer to empty
248: *
249: * state 2: waiting for silo to empty
250: * state 1: stalling so UART can empty xmit buffer
251: * state 0: done!
252: */
253: state = 2;
254: while (state) {
255: timeout(&hstim, 10, wakeup, (int)&hstim);
256: sleep((char *)&hstim, CVTTOUT, IVTTOUT, SVTTOUT);
257: if (tp->t_rawout.si_ix == tp->t_rawout.si_ox && state)
258: state--;
259: }
260: }
261:
262: --tp->t_open;
263: }
264:
265: /*
266: * Read Routine.
267: */
268: gcread( dev, iop )
269: dev_t dev;
270: register IO * iop;
271: {
272: ttread( &hstty[ dev & 15 ], iop, 0 );
273: }
274:
275: /*
276: * Write Routine.
277: */
278: gcwrite( dev, iop )
279: dev_t dev;
280: register IO * iop;
281: {
282: ttwrite( &hstty[ dev & 15 ], iop, 0 );
283: }
284:
285: /*
286: * Ioctl Routine.
287: */
288: gcioctl( dev, com, vec )
289: dev_t dev;
290: int com;
291: struct sgttyb * vec;
292: {
293: ttioctl( &hstty[ dev & 15 ], com, vec );
294: }
295:
296: /*
297: * Polling Routine.
298: */
299: gcpoll( dev, ev, msec )
300: dev_t dev;
301: int ev;
302: int msec;
303: {
304: return ttpoll( &hstty[ dev & 15 ], ev, msec );
305: }
306:
307: /*
308: * Cyclic routine - invoked every clock tick to perform raw input/output.
309: *
310: * Notes: Invoked 10 times per second.
311: */
312: gccycle( tp )
313: register TTY * tp;
314: {
315: register int resid;
316: register int c;
317:
318: /*
319: * Process rawin buf.
320: */
321: while ( tp->t_rawin.si_ix != tp->t_rawin.si_ox ) {
322:
323: ttin( tp, tp->t_rawin.si_buf[ tp->t_rawin.si_ox ] );
324:
325: if ( tp->t_rawin.si_ox >= sizeof(tp->t_rawin.si_buf) - 1 )
326: tp->t_rawin.si_ox = 0;
327: else
328: tp->t_rawin.si_ox++;
329: }
330:
331: /*
332: * Calculate free output slot count.
333: */
334: resid = sizeof(tp->t_rawout.si_buf) - 1;
335: resid += tp->t_rawout.si_ox - tp->t_rawout.si_ix;
336: resid %= sizeof(tp->t_rawout.si_buf);
337:
338: /*
339: * Fill raw output buffer.
340: */
341: while ( (--resid >= 0) && ((c = ttout(tp)) >= 0) ) {
342:
343: tp->t_rawout.si_buf[ tp->t_rawout.si_ix ] = c;
344:
345: if ( tp->t_rawout.si_ix >= sizeof(tp->t_rawout.si_buf) - 1 )
346: tp->t_rawout.si_ix = 0;
347: else
348: tp->t_rawout.si_ix++;
349: }
350:
351: /*
352: * (Re)start output, waking processes waiting to output, etc.
353: */
354: ttstart( tp );
355:
356: /*
357: * Schedule next cycle.
358: */
359: if ( tp->t_open != 0 )
360: timeout( &tp->t_rawtim, HZ/10, gccycle, tp );
361: }
362:
363: /*
364: * Interrupt driven Polling routine.
365: */
366: gcintr()
367: {
368: register TTY * tp = &hstty[0];
369: register int b;
370:
371: do {
372: if ( tp->t_open == 0 )
373: continue;
374:
375: /*
376: * Check modem status if modem control is enabled.
377: */
378: if ( tp->t_flags & T_MODC ) {
379:
380: b = inb( PORT+MSR );
381:
382: if ( b & (MS_DCTS|MS_DDSR) ) {
383:
384: if ( b & MS_DCTS ) {
385: if ( b & MS_CTS )
386: tp->t_flags &= ~T_STOP;
387: else
388: tp->t_flags |= T_STOP;
389: }
390: if ( b & MS_DDSR ) {
391: if ( b & MS_DSR )
392: tp->t_flags |= T_CARR;
393: else {
394: tp->t_flags &= ~T_CARR;
395: tthup( tp );
396: }
397: }
398: }
399: }
400:
401: b = inb( PORT+LSR );
402:
403: if ( (b & LS_BREAK) && (tp->t_flags & T_CARR) )
404: ttsignal( tp, SIGINT );
405:
406: /*
407: * Receive ready.
408: */
409: if ( b & LS_RxRDY ) {
410:
411: tp->t_rawin.si_buf[tp->t_rawin.si_ix] = inb(PORT+DREG);
412:
413: if ( tp->t_flags & T_CARR ) {
414:
415: if ( ++(tp->t_rawin.si_ix) >=
416: sizeof(tp->t_rawin.si_buf) )
417: tp->t_rawin.si_ix = 0;
418: }
419: }
420:
421: /*
422: * Transmit ready and raw output data exists.
423: */
424: if ( (b & LS_TxRDY) && ((tp->t_flags & T_STOP) == 0)
425: && (tp->t_rawout.si_ix != tp->t_rawout.si_ox) ) {
426:
427: outb( PORT+DREG,
428: tp->t_rawout.si_buf[ tp->t_rawout.si_ox ] );
429:
430: if ( ++(tp->t_rawout.si_ox) >=
431: sizeof(tp->t_rawout.si_buf) )
432: tp->t_rawout.si_ox = 0;
433: }
434:
435: } while ( ++tp <= hslimtty );
436: }
437:
438: /*
439: * Set hardware parameters.
440: */
441: gcparam( tp )
442: register TTY * tp;
443: {
444: register int b;
445: int s;
446:
447: s = sphi();
448: /*
449: * Assert required modem control lines (DTR, RTS).
450: */
451: b = 0;
452: if ( tp->t_sgttyb.sg_ospeed != B0 )
453: b |= MC_DTR | MC_RTS;
454: outb( PORT+MCR, b );
455:
456: /*
457: * Program baud rate.
458: */
459: if (b = timeconst[ tp->t_sgttyb.sg_ospeed ]) {
460: outb( PORT+LCR, LC_DLAB );
461: outb( PORT+DLL, b );
462: outb( PORT+DLH, b >> 8 );
463: }
464:
465: /*
466: * Program character size, parity.
467: */
468: switch ( tp->t_sgttyb.sg_flags & (EVENP|ODDP|RAW) ) {
469: case ODDP: b = LC_CS7|LC_PARENB; break;
470: case EVENP: b = LC_CS7|LC_PARENB|LC_PAREVEN; break;
471: default: b = LC_CS8; break;
472: }
473: outb( PORT+LCR, b );
474:
475: /*
476: * Enable Transmit Buffer Empty Interrupts.
477: */
478: outb( PORT+IER, IE_TxI );
479:
480: spl(s);
481: }
482:
483: /*
484: * Start Routine.
485: */
486: gcstart( tp )
487: register TTY * tp;
488: {
489: register int s;
490:
491: /*
492: * Transmit buffer is empty, and raw output buffer is not.
493: */
494: s = sphi();
495: if ( (inb( PORT+LSR ) & LS_TxRDY)
496: && (tp->t_rawout.si_ix != tp->t_rawout.si_ox) ) {
497:
498: /*
499: * Send next char from raw output buffer.
500: */
501: outb( PORT+DREG, tp->t_rawout.si_buf[ tp->t_rawout.si_ox ] );
502:
503: if ( ++tp->t_rawout.si_ox >= sizeof(tp->t_rawout.si_buf) )
504: tp->t_rawout.si_ox = 0;
505: }
506: spl( s );
507: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.