root/sys/arch/hp300/stand/common/ite.c
/*      $NetBSD: ite.c,v 1.23 2025/05/30 19:19:26 tsutsui Exp $ */

/*
 * Copyright (c) 1988 University of Utah.
 * Copyright (c) 1990, 1993
 *      The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * the Systems Programming Group of the University of Utah Computer
 * Science Department.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * from: Utah $Hdr: ite.c 1.24 93/06/25$
 *
 *      @(#)ite.c       8.1 (Berkeley) 7/8/93
 */

/*
 * Standalone Internal Terminal Emulator (CRT and keyboard)
 */

#ifdef ITECONSOLE

#include <sys/param.h>
#include <dev/cons.h>

#include <hp300/dev/diofbreg.h>
#include <hp300/dev/intioreg.h>
#include <hp300/dev/dioreg.h>
#include <hp300/dev/sgcreg.h>
#include <dev/ic/stireg.h>

#include <hp300/stand/common/device.h>
#include <hp300/stand/common/itevar.h>
#include <hp300/stand/common/kbdvar.h>
#include <hp300/stand/common/consdefs.h>
#include <hp300/stand/common/samachdep.h>

static void iteconfig(void);
static void ite_scroll(struct ite_data *);
static void itecheckwrap(struct ite_data *);

#define GID_STI         0x100   /* any value which is not a DIO fb, really */

static const struct itesw itesw[] = {
        {
                .ite_hwid   = GID_TOPCAT,
                .ite_probe  = NULL,
                .ite_init   = topcat_init,
                .ite_clear  = ite_dio_clear,
                .ite_putc   = ite_dio_putc8bpp,
                .ite_cursor = ite_dio_cursor,
                .ite_scroll = ite_dio_scroll
        },

        {
                .ite_hwid   = GID_GATORBOX,
                .ite_probe  = NULL,
                .ite_init   = gbox_init,
                .ite_clear  = ite_dio_clear,
                .ite_putc   = ite_dio_putc8bpp,
                .ite_cursor = ite_dio_cursor,
                .ite_scroll = gbox_scroll
        },

        {
                .ite_hwid   = GID_RENAISSANCE,
                .ite_probe  = NULL,
                .ite_init   = rbox_init,
                .ite_clear  = ite_dio_clear,
                .ite_putc   = ite_dio_putc8bpp,
                .ite_cursor = ite_dio_cursor,
                .ite_scroll = ite_dio_scroll
        },

        {
                .ite_hwid   = GID_LRCATSEYE,
                .ite_probe  = NULL,
                .ite_init   = topcat_init,
                .ite_clear  = ite_dio_clear,
                .ite_putc   = ite_dio_putc8bpp,
                .ite_cursor = ite_dio_cursor,
                .ite_scroll = ite_dio_scroll
        },

        {
                .ite_hwid   = GID_HRCCATSEYE,
                .ite_probe  = NULL,
                .ite_init   = topcat_init,
                .ite_clear  = ite_dio_clear,
                .ite_putc   = ite_dio_putc8bpp,
                .ite_cursor = ite_dio_cursor,
                .ite_scroll = ite_dio_scroll
        },

        {
                .ite_hwid   = GID_HRMCATSEYE,
                .ite_probe  = NULL,
                .ite_init   = topcat_init,
                .ite_clear  = ite_dio_clear,
                .ite_putc   = ite_dio_putc8bpp,
                .ite_cursor = ite_dio_cursor,
                .ite_scroll = ite_dio_scroll
        },

        {
                .ite_hwid   = GID_DAVINCI,
                .ite_probe  = NULL,
                .ite_init   = dvbox_init,
                .ite_clear  = ite_dio_clear,
                .ite_putc   = ite_dio_putc8bpp,
                .ite_cursor = ite_dio_cursor,
                .ite_scroll = ite_dio_scroll
        },

        {
                .ite_hwid   = GID_HYPERION,
                .ite_probe  = NULL,
                .ite_init   = hyper_init,
                .ite_clear  = ite_dio_clear,
                .ite_putc   = ite_dio_putc1bpp,
                .ite_cursor = ite_dio_cursor,
                .ite_scroll = ite_dio_scroll
        },

        {
                .ite_hwid   = GID_TIGER,
                .ite_probe  = NULL,
                .ite_init   = tvrx_init,
                .ite_clear  = ite_dio_clear,
                .ite_putc   = ite_dio_putc1bpp,
                .ite_cursor = ite_dio_cursor,
                .ite_scroll = ite_dio_scroll
        },

        {
                .ite_hwid   = GID_A1474MID,
                .ite_probe  = sti_dio_probe,
                .ite_init   = sti_iteinit_dio,
                .ite_clear  = sti_clear,
                .ite_putc   = sti_putc,
                .ite_cursor = sti_cursor,
                .ite_scroll = sti_scroll
        },

        {
                .ite_hwid   = GID_A147xVGA,
                .ite_probe  = sti_dio_probe,
                .ite_init   = sti_iteinit_dio,
                .ite_clear  = sti_clear,
                .ite_putc   = sti_putc,
                .ite_cursor = sti_cursor,
                .ite_scroll = sti_scroll
        },

        {
                .ite_hwid   = GID_STI,
                .ite_probe  = NULL,
                .ite_init   = sti_iteinit_sgc,
                .ite_clear  = sti_clear,
                .ite_putc   = sti_putc,
                .ite_cursor = sti_cursor,
                .ite_scroll = sti_scroll
        },
};

/* these guys need to be in initialized data */
static int itecons = -1;
static struct  ite_data ite_data[NITE] = { { 0 } };

/*
 * Locate all bitmapped displays
 */
static void
iteconfig(void)
{
        int dtype, fboff, slotno, i;
        uint8_t *va;
        struct hp_hw *hw;
        struct diofbreg *fb;
        struct ite_data *ip;

        i = 0;
        for (hw = sc_table; hw < &sc_table[MAXCTLRS]; hw++) {
                if (!HW_ISDEV(hw, D_BITMAP))
                        continue;
                fb = (struct diofbreg *)hw->hw_kva;
                /* XXX: redundent but safe */
                if (badaddr((void *)fb) || fb->id != GRFHWID)
                        continue;
                for (dtype = 0; dtype < __arraycount(itesw); dtype++)
                        if (itesw[dtype].ite_hwid == fb->fbid)
                                break;
                if (dtype == __arraycount(itesw))
                        continue;
                if (i >= NITE)
                        break;
                ip = &ite_data[i];
                ip->scode = hw->hw_sc;
                ip->isw = &itesw[dtype];
                ip->regbase = (void *)fb;
                fboff = (fb->fbomsb << 8) | fb->fbolsb;
                ip->fbbase = (void *)(*((uint8_t *)ip->regbase + fboff) << 16);
                /* DIO II: FB offset is relative to select code space */
                if (DIO_ISDIOII(ip->scode))
                        ip->fbbase = (uint8_t *)ip->fbbase + (int)ip->regbase;
                ip->fbwidth  = fb->fbwmsb << 8 | fb->fbwlsb;
                ip->fbheight = fb->fbhmsb << 8 | fb->fbhlsb;
                ip->dwidth   = fb->dwmsb  << 8 | fb->dwlsb;
                ip->dheight  = fb->dhmsb  << 8 | fb->dhlsb;
                /*
                 * XXX some displays (e.g. the davinci) appear
                 * to return a display height greater than the
                 * returned FB height.  Guess we should go back
                 * to getting the display dimensions from the
                 * fontrom...
                 */
                if (ip->dwidth > ip->fbwidth)
                        ip->dwidth = ip->fbwidth;
                if (ip->dheight > ip->fbheight)
                        ip->dheight = ip->fbheight;
                /* confirm hardware is what we think it is */
                if (itesw[dtype].ite_probe != NULL &&
                    (*itesw[dtype].ite_probe)(ip) != 0)
                        continue;
                ip->alive = 1;
                i++;
        }

        /*
         * Now probe for SGC frame buffers.
         */
        switch (machineid) {
        case HP_400:
        case HP_425:
        case HP_433:
                break;
        default:
                return;
        }

        /* SGC frame buffers can only be STI... */
        for (dtype = 0; dtype < __arraycount(itesw); dtype++)
                if (itesw[dtype].ite_hwid == GID_STI)
                        break;
        if (dtype == __arraycount(itesw))
                return;

        for (slotno = 0; slotno < SGC_NSLOTS; slotno++) {
                va = (uint8_t *)IIOV(SGC_BASE + (slotno * SGC_DEVSIZE));

                /* Check to see if hardware exists. */
                if (badaddr(va) != 0)
                        continue;

                /* Check hardware. */
                if (va[3] == STI_DEVTYPE1) {
                        if (i >= NITE)
                                break;
                        ip = &ite_data[i];
                        ip->scode = slotno;
                        ip->isw = &itesw[dtype];
                        /* to get CN_MIDPRI */
                        ip->regbase = (uint8_t *)(INTIOBASE + FB_BASE);
                        /* ...and do not need an ite_probe() check */
                        ip->alive = 1;
                        i++;
                        /* we only support one SGC frame buffer at the moment */
                        break;
                }
        }
}

#ifdef CONSDEBUG
/*
 * Allows us to cycle through all possible consoles (NITE ites and serial port)
 * by using SHIFT-RESET on the keyboard.
 */
int     whichconsole = -1;
#endif

void
iteprobe(struct consdev *cp)
{
        int ite;
        struct ite_data *ip;
        int unit, pri;

#ifdef CONSDEBUG
        whichconsole = (whichconsole + 1) % (NITE + 1);
#endif

        if (itecons != -1)
                return;

        iteconfig();
        unit = -1;
        pri = CN_DEAD;
        for (ite = 0; ite < NITE; ite++) {
#ifdef CONSDEBUG
                if (ite < whichconsole)
                        continue;
#endif
                ip = &ite_data[ite];
                if (ip->alive == 0)
                        continue;
                if ((int)ip->regbase == INTIOBASE + FB_BASE) {
                        pri = CN_INTERNAL;
                        unit = ite;
                } else if (unit < 0) {
                        pri = CN_NORMAL;
                        unit = ite;
                }
        }
        ip = &ite_data[unit];
        curcons_scode = ip->scode;
        cp->cn_dev = unit;
        cp->cn_pri = pri;
}

void
iteinit(struct consdev *cp)
{
        int ite = cp->cn_dev;
        struct ite_data *ip;
        const struct itesw *sp;

        if (itecons != -1)
                return;

        ip = &ite_data[ite];
        sp = ip->isw;

        ip->curx = 0;
        ip->cury = 0;
        ip->cursorx = 0;
        ip->cursory = 0;

        (*sp->ite_init)(ip);
        (*sp->ite_cursor)(ip, DRAW_CURSOR);

        itecons = ite;
        kbdinit();
}

void
iteputchar(dev_t dev, int c)
{
        struct ite_data *ip = &ite_data[itecons];
        const struct itesw *sp = ip->isw;

        c &= 0x7F;
        switch (c) {

        case '\n':
                if (++ip->cury == ip->rows) {
                        ip->cury--;
                        ite_scroll(ip);
                } else
                        (*sp->ite_cursor)(ip, MOVE_CURSOR);
                break;

        case '\r':
                ip->curx = 0;
                (*sp->ite_cursor)(ip, MOVE_CURSOR);
                break;

        case '\b':
                if (--ip->curx < 0)
                        ip->curx = 0;
                else
                        (*sp->ite_cursor)(ip, MOVE_CURSOR);
                break;

        default:
                if (c < ' ' || c == 0177)
                        break;
                (*sp->ite_putc)(ip, c, ip->cury, ip->curx);
                (*sp->ite_cursor)(ip, DRAW_CURSOR);
                itecheckwrap(ip);
                break;
        }
}

static void
itecheckwrap(struct ite_data *ip)
{
        const struct itesw *sp = ip->isw;

        if (++ip->curx == ip->cols) {
                ip->curx = 0;
                if (++ip->cury == ip->rows) {
                        --ip->cury;
                        ite_scroll(ip);
                        return;
                }
        }
        (*sp->ite_cursor)(ip, MOVE_CURSOR);
}

static void
ite_scroll(struct ite_data *ip)
{
        const struct itesw *sp = ip->isw;

        /* Erase the cursor before scrolling */
        (*sp->ite_cursor)(ip, ERASE_CURSOR);
        /* Scroll the screen up by one line */
        (*sp->ite_scroll)(ip);
        /* Clear the entire bottom line after scrolling */
        (*sp->ite_clear)(ip, ip->rows - 1, 0, 1, ip->cols);
        /* Redraw the cursor */
        (*sp->ite_cursor)(ip, DRAW_CURSOR);
}

int
itegetchar(dev_t dev)
{

#ifdef SMALL
        return 0;
#else
        return kbdgetc();
#endif
}
#endif