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