|
|
1.1 root 1: /* (-lgl
2: * COHERENT Device Driver Kit version 1.2.0
3: * Copyright (c) 1982, 1991 by Mark Williams Company.
4: * All rights reserved. May not be copied without permission.
5: *
6: * $Log: al.c,v $
7: * Revision 1.2 92/08/04 12:51:37 bin
8: * update for ker59
9: *
10: * Revision 1.6 92/04/30 08:59:22 hal
11: * Add asy. Remove silos from tty struct.
12: *
13: * Revision 1.5 92/04/13 10:13:01 hal
14: * Add AL_ADDR table.
15: * Change chip sensing for weird 16550 chips lacking SCR register.
16: *
17: * Revision 1.4 92/02/20 17:50:52 hal
18: * Do 286->S5 sgtty conversion.
19: *
20: * Revision 1.11 92/01/13 08:37:52 hal
21: * alclose() - decrement open count in alx.c
22: *
23: * Revision 1.10 91/12/20 14:09:50 hal
24: * Don't use loopback during chip sense.
25: *
26: * Revision 1.9 91/12/10 08:01:11 hal
27: * Set ALCNT automatically.
28: * Set interrupt vector before calling uart_sense().
29: *
30: * Revision 1.8 91/12/05 09:35:25 hal
31: * Working 16550A code. Nfg on GeeSee.
32: *
33: * Revision 1.7 91/12/02 19:22:00 hal
34: * Last version before FIFO testing.
35: *
36: -lgl) */
37: /*
38: * Driver for an IBM PC asyncronous
39: * line, using interrupts. The interface
40: * uses a Natty/WD 8250 chip.
41: */
42:
43: #include <sys/coherent.h>
44: #ifndef _I386
45: #include <sys/i8086.h>
46: #endif
47: #include <sys/con.h>
48: #include <errno.h>
49: #include <sys/stat.h>
50: #include <sys/tty.h>
51: #include <sys/clist.h>
52: #include <sys/ins8250.h>
53: #include <sys/sched.h>
54: #include <sys/al.h>
55: #include <sys/devices.h>
56:
57: #define minor_st(dev) (dev & 0x0f) /* up to 16 ports per driver */
58: #define DEV_TTY (alttab[minor_st(dev)])
59: #define ALPORT (((COM_DDP *)(DEV_TTY.t_ddp))->port)
60:
61: /*
62: * This driver can be compiled to drive any possible
63: * async port by appropriate definitions of:
64: * ALPORT[ab] the io port address(es)
65: * ALNUM[ab] com index number (0..3 for com[1..4])
66: * ALINT the interrupt level
67: * ALNAME the xxcon name
68: * ALMAJ the major device number
69: * ALCNT number of ports sharing the interrupt
70: *
71: * NOTE: if ALCNT is changed, alttab and alintr will need hacking
72: * Common code for the different ports is handled by alx.c
73: */
74:
75: #ifdef ALCOM1 /* COM1_3 definitions */
76: #define ALPORTa 0x3F8 /* Base of com1 port */
77: #define ALPORTb 0x3E8 /* Base of com3 port */
78: #define ALNUMa 0 /* com1 has com number of 0 */
79: #define ALNUMb 2 /* com3 has com number of 2 */
80: #define ALINT 4 /* Interrupt level of com1_3 ports */
81: #define ALNAME a0con /* CON name of com1_3 ports */
82: #define ALMAJ AL0_MAJOR /* Major number of com1_3 port */
83: #define ALCNT A0CNT /* Number of ports for this IRQ */
84: #define ALSPEEDa C1BAUD /* Name of patchable variable for com1 speed */
85: #define ALSPEEDb C3BAUD /* Name of patchable variable for com3 speed */
86: #endif
87:
88: #ifdef ALCOM2 /* COM2_4 definitions */
89: #define ALPORTa 0x2F8 /* Base of com2 port */
90: #define ALPORTb 0x2E8 /* Base of com4 port */
91: #define ALNUMa 1 /* com2 has com number of 1 */
92: #define ALNUMb 3 /* com4 has com number of 3 */
93: #define ALINT 3 /* Interrupt level of com2_4 ports */
94: #define ALNAME a1con /* CON name of com2_4 ports */
95: #define ALMAJ AL1_MAJOR /* Major number of com2_4 ports */
96: #define ALCNT A1CNT /* Number of ports for this IRQ */
97: #define ALSPEEDa C2BAUD /* Name of patchable variable for com2 speed */
98: #define ALSPEEDb C4BAUD /* Name of patchable variable for com4 speed */
99: #endif
100:
101: /*
102: * Functions.
103: */
104: int alxopen();
105: int alxclose();
106: int alxioctl();
107: int alxtimer();
108: int alxparam();
109: int alxcycle();
110: int alxstart();
111: int alxbreak();
112:
113: int alintr();
114: int alopen();
115: int alclose();
116: int alread();
117: int alwrite();
118: static int alioctl();
119: int alload();
120: int alunload();
121: int alpoll();
122: int nulldev();
123: int nonedev();
124: static int alioctl();
125: static int alioctl0();
126:
127: /*
128: * Configuration table.
129: */
130: CON ALNAME ={
131: DFCHR|DFPOL, /* Flags */
132: ALMAJ, /* Major index */
133: alopen, /* Open */
134: alclose, /* Close */
135: nulldev, /* Block */
136: alread, /* Read */
137: alwrite, /* Write */
138: #ifdef _I386
139: alioctl0, /* Ioctl */
140: #else
141: alioctl, /* Ioctl */
142: #endif
143: nulldev, /* Powerfail */
144: alxtimer, /* Timeout */
145: alload, /* Load */
146: alunload, /* Unload */
147: alpoll /* Poll */
148: };
149:
150: /*
151: * Terminal structures.
152: */
153: static COM_DDP * ddp;
154: static TTY * alttab;
155: static TTY * irqtty; /* point to alttab entry which is IRQ-enabled */
156:
157: /*
158: * to change default speeds - patch kernel variables C1BAUD..C4BAUD
159: * new value should be one of B0..B9600 in /usr/include/sgtty.h
160: */
161: int ALSPEEDa = B9600;
162: int ALSPEEDb = B9600;
163:
164: /*
165: * to enable com[34], patch here
166: * A0CNT should be 2 if you want com3, 1 otherwise
167: * A1CNT should be 2 if you want com4, 1 otherwise
168: */
169: int ALCNT = 2;
170:
171: static
172: alload()
173: {
174: register int s;
175: static int init;
176: extern int albaud[];
177: int port, i;
178: int usa, usb;
179: extern int AL_ADDR[];
180:
181: /*
182: * Set interrupt vector early in case uart_sense() causes bogus irpts.
183: */
184: setivec(ALINT, alintr); /* set interrupt vector */
185: usa = uart_sense(AL_ADDR[ALNUMa]);
186: usb = uart_sense(AL_ADDR[ALNUMb]);
187: putchar('\n');
188: if (usa == US_NONE && usb == US_NONE) {
189: ALCNT = 0;
190: } else {
191: if (usb == US_NONE)
192: ALCNT = 1;
193: else
194: ALCNT = 2;
195: }
196: if (init == 0 && ALCNT
197: && (alttab = (TTY *)kalloc(ALCNT * sizeof(TTY)))
198: && (ddp = (COM_DDP *)kalloc(ALCNT * sizeof(COM_DDP)))) {
199: kclear(alttab, ALCNT*sizeof(TTY));
200: kclear(ddp, ALCNT*sizeof(COM_DDP));
201: ++init;
202:
203: s = sphi();
204: alttab[0].t_dispeed = alttab[0].t_dospeed = ALSPEEDa;
205: alttab[0].t_ddp = (char *)&ddp[0];
206: tp_table[ALNUMa] = alttab; /* set TTY pointers for polling */
207: ddp[0].port = AL_ADDR[ALNUMa];
208: ddp[0].com_num = ALNUMa;
209: com_usage[ALNUMa].uart_type = usa;
210:
211: if (ALCNT > 1) {
212: alttab[1].t_dispeed = alttab[1].t_dospeed = ALSPEEDb;
213: alttab[1].t_ddp = (char *)&ddp[1];
214: tp_table[ALNUMb] = alttab+1;
215: ddp[1].port = AL_ADDR[ALNUMb];
216: ddp[1].com_num = ALNUMb;
217: com_usage[ALNUMb].uart_type = usb;
218: }
219:
220: for (i = 0; i < ALCNT; i++) {
221: int speed = alttab[i].t_dospeed;
222:
223: /* port = base I/O address */
224: port = ((COM_DDP *)(alttab[i].t_ddp))->port;
225: outb(port+IER, 0); /* disable port interrupts */
226: outb(port+MCR, 0); /* hangup port */
227: outb(port+LCR, LC_DLAB);
228: outb(port+DLL, albaud[speed]);
229: outb(port+DLH, albaud[speed] >> 8);
230: outb(port+LCR, LC_CS8);
231: alttab[i].t_start = alxstart;
232: alttab[i].t_param = alxparam;
233: alttab[i].t_cs_sel= cs_sel();
234: }
235:
236: spl(s);
237: } else { /* Load failed - no ports or no RAM available! */
238: clrivec(ALINT);
239: }
240: return;
241: }
242:
243: static
244: alunload()
245: {
246: int port, i;
247:
248: for (i = 0; i < ALCNT; i++) {
249: port = ((COM_DDP *)(alttab[i].t_ddp))->port;
250: outb(port+IER, 0); /* disable port interrupts */
251: outb(port+MCR, 0); /* hangup port */
252: timeout(alttab[i].t_rawtim, 0, NULL, 0);/* cancel timer */
253: }
254: if (ALCNT) {
255: clrivec(ALINT); /* release interrupt vector */
256: kfree(alttab);
257: kfree(ddp);
258: }
259: }
260:
261: static
262: alopen(dev, mode)
263: dev_t dev;
264: int mode;
265: {
266: if (minor_st(dev) < ALCNT) {
267: alxopen(dev, mode, &DEV_TTY, &irqtty);
268: } else
269: u.u_error = ENXIO;
270: }
271:
272: static
273: alclose(dev, mode)
274: dev_t dev;
275: int mode;
276: {
277: /*
278: * The real work is in alx.c.
279: */
280: alxclose(dev, mode, &DEV_TTY);
281: }
282:
283: static
284: alread(dev, iop)
285: dev_t dev;
286: IO *iop;
287: {
288: ttread(&DEV_TTY, iop, 0);
289: }
290:
291: static
292: alwrite(dev, iop)
293: dev_t dev;
294: register IO *iop;
295: {
296: register int c;
297:
298: /*
299: * Treat user writes through tty driver.
300: */
301: if (iop->io_seg != IOSYS) {
302: ttwrite(&DEV_TTY, iop, 0);
303: return;
304: }
305:
306: /*
307: * Treat kernel writes by blocking on transmit buffer.
308: */
309: while ((c = iogetc(iop)) >= 0) {
310: /*
311: * Wait until transmit buffer is empty.
312: * Check twice to prevent critical race with interrupt handler.
313: */
314: for (;;) {
315: if (inb(ALPORT+LSR) & LS_TxRDY)
316: if (inb(ALPORT+LSR) & LS_TxRDY)
317: break;
318: }
319:
320: /*
321: * Output the next character.
322: */
323: outb(ALPORT+DREG, c);
324: }
325: }
326:
327: #ifdef _I386
328: static int
329: alioctl0(dev, com, vec)
330: dev_t dev;
331: struct sgttyb *vec;
332: {
333: tioc286(dev, com, vec, alioctl);
334: }
335: #endif
336:
337: static int
338: alioctl(dev, com, vec)
339: dev_t dev;
340: struct sgttyb *vec;
341: {
342: alxioctl(dev, com, vec, &DEV_TTY);
343: }
344:
345: static
346: alpoll(dev, ev, msec)
347: dev_t dev;
348: int ev;
349: int msec;
350: {
351: return ttpoll(&DEV_TTY, ev, msec);
352: }
353:
354: static
355: alintr()
356: {
357: alxintr(irqtty);
358: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.