|
|
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.12 92/02/14 10:12:27 bin ! 8: * update by hal (post 321) ! 9: * ! 10: * Revision 1.11 92/01/13 08:37:52 hal ! 11: * alclose() - decrement open count in alx.c ! 12: * ! 13: * Revision 1.10 91/12/20 14:09:50 hal ! 14: * Don't use loopback during chip sense. ! 15: * ! 16: * Revision 1.9 91/12/10 08:01:11 hal ! 17: * Set ALCNT automatically. ! 18: * Set interrupt vector before calling uart_sense(). ! 19: * ! 20: * Revision 1.8 91/12/05 09:35:25 hal ! 21: * Working 16550A code. Nfg on GeeSee. ! 22: * ! 23: * Revision 1.7 91/12/02 19:22:00 hal ! 24: * Last version before FIFO testing. ! 25: * ! 26: -lgl) */ ! 27: /* ! 28: * Driver for an IBM PC asyncronous ! 29: * line, using interrupts. The interface ! 30: * uses a Natty/WD 8250 chip. ! 31: */ ! 32: ! 33: #include <sys/coherent.h> ! 34: #ifndef _I386 ! 35: #include <sys/i8086.h> ! 36: #endif ! 37: #include <sys/con.h> ! 38: #include <errno.h> ! 39: #include <sys/stat.h> ! 40: #include <sys/tty.h> ! 41: #include <sys/uproc.h> ! 42: #include <sys/clist.h> ! 43: #include <sys/ins8250.h> ! 44: #include <sys/sched.h> ! 45: #include <sys/al.h> ! 46: #include <sys/devices.h> ! 47: ! 48: #define minor_st(dev) (dev & 0x0f) /* up to 16 ports per driver */ ! 49: #define DEV_TTY (alttab[minor_st(dev)]) ! 50: #define ALPORT (((COM_DDP *)(DEV_TTY.t_ddp))->port) ! 51: #define TESTBAUD 0x03A5 ! 52: ! 53: /* ! 54: * This driver can be compiled to drive any possible ! 55: * async port by appropriate definitions of: ! 56: * ALPORT[ab] the io port address(es) ! 57: * ALNUM[ab] com index number (0..3 for com[1..4]) ! 58: * ALINT the interrupt level ! 59: * ALNAME the xxcon name ! 60: * ALMAJ the major device number ! 61: * ALCNT number of ports sharing the interrupt ! 62: * ! 63: * NOTE: if ALCNT is changed, alttab and alintr will need hacking ! 64: * Common code for the different ports is handled by alx.c ! 65: */ ! 66: ! 67: #ifdef ALCOM1 /* COM1_3 definitions */ ! 68: #define ALPORTa 0x3F8 /* Base of com1 port */ ! 69: #define ALPORTb 0x3E8 /* Base of com3 port */ ! 70: #define ALNUMa 0 /* com1 has com number of 0 */ ! 71: #define ALNUMb 2 /* com3 has com number of 2 */ ! 72: #define ALINT 4 /* Interrupt level of com1_3 ports */ ! 73: #define ALNAME a0con /* CON name of com1_3 ports */ ! 74: #define ALMAJ AL0_MAJOR /* Major number of com1_3 port */ ! 75: #define ALCNT A0CNT /* Number of ports for this IRQ */ ! 76: #define ALSPEEDa C1BAUD /* Name of patchable variable for com1 speed */ ! 77: #define ALSPEEDb C3BAUD /* Name of patchable variable for com3 speed */ ! 78: #endif ! 79: ! 80: #ifdef ALCOM2 /* COM2_4 definitions */ ! 81: #define ALPORTa 0x2F8 /* Base of com2 port */ ! 82: #define ALPORTb 0x2E8 /* Base of com4 port */ ! 83: #define ALNUMa 1 /* com2 has com number of 1 */ ! 84: #define ALNUMb 3 /* com4 has com number of 3 */ ! 85: #define ALINT 3 /* Interrupt level of com2_4 ports */ ! 86: #define ALNAME a1con /* CON name of com2_4 ports */ ! 87: #define ALMAJ AL1_MAJOR /* Major number of com2_4 ports */ ! 88: #define ALCNT A1CNT /* Number of ports for this IRQ */ ! 89: #define ALSPEEDa C2BAUD /* Name of patchable variable for com2 speed */ ! 90: #define ALSPEEDb C4BAUD /* Name of patchable variable for com4 speed */ ! 91: #endif ! 92: ! 93: /* ! 94: * Functions. ! 95: */ ! 96: int alxopen(); ! 97: int alxclose(); ! 98: int alxioctl(); ! 99: int alxtimer(); ! 100: int alxparam(); ! 101: int alxcycle(); ! 102: int alxstart(); ! 103: int alxbreak(); ! 104: ! 105: int alintr(); ! 106: int alopen(); ! 107: int alclose(); ! 108: int alread(); ! 109: int alwrite(); ! 110: int alioctl(); ! 111: int alload(); ! 112: int alunload(); ! 113: int alpoll(); ! 114: int nulldev(); ! 115: int nonedev(); ! 116: static int uart_sense(); ! 117: ! 118: /* ! 119: * Configuration table. ! 120: */ ! 121: CON ALNAME ={ ! 122: DFCHR|DFPOL, /* Flags */ ! 123: ALMAJ, /* Major index */ ! 124: alopen, /* Open */ ! 125: alclose, /* Close */ ! 126: nulldev, /* Block */ ! 127: alread, /* Read */ ! 128: alwrite, /* Write */ ! 129: alioctl, /* Ioctl */ ! 130: nulldev, /* Powerfail */ ! 131: alxtimer, /* Timeout */ ! 132: alload, /* Load */ ! 133: alunload, /* Unload */ ! 134: alpoll /* Poll */ ! 135: }; ! 136: ! 137: /* ! 138: * Terminal structures. ! 139: */ ! 140: static COM_DDP * ddp; ! 141: static TTY * alttab; ! 142: static TTY * irqtty; /* point to alttab entry which is IRQ-enabled */ ! 143: ! 144: /* ! 145: * to change default speeds - patch kernel variables C1BAUD..C4BAUD ! 146: * new value should be one of B0..B9600 in /usr/include/sgtty.h ! 147: */ ! 148: int ALSPEEDa = B9600; ! 149: int ALSPEEDb = B9600; ! 150: ! 151: /* ! 152: * to enable com[34], patch here ! 153: * A0CNT should be 2 if you want com3, 1 otherwise ! 154: * A1CNT should be 2 if you want com4, 1 otherwise ! 155: */ ! 156: int ALCNT = 2; ! 157: ! 158: static ! 159: alload() ! 160: { ! 161: register int s; ! 162: static int init; ! 163: extern int albaud[]; ! 164: int port, i; ! 165: int usa, usb; ! 166: ! 167: /* ! 168: * Set interrupt vector early in case uart_sense() causes bogus irpts. ! 169: */ ! 170: setivec(ALINT, alintr); /* set interrupt vector */ ! 171: usa = uart_sense(ALPORTa); ! 172: usb = uart_sense(ALPORTb); ! 173: if (usa == US_NONE && usb == US_NONE) { ! 174: ALCNT = 0; ! 175: } else { ! 176: if (usb == US_NONE) ! 177: ALCNT = 1; ! 178: else ! 179: ALCNT = 2; ! 180: } ! 181: if (init == 0 && ALCNT ! 182: && (alttab = (TTY *)kalloc(ALCNT * sizeof(TTY))) ! 183: && (ddp = (COM_DDP *)kalloc(ALCNT * sizeof(COM_DDP)))) { ! 184: kclear(alttab, ALCNT*sizeof(TTY)); ! 185: kclear(ddp, ALCNT*sizeof(COM_DDP)); ! 186: ++init; ! 187: ! 188: s = sphi(); ! 189: alttab[0].t_dispeed = alttab[0].t_dospeed = ALSPEEDa; ! 190: alttab[0].t_ddp = (char *)&ddp[0]; ! 191: tp_table[ALNUMa] = alttab; /* set TTY pointers for polling */ ! 192: ddp[0].port = ALPORTa; ! 193: ddp[0].com_num = ALNUMa; ! 194: com_usage[ALNUMa].uart_type = usa; ! 195: ! 196: if (ALCNT > 1) { ! 197: alttab[1].t_dispeed = alttab[1].t_dospeed = ALSPEEDb; ! 198: alttab[1].t_ddp = (char *)&ddp[1]; ! 199: tp_table[ALNUMb] = alttab+1; ! 200: ddp[1].port = ALPORTb; ! 201: ddp[1].com_num = ALNUMb; ! 202: com_usage[ALNUMb].uart_type = usb; ! 203: } ! 204: ! 205: for (i = 0; i < ALCNT; i++) { ! 206: int speed = alttab[i].t_dospeed; ! 207: ! 208: /* port = base I/O address */ ! 209: port = ((COM_DDP *)(alttab[i].t_ddp))->port; ! 210: outb(port+IER, 0); /* disable port interrupts */ ! 211: outb(port+MCR, 0); /* hangup port */ ! 212: outb(port+LCR, LC_DLAB); ! 213: outb(port+DLL, albaud[speed]); ! 214: outb(port+DLH, albaud[speed] >> 8); ! 215: outb(port+LCR, LC_CS8); ! 216: alttab[i].t_start = alxstart; ! 217: alttab[i].t_param = alxparam; ! 218: alttab[i].t_cs_sel= cs_sel(); ! 219: } ! 220: ! 221: spl(s); ! 222: } else { /* Load failed - no ports or no RAM available! */ ! 223: clrivec(ALINT); ! 224: } ! 225: return; ! 226: } ! 227: ! 228: static ! 229: alunload() ! 230: { ! 231: int port, i; ! 232: ! 233: for (i = 0; i < ALCNT; i++) { ! 234: port = ((COM_DDP *)(alttab[i].t_ddp))->port; ! 235: outb(port+IER, 0); /* disable port interrupts */ ! 236: outb(port+MCR, 0); /* hangup port */ ! 237: timeout(alttab[i].t_rawtim, 0, NULL, 0);/* cancel timer */ ! 238: } ! 239: if (ALCNT) { ! 240: clrivec(ALINT); /* release interrupt vector */ ! 241: kfree(alttab); ! 242: kfree(ddp); ! 243: } ! 244: } ! 245: ! 246: static ! 247: alopen(dev, mode) ! 248: dev_t dev; ! 249: int mode; ! 250: { ! 251: if (minor_st(dev) < ALCNT) { ! 252: alxopen(dev, mode, &DEV_TTY, &irqtty); ! 253: } else ! 254: u.u_error = ENXIO; ! 255: } ! 256: ! 257: static ! 258: alclose(dev, mode) ! 259: dev_t dev; ! 260: int mode; ! 261: { ! 262: /* ! 263: * The real work is in alx.c. ! 264: */ ! 265: alxclose(dev, mode, &DEV_TTY); ! 266: } ! 267: ! 268: static ! 269: alread(dev, iop) ! 270: dev_t dev; ! 271: IO *iop; ! 272: { ! 273: ttread(&DEV_TTY, iop, 0); ! 274: } ! 275: ! 276: static ! 277: alwrite(dev, iop) ! 278: dev_t dev; ! 279: register IO *iop; ! 280: { ! 281: register int c; ! 282: ! 283: /* ! 284: * Treat user writes through tty driver. ! 285: */ ! 286: if (iop->io_seg != IOSYS) { ! 287: ttwrite(&DEV_TTY, iop, 0); ! 288: return; ! 289: } ! 290: ! 291: /* ! 292: * Treat kernel writes by blocking on transmit buffer. ! 293: */ ! 294: while ((c = iogetc(iop)) >= 0) { ! 295: /* ! 296: * Wait until transmit buffer is empty. ! 297: * Check twice to prevent critical race with interrupt handler. ! 298: */ ! 299: for (;;) { ! 300: if (inb(ALPORT+LSR) & LS_TxRDY) ! 301: if (inb(ALPORT+LSR) & LS_TxRDY) ! 302: break; ! 303: } ! 304: ! 305: /* ! 306: * Output the next character. ! 307: */ ! 308: outb(ALPORT+DREG, c); ! 309: } ! 310: } ! 311: ! 312: static ! 313: alioctl(dev, com, vec) ! 314: dev_t dev; ! 315: struct sgttyb *vec; ! 316: { ! 317: alxioctl(dev, com, vec, &DEV_TTY); ! 318: } ! 319: ! 320: static ! 321: alpoll(dev, ev, msec) ! 322: dev_t dev; ! 323: int ev; ! 324: int msec; ! 325: { ! 326: return ttpoll(&DEV_TTY, ev, msec); ! 327: } ! 328: ! 329: static ! 330: alintr() ! 331: { ! 332: alxintr(irqtty); ! 333: } ! 334: ! 335: /* ! 336: * uart_sense() ! 337: * ! 338: * Given port address, return what type of 8250-family chip is found there. ! 339: * ! 340: * 0 - no chip ! 341: * 1 - 8250 or 8250B ! 342: * 2 - 8250A or 16450 ! 343: * 3 - 16550 ! 344: * 4 - 16550A ! 345: * ! 346: * Only the last of these has usable on-chip FIFO. ! 347: */ ! 348: static int uart_sense(port) ! 349: int port; ! 350: { ! 351: int ret; ! 352: unsigned ch; ! 353: short testbaud; ! 354: ! 355: /* ! 356: * See if UART is detected at port address. ! 357: * UART should have IER = 0000 xxxx ! 358: * MCR = 000x xxxx ! 359: * IIR = xx00 xxxx ! 360: * and should be write and read back the baud rate regs. ! 361: */ ! 362: if (inb(port+IER) & 0xF0 ! 363: || inb(port+MCR) & 0xE0 ! 364: || inb(port+IIR) & 0x30) { ! 365: ret = US_NONE; ! 366: goto done; ! 367: } ! 368: outb(port+LCR, LC_DLAB); ! 369: outb(port+DLL, TESTBAUD & 0xFF); ! 370: outb(port+DLH, TESTBAUD >> 8); ! 371: testbaud = inb(port+DLL) | inb(port+DLH) << 8; ! 372: outb(port+LCR, LC_CS8); ! 373: if (testbaud != TESTBAUD){ ! 374: ret = US_NONE; ! 375: goto done; ! 376: } ! 377: ! 378: /* ! 379: * Scratch register NOT found on 8250/8250B. ! 380: */ ! 381: outb(port+SCR, 0x55); ! 382: ch = inb(port+SCR); ! 383: if (ch != 0x55) { ! 384: ret = US_8250; ! 385: goto done; ! 386: } ! 387: ! 388: /* ! 389: * After trying to turn on FIFO mode, ! 390: * If IIR is 00xx xxxx, it's 8250A/16450 (no FIFO). ! 391: * If IIR is 10xx xxxx, it's 16550 (broken FIFO). ! 392: * If IIR is 11xx xxxx, it's 16550A (usable FIFO). ! 393: */ ! 394: outb(port+FCR, 0x01); ! 395: ch = inb(port+FCR); ! 396: switch (ch & 0xC0) { ! 397: case 0x00: ! 398: ret = US_16450; ! 399: break; ! 400: case 0x80: ! 401: ret = US_16550; ! 402: break; ! 403: case 0xC0: ! 404: ret = US_16550A; ! 405: break; ! 406: } ! 407: outb(port+FCR, 0x00); ! 408: done: ! 409: if (ret == US_NONE) ! 410: goto really_done; ! 411: switch(port){ ! 412: case 0x3F8: ! 413: printf("com1 "); ! 414: break; ! 415: case 0x2F8: ! 416: printf("com2 "); ! 417: break; ! 418: case 0x3E8: ! 419: printf("com3 "); ! 420: break; ! 421: case 0x2E8: ! 422: printf("com4 "); ! 423: break; ! 424: } ! 425: printf("port %x: ", port); ! 426: switch (ret) { ! 427: case US_NONE: ! 428: printf("no UART\n"); ! 429: break; ! 430: case US_8250: ! 431: printf("8250/8250B\n"); ! 432: break; ! 433: case US_16450: ! 434: printf("8250A/16450\n"); ! 435: break; ! 436: case US_16550: ! 437: printf("16550 - no FIFO\n"); ! 438: break; ! 439: case US_16550A: ! 440: printf("16550A - FIFO\n"); ! 441: break; ! 442: } ! 443: really_done: ! 444: return ret; ! 445: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.