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