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