[BACK]Return to com_subr.c CVS log [TXT][DIR] Up to [local] / sys / dev / ic

Annotation of sys/dev/ic/com_subr.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: com_subr.c,v 1.10 2007/03/20 17:37:34 deraadt Exp $   */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 1997 - 1999, Jason Downs.  All rights reserved.
        !             5:  *
        !             6:  * Redistribution and use in source and binary forms, with or without
        !             7:  * modification, are permitted provided that the following conditions
        !             8:  * are met:
        !             9:  * 1. Redistributions of source code must retain the above copyright
        !            10:  *    notice, this list of conditions and the following disclaimer.
        !            11:  * 2. Redistributions in binary form must reproduce the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer in the
        !            13:  *    documentation and/or other materials provided with the distribution.
        !            14:  *
        !            15:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
        !            16:  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
        !            17:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
        !            18:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
        !            19:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            20:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            21:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
        !            22:  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            23:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            24:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            25:  * SUCH DAMAGE.
        !            26:  */
        !            27: /*-
        !            28:  * Copyright (c) 1993, 1994, 1995, 1996
        !            29:  *     Charles M. Hannum.  All rights reserved.
        !            30:  * Copyright (c) 1991 The Regents of the University of California.
        !            31:  * All rights reserved.
        !            32:  *
        !            33:  * Redistribution and use in source and binary forms, with or without
        !            34:  * modification, are permitted provided that the following conditions
        !            35:  * are met:
        !            36:  * 1. Redistributions of source code must retain the above copyright
        !            37:  *    notice, this list of conditions and the following disclaimer.
        !            38:  * 2. Redistributions in binary form must reproduce the above copyright
        !            39:  *    notice, this list of conditions and the following disclaimer in the
        !            40:  *    documentation and/or other materials provided with the distribution.
        !            41:  * 3. Neither the name of the University nor the names of its contributors
        !            42:  *    may be used to endorse or promote products derived from this software
        !            43:  *    without specific prior written permission.
        !            44:  *
        !            45:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            46:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            47:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            48:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            49:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            50:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            51:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            52:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            53:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            54:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            55:  * SUCH DAMAGE.
        !            56:  *
        !            57:  *     @(#)com.c       7.5 (Berkeley) 5/16/91
        !            58:  */
        !            59:
        !            60: /*
        !            61:  * COM driver, based on HP dca driver
        !            62:  * uses National Semiconductor NS16450/NS16550AF UART
        !            63:  */
        !            64: #include <sys/param.h>
        !            65: #include <sys/systm.h>
        !            66: #include <sys/kernel.h>
        !            67: #include <sys/device.h>
        !            68: #include <sys/tty.h>
        !            69:
        !            70: #include "com.h"
        !            71: #ifdef i386
        !            72: #include "pccom.h"
        !            73: #else
        !            74: #define        NPCCOM  0
        !            75: #endif
        !            76:
        !            77: #include <machine/bus.h>
        !            78: #if defined(__sparc64__) || !defined(__sparc__)
        !            79: #include <machine/intr.h>
        !            80: #endif
        !            81:
        !            82: #if !defined(__sparc__) || defined(__sparc64__)
        !            83: #define        COM_CONSOLE
        !            84: #include <dev/cons.h>
        !            85: #endif
        !            86:
        !            87: #include <dev/ic/comreg.h>
        !            88: #include <dev/ic/ns16550reg.h>
        !            89: #define        com_lcr com_cfcr
        !            90:
        !            91: #if NCOM > 0
        !            92: #include <dev/ic/comvar.h>
        !            93: #endif
        !            94: #if NPCCOM > 0
        !            95: #include <i386/isa/pccomvar.h>
        !            96: #endif
        !            97:
        !            98: #ifdef COM_PXA2X0
        !            99: #define com_isr 8
        !           100: #define ISR_SEND       (ISR_RXPL | ISR_XMODE | ISR_XMITIR)
        !           101: #define ISR_RECV       (ISR_RXPL | ISR_XMODE | ISR_RCVEIR)
        !           102: #endif
        !           103:
        !           104: #ifdef COM_CONSOLE
        !           105: #include <sys/conf.h>
        !           106: cdev_decl(com);
        !           107: #endif
        !           108:
        !           109: void   com_enable_debugport(struct com_softc *);
        !           110: void   com_fifo_probe(struct com_softc *);
        !           111:
        !           112: #if defined(COM_CONSOLE) || defined(KGDB)
        !           113: void
        !           114: com_enable_debugport(sc)
        !           115:        struct com_softc *sc;
        !           116: {
        !           117:        int s;
        !           118:
        !           119:        /* Turn on line break interrupt, set carrier. */
        !           120:        s = splhigh();
        !           121: #ifdef KGDB
        !           122:        SET(sc->sc_ier, IER_ERXRDY);
        !           123: #ifdef COM_PXA2X0
        !           124:        if (sc->sc_uarttype == COM_UART_PXA2X0)
        !           125:                sc->sc_ier |= IER_EUART | IER_ERXTOUT;
        !           126: #endif
        !           127:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, com_ier, sc->sc_ier);
        !           128: #endif
        !           129:        SET(sc->sc_mcr, MCR_DTR | MCR_RTS | MCR_IENABLE);
        !           130:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, com_mcr, sc->sc_mcr);
        !           131:
        !           132:        splx(s);
        !           133: }
        !           134: #endif /* COM_CONSOLED || KGDB */
        !           135:
        !           136: void
        !           137: com_attach_subr(sc)
        !           138:        struct com_softc *sc;
        !           139: {
        !           140:        bus_space_tag_t iot = sc->sc_iot;
        !           141:        bus_space_handle_t ioh = sc->sc_ioh;
        !           142:        u_int8_t lcr;
        !           143:
        !           144:        sc->sc_ier = 0;
        !           145: #ifdef COM_PXA2X0
        !           146:        if (sc->sc_uarttype == COM_UART_PXA2X0)
        !           147:                sc->sc_ier |= IER_EUART;
        !           148: #endif
        !           149:
        !           150:        /* disable interrupts */
        !           151:        bus_space_write_1(iot, ioh, com_ier, sc->sc_ier);
        !           152:
        !           153: #ifdef COM_CONSOLE
        !           154:        if (sc->sc_iobase == comconsaddr) {
        !           155:                comconsattached = 1;
        !           156:                delay(10000);                   /* wait for output to finish */
        !           157:                SET(sc->sc_hwflags, COM_HW_CONSOLE);
        !           158:                SET(sc->sc_swflags, COM_SW_SOFTCAR);
        !           159:        }
        !           160: #endif
        !           161:
        !           162:        /*
        !           163:         * Probe for all known forms of UART.
        !           164:         */
        !           165:        lcr = bus_space_read_1(iot, ioh, com_lcr);
        !           166:        bus_space_write_1(iot, ioh, com_lcr, LCR_EFR);
        !           167:        bus_space_write_1(iot, ioh, com_efr, 0);
        !           168:        bus_space_write_1(iot, ioh, com_lcr, 0);
        !           169:
        !           170:        bus_space_write_1(iot, ioh, com_fifo, FIFO_ENABLE);
        !           171:        delay(100);
        !           172:
        !           173:        /*
        !           174:         * Skip specific probes if attachment code knows it already.
        !           175:         */
        !           176:        if (sc->sc_uarttype == COM_UART_UNKNOWN)
        !           177:                switch (bus_space_read_1(iot, ioh, com_iir) >> 6) {
        !           178:                case 0:
        !           179:                        sc->sc_uarttype = COM_UART_16450;
        !           180:                        break;
        !           181:                case 2:
        !           182:                        sc->sc_uarttype = COM_UART_16550;
        !           183:                        break;
        !           184:                case 3:
        !           185:                        sc->sc_uarttype = COM_UART_16550A;
        !           186:                        break;
        !           187:                default:
        !           188:                        sc->sc_uarttype = COM_UART_UNKNOWN;
        !           189:                        break;
        !           190:                }
        !           191:
        !           192:        if (sc->sc_uarttype == COM_UART_16550A) { /* Probe for ST16650s */
        !           193:                bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB);
        !           194:                if (bus_space_read_1(iot, ioh, com_efr) == 0) {
        !           195:                        sc->sc_uarttype = COM_UART_ST16650;
        !           196:                } else {
        !           197:                        bus_space_write_1(iot, ioh, com_lcr, LCR_EFR);
        !           198:                        if (bus_space_read_1(iot, ioh, com_efr) == 0)
        !           199:                                sc->sc_uarttype = COM_UART_ST16650V2;
        !           200:                }
        !           201:        }
        !           202:
        !           203: #if NPCCOM > 0 /* until com works with large FIFOs */
        !           204:        if (sc->sc_uarttype == COM_UART_ST16650V2) { /* Probe for XR16850s */
        !           205:                u_int8_t dlbl, dlbh;
        !           206:
        !           207:                /* Enable latch access and get the current values. */
        !           208:                bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB);
        !           209:                dlbl = bus_space_read_1(iot, ioh, com_dlbl);
        !           210:                dlbh = bus_space_read_1(iot, ioh, com_dlbh);
        !           211:
        !           212:                /* Zero out the latch divisors */
        !           213:                bus_space_write_1(iot, ioh, com_dlbl, 0);
        !           214:                bus_space_write_1(iot, ioh, com_dlbh, 0);
        !           215:
        !           216:                if (bus_space_read_1(iot, ioh, com_dlbh) == 0x10) {
        !           217:                        sc->sc_uarttype = COM_UART_XR16850;
        !           218:                        sc->sc_uartrev = bus_space_read_1(iot, ioh, com_dlbl);
        !           219:                }
        !           220:
        !           221:                /* Reset to original. */
        !           222:                bus_space_write_1(iot, ioh, com_dlbl, dlbl);
        !           223:                bus_space_write_1(iot, ioh, com_dlbh, dlbh);
        !           224:        }
        !           225: #endif
        !           226:
        !           227:        if (sc->sc_uarttype == COM_UART_16550A) { /* Probe for TI16750s */
        !           228:                bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB);
        !           229:                bus_space_write_1(iot, ioh, com_fifo,
        !           230:                    FIFO_ENABLE | FIFO_ENABLE_64BYTE);
        !           231:                if ((bus_space_read_1(iot, ioh, com_iir) >> 5) == 7) {
        !           232: #if 0
        !           233:                        bus_space_write_1(iot, ioh, com_lcr, 0);
        !           234:                        if ((bus_space_read_1(iot, ioh, com_iir) >> 5) == 6)
        !           235: #endif
        !           236:                                sc->sc_uarttype = COM_UART_TI16750;
        !           237:                }
        !           238:                bus_space_write_1(iot, ioh, com_fifo, FIFO_ENABLE);
        !           239:        }
        !           240:
        !           241:        /* Reset the LCR (latch access is probably enabled). */
        !           242:        bus_space_write_1(iot, ioh, com_lcr, lcr);
        !           243:        if (sc->sc_uarttype == COM_UART_16450) { /* Probe for 8250 */
        !           244:                u_int8_t scr0, scr1, scr2;
        !           245:
        !           246:                scr0 = bus_space_read_1(iot, ioh, com_scratch);
        !           247:                bus_space_write_1(iot, ioh, com_scratch, 0xa5);
        !           248:                scr1 = bus_space_read_1(iot, ioh, com_scratch);
        !           249:                bus_space_write_1(iot, ioh, com_scratch, 0x5a);
        !           250:                scr2 = bus_space_read_1(iot, ioh, com_scratch);
        !           251:                bus_space_write_1(iot, ioh, com_scratch, scr0);
        !           252:
        !           253:                if ((scr1 != 0xa5) || (scr2 != 0x5a))
        !           254:                        sc->sc_uarttype = COM_UART_8250;
        !           255:        }
        !           256:
        !           257:        /*
        !           258:         * Print UART type and initialize ourself.
        !           259:         */
        !           260:        switch (sc->sc_uarttype) {
        !           261:        case COM_UART_UNKNOWN:
        !           262:                printf(": unknown uart\n");
        !           263:                break;
        !           264:        case COM_UART_8250:
        !           265:                printf(": ns8250, no fifo\n");
        !           266:                break;
        !           267:        case COM_UART_16450:
        !           268:                printf(": ns16450, no fifo\n");
        !           269:                break;
        !           270:        case COM_UART_16550:
        !           271:                printf(": ns16550, no working fifo\n");
        !           272:                break;
        !           273:        case COM_UART_16550A:
        !           274:                if (sc->sc_fifolen == 0)
        !           275:                        sc->sc_fifolen = 16;
        !           276:                printf(": ns16550a, %d byte fifo\n", sc->sc_fifolen);
        !           277:                SET(sc->sc_hwflags, COM_HW_FIFO);
        !           278:                break;
        !           279: #ifdef COM_PXA2X0
        !           280:        case COM_UART_PXA2X0:
        !           281:                printf(": pxa2x0, 32 byte fifo");
        !           282:                SET(sc->sc_hwflags, COM_HW_FIFO);
        !           283:                sc->sc_fifolen = 32;
        !           284:                if (sc->sc_iobase == comsiraddr) {
        !           285:                        SET(sc->sc_hwflags, COM_HW_SIR);
        !           286:                        printf(" (SIR)");
        !           287:                }
        !           288:                printf("\n");
        !           289:                break;
        !           290: #endif
        !           291:        case COM_UART_ST16650:
        !           292:                printf(": st16650, no working fifo\n");
        !           293:                break;
        !           294:        case COM_UART_ST16650V2:
        !           295:                if (sc->sc_fifolen == 0)
        !           296:                        sc->sc_fifolen = 32;
        !           297:                printf(": st16650, %d byte fifo\n", sc->sc_fifolen);
        !           298:                SET(sc->sc_hwflags, COM_HW_FIFO);
        !           299:                break;
        !           300:        case COM_UART_ST16C654:
        !           301:                printf(": st16c654, 64 byte fifo\n");
        !           302:                SET(sc->sc_hwflags, COM_HW_FIFO);
        !           303:                sc->sc_fifolen = 64;
        !           304:                break;
        !           305:        case COM_UART_TI16750:
        !           306:                printf(": ti16750, 64 byte fifo\n");
        !           307:                SET(sc->sc_hwflags, COM_HW_FIFO);
        !           308:                sc->sc_fifolen = 64;
        !           309:                break;
        !           310: #if NPCCOM > 0
        !           311:        case COM_UART_XR16850:
        !           312:                printf(": xr16850 (rev %d), 128 byte fifo\n", sc->sc_uartrev);
        !           313:                SET(sc->sc_hwflags, COM_HW_FIFO);
        !           314:                sc->sc_fifolen = 128;
        !           315:                break;
        !           316: #ifdef COM_UART_OX16C950
        !           317:        case COM_UART_OX16C950:
        !           318:                printf(": ox16c950 (rev %d), 128 byte fifo\n", sc->sc_uartrev);
        !           319:                SET(sc->sc_hwflags, COM_HW_FIFO);
        !           320:                sc->sc_fifolen = 128;
        !           321:                break;
        !           322: #endif
        !           323: #endif
        !           324:        default:
        !           325:                panic("comattach: bad fifo type");
        !           326:        }
        !           327:
        !           328: #ifdef notyet
        !           329:        com_fifo_probe(sc);
        !           330: #endif
        !           331:
        !           332:        if (sc->sc_fifolen == 0) {
        !           333:                CLR(sc->sc_hwflags, COM_HW_FIFO);
        !           334:                sc->sc_fifolen = 1;
        !           335:        }
        !           336:
        !           337:        /* clear and disable fifo */
        !           338:        bus_space_write_1(iot, ioh, com_fifo, FIFO_RCV_RST | FIFO_XMT_RST);
        !           339:        (void)bus_space_read_1(iot, ioh, com_data);
        !           340:        bus_space_write_1(iot, ioh, com_fifo, 0);
        !           341:
        !           342:        sc->sc_mcr = 0;
        !           343:        bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr);
        !           344:
        !           345: #ifdef KGDB
        !           346:        /*
        !           347:         * Allow kgdb to "take over" this port.  If this is
        !           348:         * the kgdb device, it has exclusive use.
        !           349:         */
        !           350:
        !           351:        if (iot == com_kgdb_iot && sc->sc_iobase == com_kgdb_addr &&
        !           352:            !ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
        !           353:                printf("%s: kgdb\n", sc->sc_dev.dv_xname);
        !           354:                SET(sc->sc_hwflags, COM_HW_KGDB);
        !           355:        }
        !           356: #endif /* KGDB */
        !           357:
        !           358: #ifdef COM_CONSOLE
        !           359:        if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
        !           360:                int maj;
        !           361:
        !           362:                /* locate the major number */
        !           363:                for (maj = 0; maj < nchrdev; maj++)
        !           364:                        if (cdevsw[maj].d_open == comopen)
        !           365:                                break;
        !           366:
        !           367:                if (maj < nchrdev && cn_tab->cn_dev == NODEV)
        !           368:                        cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
        !           369:
        !           370:                printf("%s: console\n", sc->sc_dev.dv_xname);
        !           371:        }
        !           372: #endif
        !           373:
        !           374:        timeout_set(&sc->sc_diag_tmo, comdiag, sc);
        !           375:        timeout_set(&sc->sc_dtr_tmo, com_raisedtr, sc);
        !           376: #if NCOM > 0
        !           377: #ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
        !           378:        sc->sc_si = softintr_establish(IPL_TTY, comsoft, sc);
        !           379:        if (sc->sc_si == NULL)
        !           380:                panic("%s: can't establish soft interrupt",
        !           381:                    sc->sc_dev.dv_xname);
        !           382: #else
        !           383:        timeout_set(&sc->sc_comsoft_tmo, comsoft, sc);
        !           384: #endif
        !           385: #endif /* NCOM */
        !           386:
        !           387:        /*
        !           388:         * If there are no enable/disable functions, assume the device
        !           389:         * is always enabled.
        !           390:         */
        !           391:        if (!sc->enable)
        !           392:                sc->enabled = 1;
        !           393:
        !           394: #if defined(COM_CONSOLE) || defined(KGDB)
        !           395:        if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE|COM_HW_KGDB))
        !           396:                com_enable_debugport(sc);
        !           397: #endif
        !           398: }
        !           399:
        !           400: void
        !           401: com_fifo_probe(struct com_softc *sc)
        !           402: {
        !           403:        bus_space_handle_t ioh = sc->sc_ioh;
        !           404:        bus_space_tag_t iot = sc->sc_iot;
        !           405:        u_int8_t fifo, ier;
        !           406:        int timo, len;
        !           407:
        !           408:        if (!ISSET(sc->sc_hwflags, COM_HW_FIFO))
        !           409:                return;
        !           410:
        !           411:        ier = 0;
        !           412: #ifdef COM_PXA2X0
        !           413:        if (sc->sc_uarttype == COM_UART_PXA2X0)
        !           414:                ier |= IER_EUART;
        !           415: #endif
        !           416:        bus_space_write_1(iot, ioh, com_ier, ier);
        !           417:        bus_space_write_1(iot, ioh, com_lcr, LCR_DLAB);
        !           418:        bus_space_write_1(iot, ioh, com_dlbl, 3);
        !           419:        bus_space_write_1(iot, ioh, com_dlbh, 0);
        !           420:        bus_space_write_1(iot, ioh, com_lcr, LCR_PNONE | LCR_8BITS);
        !           421:        bus_space_write_1(iot, ioh, com_mcr, MCR_LOOPBACK);
        !           422:
        !           423:        fifo = FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST;
        !           424:        if (sc->sc_uarttype == COM_UART_TI16750)
        !           425:                fifo |= FIFO_ENABLE_64BYTE;
        !           426:
        !           427:        bus_space_write_1(iot, ioh, com_fifo, fifo);
        !           428:
        !           429:        for (len = 0; len < 256; len++) {
        !           430:                bus_space_write_1(iot, ioh, com_data, (len + 1));
        !           431:                timo = 2000;
        !           432:                while (!ISSET(bus_space_read_1(iot, ioh, com_lsr),
        !           433:                    LSR_TXRDY) && --timo)
        !           434:                        delay(1);
        !           435:                if (!timo)
        !           436:                        break;
        !           437:        }
        !           438:
        !           439:        delay(100);
        !           440:
        !           441:        for (len = 0; len < 256; len++) {
        !           442:                timo = 2000;
        !           443:                while (!ISSET(bus_space_read_1(iot, ioh, com_lsr),
        !           444:                    LSR_RXRDY) && --timo)
        !           445:                        delay(1);
        !           446:                if (!timo || bus_space_read_1(iot, ioh, com_data) != (len + 1))
        !           447:                        break;
        !           448:        }
        !           449:
        !           450:        /* For safety, always use the smaller value. */
        !           451:        if (sc->sc_fifolen > len) {
        !           452:                printf("%s: probed fifo depth: %d bytes\n",
        !           453:                    sc->sc_dev.dv_xname, len);
        !           454:                sc->sc_fifolen = len;
        !           455:        }
        !           456: }

CVSweb