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