|
|
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.