diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /sys/arch/atari/dev |
initial import of NetBSD tree
Diffstat (limited to 'sys/arch/atari/dev')
37 files changed, 15636 insertions, 0 deletions
diff --git a/sys/arch/atari/dev/atari5380.c b/sys/arch/atari/dev/atari5380.c new file mode 100644 index 00000000000..b58b7ab7a4d --- /dev/null +++ b/sys/arch/atari/dev/atari5380.c @@ -0,0 +1,840 @@ +/* $NetBSD: atari5380.c,v 1.4 1995/10/05 08:52:53 leo Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman. + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Leo Weppelman. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/buf.h> +#include <scsi/scsi_all.h> +#include <scsi/scsi_message.h> +#include <scsi/scsiconf.h> + +/* + * Include the driver definitions + */ +#include <atari/dev/ncr5380reg.h> + +#include <machine/stdarg.h> +#include <machine/iomap.h> +#include <machine/mfp.h> + +#if defined(FALCON_SCSI) +#include <machine/dma.h> +#endif + +/* + * This is crap, but because the interrupts now run at MFP spl-level (6), + * splbio() is not enough at some places. The code should be checked to + * find out where splhigh() is needed and where splbio() should be used. + * Now that I use this interrupt sceme, the spl values are fake! + */ +#undef splbio() +#define splbio() splhigh() + +/* + * Set the various driver options + */ +#define NREQ 18 /* Size of issue queue */ +#define AUTO_SENSE 1 /* Automatically issue a request-sense */ + +#define DRNAME ncrscsi /* used in various prints */ +#undef DBG_SEL /* Show the selection process */ +#undef DBG_REQ /* Show enqueued/ready requests */ +#undef DBG_ERR_RET /* Show requests with != 0 return code */ +#undef DBG_NOWRITE /* Do not allow writes to the targets */ +#undef DBG_PIO /* Show the polled-I/O process */ +#undef DBG_INF /* Show information transfer process */ +#define DBG_NOSTATIC /* No static functions, all in DDB trace*/ +#define DBG_PID /* Keep track of driver */ +#define REAL_DMA /* Use DMA if sensible */ +#if defined(FALCON_SCSI) +#define REAL_DMA_POLL 1 /* 1: Poll for end of DMA-transfer */ +#else +#define REAL_DMA_POLL 0 /* 1: Poll for end of DMA-transfer */ +#endif +#undef USE_PDMA /* Use special pdma-transfer function */ +#define MIN_PHYS 65536 /*BARF!!!!*/ + +/* + * The atari specific driver options + */ +#undef NO_TTRAM_DMA /* Do not use DMA to TT-ram. This */ + /* fails on older atari's */ +#define ENABLE_NCR5380(sc) cur_softc = sc; + +/* + * Functions that do nothing on the atari + */ +#define pdma_ready() 0 + +#if defined(TT_SCSI) +/* + * Define all the things we need of the DMA-controller + */ +#define SCSI_DMA ((struct scsi_dma *)AD_SCSI_DMA) +#define SCSI_5380 ((struct scsi_5380 *)AD_NCR5380) + +struct scsi_dma { + volatile u_char s_dma_ptr[8]; /* use only the odd bytes */ + volatile u_char s_dma_cnt[8]; /* use only the odd bytes */ + volatile u_char s_dma_res[4]; /* data residue register */ + volatile u_char s_dma_gap; /* not used */ + volatile u_char s_dma_ctrl; /* control register */ +}; + +#define set_scsi_dma(addr, val) (void)( \ + { \ + u_char *address = (u_char*)addr+1; \ + u_long nval = (u_long)val; \ + __asm("movepl %0, %1@(0)": :"d" (nval), "a" (address)); \ + }) + +#define get_scsi_dma(addr, res) ( \ + { \ + u_char *address = (u_char*)addr+1; \ + u_long nval; \ + __asm("movepl %1@(0), %0": "=d" (nval) : "a" (address)); \ + res = (u_long)nval; \ + }) + +/* + * Defines for TT-DMA control register + */ +#define SD_BUSERR 0x80 /* 1 = transfer caused bus error*/ +#define SD_ZERO 0x40 /* 1 = byte counter is zero */ +#define SD_ENABLE 0x02 /* 1 = Enable DMA */ +#define SD_OUT 0x01 /* Direction: memory to SCSI */ +#define SD_IN 0x00 /* Direction: SCSI to memory */ + +/* + * Define the 5380 register set + */ +struct scsi_5380 { + volatile u_char scsi_5380[16]; /* use only the odd bytes */ +}; +#endif /* TT_SCSI */ + +/********************************************** + * Variables present for both TT and Falcon. * + **********************************************/ + +/* + * Softc of currently active controller (a bit of fake; we only have one) + */ +static struct ncr_softc *cur_softc; + +#if defined(TT_SCSI) && !defined(FALCON_SCSI) +/* + * We can be more efficient for some functions when only TT_SCSI is selected + */ +#define GET_5380_REG(rnum) SCSI_5380->scsi_5380[(rnum << 1) | 1] +#define SET_5380_REG(rnum,val) (SCSI_5380->scsi_5380[(rnum << 1) | 1] = val) + +#define scsi_mach_init(sc) scsi_tt_init(sc) +#define scsi_ienable() scsi_tt_ienable() +#define scsi_idisable() scsi_tt_idisable() +#define scsi_clr_ipend() scsi_tt_clr_ipend() +#define scsi_dma_setup(r,p,m) scsi_tt_dmasetup(r, p, m) +#define wrong_dma_range(r,d) tt_wrong_dma_range(r, d) +#define poll_edma(reqp) tt_poll_edma(reqp) +#define get_dma_result(r, b) tt_get_dma_result(r, b) + +#define fair_to_keep_dma() 1 +#define claimed_dma() 1 +#define reconsider_dma() + +#endif /* defined(TT_SCSI) && !defined(FALCON_SCSI) */ + +#if defined(TT_SCSI) + +/* + * Define these too, so we can use them locally... + */ +#define GET_TT_REG(rnum) SCSI_5380->scsi_5380[(rnum << 1) | 1] +#define SET_TT_REG(rnum,val) (SCSI_5380->scsi_5380[(rnum << 1) | 1] = val) + +#ifdef NO_TTRAM_DMA +static int tt_wrong_dma_range(reqp, dm) +SC_REQ *reqp; +struct dma_chain *dm; +{ + if (dm->dm_addr & 0xff000000) { + reqp->dr_flag |= DRIVER_BOUNCING; + return(1); + } + return(0); +} +#else +#define tt_wrong_dma_range(reqp, dm) 0 +#endif + +static void scsi_tt_init(sc) +struct ncr_softc *sc; +{ + /* + * Enable SCSI-related interrupts + */ + MFP2->mf_aer |= 0x80; /* SCSI IRQ goes HIGH!!!!! */ + + MFP2->mf_ierb |= IB_SCDM; /* SCSI-dma interrupts */ + MFP2->mf_iprb &= ~IB_SCDM; + MFP2->mf_imrb |= IB_SCDM; + + MFP2->mf_iera |= IA_SCSI; /* SCSI-5380 interrupts */ + MFP2->mf_ipra &= ~IA_SCSI; + MFP2->mf_imra |= IA_SCSI; + + /* + * LWP: DMA transfers to TT-ram causes data to be garbeled + * without notice on some revisons of the TT-mainboard. + * When program's generate misterious Segmentations faults, + * try turning on NO_TTRAM_DMA. + */ +#ifdef NO_TTRAM_DMA + printf(": DMA to TT-RAM is disabled!"); +#endif +} + +static u_char get_tt_5380_reg(rnum) +u_short rnum; +{ + return(SCSI_5380->scsi_5380[(rnum << 1) | 1]); +} + +static void set_tt_5380_reg(rnum, val) +u_short rnum, val; +{ + SCSI_5380->scsi_5380[(rnum << 1) | 1] = val; +} + +extern __inline__ void scsi_tt_ienable() +{ + int sps = splbio(); + MFP2->mf_ierb |= IB_SCDM; + MFP2->mf_iera |= IA_SCSI; + splx(sps); +} + +extern __inline__ scsi_tt_idisable() +{ + int sps = splbio(); + MFP2->mf_ierb &= ~IB_SCDM; + MFP2->mf_iera &= ~IA_SCSI; + splx(sps); +} + +extern __inline__ scsi_tt_clr_ipend() +{ + int tmp; + + SCSI_DMA->s_dma_ctrl = 0; + tmp = GET_TT_REG(NCR5380_IRCV); +} + +static void scsi_tt_dmasetup(reqp, phase, mode) +SC_REQ *reqp; +u_int phase; +u_char mode; +{ + if (PH_IN(phase)) { + SCSI_DMA->s_dma_ctrl = SD_IN; + set_scsi_dma(&(SCSI_DMA->s_dma_ptr), reqp->dm_cur->dm_addr); + set_scsi_dma(&(SCSI_DMA->s_dma_cnt), reqp->dm_cur->dm_count); + SET_TT_REG(NCR5380_ICOM, 0); + SET_TT_REG(NCR5380_MODE, mode); + SCSI_DMA->s_dma_ctrl = SD_ENABLE; + SET_TT_REG(NCR5380_IRCV, 0); + } + else { + SCSI_DMA->s_dma_ctrl = SD_OUT; + set_scsi_dma(&(SCSI_DMA->s_dma_ptr), reqp->dm_cur->dm_addr); + set_scsi_dma(&(SCSI_DMA->s_dma_cnt), reqp->dm_cur->dm_count); + SET_TT_REG(NCR5380_MODE, mode); + SET_TT_REG(NCR5380_ICOM, SC_ADTB); + SET_TT_REG(NCR5380_DMSTAT, 0); + SCSI_DMA->s_dma_ctrl = SD_ENABLE|SD_OUT; + } +} + +static int +tt_poll_edma(reqp) +SC_REQ *reqp; +{ + u_char dmstat, dmastat; + int timeout = 9000; /* XXX */ + + /* + * We wait here until the DMA has finished. This can be + * achieved by checking the following conditions: + * - 5380: + * - End of DMA flag is set + * - We lost BSY (error!!) + * - A phase mismatch has occured (partial transfer) + * - DMA-controller: + * - A bus error occurred (Kernel error!!) + * - All bytes are transferred + * If one of the terminating conditions was met, we call + * 'dma_ready' to check errors and perform the bookkeeping. + */ + + for (;;) { + delay(20); + if (--timeout <= 0) { + ncr_tprint(reqp, "timeout on polled transfer\n"); + reqp->xs->error = XS_DRIVER_STUFFUP; + return(0); + } + dmstat = GET_TT_REG(NCR5380_DMSTAT); + dmastat = SCSI_DMA->s_dma_ctrl; + if (dmstat & (SC_END_DMA|SC_BSY_ERR|SC_IRQ_SET)) + break; + if (!(dmstat & SC_PHS_MTCH)) + break; + if (dmastat & (SD_BUSERR|SD_ZERO)) + break; + } + return(1); +} + +/* + * Convert physical DMA address to a virtual address. + */ +static u_char * +ptov(reqp, phaddr) +SC_REQ *reqp; +u_long *phaddr; +{ + struct dma_chain *dm; + u_char *vaddr; + + dm = reqp->dm_chain; + vaddr = reqp->xdata_ptr; + for(; dm < reqp->dm_cur; dm++) + vaddr += dm->dm_count; + vaddr += (u_long)phaddr - dm->dm_addr; + return(vaddr); +} + +static int +tt_get_dma_result(reqp, bytes_left) +SC_REQ *reqp; +u_long *bytes_left; +{ + int dmastat, dmstat; + u_char *byte_p; + u_long leftover; + + dmastat = SCSI_DMA->s_dma_ctrl; + dmstat = GET_TT_REG(NCR5380_DMSTAT); + get_scsi_dma(SCSI_DMA->s_dma_cnt, leftover); + get_scsi_dma(SCSI_DMA->s_dma_ptr, (u_long)byte_p); + + if (dmastat & SD_BUSERR) { + /* + * The DMA-controller seems to access 8 bytes beyond + * it's limits on output. Therefore check also the byte + * count. If it's zero, ignore the bus error. + */ + if (leftover != 0) { + ncr_tprint(reqp, + "SCSI-DMA buserror - accessing 0x%x\n", byte_p); + reqp->xs->error = XS_DRIVER_STUFFUP; + } + } + + /* + * We handle the following special condition below: + * -- The device disconnects in the middle of a write operation -- + * In this case, the 5380 has already pre-fetched the next byte from + * the DMA-controller before the phase mismatch occurs. Therefore, + * leftover is 1 too low. + * This does not always happen! Therefore, we only do this when + * leftover is odd. This assumes that DMA transfers are _even_! This + * is normally the case on disks and types but might not always be. + * XXX: Check if ACK is consistently high on these occasions LWP + */ + if ((leftover & 1) && !(dmstat & SC_PHS_MTCH) && PH_OUT(reqp->phase)) + leftover++; + + /* + * Check if there are some 'restbytes' left in the DMA-controller. + */ + if (((u_long)byte_p & 3) && PH_IN(reqp->phase)) { + u_char *p, *q; + + p = ptov(reqp, (u_long)byte_p & ~3); + q = (u_char*)&(SCSI_DMA->s_dma_res); + switch ((u_long)byte_p & 3) { + case 3: *p++ = *q++; + case 2: *p++ = *q++; + case 1: *p++ = *q++; + } + } + *bytes_left = leftover; + return ((dmastat & (SD_BUSERR|SD_ZERO)) ? 1 : 0); +} + +#endif /* defined(TT_SCSI) */ + +#if defined(FALCON_SCSI) && !defined(TT_SCSI) + +#define GET_5380_REG(rnum) get_falcon_5380_reg(rnum) +#define SET_5380_REG(rnum,val) set_falcon_5380_reg(rnum, val) +#define scsi_mach_init(sc) scsi_falcon_init(sc) +#define scsi_ienable() scsi_falcon_ienable() +#define scsi_idisable() scsi_falcon_idisable() +#define scsi_clr_ipend() scsi_falcon_clr_ipend() +#define scsi_dma_setup(r,p,m) scsi_falcon_dmasetup(r, p, m) +#define wrong_dma_range(r,d) falcon_wrong_dma_range(r, d) +#define poll_edma(reqp) falcon_poll_edma(reqp) +#define get_dma_result(r, b) falcon_get_dma_result(r, b) + +#define fair_to_keep_dma() (!st_dmawanted()) +#define claimed_dma() falcon_claimed_dma() +#define reconsider_dma() falcon_reconsider_dma() + +#endif /* defined(FALCON_SCSI) && !defined(TT_SCSI) */ + +#if defined(FALCON_SCSI) + +static void fscsi_int __P((void)); + +static void scsi_falcon_init(sc) +struct ncr_softc *sc; +{ + /* + * Enable disk related interrupts + */ + MFP->mf_ierb |= IB_DINT; + MFP->mf_iprb &= ~IB_DINT; + MFP->mf_imrb |= IB_DINT; +} + +static u_char get_falcon_5380_reg(rnum) +u_short rnum; +{ + DMA->dma_mode = DMA_SCSI + rnum; + return(DMA->dma_data); +} + +static void set_falcon_5380_reg(rnum, val) +u_short rnum, val; +{ + DMA->dma_mode = DMA_SCSI + rnum; + DMA->dma_data = val; +} + +extern __inline__ void scsi_falcon_ienable() +{ + MFP->mf_ierb |= IB_DINT; +} + +extern __inline__ scsi_falcon_idisable() +{ + MFP->mf_ierb &= ~IB_DINT; +} + +extern __inline__ scsi_falcon_clr_ipend() +{ + int tmp; + + tmp = get_falcon_5380_reg(NCR5380_IRCV); +} + +static int falcon_wrong_dma_range(reqp, dm) +SC_REQ *reqp; +struct dma_chain *dm; +{ + /* + * Do not allow chains yet! See also comment with + * falcon_poll_edma() !!! + */ + if (((dm - reqp->dm_chain) > 0) || (dm->dm_addr & 0xff000000)) { + reqp->dr_flag |= DRIVER_BOUNCING; + return(1); + } + /* + * Never allow DMA to happen on a Falcon when the transfer + * size is no multiple of 512. This is the transfer unit of the + * ST DMA-controller. + */ + if(dm->dm_count & 511) + return(1); + return(0); +} + +static int falcon_lock = 0; + +extern __inline__ falcon_claimed_dma() +{ + if (!(falcon_lock & DMA_LOCK_GRANT)) { + if (falcon_lock) { + /* + * DMA access is being claimed. + */ + return(0); + } + if (!st_dmagrab(fscsi_int, run_main, &connected,&falcon_lock,1)) + return(0); + } + return(1); +} + +extern __inline__ void falcon_reconsider_dma() +{ + if (falcon_lock && (connected == NULL) && (discon_q == NULL)) { + /* + * No need to keep DMA locked by us as we are not currently + * connected and no disconnected jobs are pending. + */ + st_dmafree(&connected, &falcon_lock); + } + + if (!falcon_lock && (issue_q != NULL)) { + /* + * We must (re)claim DMA access as there are jobs + * waiting in the issue queue. + */ + st_dmagrab(fscsi_int, run_main, &connected, &falcon_lock, 0); + } +} + +static void fal1_dma(dir, nsects, reqp) +u_int dir, nsects; +SC_REQ *reqp; +{ + dir <<= 8; + st_dmaaddr_set((caddr_t)reqp->dm_cur->dm_addr); + DMA->dma_mode = 0x90 | dir; + DMA->dma_mode = 0x90 | (dir ^ DMA_WRBIT); + DMA->dma_mode = 0x90 | dir; + delay(40); /* XXX: LWP - is this really needed ? */ + DMA->dma_data = nsects; + delay(40); /* XXX: LWP - is this really needed ? */ + DMA->dma_mode = 0x10 | dir; + delay(40); /* XXX: LWP - is this really needed ? */ +} + +static void scsi_falcon_dmasetup(reqp, phase, mode) +SC_REQ *reqp; +u_int phase; +u_char mode; +{ + int nsects = reqp->dm_cur->dm_count / 512; /* XXX */ + + /* + * XXX: We should probably clear the fifo before putting the + * 5380 into DMA-mode. + */ + if (PH_IN(phase)) { + set_falcon_5380_reg(NCR5380_ICOM, 0); + set_falcon_5380_reg(NCR5380_MODE, mode); + set_falcon_5380_reg(NCR5380_IRCV, 0); + fal1_dma(0, nsects, reqp); + } + else { + set_falcon_5380_reg(NCR5380_MODE, mode); + set_falcon_5380_reg(NCR5380_ICOM, SC_ADTB); + set_falcon_5380_reg(NCR5380_DMSTAT, 0); + fal1_dma(1, nsects, reqp); + } +} + +/* + * Falcon SCSI interrupt. _Always_ called at spl1! + */ +static void fscsi_int() +{ + int itype; + int dma_done; + + if (get_falcon_5380_reg(NCR5380_DMSTAT) & SC_IRQ_SET) { + scsi_falcon_idisable(); + ncr_ctrl_intr(cur_softc); + } +} + +static int +falcon_poll_edma(reqp) +SC_REQ *reqp; +{ + int timeout = 9000; /* XXX */ + + /* + * Because of the Falcon hardware, it is impossible to reach + * the 5380 while doing DMA-transfers. So we have to rely on + * the interrupt line to determine if DMA-has finished. the + * DMA-controller itself will never fire an interrupt. This means + * that 'broken-up' DMA transfers are not (yet) possible on the + * Falcon. + */ + for (;;) { + delay(20); + if (--timeout <= 0) { + ncr_tprint(reqp, "Timeout on polled transfer\n"); + reqp->xs->error = XS_DRIVER_STUFFUP; + return(0); + } + if (!(MFP->mf_gpip & IO_DINT)) + break; + } + return(1); +} + +static int +falcon_get_dma_result(reqp, bytes_left) +SC_REQ *reqp; +u_long *bytes_left; +{ + int rv = 0; + int st_dmastat; + u_long bytes_done; + + /* + * Select sector counter register first (See Atari docu.) + */ + DMA->dma_mode = 0x90; + if (!(st_dmastat = DMA->dma_stat) & 0x01) { + /* + * Misc. DMA-error according to Atari... + */ + ncr_tprint(reqp, "Unknow ST-SCSI error near 0x%x\n", + st_dmaaddr_get()); + reqp->xs->error = XS_DRIVER_STUFFUP; + rv = 1; + } + if (st_dmastat & 0x02) { + /* + * Bytecount not zero.... As the fifo loads in 16 byte + * chunks, check if bytes are stuck in fifo. + * As we don't use DMA on chunks less than 512 bytes + * on the Falcon, report any residual not a multiple of + * 512 as an error... + */ + bytes_done = st_dmaaddr_get() - reqp->dm_cur->dm_addr; + if (bytes_done & 511) { + ncr_tprint(reqp, "Some bytes stuck in fifo\n"); + bytes_done &= ~511; + reqp->xs->error = XS_DRIVER_STUFFUP; + } + *bytes_left = reqp->dm_cur->dm_count - bytes_done; + } + else { + *bytes_left = 0; + rv = 1; + } + return(rv); +} + +#endif /* defined(FALCON_SCSI) */ + +#if defined(TT_SCSI) && defined(FALCON_SCSI) +/* + * Define some functions to support _both_ TT and Falcon SCSI + */ + +/* + * Register access will be done through the following 2 function pointers. + */ +static u_char (*get_5380_reg)(); +static void (*set_5380_reg)(); + +#define GET_5380_REG (*get_5380_reg) +#define SET_5380_REG (*set_5380_reg) + +static void scsi_mach_init(sc) +struct ncr_softc *sc; +{ + if (machineid & ATARI_FALCON) { + get_5380_reg = get_falcon_5380_reg; + set_5380_reg = set_falcon_5380_reg; + scsi_falcon_init(sc); + } + else { + get_5380_reg = get_tt_5380_reg; + set_5380_reg = set_tt_5380_reg; + scsi_tt_init(sc); + } +} + +extern __inline__ void scsi_ienable() +{ + if (machineid & ATARI_FALCON) + scsi_falcon_ienable(); + else scsi_tt_ienable(); +} + +extern __inline__ void scsi_idisable() +{ + if (machineid & ATARI_FALCON) + scsi_falcon_idisable(); + else scsi_tt_idisable(); +} + +extern __inline__ scsi_clr_ipend() +{ + if (machineid & ATARI_FALCON) + scsi_falcon_clr_ipend(); + else scsi_tt_clr_ipend(); +} + +extern __inline__ scsi_dma_setup(reqp, phase, mbase) +SC_REQ *reqp; +u_int phase; +u_char mbase; +{ + if (machineid & ATARI_FALCON) + scsi_falcon_dmasetup(reqp, phase, mbase); + else scsi_tt_dmasetup(reqp, phase, mbase); +} + +extern __inline__ int wrong_dma_range(reqp, dm) +SC_REQ *reqp; +struct dma_chain *dm; +{ + if (machineid & ATARI_FALCON) + return(falcon_wrong_dma_range(reqp, dm)); + else return(tt_wrong_dma_range(reqp, dm)); +} + +extern __inline__ int poll_edma(reqp) +SC_REQ *reqp; +{ + if (machineid & ATARI_FALCON) + return(falcon_poll_edma(reqp)); + else return(tt_poll_edma(reqp)); +} + +extern __inline__ int get_dma_result(reqp, bytes_left) +SC_REQ *reqp; +u_long *bytes_left; +{ + if (machineid & ATARI_FALCON) + return(falcon_get_dma_result(reqp, bytes_left)); + else return(tt_get_dma_result(reqp, bytes_left)); +} + +/* + * Locking stuff. All turns into NOP's on the TT. + */ +#define fair_to_keep_dma() ((machineid & ATARI_FALCON) ? \ + !st_dmawanted() : 1) +#define claimed_dma() ((machineid & ATARI_FALCON) ? \ + falcon_claimed_dma() : 1) +#define reconsider_dma() { \ + if(machineid & ATARI_FALCON) \ + falcon_reconsider_dma();\ + } +#endif /* defined(TT_SCSI) && defined(FALCON_SCSI) */ + +/********************************************** + * Functions present for both TT and Falcon. * + **********************************************/ +/* + * Our autoconfig matching function + */ +static int +machine_match(pdp, cdp, auxp, cd) +struct device *pdp; +struct cfdata *cdp; +void *auxp; +struct cfdriver *cd; +{ + if (strcmp(auxp, cd->cd_name)) + return(0); + if (cdp->cf_unit != 0) /* Only one unit */ + return(0); + return(1); +} + +/* + * Bounce buffer (de)allocation. Those buffers are gotten from the ST-mem + * pool. Allocation here is both contiguous and in the lower 16Mb of + * the address space. Thus being DMA-able for all controllers. + */ +static u_char * +alloc_bounceb(len) +u_long len; +{ + u_long tmp; + + return((u_char *)alloc_stmem(len, &tmp)); +} + +static void +free_bounceb(bounceb) +u_char *bounceb; +{ + free_stmem(bounceb); +} + +/* + * 5380 interrupt. + */ +scsi_ctrl(sr) +int sr; /* sr at time of interrupt */ +{ + if (GET_5380_REG(NCR5380_DMSTAT) & SC_IRQ_SET) { + scsi_idisable(); + if (!BASEPRI(sr)) + add_sicallback(ncr_ctrl_intr, cur_softc, 0); + else { + spl1(); + ncr_ctrl_intr(cur_softc); + } + } +} + +/* + * DMA controller interrupt + */ +scsi_dma(sr) +int sr; /* sr at time of interrupt */ +{ + SC_REQ *reqp; + + if ((reqp = connected) && (reqp->dr_flag & DRIVER_IN_DMA)) { + scsi_idisable(); + if (!BASEPRI(sr)) + add_sicallback(ncr_dma_intr, cur_softc, 0); + else { + spl1(); + ncr_dma_intr(cur_softc); + } + } +} + +/* + * Last but not least... Include the general driver code + */ +#include "atari/dev/ncr5380.c" diff --git a/sys/arch/atari/dev/clock.c b/sys/arch/atari/dev/clock.c new file mode 100644 index 00000000000..c1471e4dc8d --- /dev/null +++ b/sys/arch/atari/dev/clock.c @@ -0,0 +1,466 @@ +/* $NetBSD: clock.c,v 1.4 1995/09/23 20:23:28 leo Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1982, 1990 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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: clock.c 1.18 91/01/21$ + * + * @(#)clock.c 7.6 (Berkeley) 5/7/91 + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <machine/psl.h> +#include <machine/cpu.h> +#include <machine/iomap.h> +#include <machine/mfp.h> +#include <atari/dev/clockreg.h> + +#if defined(GPROF) && defined(PROFTIMER) +#include <machine/profile.h> +#endif + +/* + * Machine-dependent clock routines. + * + * Startrtclock restarts the real-time clock, which provides + * hardclock interrupts to kern_clock.c. + * + * Inittodr initializes the time of day hardware which provides + * date functions. + * + * Resettodr restores the time of day hardware after a time change. + * + * A note on the real-time clock: + * We actually load the clock with CLK_INTERVAL-1 instead of CLK_INTERVAL. + * This is because the counter decrements to zero after N+1 enabled clock + * periods where N is the value loaded into the counter. + */ + +int clockmatch __P((struct device *, struct cfdata *, void *)); +void clockattach __P((struct device *, struct device *, void *)); + +struct cfdriver clockcd = { + NULL, "clock", (cfmatch_t)clockmatch, clockattach, + DV_DULL, sizeof(struct device), NULL, 0 +}; + +static u_long gettod __P((void)); +static int settod __P((u_long)); + +static int divisor; + +int +clockmatch(pdp, cfp, auxp) +struct device *pdp; +struct cfdata *cfp; +void *auxp; +{ + if(!strcmp("clock", auxp)) + return(1); + return(0); +} + +/* + * Start the real-time clock. + */ +void clockattach(pdp, dp, auxp) +struct device *pdp, *dp; +void *auxp; +{ + /* + * Initialize Timer-A in the ST-MFP. We use a divisor of 200. + * The MFP clock runs at 2457600Hz. Therefore the timer runs + * at an effective rate of: 2457600/200 = 12288Hz. The + * following expression works for 48, 64 or 96 hz. + */ + divisor = 12288/hz; + MFP->mf_tacr = 0; /* Stop timer */ + MFP->mf_iera &= ~IA_TIMA; /* Disable timer interrupts */ + MFP->mf_tadr = divisor; /* Set divisor */ + + printf(": system hz %d timer-A divisor 200/%d\n", hz, divisor); + + /* + * Initialize Timer-B in the ST-MFP. This timer is used by the 'delay' + * function below. This time is setup to be continueously counting from + * 255 back to zero at a frequency of 614400Hz. + */ + MFP->mf_tbcr = 0; /* Stop timer */ + MFP->mf_iera &= ~IA_TIMB; /* Disable timer interrupts */ + MFP->mf_tbdr = 0; + MFP->mf_tbcr = T_Q004; /* Start timer */ + +} + +void cpu_initclocks() +{ + MFP->mf_tacr = T_Q200; /* Start timer */ + MFP->mf_ipra &= ~IA_TIMA; /* Clear pending interrupts */ + MFP->mf_iera |= IA_TIMA; /* Enable timer interrupts */ + MFP->mf_imra |= IA_TIMA; /* ..... */ +} + +setstatclockrate(hz) + int hz; +{ +} + +/* + * Returns number of usec since last recorded clock "tick" + * (i.e. clock interrupt). + */ +clkread() +{ + u_int delta; + + delta = ((divisor - MFP->mf_tadr) * tick) / divisor; + /* + * Account for pending clock interrupts + */ + if(MFP->mf_iera & IA_TIMA) + return(delta + tick); + return(delta); +} + +#define TIMB_FREQ 614400 +#define TIMB_LIMIT 256 + +/* + * Wait "n" microseconds. + * Relies on MFP-Timer B counting down from TIMB_LIMIT at TIMB_FREQ Hz. + * Note: timer had better have been programmed before this is first used! + */ +void delay(n) +int n; +{ + int tick, otick; + + /* + * Read the counter first, so that the rest of the setup overhead is + * counted. + */ + otick = MFP->mf_tbdr; + + /* + * Calculate ((n * TIMER_FREQ) / 1e6) using explicit assembler code so + * we can take advantage of the intermediate 64-bit quantity to prevent + * loss of significance. + */ + n -= 5; + if(n < 0) + return; + { + u_int temp; + + __asm __volatile ("mulul %2,%1:%0" : "=d" (n), "=d" (temp) + : "d" (TIMB_FREQ)); + __asm __volatile ("divul %1,%2:%0" : "=d" (n) + : "d"(1000000),"d"(temp),"0"(n)); + } + + while(n > 0) { + tick = MFP->mf_tbdr; + if(tick > otick) + n -= TIMB_LIMIT - (tick - otick); + else n -= otick - tick; + otick = tick; + } +} + +#ifdef PROFTIMER +/* + * This code allows the amiga kernel to use one of the extra timers on + * the clock chip for profiling, instead of the regular system timer. + * The advantage of this is that the profiling timer can be turned up to + * a higher interrupt rate, giving finer resolution timing. The profclock + * routine is called from the lev6intr in locore, and is a specialized + * routine that calls addupc. The overhead then is far less than if + * hardclock/softclock was called. Further, the context switch code in + * locore has been changed to turn the profile clock on/off when switching + * into/out of a process that is profiling (startprofclock/stopprofclock). + * This reduces the impact of the profiling clock on other users, and might + * possibly increase the accuracy of the profiling. + */ +int profint = PRF_INTERVAL; /* Clock ticks between interrupts */ +int profscale = 0; /* Scale factor from sys clock to prof clock */ +char profon = 0; /* Is profiling clock on? */ + +/* profon values - do not change, locore.s assumes these values */ +#define PRF_NONE 0x00 +#define PRF_USER 0x01 +#define PRF_KERNEL 0x80 + +initprofclock() +{ +#if NCLOCK > 0 + struct proc *p = curproc; /* XXX */ + + /* + * If the high-res timer is running, force profiling off. + * Unfortunately, this gets reflected back to the user not as + * an error but as a lack of results. + */ + if (clockon) { + p->p_stats->p_prof.pr_scale = 0; + return; + } + /* + * Keep track of the number of user processes that are profiling + * by checking the scale value. + * + * XXX: this all assumes that the profiling code is well behaved; + * i.e. profil() is called once per process with pcscale non-zero + * to turn it on, and once with pcscale zero to turn it off. + * Also assumes you don't do any forks or execs. Oh well, there + * is always adb... + */ + if (p->p_stats->p_prof.pr_scale) + profprocs++; + else + profprocs--; +#endif + /* + * The profile interrupt interval must be an even divisor + * of the CLK_INTERVAL so that scaling from a system clock + * tick to a profile clock tick is possible using integer math. + */ + if (profint > CLK_INTERVAL || (CLK_INTERVAL % profint) != 0) + profint = CLK_INTERVAL; + profscale = CLK_INTERVAL / profint; +} + +startprofclock() +{ + unsigned short interval; + + /* stop timer B */ + ciab.crb = ciab.crb & 0xc0; + + /* load interval into registers. + the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz */ + + interval = profint - 1; + + /* order of setting is important ! */ + ciab.tblo = interval & 0xff; + ciab.tbhi = interval >> 8; + + /* enable interrupts for timer B */ + ciab.icr = (1<<7) | (1<<1); + + /* start timer B in continuous shot mode */ + ciab.crb = (ciab.crb & 0xc0) | 1; +} + +stopprofclock() +{ + /* stop timer B */ + ciab.crb = ciab.crb & 0xc0; +} + +#ifdef GPROF +/* + * profclock() is expanded in line in lev6intr() unless profiling kernel. + * Assumes it is called with clock interrupts blocked. + */ +profclock(pc, ps) + caddr_t pc; + int ps; +{ + /* + * Came from user mode. + * If this process is being profiled record the tick. + */ + if (USERMODE(ps)) { + if (p->p_stats.p_prof.pr_scale) + addupc(pc, &curproc->p_stats.p_prof, 1); + } + /* + * Came from kernel (supervisor) mode. + * If we are profiling the kernel, record the tick. + */ + else if (profiling < 2) { + register int s = pc - s_lowpc; + + if (s < s_textsize) + kcount[s / (HISTFRACTION * sizeof (*kcount))]++; + } + /* + * Kernel profiling was on but has been disabled. + * Mark as no longer profiling kernel and if all profiling done, + * disable the clock. + */ + if (profiling && (profon & PRF_KERNEL)) { + profon &= ~PRF_KERNEL; + if (profon == PRF_NONE) + stopprofclock(); + } +} +#endif +#endif + +/* + * Initialize the time of day register, based on the time base which is, e.g. + * from a filesystem. + */ +inittodr(base) +time_t base; +{ + u_long timbuf = base; /* assume no battery clock exists */ + + timbuf = gettod(); + + if(timbuf < base) { + printf("WARNING: bad date in battery clock\n"); + timbuf = base; + } + + /* Battery clock does not store usec's, so forget about it. */ + time.tv_sec = timbuf; +} + +resettodr() +{ + if(settod(time.tv_sec) == 1) + return; + printf("Cannot set battery backed clock\n"); +} + +static char dmsize[12] = +{ + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +static char ldmsize[12] = +{ + 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +static u_long +gettod() +{ + int i, sps; + u_long new_time = 0; + char *msize; + mc_todregs clkregs; + + sps = splhigh(); + MC146818_GETTOD(RTC, &clkregs); + splx(sps); + + if(range_test(clkregs[MC_HOUR], 0, 23)) + return(0); + if(range_test(clkregs[MC_DOM], 1, 31)) + return(0); + if (range_test(clkregs[MC_MONTH], 1, 12)) + return(0); + if(range_test(clkregs[MC_YEAR], 0, 2000 - GEMSTARTOFTIME)) + return(0); + clkregs[MC_YEAR] += GEMSTARTOFTIME; + + for(i = BSDSTARTOFTIME; i < clkregs[MC_YEAR]; i++) { + if(is_leap(i)) + new_time += 366; + else new_time += 365; + } + + msize = is_leap(clkregs[MC_YEAR]) ? ldmsize : dmsize; + for(i = 0; i < (clkregs[MC_MONTH] - 1); i++) + new_time += msize[i]; + new_time += clkregs[MC_DOM] - 1; + new_time *= SECS_DAY; + new_time += (clkregs[MC_HOUR] * 3600) + (clkregs[MC_MIN] * 60); + return(new_time + clkregs[MC_SEC]); +} + +static int +settod(newtime) +u_long newtime; +{ + register long days, rem, year; + register char *ml; + int sps, sec, min, hour, month; + mc_todregs clkregs; + + /* Number of days since Jan. 1 'BSDSTARTOFTIME' */ + days = newtime / SECS_DAY; + rem = newtime % SECS_DAY; + + /* + * Calculate sec, min, hour + */ + hour = rem / SECS_HOUR; + rem %= SECS_HOUR; + min = rem / 60; + sec = rem % 60; + + /* + * Figure out the year. Day in year is left in 'days'. + */ + year = BSDSTARTOFTIME; + while(days >= (rem = is_leap(year) ? 366 : 365)) { + ++year; + days -= rem; + } + + /* + * Determine the month + */ + ml = is_leap(year) ? ldmsize : dmsize; + for(month = 0; days >= ml[month]; ++month) + days -= ml[month]; + + /* + * Now that everything is calculated, program the RTC + */ + mc146818_write(RTC, MC_REGA, MC_BASE_32_KHz); + mc146818_write(RTC, MC_REGB, MC_REGB_24HR | MC_REGB_BINARY); + sps = splhigh(); + MC146818_GETTOD(RTC, &clkregs); + clkregs[MC_SEC] = sec; + clkregs[MC_MIN] = min; + clkregs[MC_HOUR] = hour; + clkregs[MC_DOM] = days+1; + clkregs[MC_MONTH] = month+1; + clkregs[MC_YEAR] = year - GEMSTARTOFTIME; + MC146818_PUTTOD(RTC, &clkregs); + splx(sps); + + return(1); +} diff --git a/sys/arch/atari/dev/clockioctl.h b/sys/arch/atari/dev/clockioctl.h new file mode 100644 index 00000000000..03f16574b05 --- /dev/null +++ b/sys/arch/atari/dev/clockioctl.h @@ -0,0 +1,47 @@ +/* $NetBSD: clockioctl.h,v 1.1.1.1 1995/03/26 07:12:13 leo Exp $ */ + +/* + * Copyright (c) 1989 University of Utah. + * Copyright (c) 1990 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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: clockioctl.h 1.1 90/07/09$ + * + * @(#)clockioctl.h 7.2 (Berkeley) 11/2/90 + */ + +#define CLOCKMAP _IOWR('C', 1, int) +#define CLOCKUNMAP _IOW('C', 2, int) +#define CLOCKGETRES _IOR('C', 3, int) diff --git a/sys/arch/atari/dev/clockreg.h b/sys/arch/atari/dev/clockreg.h new file mode 100644 index 00000000000..9ced9f98abb --- /dev/null +++ b/sys/arch/atari/dev/clockreg.h @@ -0,0 +1,79 @@ +/* $NetBSD: clockreg.h,v 1.3 1995/06/28 04:30:40 cgd Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman. + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Leo Weppelman. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef _CLOCKREG_H +#define _CLOCKREG_H +/* + * Atari TT hardware: + * Motorola MC146818A RealTimeClock + */ + +#define RTC ((struct rtc *)AD_RTC) + +struct rtc { + volatile u_char rtc_dat[4]; +}; + +#define rtc_regno rtc_dat[1] /* register nr. select */ +#define rtc_data rtc_dat[3] /* data register */ + +/* + * Pull in general mc146818 definitions + */ +#include <dev/ic/mc146818reg.h> + +__inline__ u_int mc146818_read(rtc, regno) +void *rtc; +u_int regno; +{ + ((struct rtc *)rtc)->rtc_regno = regno; + return(((struct rtc *)rtc)->rtc_data & 0377); +} + +__inline__ void mc146818_write(rtc, regno, value) +void *rtc; +u_int regno, value; +{ + ((struct rtc *)rtc)->rtc_regno = regno; + ((struct rtc *)rtc)->rtc_data = value; +} + +/* + * Some useful constants/macros + */ +#define is_leap(x) (!(x % 4) && ((x % 100) || !(x % 1000))) +#define range_test(n, l, h) ((n) < (l) || (n) > (h)) +#define SECS_DAY 86400L +#define SECS_HOUR 3600L +#define GEMSTARTOFTIME ((machineid & ATARI_CLKBROKEN) ? 1970 : 1968) +#define BSDSTARTOFTIME 1970 +#endif /* _CLOCKREG_H */ diff --git a/sys/arch/atari/dev/dma.c b/sys/arch/atari/dev/dma.c new file mode 100644 index 00000000000..4be5f26b62a --- /dev/null +++ b/sys/arch/atari/dev/dma.c @@ -0,0 +1,277 @@ +/* $NetBSD: dma.c,v 1.4 1995/05/14 15:46:17 leo Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman. + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Leo Weppelman. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * This file contains special code dealing with the DMA interface + * on the Atari ST. + * + * The DMA circuitry requires some special treatment for the peripheral + * devices which make use of the ST's DMA feature (the hard disk and the + * floppy drive). + * All devices using DMA need mutually exclusive access and can follow some + * standard pattern which will be provided in this file. + * + * The file contains the following entry points: + * + * st_dmagrab: ensure exclusive access to the DMA circuitry + * st_dmafree: free exclusive access to the DMA circuitry + * st_dmawanted: somebody is queued waiting for DMA-access + * dmaint: DMA interrupt routine, switches to the current driver + * st_dmaaddr_set: specify 24 bit RAM address + * st_dmaaddr_get: get address of last DMA-op + * st_dmacomm: program DMA, flush FIFO first + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/queue.h> +#include <machine/cpu.h> +#include <machine/iomap.h> +#include <machine/dma.h> + +#define NDMA_DEV 10 /* Max 2 floppy's, 8 hard-disks */ +typedef struct dma_entry { + TAILQ_ENTRY(dma_entry) entries; /* List pointers */ + void (*call_func)(); /* Call when lock granted */ + void (*int_func)(); /* Call on DMA interrupt */ + void *softc; /* Arg. to int_func */ + int *lock_stat; /* status of DMA lock */ +} DMA_ENTRY; + +/* + * Preallocated entries. An allocator seem an overkill here. + */ +static DMA_ENTRY dmatable[NDMA_DEV]; /* preallocated entries */ +static int sched_soft = 0; /* callback scheduled */ + +/* + * Heads of free and active lists: + */ +static TAILQ_HEAD(freehead, dma_entry) dma_free; +static TAILQ_HEAD(acthead, dma_entry) dma_active; + +static int must_init = 1; /* Must initialize */ + +static void cdmasoft __P((void)); +static void init_queues __P((void)); + +static void init_queues() +{ + int i; + + TAILQ_INIT(&dma_free); + TAILQ_INIT(&dma_active); + + for(i = 0; i < NDMA_DEV; i++) + TAILQ_INSERT_HEAD(&dma_free, &dmatable[i], entries); +} + +int st_dmagrab(int_func, call_func, softc, lock_stat, rcaller) +void (*int_func)(); +void (*call_func)(); +void *softc; +int *lock_stat; +int rcaller; +{ + int sps; + DMA_ENTRY *req; + + if(must_init) { + init_queues(); + must_init = 0; + } + *lock_stat = DMA_LOCK_REQ; + + sps = splhigh(); + + /* + * Create a request... + */ + if(dma_free.tqh_first == NULL) + panic("st_dmagrab: Too many outstanding requests\n"); + req = dma_free.tqh_first; + TAILQ_REMOVE(&dma_free, dma_free.tqh_first, entries); + req->call_func = call_func; + req->int_func = int_func; + req->softc = softc; + req->lock_stat = lock_stat; + TAILQ_INSERT_TAIL(&dma_active, req, entries); + + if(dma_active.tqh_first != req) { + splx(sps); + return(0); + } + splx(sps); + + /* + * We're at the head of the queue, ergo: we got the lock. + */ + *lock_stat = DMA_LOCK_GRANT; + + if(rcaller) { + /* + * Just return to caller immediately without going + * through 'call_func' first. + */ + return(1); + } + + (*call_func)(softc); /* Call followup function */ + return(0); +} + +void +st_dmafree(softc, lock_stat) +void *softc; +int *lock_stat; +{ + int sps; + DMA_ENTRY *req; + + sps = splhigh(); + + /* + * Some validity checks first. + */ + if((req = dma_active.tqh_first) == NULL) + panic("st_dmafree: empty active queue\n"); + if(req->softc != softc) + printf("Caller of st_dmafree is not lock-owner!\n"); + + /* + * Clear lock status, move request from active to free queue. + */ + *lock_stat = 0; + TAILQ_REMOVE(&dma_active, req, entries); + TAILQ_INSERT_HEAD(&dma_free, req, entries); + + if((req = dma_active.tqh_first) != NULL) { + /* + * Call next request through softint handler. This avoids + * spl-conflicts. + */ + *req->lock_stat = DMA_LOCK_GRANT; + add_sicallback(req->call_func, req->softc, 0); + } + splx(sps); + return; +} + +int +st_dmawanted() +{ + return(dma_active.tqh_first->entries.tqe_next != NULL); +} + +cdmaint(sr) +long sr; /* sr at time of interrupt */ +{ + if(dma_active.tqh_first != NULL) { + if(!BASEPRI(sr)) { + if(!sched_soft++) + add_sicallback(cdmasoft, 0, 0); + } + else { + spl1(); + cdmasoft(); + } + } + else printf("DMA interrupt discarded\n"); +} + +static void cdmasoft() +{ + int s; + void (*int_func)(); + void *softc; + + /* + * Prevent a race condition here. DMA might be freed while + * the callback was pending! + */ + s = splhigh(); + sched_soft = 0; + if(dma_active.tqh_first != NULL) { + int_func = dma_active.tqh_first->int_func; + softc = dma_active.tqh_first->softc; + } + else int_func = NULL; + splx(s); + + if(int_func != NULL) + (*int_func)(softc); +} + +/* + * Setup address for DMA-transfer. + * Note: The order _is_ important! + */ +void +st_dmaaddr_set(address) +caddr_t address; +{ + register u_long ad = (u_long)address; + + DMA->dma_addr[AD_LOW ] = (ad ) & 0xff; + DMA->dma_addr[AD_MID ] = (ad >> 8) & 0xff; + DMA->dma_addr[AD_HIGH] = (ad >>16) & 0xff; +} + +/* + * Get address from DMA unit. + */ +u_long +st_dmaaddr_get() +{ + register u_long ad = 0; + + ad = (DMA->dma_addr[AD_LOW ] & 0xff); + ad |= (DMA->dma_addr[AD_MID ] & 0xff) << 8; + ad |= (DMA->dma_addr[AD_HIGH] & 0xff) <<16; + return(ad); +} + +/* + * Program the DMA-controller to transfer 'nblk' blocks of 512 bytes. + * The DMA_WRBIT trick flushes the FIFO before doing DMA. + */ +void +st_dmacomm(mode, nblk) +int mode, nblk; +{ + DMA->dma_mode = mode; + DMA->dma_mode = mode ^ DMA_WRBIT; + DMA->dma_mode = mode; + DMA->dma_data = nblk; + DMA->dma_mode = DMA_SCREG | (mode & DMA_WRBIT); +} diff --git a/sys/arch/atari/dev/event.c b/sys/arch/atari/dev/event.c new file mode 100644 index 00000000000..c4ae6c8b89f --- /dev/null +++ b/sys/arch/atari/dev/event.c @@ -0,0 +1,173 @@ +/* $NetBSD: event.c,v 1.2 1995/06/25 19:05:23 leo Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + * + * @(#)event.c 8.1 (Berkeley) 6/11/93 + * + * from: Header: event.c,v 1.5 92/11/26 01:10:44 torek Exp (LBL) + */ + +/* + * Internal `Firm_event' interface for the keyboard and mouse drivers. + */ + +#include <sys/param.h> +#include <sys/fcntl.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#include <sys/systm.h> +#include <sys/vnode.h> + +#include <atari/dev/vuid_event.h> +#include <atari/dev/event_var.h> + +/* + * Initialize a firm_event queue. + */ +void +ev_init(ev) + register struct evvar *ev; +{ + + ev->ev_get = ev->ev_put = 0; + ev->ev_q = malloc((u_long)EV_QSIZE * sizeof(struct firm_event), + M_DEVBUF, M_WAITOK); + bzero((caddr_t)ev->ev_q, EV_QSIZE * sizeof(struct firm_event)); +} + +/* + * Tear down a firm_event queue. + */ +void +ev_fini(ev) + register struct evvar *ev; +{ + + free(ev->ev_q, M_DEVBUF); +} + +/* + * User-level interface: read, select. + * (User cannot write an event queue.) + */ +int +ev_read(ev, uio, flags) + register struct evvar *ev; + struct uio *uio; + int flags; +{ + int s, n, cnt, error; + + /* + * Make sure we can return at least 1. + */ + if (uio->uio_resid < sizeof(struct firm_event)) + return (EMSGSIZE); /* ??? */ + s = splev(); + while (ev->ev_get == ev->ev_put) { + if (flags & IO_NDELAY) { + splx(s); + return (EWOULDBLOCK); + } + ev->ev_wanted = 1; + error = tsleep((caddr_t)ev, PEVENT | PCATCH, "firm_event", 0); + if (error) { + splx(s); + return (error); + } + } + /* + * Move firm_events from tail end of queue (there is at least one + * there). + */ + if (ev->ev_put < ev->ev_get) + cnt = EV_QSIZE - ev->ev_get; /* events in [get..QSIZE) */ + else + cnt = ev->ev_put - ev->ev_get; /* events in [get..put) */ + splx(s); + n = howmany(uio->uio_resid, sizeof(struct firm_event)); + if (cnt > n) + cnt = n; + error = uiomove((caddr_t)&ev->ev_q[ev->ev_get], + cnt * sizeof(struct firm_event), uio); + n -= cnt; + /* + * If we do not wrap to 0, used up all our space, or had an error, + * stop. Otherwise move from front of queue to put index, if there + * is anything there to move. + */ + if ((ev->ev_get = (ev->ev_get + cnt) % EV_QSIZE) != 0 || + n == 0 || error || (cnt = ev->ev_put) == 0) + return (error); + if (cnt > n) + cnt = n; + error = uiomove((caddr_t)&ev->ev_q[0], + cnt * sizeof(struct firm_event), uio); + ev->ev_get = cnt; + return (error); +} + +int +ev_select(ev, rw, p) + register struct evvar *ev; + int rw; + struct proc *p; +{ + int s = splev(); + + switch (rw) { + + case FREAD: + /* succeed if there is something to read */ + if (ev->ev_get != ev->ev_put) { + splx(s); + return (1); + } + selrecord(p, &ev->ev_sel); + break; + + case FWRITE: + return (1); /* always fails => never blocks */ + } + splx(s); + return (0); +} diff --git a/sys/arch/atari/dev/event_var.h b/sys/arch/atari/dev/event_var.h new file mode 100644 index 00000000000..766bc2632fa --- /dev/null +++ b/sys/arch/atari/dev/event_var.h @@ -0,0 +1,89 @@ +/* $NetBSD: event_var.h,v 1.1.1.1 1995/03/26 07:12:13 leo Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + * + * @(#)event_var.h 8.1 (Berkeley) 6/11/93 + * + * from: Header: event_var.h,v 1.5 92/11/26 01:11:51 torek Exp (LBL) + */ + +/* + * Internal `Firm_event' interface for the keyboard and mouse drivers. + * The drivers are expected not to place events in the queue above spltty(), + * i.e., are expected to run off serial ports. + */ + +/* EV_QSIZE should be a power of two so that `%' is fast */ +#define EV_QSIZE 256 /* may need tuning; this uses 2k */ + +struct evvar { + u_int ev_get; /* get (read) index (modified synchronously) */ + volatile u_int ev_put; /* put (write) index (modified by interrupt) */ + struct selinfo ev_sel; /* process selecting */ + struct proc *ev_io; /* process that opened queue (can get SIGIO) */ + char ev_wanted; /* wake up on input ready */ + char ev_async; /* send SIGIO on input ready */ + struct firm_event *ev_q;/* circular buffer (queue) of events */ +}; + +#define splev() spltty() + +#define EV_WAKEUP(ev) { \ + selwakeup(&(ev)->ev_sel); \ + if ((ev)->ev_wanted) { \ + (ev)->ev_wanted = 0; \ + wakeup((caddr_t)(ev)); \ + } \ + if ((ev)->ev_async) \ + psignal((ev)->ev_io, SIGIO); \ +} + +void ev_init __P((struct evvar *)); +void ev_fini __P((struct evvar *)); +int ev_read __P((struct evvar *, struct uio *, int)); +int ev_select __P((struct evvar *, int, struct proc *)); + +/* + * PEVENT is set just above PSOCK, which is just above TTIPRI, on the + * theory that mouse and keyboard `user' input should be quick. + */ +#define PEVENT 23 diff --git a/sys/arch/atari/dev/fd.c b/sys/arch/atari/dev/fd.c new file mode 100644 index 00000000000..586e0b2f53a --- /dev/null +++ b/sys/arch/atari/dev/fd.c @@ -0,0 +1,1202 @@ +/* $NetBSD: fd.c,v 1.10.2.1 1995/10/14 20:19:41 leo Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman. + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Leo Weppelman. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * This file contains a driver for the Floppy Disk Controller (FDC) + * on the Atari TT. It uses the WD 1772 chip, modified for steprates. + * + * The ST floppy disk controller shares the access to the DMA circuitry + * with other devices. For this reason the floppy disk controller makes + * use of some special DMA accessing code. + * + * Interrupts from the FDC are in fact DMA interrupts which get their + * first level handling in 'dma.c' . If the floppy driver is currently + * using DMA the interrupt is signalled to 'fdcint'. + * + * TODO: + * - Test it with 2 drives (I don't have them) + * - Test it with an HD-drive (Don't have that either) + * - Finish ioctl's + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <sys/device.h> +#include <sys/ioctl.h> +#include <sys/fcntl.h> +#include <sys/conf.h> +#include <sys/disklabel.h> +#include <sys/disk.h> +#include <sys/dkbad.h> +#include <atari/atari/device.h> +#include <machine/disklabel.h> +#include <machine/iomap.h> +#include <machine/mfp.h> +#include <machine/dma.h> +#include <machine/video.h> +#include <atari/dev/fdreg.h> + +/* + * Be verbose for debugging + */ +/*#define FLP_DEBUG 1 */ + +#define FDC_MAX_DMA_AD 0x1000000 /* No DMA possible beyond */ + +/* Parameters for the disk drive. */ +#define SECTOR_SIZE 512 /* physical sector size in bytes */ +#define NR_DRIVES 2 /* maximum number of drives */ +#define NR_TYPES 3 /* number of diskette/drive combinations*/ +#define MAX_ERRORS 10 /* how often to try rd/wt before quitting*/ +#define STEP_DELAY 6000 /* 6ms (6000us) delay after stepping */ + + +#define INV_TRK 32000 /* Should fit in unsigned short */ +#define INV_PART NR_TYPES + +/* + * Driver states + */ +#define FLP_IDLE 0x00 /* floppy is idle */ +#define FLP_MON 0x01 /* idle with motor on */ +#define FLP_STAT 0x02 /* determine floppy status */ +#define FLP_XFER 0x04 /* read/write data from floppy */ + +/* + * Timer delay's + */ +#define FLP_MONDELAY (3 * hz) /* motor-on delay */ +#define FLP_XFERDELAY (2 * hz) /* timeout on transfer */ + +/* + * The density codes + */ +#define FLP_DD 0 /* Double density */ +#define FLP_HD 1 /* High density */ + + +#define b_block b_resid /* FIXME: this is not the place */ + +/* + * Global data for all physical floppy devices + */ +static short selected = 0; /* drive/head currently selected*/ +static short motoron = 0; /* motor is spinning */ +static short nopens = 0; /* Number of opens executed */ + +static short fd_state = FLP_IDLE; /* Current driver state */ +static int lock_stat= 0; /* dma locking status */ +static short fd_cmd = 0; /* command being executed */ +static char *fd_error= NULL; /* error from fd_xfer_ok() */ + +/* + * Private per device data + */ +struct fd_softc { + struct dkdevice dkdev; + struct buf bufq; /* queue of buf's */ + int unit; /* unit for atari controlling hw*/ + int nheads; /* number of heads in use */ + int nsectors; /* number of sectors/track */ + int density; /* density code */ + int nblocks; /* number of blocks on disk */ + int curtrk; /* track head positioned on */ + short flags; /* misc flags */ + short part; /* Current open partition */ + int sector; /* logical sector for I/O */ + caddr_t io_data; /* KVA for data transfer */ + int io_bytes; /* bytes left for I/O */ + int io_dir; /* B_READ/B_WRITE */ + int errcnt; /* current error count */ + u_char *bounceb; /* Bounce buffer */ + +}; + +/* + * Flags in fd_softc: + */ +#define FLPF_NOTRESP 0x001 /* Unit not responding */ +#define FLPF_ISOPEN 0x002 /* Unit is open */ +#define FLPF_SPARE 0x004 /* Not used */ +#define FLPF_HAVELAB 0x008 /* We have a valid label */ +#define FLPF_BOUNCE 0x010 /* Now using the bounce buffer */ +#define FLPF_WRTPROT 0x020 /* Unit is write-protected */ +#define FLPF_EMPTY 0x040 /* Unit is empty */ +#define FLPF_INOPEN 0x080 /* Currently being opened */ +#define FLPF_GETSTAT 0x100 /* Getting unit status */ + +struct fd_types { + int nheads; /* Heads in use */ + int nsectors; /* sectors per track */ + int nblocks; /* number of blocks */ + int density; /* density code */ +} fdtypes[NR_TYPES] = { + { 1, 9, 720 , FLP_DD }, /* 360 Kb */ + { 2, 9, 1440 , FLP_DD }, /* 720 Kb */ + { 2, 18, 2880 , FLP_HD }, /* 1.44 Mb */ +}; + +typedef void (*FPV)(); + +/* + * Private drive functions.... + */ +static void fdstart __P((struct fd_softc *)); +static void fddone __P((struct fd_softc *)); +static void fdstatus __P((struct fd_softc *)); +static void fd_xfer __P((struct fd_softc *)); +static void fdcint __P((struct fd_softc *)); +static int fd_xfer_ok __P((struct fd_softc *)); +static void fdmotoroff __P((struct fd_softc *)); +static void fdminphys __P((struct buf *)); +static void fdtestdrv __P((struct fd_softc *)); +static int fdgetdisklabel __P((struct fd_softc *, dev_t)); +static int fdselect __P((int, int, int)); +static void fddeselect __P((void)); + +extern __inline__ u_char read_fdreg(u_short regno) +{ + DMA->dma_mode = regno; + return(DMA->dma_data); +} + +extern __inline__ void write_fdreg(u_short regno, u_short val) +{ + DMA->dma_mode = regno; + DMA->dma_data = val; +} + +extern __inline__ u_char read_dmastat(void) +{ + DMA->dma_mode = FDC_CS | DMA_SCREG; + return(DMA->dma_stat); +} + +/* + * Autoconfig stuff.... + */ +static int fdcmatch __P((struct device *, struct cfdata *, void *)); +static int fdcprint __P((void *, char *)); +static void fdcattach __P((struct device *, struct device *, void *)); + +struct cfdriver fdccd = { + NULL, "fdc", (cfmatch_t)fdcmatch, fdcattach, DV_DULL, + sizeof(struct device), NULL, 0 }; + +static int +fdcmatch(pdp, cfp, auxp) +struct device *pdp; +struct cfdata *cfp; +void *auxp; +{ + if(strcmp("fdc", auxp) || cfp->cf_unit != 0) + return(0); + return(1); +} + +static void +fdcattach(pdp, dp, auxp) +struct device *pdp, *dp; +void *auxp; +{ + struct fd_softc fdsoftc; + int i, nfound = 0; + + printf("\n"); + fddeselect(); + for(i = 0; i < NR_DRIVES; i++) { + + /* + * Test if unit is present + */ + fdsoftc.unit = i; + fdsoftc.flags = 0; + st_dmagrab(fdcint, fdtestdrv, &fdsoftc, &lock_stat, 0); + st_dmafree(&fdsoftc, &lock_stat); + + if(!(fdsoftc.flags & FLPF_NOTRESP)) { + nfound++; + config_found(dp, (void*)i, fdcprint); + } + } + + if(nfound) { + /* + * enable disk related interrupts + */ + MFP->mf_ierb |= IB_DINT; + MFP->mf_iprb &= ~IB_DINT; + MFP->mf_imrb |= IB_DINT; + } +} + +static int +fdcprint(auxp, pnp) +void *auxp; +char *pnp; +{ + return(UNCONF); +} + +static int fdmatch __P((struct device *, struct cfdata *, void *)); +static void fdattach __P((struct device *, struct device *, void *)); + void fdstrategy __P((struct buf *)); +struct dkdriver fddkdriver = { fdstrategy }; + +struct cfdriver fdcd = { + NULL, "fd", (cfmatch_t)fdmatch, fdattach, DV_DISK, + sizeof(struct fd_softc), NULL, 0 }; + +static int +fdmatch(pdp, cfp, auxp) +struct device *pdp; +struct cfdata *cfp; +void *auxp; +{ + int unit = (int)auxp; + return(1); +} + +static void +fdattach(pdp, dp, auxp) +struct device *pdp, *dp; +void *auxp; +{ + struct fd_softc *sc; + + sc = (struct fd_softc *)dp; + + printf("\n"); + + sc->dkdev.dk_driver = &fddkdriver; +} + +fdioctl(dev, cmd, addr, flag, p) +dev_t dev; +u_long cmd; +int flag; +caddr_t addr; +struct proc *p; +{ + struct fd_softc *sc; + void *data; + + sc = getsoftc(fdcd, DISKUNIT(dev)); + + if((sc->flags & FLPF_HAVELAB) == 0) + return(EBADF); + + switch(cmd) { + case DIOCSBAD: + return(EINVAL); + case DIOCGDINFO: + *(struct disklabel *)addr = sc->dkdev.dk_label; + return(0); + case DIOCGPART: + ((struct partinfo *)addr)->disklab = + &sc->dkdev.dk_label; + ((struct partinfo *)addr)->part = + &sc->dkdev.dk_label.d_partitions[DISKPART(dev)]; + return(0); +#ifdef notyet /* XXX LWP */ + case DIOCSRETRIES: + case DIOCSSTEP: + case DIOCSDINFO: + case DIOCWDINFO: + case DIOCWLABEL: +#endif /* notyet */ + default: + return(ENOTTY); + } +} + +/* + * Open the device. If this is the first open on both the floppy devices, + * intialize the controller. + * Note that partition info on the floppy device is used to distinguise + * between 780Kb and 360Kb floppy's. + * partition 0: 360Kb + * partition 1: 780Kb + */ +Fdopen(dev, flags, devtype, proc) +dev_t dev; +int flags, devtype; +struct proc *proc; +{ + struct fd_softc *sc; + int sps; + +#ifdef FLP_DEBUG + printf("Fdopen dev=0x%x\n", dev); +#endif + + if(DISKPART(dev) >= NR_TYPES) + return(ENXIO); + + if((sc = getsoftc(fdcd, DISKUNIT(dev))) == NULL) + return(ENXIO); + + /* + * If no floppy currently open, reset the controller and select + * floppy type. + */ + if(!nopens) { + +#ifdef FLP_DEBUG + printf("Fdopen device not yet open\n"); +#endif + nopens++; + write_fdreg(FDC_CS, IRUPT); + delay(40); + } + + /* + * Sleep while other process is opening the device + */ + sps = splbio(); + while(sc->flags & FLPF_INOPEN) + tsleep((caddr_t)sc, PRIBIO, "Fdopen", 0); + splx(sps); + + if(!(sc->flags & FLPF_ISOPEN)) { + /* + * Initialise some driver values. + */ + int part = DISKPART(dev); + void *addr; + + sc->bufq.b_actf = NULL; + sc->unit = DISKUNIT(dev); + sc->part = part; + sc->nheads = fdtypes[part].nheads; + sc->nsectors = fdtypes[part].nsectors; + sc->nblocks = fdtypes[part].nblocks; + sc->density = fdtypes[part].density; + sc->curtrk = INV_TRK; + sc->sector = 0; + sc->errcnt = 0; + sc->bounceb = (u_char*)alloc_stmem(SECTOR_SIZE, &addr); + if(sc->bounceb == NULL) + return(ENOMEM); /* XXX */ + + /* + * Go get write protect + loaded status + */ + sc->flags |= FLPF_INOPEN|FLPF_GETSTAT; + sps = splbio(); + st_dmagrab(fdcint, fdstatus, sc, &lock_stat, 0); + while(sc->flags & FLPF_GETSTAT) + tsleep((caddr_t)sc, PRIBIO, "Fdopen", 0); + splx(sps); + wakeup((caddr_t)sc); + + if((sc->flags & FLPF_WRTPROT) && (flags & FWRITE)) { + sc->flags = 0; + return(EPERM); + } + if(sc->flags & FLPF_EMPTY) { + sc->flags = 0; + return(ENXIO); + } + sc->flags &= ~(FLPF_INOPEN|FLPF_GETSTAT); + sc->flags |= FLPF_ISOPEN; + } + else { + /* + * Multiply opens are granted when accessing the same type of + * floppy (eq. the same partition). + */ + if(sc->part != DISKPART(dev)) + return(ENXIO); /* XXX temporarely out of business */ + } + fdgetdisklabel(sc, dev); +#ifdef FLP_DEBUG + printf("Fdopen open succeeded on type %d\n", sc->part); +#endif +} + +fdclose(dev, flags, devtype, proc) +dev_t dev; +int flags, devtype; +struct proc *proc; +{ + struct fd_softc *sc; + + sc = getsoftc(fdcd, DISKUNIT(dev)); + free_stmem(sc->bounceb); + sc->flags = 0; + nopens--; + +#ifdef FLP_DEBUG + printf("Closed floppy device -- nopens: %d\n", nopens); +#endif + return(0); +} + +void +fdstrategy(bp) +struct buf *bp; +{ + struct fd_softc *sc; + struct disklabel *lp; + int sps, nblocks; + + sc = getsoftc(fdcd, DISKUNIT(bp->b_dev)); + +#ifdef FLP_DEBUG + printf("fdstrategy: 0x%x\n", bp); +#endif + + /* + * check for valid partition and bounds + */ + lp = &sc->dkdev.dk_label; + if ((sc->flags & FLPF_HAVELAB) == 0) { + bp->b_error = EIO; + goto bad; + } + if (bounds_check_with_label(bp, lp, 0) <= 0) + goto done; + + if (bp->b_bcount == 0) + goto done; + + /* + * queue the buf and kick the low level code + */ + sps = splbio(); + disksort(&sc->bufq, bp); + if (!lock_stat) { + if (fd_state & FLP_MON) + untimeout((FPV)fdmotoroff, (void*)sc); + fd_state = FLP_IDLE; + st_dmagrab(fdcint, fdstart, sc, &lock_stat, 0); + } + splx(sps); + + return; +bad: + bp->b_flags |= B_ERROR; +done: + bp->b_resid = bp->b_bcount; + biodone(bp); +} + +/* + * no dumps to floppy disks thank you. + */ +int +fddump(dev_t dev) +{ + return(ENXIO); +} + +/* + * no dumps to floppy disks thank you. + */ +int +fdsize(dev) +dev_t dev; +{ + return(-1); +} + +int +fdread(dev, uio) +dev_t dev; +struct uio *uio; +{ + return(physio(fdstrategy, NULL, dev, B_READ, fdminphys, uio)); +} + +int +fdwrite(dev, uio) +dev_t dev; +struct uio *uio; +{ + return(physio(fdstrategy, NULL, dev, B_WRITE, fdminphys, uio)); +} + +/* + * Called through DMA-dispatcher, get status. + */ +static void +fdstatus(sc) +struct fd_softc *sc; +{ +#ifdef FLP_DEBUG + printf("fdstatus\n"); +#endif + sc->errcnt = 0; + fd_state = FLP_STAT; + fd_xfer(sc); +} + +/* + * Called through the dma-dispatcher. So we know we are the only ones + * messing with the floppy-controler. + * Initialize some fields in the fdsoftc for the state-machine and get + * it going. + */ +static void +fdstart(sc) +struct fd_softc *sc; +{ + struct buf *bp; + + bp = sc->bufq.b_actf; + sc->sector = bp->b_blkno; /* Start sector for I/O */ + sc->io_data = bp->b_data; /* KVA base for I/O */ + sc->io_bytes = bp->b_bcount; /* Transfer size in bytes */ + sc->io_dir = bp->b_flags & B_READ;/* Direction of transfer */ + sc->errcnt = 0; /* No errors yet */ + fd_state = FLP_XFER; /* Yes, we're going to transfer */ + + fd_xfer(sc); +} + +/* + * The current transaction is finished (for good or bad). Let go of + * the the dma-resources. Call biodone() to finish the transaction. + * Find a new transaction to work on. + */ +static void +fddone(sc) +register struct fd_softc *sc; +{ + struct buf *bp, *dp; + struct fd_softc *sc1; + int i, sps; + + /* + * Give others a chance to use the dma. + */ + st_dmafree(sc, &lock_stat); + + + if(fd_state != FLP_STAT) { + /* + * Finish current transaction. + */ + sps = splbio(); + dp = &sc->bufq; + bp = dp->b_actf; + if(bp == NULL) + panic("fddone"); + dp->b_actf = bp->b_actf; + splx(sps); + +#ifdef FLP_DEBUG + printf("fddone: unit: %d, buf: %x, resid: %d\n",sc->unit,bp, + sc->io_bytes); +#endif + bp->b_resid = sc->io_bytes; + biodone(bp); + } + fd_state = FLP_MON; + + if(lock_stat) + return; /* XXX Is this possible? */ + + /* + * Find a new transaction on round-robin basis. + */ + for(i = sc->unit + 1; ;i++) { + if(i >= fdcd.cd_ndevs) + i = 0; + if((sc1 = fdcd.cd_devs[i]) == NULL) + continue; + if(sc1->bufq.b_actf) + break; + if(i == sc->unit) { + timeout((FPV)fdmotoroff, (void*)sc, FLP_MONDELAY); +#ifdef FLP_DEBUG + printf("fddone: Nothing to do\n"); +#endif + return; /* No work */ + } + } + fd_state = FLP_IDLE; +#ifdef FLP_DEBUG + printf("fddone: Staring job on unit %d\n", sc1->unit); +#endif + st_dmagrab(fdcint, fdstart, sc1, &lock_stat, 0); +} + +static int +fdselect(drive, head, dense) +int drive, head, dense; +{ + int i, sps, spinning; +#ifdef FLP_DEBUG + printf("fdselect: drive=%d, head=%d, dense=%d\n", drive, head, dense); +#endif + i = ((drive == 1) ? PA_FLOP1 : PA_FLOP0) | head; + spinning = motoron; + motoron = 1; + + switch(dense) { + case FLP_DD: + DMA->dma_drvmode = 0; + break; + case FLP_HD: + DMA->dma_drvmode = (FDC_HDSET|FDC_HDSIG); + break; + default: + panic("fdselect: unknown density code\n"); + } + if(i != selected) { + sps = splhigh(); + + selected = i; + SOUND->sd_selr = YM_IOA; + SOUND->sd_wdat = (SOUND->sd_rdat & 0x78) | (i ^ 0x07); + splx(sps); + } + return(spinning); +} + +static void +fddeselect() +{ + int sps; + + sps = splhigh(); + SOUND->sd_selr = YM_IOA; + SOUND->sd_wdat = SOUND->sd_rdat | 0x07; + splx(sps); + + motoron = selected = 0; + DMA->dma_drvmode = 0; +} + +/**************************************************************************** + * The following functions assume to be running as a result of a * + * disk-interrupt (e.q. spl = splbio). * + * They form the finit-state machine, the actual driver. * + * * + * fdstart()/ --> fd_xfer() -> activate hardware * + * fdopen() ^ * + * | * + * +-- not ready -<------------+ * + * | * + * fdmotoroff()/ --> fdcint() -> fd_xfer_ok() ---+ * + * h/w interrupt | * + * \|/ * + * finished ---> fdone() * + * * + ****************************************************************************/ +static void +fd_xfer(sc) +struct fd_softc *sc; +{ + register int head = 0; + register int track, sector, hbit; + int i; + u_long phys_addr; + + switch(fd_state) { + case FLP_XFER: + /* + * Calculate head/track values + */ + track = sc->sector / sc->nsectors; + head = track % sc->nheads; + track = track / sc->nheads; +#ifdef FLP_DEBUG + printf("fd_xfer: sector:%d,head:%d,track:%d\n", sc->sector,head, + track); +#endif + break; + + case FLP_STAT: + /* + * FLP_STAT only wants to recalibrate + */ + sc->curtrk = INV_TRK; + break; + default: + panic("fd_xfer: wrong state (0x%x)", fd_state); + } + + /* + * Select the drive. + */ + hbit = fdselect(sc->unit, head, sc->density) ? HBIT : 0; + + if(sc->curtrk == INV_TRK) { + /* + * Recalibrate, since we lost track of head positioning. + * The floppy disk controller has no way of determining its + * absolute arm position (track). Instead, it steps the + * arm a track at a time and keeps track of where it + * thinks it is (in software). However, after a SEEK, the + * hardware reads information from the diskette telling + * where the arm actually is. If the arm is in the wrong place, + * a recalibration is done, which forces the arm to track 0. + * This way the controller can get back into sync with reality. + */ + fd_cmd = RESTORE; + write_fdreg(FDC_CS, RESTORE|VBIT|hbit); + timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY); + +#ifdef FLP_DEBUG + printf("fd_xfer:Recalibrating drive %d\n", sc->unit); +#endif + return; + } + + write_fdreg(FDC_TR, sc->curtrk); + + /* + * Issue a SEEK command on the indicated drive unless the arm is + * already positioned on the correct track. + */ + if(track != sc->curtrk) { + sc->curtrk = track; /* be optimistic */ + write_fdreg(FDC_DR, track); + write_fdreg(FDC_CS, SEEK|RATE6|VBIT|hbit); + timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY); + fd_cmd = SEEK; +#ifdef FLP_DEBUG + printf("fd_xfer:Seek to track %d on drive %d\n",track,sc->unit); +#endif + return; + } + + /* + * The drive is now on the proper track. Read or write 1 block. + */ + sector = sc->sector % sc->nsectors; + sector++; /* start numbering at 1 */ + + write_fdreg(FDC_SR, sector); + + phys_addr = (u_long)kvtop(sc->io_data); + if(phys_addr >= FDC_MAX_DMA_AD) { + /* + * We _must_ bounce this address + */ + phys_addr = (u_long)kvtop(sc->bounceb); + if(sc->io_dir == B_WRITE) + bcopy(sc->io_data, sc->bounceb, SECTOR_SIZE); + sc->flags |= FLPF_BOUNCE; + } + st_dmaaddr_set((caddr_t)phys_addr); /* DMA address setup */ + +#ifdef FLP_DEBUG + printf("fd_xfer:Start io (io_addr:%x)\n", kvtop(sc->io_data)); +#endif + + if(sc->io_dir == B_READ) { + /* Issue the command */ + st_dmacomm(DMA_FDC | DMA_SCREG, 1); + write_fdreg(FDC_CS, F_READ|hbit); + fd_cmd = F_READ; + } + else { + /* Issue the command */ + st_dmacomm(DMA_WRBIT | DMA_FDC | DMA_SCREG, 1); + write_fdreg(DMA_WRBIT | FDC_CS, F_WRITE|hbit|EBIT|PBIT); + fd_cmd = F_WRITE; + } + timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY); +} + +/* return values of fd_xfer_ok(): */ +#define X_OK 0 +#define X_AGAIN 1 +#define X_ERROR 2 +#define X_FAIL 3 + +/* + * Hardware interrupt function. + */ +static void +fdcint(sc) +struct fd_softc *sc; +{ + struct buf *bp; + +#ifdef FLP_DEBUG + printf("fdcint: unit = %d\n", sc->unit); +#endif + + /* + * Cancel timeout (we made it, didn't we) + */ + untimeout((FPV)fdmotoroff, (void*)sc); + + switch(fd_xfer_ok(sc)) { + case X_ERROR : + if(++(sc->errcnt) < MAX_ERRORS) { + /* + * Command failed but still retries left. + */ + break; + } + /* FALL THROUGH */ + case X_FAIL : + /* + * Non recoverable error. Fall back to motor-on + * idle-state. + */ + if(fd_error != NULL) { + printf("Floppy error: %s\n", fd_error); + fd_error = NULL; + } + + if(fd_state == FLP_STAT) { + sc->flags |= FLPF_EMPTY; + sc->flags &= ~FLPF_GETSTAT; + wakeup((caddr_t)sc); + fddone(sc); + return; + } + + bp = sc->bufq.b_actf; + + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + fd_state = FLP_MON; + + break; + case X_AGAIN: + /* + * Start next part of state machine. + */ + break; + case X_OK: + /* + * Command ok and finished. Reset error-counter. + * If there are no more bytes to transfer fall back + * to motor-on idle state. + */ + sc->errcnt = 0; + + if(fd_state == FLP_STAT) { + sc->flags &= ~FLPF_GETSTAT; + wakeup((caddr_t)sc); + fddone(sc); + return; + } + + if((sc->flags & FLPF_BOUNCE) && (sc->io_dir == B_READ)) + bcopy(sc->bounceb, sc->io_data, SECTOR_SIZE); + sc->flags &= ~FLPF_BOUNCE; + + sc->sector++; + sc->io_data += SECTOR_SIZE; + sc->io_bytes -= SECTOR_SIZE; + if(sc->io_bytes <= 0) + fd_state = FLP_MON; + } + if(fd_state == FLP_MON) + fddone(sc); + else fd_xfer(sc); +} + +/* + * Determine status of last command. Should only be called through + * 'fdcint()'. + * Returns: + * X_ERROR : Error on command; might succeed next time. + * X_FAIL : Error on command; will never succeed. + * X_AGAIN : Part of a command succeeded, call 'fd_xfer()' to complete. + * X_OK : Command succeeded and is complete. + * + * This function only affects sc->curtrk. + */ +static int +fd_xfer_ok(sc) +register struct fd_softc *sc; +{ + register int status; + +#ifdef FLP_DEBUG + printf("fd_xfer_ok: cmd: 0x%x, state: 0x%x\n", fd_cmd, fd_state); +#endif + switch(fd_cmd) { + case IRUPT: + /* + * Timeout. Force a recalibrate before we try again. + */ + status = read_fdreg(FDC_CS); + + fd_error = "Timeout"; + sc->curtrk = INV_TRK; + return(X_ERROR); + case F_READ: + /* + * Test for DMA error + */ + status = read_dmastat(); + if(!(status & DMAOK)) { + fd_error = "Dma error"; + return(X_ERROR); + } + /* + * Get controller status and check for errors. + */ + status = read_fdreg(FDC_CS); + if(status & (RNF | CRCERR | LD_T00)) { + fd_error = "Read error"; + if(status & RNF) + sc->curtrk = INV_TRK; + return(X_ERROR); + } + break; + case F_WRITE: + /* + * Test for DMA error + */ + status = read_dmastat(); + if(!(status & DMAOK)) { + fd_error = "Dma error"; + return(X_ERROR); + } + /* + * Get controller status and check for errors. + */ + status = read_fdreg(FDC_CS); + if(status & WRI_PRO) { + fd_error = "Write protected"; + return(X_FAIL); + } + if(status & (RNF | CRCERR | LD_T00)) { + fd_error = "Write error"; + sc->curtrk = INV_TRK; + return(X_ERROR); + } + break; + case SEEK: + status = read_fdreg(FDC_CS); + if(status & (RNF | CRCERR)) { + fd_error = "Seek error"; + sc->curtrk = INV_TRK; + return(X_ERROR); + } + return(X_AGAIN); + case RESTORE: + /* + * Determine if the recalibration succeeded. + */ + status = read_fdreg(FDC_CS); + if(status & RNF) { + fd_error = "Recalibrate error"; + /* reset controller */ + write_fdreg(FDC_CS, IRUPT); + sc->curtrk = INV_TRK; + return(X_ERROR); + } + sc->curtrk = 0; + if(fd_state == FLP_STAT) { + if(status & WRI_PRO) + sc->flags |= FLPF_WRTPROT; + break; + } + return(X_AGAIN); + default: + fd_error = "Driver error: fd_xfer_ok : Unknown state"; + return(X_FAIL); + } + return(X_OK); +} + +/* + * All timeouts will call this function. + */ +static void +fdmotoroff(sc) +struct fd_softc *sc; +{ + int sps; + + /* + * Get at harware interrupt level + */ + sps = splbio(); + +#if FLP_DEBUG + printf("fdmotoroff, state = 0x%x\n", fd_state); +#endif + + switch(fd_state) { + case FLP_STAT : + case FLP_XFER : + /* + * Timeout during a transfer; cancel transaction + * set command to 'IRUPT'. + * A drive-interrupt is simulated to trigger the state + * machine. + */ + /* + * Cancel current transaction + */ + fd_cmd = IRUPT; + write_fdreg(FDC_CS, IRUPT); + delay(20); + (void)read_fdreg(FDC_CS); + write_fdreg(FDC_CS, RESTORE); + break; + + case FLP_MON : + /* + * Turn motor off. + */ + if(selected) + fddeselect(); + fd_state = FLP_IDLE; + break; + } + splx(sps); +} + +/* + * min byte count to whats left of the track in question + */ +static void +fdminphys(bp) +struct buf *bp; +{ + struct fd_softc *sc; + int sec, toff, tsz; + + if((sc = getsoftc(fdcd, DISKUNIT(bp->b_dev))) == NULL) + panic("fdminphys: couldn't get softc"); + + sec = bp->b_blkno % (sc->nsectors * sc->nheads); + toff = sec * SECTOR_SIZE; + tsz = sc->nsectors * sc->nheads * SECTOR_SIZE; + +#ifdef FLP_DEBUG + printf("fdminphys: before %d", bp->b_bcount); +#endif + + bp->b_bcount = min(bp->b_bcount, tsz - toff); + +#ifdef FLP_DEBUG + printf(" after %d\n", bp->b_bcount); +#endif + + minphys(bp); +} + +/* + * Used to find out wich drives are actually connected. We do this by issueing + * is 'RESTORE' command and check if the 'track-0' bit is set. This also works + * if the drive is present but no floppy is inserted. + */ +static void +fdtestdrv(fdsoftc) +struct fd_softc *fdsoftc; +{ + int i, status; + + /* + * Select the right unit and head. + */ + fdselect(fdsoftc->unit, 0, FLP_DD); + + write_fdreg(FDC_CS, RESTORE|HBIT); + + /* + * Wait for about 2 seconds. + */ + delay(2000000); + + status = read_fdreg(FDC_CS); + if(status & (RNF|BUSY)) { + write_fdreg(FDC_CS, IRUPT); /* reset controller */ + delay(40); + } + + if(!(status & LD_T00)) + fdsoftc->flags |= FLPF_NOTRESP; + + fddeselect(); +} + +/* + * Build disk label. For now we only create a label from what we know + * from 'sc'. + */ +static int +fdgetdisklabel(sc, dev) +struct fd_softc *sc; +dev_t dev; +{ + struct disklabel *lp, *dlp; + int part; + + /* + * If we already got one, get out. + */ + if(sc->flags & FLPF_HAVELAB) + return(0); + +#ifdef FLP_DEBUG + printf("fdgetdisklabel()\n"); +#endif + + part = DISKPART(dev); + lp = &sc->dkdev.dk_label; + bzero(lp, sizeof(struct disklabel)); + + lp->d_secsize = SECTOR_SIZE; + lp->d_ntracks = sc->nheads; + lp->d_nsectors = sc->nsectors; + lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; + lp->d_ncylinders = sc->nblocks / lp->d_secpercyl; + lp->d_secperunit = sc->nblocks; + + lp->d_type = DTYPE_FLOPPY; + lp->d_rpm = 300; /* good guess I suppose. */ + lp->d_interleave = 1; /* FIXME: is this OK? */ + lp->d_bbsize = 0; + lp->d_sbsize = 0; + lp->d_npartitions = part + 1; + lp->d_trkseek = STEP_DELAY; + lp->d_magic = DISKMAGIC; + lp->d_magic2 = DISKMAGIC; + lp->d_checksum = dkcksum(lp); + lp->d_partitions[part].p_size = lp->d_secperunit; + lp->d_partitions[part].p_fstype = FS_UNUSED; + lp->d_partitions[part].p_fsize = 1024; + lp->d_partitions[part].p_frag = 8; + sc->flags |= FLPF_HAVELAB; + + return(0); +} diff --git a/sys/arch/atari/dev/fdreg.h b/sys/arch/atari/dev/fdreg.h new file mode 100644 index 00000000000..255fea0126d --- /dev/null +++ b/sys/arch/atari/dev/fdreg.h @@ -0,0 +1,93 @@ +/* $NetBSD: fdreg.h,v 1.2 1995/04/22 22:18:21 leo Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman. + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Leo Weppelman. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef _FDREG_H +#define _FDREG_H +/* + * Atari TT hardware: + * Western Digital 1772 Floppy Disk Controller. + */ + +/* + * Accessing the FDC registers is indirect through ST-specific + * DMA circuitry. See also dma.h. + */ +#define FDC_CS (DMA_FDC ) /* command/status */ +#define FDC_TR (DMA_FDC| DMA_A0) /* track register */ +#define FDC_SR (DMA_FDC|DMA_A1 ) /* sector register */ +#define FDC_DR (DMA_FDC|DMA_A1|DMA_A0) /* data register */ + +/* + * commands (relevant bits/fields indicated) + */ +#define RESTORE 0x00 /* ( HVRR) seek to track 0 */ +#define SEEK 0x10 /* ( HVRR) seek to track */ +#define STEP 0x20 /* (UHVRR) step in same direction */ +#define STEPI 0x40 /* (UHVRR) step in */ +#define STEPO 0x60 /* (UHVRR) step out */ +#define F_READ 0x80 /* (MHE00) read sector */ +#define F_WRITE 0xA0 /* (MHEPA) write sector */ +#define READID 0xC0 /* ( HE00) read sector ID */ +#define READTR 0xE0 /* ( HE00) read track */ +#define WRITETR 0xF0 /* ( HEP0) write track */ +#define IRUPT 0xD0 /* ( IIII) force interrupt */ + +/* + * other bits/fields in command register + */ +#define RATE6 0x00 /* not 2, but 6 msec steprate */ +#define RATE12 0x01 /* not 3, but 12 msec steprate */ +#define RATE2 0x02 /* not 5, but 2 msec steprate */ +#define RATE3 0x03 /* not 6, but 3 msec steprate */ +#define VBIT 0x04 /* verify sector ID */ +#define HBIT 0x08 /* suppress motor on sequence */ +#define UBIT 0x10 /* update track register */ +#define EBIT 0x04 /* wait 30 msec to settle */ +#define MBIT 0x10 /* multi-sector */ +#define PBIT 0x02 /* write precompensate */ +#define A0BIT 0x01 /* suppress (?) data address mark */ +#define IINDEX 0x04 /* interrupt on each index pulse */ +#define IFORCE 0x08 /* force interrupt */ + +/* + * status register + */ +#define BUSY 0x01 /* set if command under execution */ +#define DRQ 0x02 /* Data Register status (pin c1) */ +#define LD_T00 0x04 /* lost data; track 00 */ +#define CRCERR 0x08 /* CRC error */ +#define RNF 0x10 /* Record Not Found */ +#define RT_SU 0x20 /* Record Type; Spin Up completed */ +#define WRI_PRO 0x40 /* Write Protected */ +#define MOTORON 0x80 /* Motor On */ + +#endif /* _FDREG_H */ diff --git a/sys/arch/atari/dev/font.h b/sys/arch/atari/dev/font.h new file mode 100644 index 00000000000..c96b55a429e --- /dev/null +++ b/sys/arch/atari/dev/font.h @@ -0,0 +1,48 @@ +/* $NetBSD: font.h,v 1.1.1.1 1995/03/26 07:12:13 leo Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman. + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Leo Weppelman. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef _FONT_H +#define _FONT_H +/* + * What we like to know about fonts... + */ +typedef struct { + short boldsmear; + unsigned char width; + unsigned char height; + unsigned char baseline; + unsigned char font_lo; + unsigned char font_hi; + unsigned char *font_p; +} font_info; + +#endif /* _FONT_H */ diff --git a/sys/arch/atari/dev/font_8x16.c b/sys/arch/atari/dev/font_8x16.c new file mode 100644 index 00000000000..fa852f2f2a3 --- /dev/null +++ b/sys/arch/atari/dev/font_8x16.c @@ -0,0 +1,565 @@ +/* $NetBSD: font_8x16.c,v 1.2 1995/09/23 20:25:34 leo Exp $ */ + +/* + * Copyright (c) 1992, 1993, 1994 Hellmuth Michaelis and Joerg Wunsch + * + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by + * Hellmuth Michaelis and Joerg Wunsch + * 4. The name authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. + */ + +/* + * Translated into compiler and human readable for for the Atari-TT port of + * NetBSD by Leo Weppelman. + * + * Reorganized and edited some chars to fit the iso-8859-1 fontset by + * Thomas Gerner + */ +#include <atari/dev/font.h> + +char fontname_8x16[64] = "vt220iso.816"; + +extern unsigned char fontdata_8x16[]; +font_info font_info_8x16 = { 1, 8, 16, 14, 0, 255, &fontdata_8x16[0] }; + +int fontheight_8x16 = 16; +int fontwidth_8x16 = 8; + +unsigned char fontdata_8x16[] = { +/* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x01 */ 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x7e, 0x7e, 0xff, + 0xff, 0x7e, 0x7e, 0x3c, 0x3c, 0x18, 0x18, 0x00, +/* 0x02 */ 0x42, 0x99, 0x99, 0x42, 0x42, 0x99, 0x99, 0x42, + 0x42, 0x99, 0x99, 0x42, 0x42, 0x99, 0x99, 0x42, +/* 0x03 */ 0x00, 0x00, 0x90, 0x90, 0xf0, 0x90, 0x90, 0x00, + 0x3e, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, +/* 0x04 */ 0x00, 0x00, 0xf0, 0x80, 0xe0, 0x80, 0x80, 0x00, + 0x1e, 0x10, 0x1c, 0x10, 0x10, 0x00, 0x00, 0x00, +/* 0x05 */ 0x00, 0x00, 0x60, 0x90, 0x80, 0x90, 0x60, 0x00, + 0x1c, 0x12, 0x1c, 0x12, 0x12, 0x00, 0x00, 0x00, +/* 0x06 */ 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0xf0, 0x00, + 0x1e, 0x10, 0x1c, 0x10, 0x10, 0x00, 0x00, 0x00, +/* 0x07 */ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, + 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, +/* 0x09 */ 0x00, 0x00, 0x88, 0x98, 0xa8, 0xc8, 0x88, 0x00, + 0x10, 0x10, 0x10, 0x10, 0x1e, 0x00, 0x00, 0x00, +/* 0x0a */ 0x00, 0x00, 0x88, 0x88, 0x50, 0x50, 0x20, 0x00, + 0x3e, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, +/* 0x0b */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +/* 0x0d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +/* 0x0e */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +/* 0x10 */ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x11 */ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x12 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x13 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, +/* 0x14 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, +/* 0x15 */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +/* 0x16 */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +/* 0x17 */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +/* 0x19 */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +/* 0x1a */ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, + 0x0c, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, +/* 0x1b */ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, + 0x30, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, +/* 0x1c */ 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, +/* 0x1d */ 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, + 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e */ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, + 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00, +/* 0x1f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* ' ' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* '!' */ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, +/* '"' */ 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* '#' */ 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, + 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, +/* '$' */ 0x00, 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, + 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00, +/* '%' */ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, + 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, +/* '&' */ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, + 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +/* ''' */ 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* '(' */ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, +/* ')' */ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, +/* '*' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, + 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* '+' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, + 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* ',' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, +/* '-' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* '.' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, +/* '/' */ 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, + 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, +/* '0' */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, + 0xe6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* '1' */ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, +/* '2' */ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, + 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, +/* '3' */ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, + 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* '4' */ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, + 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, +/* '5' */ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, + 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* '6' */ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* '7' */ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, + 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, +/* '8' */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* '9' */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, + 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00, +/* ':' */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, +/* ';' */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, +/* '<' */ 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, + 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, +/* '=' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, + 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* '>' */ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, + 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, +/* '?' */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, + 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, +/* '@' */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, + 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 'A' */ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, + 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +/* 'B' */ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, + 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00, +/* 'C' */ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, + 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 'D' */ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, +/* 'E' */ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, + 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, +/* 'F' */ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, + 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, +/* 'G' */ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, + 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, +/* 'H' */ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +/* 'I' */ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 'J' */ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, +/* 'K' */ 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, + 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, +/* 'L' */ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, + 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, +/* 'M' */ 0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +/* 'N' */ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, + 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +/* 'O' */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 'P' */ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, + 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, +/* 'Q' */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00, +/* 'R' */ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, + 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, +/* 'S' */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, + 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 'T' */ 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 'U' */ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 'V' */ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, +/* 'W' */ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, + 0xd6, 0xfe, 0xee, 0x6c, 0x00, 0x00, 0x00, 0x00, +/* 'X' */ 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x7c, 0x38, 0x38, + 0x7c, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +/* 'Y' */ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, + 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 'Z' */ 0x00, 0x00, 0xfe, 0xc6, 0x86, 0x0c, 0x18, 0x30, + 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, +/* '[' */ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* '\' */ 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, + 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, +/* ']' */ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* '^' */ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* '_' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, +/* '`' */ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 'a' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, + 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +/* 'b' */ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, + 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 'c' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, + 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 'd' */ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, + 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +/* 'e' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, + 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 'f' */ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, + 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, +/* 'g' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, +/* 'h' */ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, + 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, +/* 'i' */ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 'j' */ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, +/* 'k' */ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, + 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, +/* 'l' */ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 'm' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, + 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00, 0x00, +/* 'n' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, +/* 'o' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 'p' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, +/* 'q' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, +/* 'r' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, + 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, +/* 's' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, + 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 't' */ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, + 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, +/* 'u' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +/* 'v' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, + 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, +/* 'w' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, + 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00, 0x00, +/* 'x' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, + 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, +/* 'y' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, +/* 'z' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, + 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, +/* '{' */ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, + 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00, +/* '|' */ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, +/* '}' */ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, + 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, +/* '~' */ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7f */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, + 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x81 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x82 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x83 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x84 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x85 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x86 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x87 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x88 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x89 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x91 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x92 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x93 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x94 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x95 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x97 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x98 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x99 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa1 */ 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, + 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, +/* 0xa2 */ 0x00, 0x18, 0x18, 0x3c, 0x66, 0x60, 0x60, 0x60, + 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, +/* 0xa3 */ 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, + 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00, +/* 0xa4 */ 0xc3, 0x3c, 0x66, 0x42, 0x66, 0x3c, 0xc3, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa5 */ 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, + 0x7e, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, +/* 0xa6 */ 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, +/* 0xa7 */ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, + 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, +/* 0xa8 */ 0x00, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa9 */ 0x00, 0x7c, 0xc6, 0x82, 0x9a, 0xa6, 0xa2, 0xa6, + 0x9a, 0x82, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xaa */ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, + 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, + 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae */ 0x00, 0x7c, 0xc6, 0x82, 0xba, 0xa6, 0xba, 0xaa, + 0xa6, 0x82, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xaf */ 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb0 */ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb1 */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, + 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, +/* 0xb2 */ 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb3 */ 0x00, 0x70, 0xd8, 0x30, 0x30, 0xd8, 0x70, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb4 */ 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb5 */ 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, +/* 0xb6 */ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, +/* 0xb7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x00, +/* 0xb9 */ 0x00, 0x30, 0x70, 0xf0, 0x30, 0x30, 0x78, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba */ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, + 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc */ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, + 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00, 0x00, +/* 0xbd */ 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, + 0x60, 0xdc, 0x86, 0x0c, 0x18, 0x3e, 0x00, 0x00, +/* 0xbe */ 0x00, 0xc0, 0x60, 0xc2, 0x66, 0xcc, 0x18, 0x30, + 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00, 0x00, +/* 0xbf */ 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, + 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xc0 */ 0x18, 0x0c, 0x06, 0x00, 0x38, 0x6c, 0xc6, 0xc6, + 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +/* 0xc1 */ 0x18, 0x30, 0x60, 0x00, 0x38, 0x6c, 0xc6, 0xc6, + 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +/* 0xc2 */ 0x10, 0x38, 0x6c, 0x00, 0x38, 0x6c, 0xc6, 0xc6, + 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +/* 0xc3 */ 0x76, 0xdc, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, + 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +/* 0xc4 */ 0xc6, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, + 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +/* 0xc5 */ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, + 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +/* 0xc6 */ 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, + 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, +/* 0xc7 */ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, + 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, +/* 0xc8 */ 0x18, 0x0c, 0x06, 0x00, 0xfe, 0x66, 0x60, 0x7c, + 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, +/* 0xc9 */ 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, + 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, +/* 0xca */ 0x10, 0x38, 0x6c, 0x00, 0xfe, 0x66, 0x60, 0x7c, + 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, +/* 0xcb */ 0x00, 0xc6, 0x00, 0xfe, 0x66, 0x60, 0x60, 0x7c, + 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, +/* 0xcc */ 0x18, 0x0c, 0x06, 0x00, 0x3c, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0xcd */ 0x18, 0x30, 0x60, 0x00, 0x3c, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0xce */ 0x10, 0x38, 0x6c, 0x00, 0x3c, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0xcf */ 0x00, 0x66, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0xd0 */ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0xf6, 0x66, + 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, +/* 0xd1 */ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, + 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +/* 0xd2 */ 0x18, 0x0c, 0x06, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xd3 */ 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xd4 */ 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xd5 */ 0x76, 0xdc, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xd6 */ 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xd7 */ 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, + 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd8 */ 0x00, 0x06, 0x7e, 0xce, 0xce, 0xce, 0xd6, 0xd6, + 0xe6, 0xe6, 0xe6, 0xfc, 0xc0, 0x00, 0x00, 0x00, +/* 0xd9 */ 0x18, 0x0c, 0x06, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xda */ 0x18, 0x30, 0x60, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xdb */ 0x10, 0x38, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xdc */ 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xdd */ 0x18, 0x30, 0x60, 0x00, 0x66, 0x66, 0x66, 0x3c, + 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0xde */ 0x00, 0xf0, 0x60, 0x7c, 0x66, 0x66, 0x66, 0x7c, + 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, +/* 0xdf */ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, + 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00, +/* 0xe0 */ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, + 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +/* 0xe1 */ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, + 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +/* 0xe2 */ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, + 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +/* 0xe3 */ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x78, 0x0c, 0x7c, + 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +/* 0xe4 */ 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, + 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +/* 0xe5 */ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, + 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +/* 0xe6 */ 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xb2, 0x32, + 0x7e, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00, 0x00, +/* 0xe7 */ 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, + 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, 0x00, +/* 0xe8 */ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, + 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xe9 */ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, + 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xea */ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, + 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xeb */ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, + 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xec */ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0xed */ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0xee */ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0xef */ 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +/* 0xf0 */ 0x00, 0x00, 0x3e, 0x30, 0x18, 0x7c, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xf1 */ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, +/* 0xf2 */ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xf3 */ 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xf4 */ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xf5 */ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x7c, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xf6 */ 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +/* 0xf7 */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf8 */ 0x00, 0x00, 0x00, 0x00, 0x06, 0x7e, 0xce, 0xce, + 0xd6, 0xe6, 0xe6, 0xfc, 0xc0, 0x00, 0x00, 0x00, +/* 0xf9 */ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +/* 0xfa */ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +/* 0xfb */ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +/* 0xfc */ 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +/* 0xfd */ 0x00, 0x18, 0x30, 0x60, 0x00, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, +/* 0xfe */ 0x00, 0x00, 0x00, 0xf0, 0x60, 0x7c, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, +/* 0xff */ 0x00, 0xc6, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00 +}; diff --git a/sys/arch/atari/dev/font_8x8.c b/sys/arch/atari/dev/font_8x8.c new file mode 100644 index 00000000000..0817d2b8845 --- /dev/null +++ b/sys/arch/atari/dev/font_8x8.c @@ -0,0 +1,307 @@ +/* $NetBSD: font_8x8.c,v 1.2 1995/09/23 20:25:36 leo Exp $ */ + +/* + * Copyright (c) 1992, 1993, 1994 Hellmuth Michaelis and Joerg Wunsch + * + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by + * Hellmuth Michaelis and Joerg Wunsch + * 4. The name authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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. + */ + +/* + * Translated into compiler and human readable for for the Atari-TT port of + * NetBSD by Leo Weppelman. + * + * Reorganized and edited some chars to fit the iso-8859-1 fontset + * by Thomas Gerner + */ +#include <atari/dev/font.h> + +char fontname_8x8[64] = "vt220iso.808"; + +extern unsigned char fontdata_8x8[]; + +font_info font_info_8x8 = { 1, 8, 8, 6, 0, 255, &fontdata_8x8[0] }; + +unsigned char fontdata_8x8[] = { +/* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x01 */ 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x3c, 0x18, +/* 0x02 */ 0x5a, 0x99, 0x42, 0x99, 0x5a, 0x81, 0x5a, 0x99, +/* 0x03 */ 0x44, 0x44, 0x7c, 0x44, 0x3e, 0x08, 0x08, 0x08, +/* 0x04 */ 0x7c, 0x40, 0x78, 0x40, 0x3e, 0x20, 0x3c, 0x20, +/* 0x05 */ 0x3c, 0x40, 0x40, 0x3c, 0x3c, 0x22, 0x3c, 0x26, +/* 0x06 */ 0x40, 0x40, 0x40, 0x7c, 0x3e, 0x20, 0x3c, 0x20, +/* 0x07 */ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, +/* 0x08 */ 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00, +/* 0x09 */ 0x64, 0x54, 0x4c, 0x44, 0x20, 0x20, 0x20, 0x3e, +/* 0x0a */ 0x44, 0x44, 0x28, 0x10, 0x3e, 0x08, 0x08, 0x08, +/* 0x0b */ 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, +/* 0x0c */ 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, +/* 0x0d */ 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, +/* 0x0e */ 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, +/* 0x0f */ 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, +/* 0x10 */ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x11 */ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x12 */ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, +/* 0x13 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, +/* 0x14 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, +/* 0x15 */ 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, +/* 0x16 */ 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, +/* 0x17 */ 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, +/* 0x18 */ 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, +/* 0x19 */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +/* 0x1a */ 0x30, 0x18, 0x0c, 0x18, 0x30, 0xfe, 0x00, 0xfe, +/* 0x1b */ 0x18, 0x30, 0x60, 0x30, 0x18, 0xfe, 0x00, 0xfe, +/* 0x1c */ 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, +/* 0x1d */ 0x02, 0x04, 0x7e, 0x08, 0x10, 0x7e, 0x20, 0x40, +/* 0x1e */ 0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00, +/* 0x1f */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, +/* ' ' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* '!' */ 0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00, +/* '"' */ 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, +/* '#' */ 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, +/* '$' */ 0x30, 0x7c, 0xc0, 0x7c, 0x06, 0xfc, 0x30, 0x00, +/* '%' */ 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00, +/* '&' */ 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xce, 0x7b, 0x00, +/* ''' */ 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, +/* '(' */ 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, +/* ')' */ 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, +/* '*' */ 0x00, 0x6c, 0x38, 0xfe, 0x38, 0x6c, 0x00, 0x00, +/* '+' */ 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00, +/* ',' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60, +/* '-' */ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, +/* '.' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, +/* '/' */ 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, +/* '0' */ 0x7c, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0x7c, 0x00, +/* '1' */ 0x30, 0x70, 0xb0, 0x30, 0x30, 0x30, 0xfc, 0x00, +/* '2' */ 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xc0, 0xfc, 0x00, +/* '3' */ 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00, +/* '4' */ 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, +/* '5' */ 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00, +/* '6' */ 0x78, 0xcc, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00, +/* '7' */ 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00, +/* '8' */ 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00, +/* '9' */ 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, +/* ':' */ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00, +/* ';' */ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60, +/* '<' */ 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00, +/* '=' */ 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, +/* '>' */ 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, +/* '?' */ 0x3c, 0x66, 0x06, 0x0c, 0x18, 0x00, 0x18, 0x00, +/* '@' */ 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x7e, 0x00, +/* 'A' */ 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00, +/* 'B' */ 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, +/* 'C' */ 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00, +/* 'D' */ 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, +/* 'E' */ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00, +/* 'F' */ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, +/* 'G' */ 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00, +/* 'H' */ 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00, +/* 'I' */ 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, +/* 'J' */ 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, +/* 'K' */ 0xe6, 0x6c, 0x78, 0x70, 0x78, 0x6c, 0xe6, 0x00, +/* 'L' */ 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, +/* 'M' */ 0xc6, 0xee, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0x00, +/* 'N' */ 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, +/* 'O' */ 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, +/* 'P' */ 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, +/* 'Q' */ 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00, +/* 'R' */ 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00, +/* 'S' */ 0x78, 0xcc, 0xc0, 0x78, 0x0c, 0xcc, 0x78, 0x00, +/* 'T' */ 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, +/* 'U' */ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, +/* 'V' */ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00, +/* 'W' */ 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xfe, 0xc6, 0x00, +/* 'X' */ 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, +/* 'Y' */ 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00, +/* 'Z' */ 0xfc, 0xcc, 0x98, 0x30, 0x64, 0xcc, 0xfc, 0x00, +/* '[' */ 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, +/* '\' */ 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, +/* ']' */ 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, +/* '^' */ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, +/* '_' */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, +/* '`' */ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 'a' */ 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, +/* 'b' */ 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xfc, 0x00, +/* 'c' */ 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00, +/* 'd' */ 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x7e, 0x00, +/* 'e' */ 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, +/* 'f' */ 0x38, 0x6c, 0x60, 0xf8, 0x60, 0x60, 0xf0, 0x00, +/* 'g' */ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, +/* 'h' */ 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, +/* 'i' */ 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, +/* 'j' */ 0x0c, 0x00, 0x1c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, +/* 'k' */ 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00, +/* 'l' */ 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, +/* 'm' */ 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00, +/* 'n' */ 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, +/* 'o' */ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00, +/* 'p' */ 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, +/* 'q' */ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e, +/* 'r' */ 0x00, 0x00, 0xdc, 0x76, 0x60, 0x60, 0xf0, 0x00, +/* 's' */ 0x00, 0x00, 0x7c, 0xc0, 0x7c, 0x06, 0xfc, 0x00, +/* 't' */ 0x10, 0x30, 0x7c, 0x30, 0x30, 0x36, 0x1c, 0x00, +/* 'u' */ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, +/* 'v' */ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0x7c, 0x38, 0x00, +/* 'w' */ 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00, +/* 'x' */ 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, +/* 'y' */ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, +/* 'z' */ 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, +/* '{' */ 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00, +/* '|' */ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, +/* '}' */ 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00, +/* '~' */ 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7f */ 0x10, 0x38, 0x6c, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, +/* 0x80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x81 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x82 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x83 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x84 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x85 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x86 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x87 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x88 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x89 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x91 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x92 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x93 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x94 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x95 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x96 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x97 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x98 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x99 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa1 */ 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, +/* 0xa2 */ 0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18, +/* 0xa3 */ 0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00, +/* 0xa4 */ 0x00, 0xc3, 0xdb, 0x3c, 0x66, 0x3c, 0xdb, 0xc3, +/* 0xa5 */ 0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30, +/* 0xa6 */ 0x18, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x18, +/* 0xa7 */ 0x7e, 0xc3, 0xfc, 0x66, 0x66, 0x3f, 0xc3, 0x7e, +/* 0xa8 */ 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa9 */ 0x7c, 0x82, 0x9a, 0xa2, 0xa2, 0x9a, 0x82, 0x7c, +/* 0xaa */ 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, +/* 0xab */ 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00, +/* 0xac */ 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, +/* 0xad */ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, +/* 0xae */ 0x7c, 0x82, 0xba, 0xaa, 0xb2, 0xaa, 0x82, 0x7c, +/* 0xaf */ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb0 */ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, +/* 0xb1 */ 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00, +/* 0xb2 */ 0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00, +/* 0xb3 */ 0x70, 0x18, 0x30, 0x18, 0x70, 0x00, 0x00, 0x00, +/* 0xb4 */ 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb5 */ 0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0, +/* 0xb6 */ 0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00, +/* 0xb7 */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, +/* 0xb8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x78, +/* 0xb9 */ 0x38, 0x78, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, +/* 0xba */ 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, +/* 0xbb */ 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00, +/* 0xbc */ 0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03, +/* 0xbd */ 0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f, +/* 0xbe */ 0xc3, 0x66, 0xcc, 0x5b, 0xb7, 0x6f, 0xcf, 0x03, +/* 0xbf */ 0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00, +/* 0xc0 */ 0xe0, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, +/* 0xc1 */ 0x0e, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, +/* 0xc2 */ 0x7c, 0x82, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x00, +/* 0xc3 */ 0xfe, 0x00, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x00, +/* 0xc4 */ 0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, +/* 0xc5 */ 0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00, +/* 0xc6 */ 0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00, +/* 0xc7 */ 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78, +/* 0xc8 */ 0xe0, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00, +/* 0xc9 */ 0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00, +/* 0xca */ 0x78, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00, +/* 0xcb */ 0xcc, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00, +/* 0xcc */ 0x70, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, +/* 0xcd */ 0x0e, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, +/* 0xce */ 0x7e, 0x81, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, +/* 0xcf */ 0x66, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, +/* 0xd0 */ 0xfc, 0x66, 0x66, 0xf6, 0x66, 0x66, 0xfc, 0x00, +/* 0xd1 */ 0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00, +/* 0xd2 */ 0x70, 0x00, 0x18, 0x3c, 0x66, 0x3c, 0x18, 0x00, +/* 0xd3 */ 0x0e, 0x00, 0x18, 0x3c, 0x66, 0x3c, 0x18, 0x00, +/* 0xd4 */ 0x3c, 0x42, 0x18, 0x3c, 0x66, 0x3c, 0x18, 0x00, +/* 0xd5 */ 0x7e, 0x00, 0x18, 0x3c, 0x66, 0x3c, 0x18, 0x00, +/* 0xd6 */ 0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00, +/* 0xd7 */ 0x00, 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82, +/* 0xd8 */ 0x00, 0x02, 0x7c, 0xce, 0xd6, 0xe6, 0x7c, 0x80, +/* 0xd9 */ 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, +/* 0xda */ 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, +/* 0xdb */ 0x78, 0x84, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x00, +/* 0xdc */ 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, +/* 0xdd */ 0x1c, 0x00, 0xcc, 0xcc, 0x78, 0x30, 0x78, 0x00, +/* 0xde */ 0xf0, 0x60, 0x78, 0x6c, 0x78, 0x60, 0xf0, 0x00, +/* 0xdf */ 0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0, +/* 0xe0 */ 0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, +/* 0xe1 */ 0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, +/* 0xe2 */ 0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00, +/* 0xe3 */ 0xfe, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, +/* 0xe4 */ 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, +/* 0xe5 */ 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00, +/* 0xe6 */ 0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00, +/* 0xe7 */ 0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38, +/* 0xe8 */ 0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, +/* 0xe9 */ 0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, +/* 0xea */ 0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00, +/* 0xeb */ 0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00, +/* 0xec */ 0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, +/* 0xed */ 0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, +/* 0xee */ 0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, +/* 0xef */ 0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00, +/* 0xf0 */ 0x00, 0x7c, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x00, +/* 0xf1 */ 0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00, +/* 0xf2 */ 0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, +/* 0xf3 */ 0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, +/* 0xf4 */ 0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, +/* 0xf5 */ 0x00, 0xfc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, +/* 0xf6 */ 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00, +/* 0xf7 */ 0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00, +/* 0xf8 */ 0x02, 0x3a, 0x6c, 0xd6, 0xd6, 0x6c, 0xb8, 0x80, +/* 0xf9 */ 0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, +/* 0xfa */ 0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, +/* 0xfb */ 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, +/* 0xfc */ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, +/* 0xfd */ 0x00, 0x1c, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, +/* 0xfe */ 0x00, 0xc0, 0xc0, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0, +/* 0xff */ 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8 +}; diff --git a/sys/arch/atari/dev/grf.c b/sys/arch/atari/dev/grf.c new file mode 100644 index 00000000000..81f78e5577b --- /dev/null +++ b/sys/arch/atari/dev/grf.c @@ -0,0 +1,567 @@ +/* $NetBSD: grf.c,v 1.6 1995/06/26 19:55:45 leo Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1990 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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: grf.c 1.31 91/01/21$ + * + * @(#)grf.c 7.8 (Berkeley) 5/7/91 + */ + +/* + * Graphics display driver for the Atari + * This is the hardware-independent portion of the driver. + * Hardware access is through the grf_softc->g_mode routine. + */ + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/ioctl.h> +#include <sys/device.h> +#include <sys/file.h> +#include <sys/malloc.h> +#include <sys/conf.h> +#include <sys/systm.h> +#include <sys/vnode.h> +#include <sys/mman.h> +#include <vm/vm.h> +#include <vm/vm_kern.h> +#include <vm/vm_page.h> +#include <vm/vm_pager.h> +#include <machine/cpu.h> +#include <atari/atari/device.h> +#include <atari/dev/grfioctl.h> +#include <atari/dev/grfabs_reg.h> +#include <atari/dev/grfvar.h> +#include <atari/dev/itevar.h> +#include <atari/dev/viewioctl.h> +#include <atari/dev/viewvar.h> + +#include "grf.h" +#if NGRF > 0 + +#include "ite.h" +#if NITE == 0 +#define ite_on(u,f) +#define ite_off(u,f) +#define ite_reinit(d) +#endif + +int grfopen __P((dev_t, int, int, struct proc *)); +int grfclose __P((dev_t, int)); +int grfioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); +int grfselect __P((dev_t, int)); +int grfmmap __P((dev_t, int, int)); + +int grfon __P((dev_t)); +int grfoff __P((dev_t)); +int grfsinfo __P((dev_t, struct grfdyninfo *)); +#ifdef BANKEDDEVPAGER +int grfbanked_get __P((dev_t, off_t, int)); +int grfbanked_cur __P((dev_t)); +int grfbanked_set __P((dev_t, int)); +#endif +static void grf_viewsync __P((struct grf_softc *)); +static int grf_mode __P((struct grf_softc *, int, void *, int, int)); + +int grfbusprint __P((void *auxp, char *)); +int grfbusmatch __P((struct device *, struct cfdata *, void *)); +void grfbusattach __P((struct device *, struct device *, void *)); + +void grfattach __P((struct device *, struct device *, void *)); +int grfmatch __P((struct device *, struct cfdata *, void *)); +int grfprint __P((void *, char *)); +/* + * pointers to grf drivers device structs + */ +struct grf_softc *grfsp[NGRF]; + + +struct cfdriver grfbuscd = { + NULL, "grfbus", (cfmatch_t)grfbusmatch, grfbusattach, DV_DULL, + sizeof(struct device) +}; + +struct cfdriver grfcd = { + NULL, "grf", (cfmatch_t)grfmatch, grfattach, DV_DULL, + sizeof(struct grf_softc), NULL, 0 +}; + +/* + * only used in console init. + */ +static struct cfdata *cfdata_gbus = NULL; +static struct cfdata *cfdata_grf = NULL; + +int +grfbusmatch(pdp, cfp, auxp) +struct device *pdp; +struct cfdata *cfp; +void *auxp; +{ + if(strcmp(auxp, grfbuscd.cd_name)) + return(0); + + if((atari_realconfig == 0) || (cfdata_gbus == NULL)) { + /* + * Probe layers we depend on + */ + if(grfabs_probe() == 0) + return(0); + viewprobe(); + + if(atari_realconfig == 0) { + /* + * XXX: console init opens view 0 + */ + if(viewopen(0, 0)) + return(0); + cfdata_gbus = cfp; + } + } + return(1); /* Always there */ +} + +void +grfbusattach(pdp, dp, auxp) +struct device *pdp, *dp; +void *auxp; +{ + static int did_cons = 0; + int i; + + if(dp == NULL) { /* Console init */ + did_cons = 1; + i = 0; + atari_config_found(cfdata_gbus, NULL, (void*)&i, grfbusprint); + } + else { + printf("\n"); + for(i = 0; i < NGRF; i++) { + /* + * Skip opening view[0] when we this is the console. + */ + if(!did_cons || (i > 0)) + if(viewopen(i, 0)) + break; + config_found(dp, (void*)&i, grfbusprint); + } + } +} + +int +grfbusprint(auxp, name) +void *auxp; +char *name; +{ + if(name == NULL) + return(UNCONF); + return(QUIET); +} + + +int +grfmatch(pdp, cfp, auxp) +struct device *pdp; +struct cfdata *cfp; +void *auxp; +{ + int unit = *(int*)auxp; + + /* + * Match only on unit indicated by grfbus attach. + */ + if(cfp->cf_unit != unit) + return(0); + + cfdata_grf = cfp; + return(1); +} + +/* + * attach: initialize the grf-structure and try to attach an ite to us. + * note : dp is NULL during early console init. + */ +void +grfattach(pdp, dp, auxp) +struct device *pdp, *dp; +void *auxp; +{ + static struct grf_softc congrf; + struct grf_softc *gp; + int maj; + + /* + * find our major device number + */ + for(maj = 0; maj < nchrdev; maj++) + if (cdevsw[maj].d_open == grfopen) + break; + + /* + * Handle exeption case: early console init + */ + if(dp == NULL) { + congrf.g_unit = 0; + congrf.g_grfdev = makedev(maj, 0); + congrf.g_flags = GF_ALIVE; + congrf.g_mode = grf_mode; + congrf.g_conpri = grfcc_cnprobe(); + congrf.g_viewdev = congrf.g_unit; + grfcc_iteinit(&congrf); + grf_viewsync(&congrf); + + /* Attach console ite */ + atari_config_found(cfdata_grf, NULL, &congrf, grfprint); + return; + } + + gp = (struct grf_softc *)dp; + gp->g_unit = gp->g_device.dv_unit; + grfsp[gp->g_unit] = gp; + + if((cfdata_grf != NULL) && (gp->g_unit == 0)) { + /* + * We inited earlier just copy the info, take care + * not to copy the device struct though. + */ + bcopy(&congrf.g_display, &gp->g_display, + (char *)&gp[1] - (char *)&gp->g_display); + } + else { + gp->g_grfdev = makedev(maj, gp->g_unit); + gp->g_flags = GF_ALIVE; + gp->g_mode = grf_mode; + gp->g_conpri = 0; + gp->g_viewdev = gp->g_unit; + grfcc_iteinit(gp); + grf_viewsync(gp); + } + + printf(": width %d height %d", gp->g_display.gd_dwidth, + gp->g_display.gd_dheight); + if(gp->g_display.gd_colors == 2) + printf(" monochrome\n"); + else printf(" colors %d\n", gp->g_display.gd_colors); + + /* + * try and attach an ite + */ + config_found(dp, gp, grfprint); +} + +int +grfprint(auxp, pnp) +void *auxp; +char *pnp; +{ + if(pnp) + printf("ite at %s", pnp); + return(UNCONF); +} + +/*ARGSUSED*/ +int +grfopen(dev, flags, devtype, p) + dev_t dev; + int flags, devtype; + struct proc *p; +{ + struct grf_softc *gp; + + if (GRFUNIT(dev) >= NGRF) + return(ENXIO); + + gp = grfsp[GRFUNIT(dev)]; + + if ((gp->g_flags & GF_ALIVE) == 0) + return(ENXIO); + + if ((gp->g_flags & (GF_OPEN|GF_EXCLUDE)) == (GF_OPEN|GF_EXCLUDE)) + return(EBUSY); + grf_viewsync(gp); + + return(0); +} + +/*ARGSUSED*/ +int +grfclose(dev, flags) + dev_t dev; + int flags; +{ + struct grf_softc *gp; + + gp = grfsp[GRFUNIT(dev)]; + (void)grfoff(dev); + gp->g_flags &= GF_ALIVE; + return(0); +} + +/*ARGSUSED*/ +int +grfioctl(dev, cmd, data, flag, p) +dev_t dev; +u_long cmd; +int flag; +caddr_t data; +struct proc *p; +{ + struct grf_softc *gp; + int error; + + gp = grfsp[GRFUNIT(dev)]; + error = 0; + + switch (cmd) { + case OGRFIOCGINFO: + /* argl.. no bank-member.. */ + bcopy((caddr_t)&gp->g_display, data, sizeof(struct grfinfo)-4); + break; + case GRFIOCGINFO: + bcopy((caddr_t)&gp->g_display, data, sizeof(struct grfinfo)); + break; + case GRFIOCON: + error = grfon(dev); + break; + case GRFIOCOFF: + error = grfoff(dev); + break; + case GRFIOCSINFO: + error = grfsinfo(dev, (struct grfdyninfo *) data); + break; + case GRFGETVMODE: + return(gp->g_mode(gp, GM_GRFGETVMODE, data)); + case GRFSETVMODE: + error = gp->g_mode(gp, GM_GRFSETVMODE, data); + if (error == 0 && gp->g_itedev) + ite_reinit(gp->g_itedev); + break; + case GRFGETNUMVM: + return(gp->g_mode(gp, GM_GRFGETNUMVM, data)); + /* + * these are all hardware dependant, and have to be resolved + * in the respective driver. + */ + case GRFIOCPUTCMAP: + case GRFIOCGETCMAP: + case GRFIOCSSPRITEPOS: + case GRFIOCGSPRITEPOS: + case GRFIOCSSPRITEINF: + case GRFIOCGSPRITEINF: + case GRFIOCGSPRITEMAX: + default: + /* + * check to see whether it's a command recognized by the + * view code. + */ + return(viewioctl(gp->g_viewdev, cmd, data, flag, p)); + error = EINVAL; + break; + + } + return(error); +} + +/*ARGSUSED*/ +int +grfselect(dev, rw) + dev_t dev; + int rw; +{ + if (rw == FREAD) + return(0); + return(1); +} + +/* + * map the contents of a graphics display card into process' + * memory space. + */ +int +grfmmap(dev, off, prot) +dev_t dev; +int off, prot; +{ + struct grf_softc *gp; + struct grfinfo *gi; + + gp = grfsp[GRFUNIT(dev)]; + gi = &gp->g_display; + + /* + * frame buffer + */ + if ((off >= 0) && (off < gi->gd_fbsize)) + return (((u_int)gi->gd_fbaddr + off) >> PGSHIFT); + return(-1); +} + +int +grfon(dev) + dev_t dev; +{ + struct grf_softc *gp; + + gp = grfsp[GRFUNIT(dev)]; + + if (gp->g_flags & GF_GRFON) + return(0); + + gp->g_flags |= GF_GRFON; + if (gp->g_itedev != NODEV) + ite_off(gp->g_itedev, 3); + + return(gp->g_mode(gp, (dev & GRFOVDEV) ? GM_GRFOVON : GM_GRFON)); +} + +int +grfoff(dev) + dev_t dev; +{ + struct grf_softc *gp; + int error; + + gp = grfsp[GRFUNIT(dev)]; + + if ((gp->g_flags & GF_GRFON) == 0) + return(0); + + gp->g_flags &= ~GF_GRFON; + error = gp->g_mode(gp, (dev & GRFOVDEV) ? GM_GRFOVOFF : GM_GRFOFF); + + /* + * Closely tied together no X's + */ + if (gp->g_itedev != NODEV) + ite_on(gp->g_itedev, 2); + + return(error); +} + +int +grfsinfo(dev, dyninfo) + dev_t dev; + struct grfdyninfo *dyninfo; +{ + struct grf_softc *gp; + int error; + + gp = grfsp[GRFUNIT(dev)]; + error = gp->g_mode(gp, GM_GRFCONFIG, dyninfo); + + /* + * Closely tied together no X's + */ + if (gp->g_itedev != NODEV) + ite_reinit(gp->g_itedev); + return(error); +} + +/* + * Get the grf-info in sync with underlying view. + */ +static void +grf_viewsync(gp) +struct grf_softc *gp; +{ + struct view_size vs; + bmap_t bm; + struct grfinfo *gi; + + gi = &gp->g_display; + + viewioctl(gp->g_viewdev, VIOCGBMAP, &bm, 0, -1); + + gp->g_data = (caddr_t) 0xDeadBeaf; /* not particularly clean.. */ + + gi->gd_fbaddr = bm.hw_address; + gi->gd_fbsize = bm.depth*bm.bytes_per_row*bm.rows; + + if(viewioctl(gp->g_viewdev, VIOCGSIZE, &vs, 0, -1)) { + /* + * fill in some default values... + * XXX: Should _never_ happen + */ + vs.width = 640; + vs.height = 400; + vs.depth = 1; + } + gi->gd_colors = 1 << vs.depth; + gi->gd_planes = vs.depth; + + gi->gd_fbwidth = vs.width; + gi->gd_fbheight = vs.height; + gi->gd_dyn.gdi_fbx = 0; + gi->gd_dyn.gdi_fby = 0; + gi->gd_dyn.gdi_dwidth = vs.width; + gi->gd_dyn.gdi_dheight = vs.height; + gi->gd_dyn.gdi_dx = 0; + gi->gd_dyn.gdi_dy = 0; +} + +/* + * Change the mode of the display. + * Right now all we can do is grfon/grfoff. + * Return a UNIX error number or 0 for success. + */ +/*ARGSUSED*/ +static int +grf_mode(gp, cmd, arg, a2, a3) +struct grf_softc *gp; +int cmd, a2, a3; +void *arg; +{ + switch (cmd) { + case GM_GRFON: + /* + * Get in sync with view, ite might have changed it. + */ + grf_viewsync(gp); + viewioctl(gp->g_viewdev, VIOCDISPLAY, NULL, 0, -1); + return(0); + case GM_GRFOFF: + viewioctl(gp->g_viewdev, VIOCREMOVE, NULL, 0, -1); + return(0); + case GM_GRFCONFIG: + default: + break; + } + return(EINVAL); +} +#endif /* NGRF > 0 */ diff --git a/sys/arch/atari/dev/grfabs.c b/sys/arch/atari/dev/grfabs.c new file mode 100644 index 00000000000..65f3eb3933c --- /dev/null +++ b/sys/arch/atari/dev/grfabs.c @@ -0,0 +1,229 @@ +/* $NetBSD: grfabs.c,v 1.7 1995/09/23 20:29:16 leo Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman. + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Leo Weppelman. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * atari abstract graphics driver. + */ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/queue.h> +#include <sys/malloc.h> + +#include <machine/cpu.h> +#include <machine/iomap.h> +#include <machine/video.h> +#include <machine/mfp.h> +#include <atari/dev/grfabs_reg.h> + +/* + * Function decls + */ +static dmode_t *get_best_display_mode __P((dimen_t *, int, dmode_t *)); + +/* + * List of available graphic modes + */ +static MODES modes; + +/* + * Ugh.. Stuff needed to allocate console structures before the VM-system + * is running. There is no malloc() available at that time. + * Decision to use these: atari_realconfig == 0 + */ +view_t gra_con_view; +colormap_t gra_con_cmap; +long gra_con_colors[MAX_CENTRIES]; + +/* + * Default colors..... + * Currently the TT-low (256 colors) just uses 16 times the 16-color default. + * If you have a sensible 256 scale, feel free to add..... + * The first 2 colors in all maps are {black,white}, so ite (text) displays + * are initially readable. Also, this enables me to supply only 1 map. The + * 4 color mode uses the first four entries of the 16 color mode thus giving + * a gray scale display. (Maybe we can add an intensity bit to the ite...) + */ +u_long gra_def_color16[16] = { + 0x00000000, /* black */ + 0x00ffffff, /* white */ + 0x000c0c0c, /* light gray */ + 0x00808008, /* gray */ + 0x0000000c, /* blue */ + 0x00000c00, /* green */ + 0x00000c0c, /* cyan */ + 0x00c00000, /* red */ + 0x00c0000c, /* magenta */ + 0x00c00c00, /* brown */ + 0x000000ff, /* light blue */ + 0x0000ff00, /* light green */ + 0x0000ffff, /* light cyan */ + 0x00ff0000, /* light red */ + 0x00ff00ff, /* light magenta */ + 0x00ffff00 /* light brown */ +}; + +/* + * XXX: called from ite console init routine. + * Initialize list of posible video modes. + */ +int +grfabs_probe() +{ + static int inited = 0; + + if (inited) + return (1); /* Has to be done only once */ + inited++; + + LIST_INIT(&modes); + +#ifdef FALCON_VIDEO + if (machineid & ATARI_FALCON) + falcon_probe_video(&modes); +#endif /* FALCON_VIDEO */ +#ifdef TT_VIDEO + if (machineid & ATARI_TT) + tt_probe_video(&modes); +#endif /* TT_VIDEO */ + return ((modes.lh_first == NULL) ? 0 : 1); +} + +view_t * +grf_alloc_view(d, dim, depth) +dmode_t *d; +dimen_t *dim; +u_char depth; +{ + if (!d) + d = get_best_display_mode(dim, depth, NULL); + if (d) + return ((d->grfabs_funcs->alloc_view)(d, dim, depth)); + return(NULL); +} + +dmode_t * +grf_get_best_mode(dim, depth) +dimen_t *dim; +u_char depth; +{ + return (get_best_display_mode(dim, depth, NULL)); +} + +void grf_display_view(v) +view_t *v; +{ + (v->mode->grfabs_funcs->display_view)(v); +} + +void grf_remove_view(v) +view_t *v; +{ + (v->mode->grfabs_funcs->remove_view)(v); +} + +void grf_free_view(v) +view_t *v; +{ + (v->mode->grfabs_funcs->free_view)(v); +} + +int +grf_get_colormap(v, cm) +view_t *v; +colormap_t *cm; +{ + colormap_t *gcm; + int i, n; + u_long *sv_entry; + + gcm = v->colormap; + n = cm->size < gcm->size ? cm->size : gcm->size; + + /* + * Copy struct from view but be carefull to keep 'entry' + */ + sv_entry = cm->entry; + *cm = *gcm; + cm->entry = sv_entry; + + /* + * Copy the colors + */ + bzero(cm->entry, cm->size * sizeof(long)); + for (i = 0; i < n; i++) + cm->entry[i] = gcm->entry[i]; + return (0); +} + +int +grf_use_colormap(v, cm) +view_t *v; +colormap_t *cm; +{ + return (v->mode->grfabs_funcs->use_colormap)(v, cm); +} + +static dmode_t * +get_best_display_mode(dim, depth, curr_mode) +int depth; +dimen_t *dim; +dmode_t *curr_mode; +{ + dmode_t *save; + dmode_t *dm; + long dt, dx, dy, ct; + + save = NULL; + dm = modes.lh_first; + while (dm != NULL) { + dx = abs(dm->size.width - dim->width); + dy = abs(dm->size.height - dim->height); + ct = dx + dy; + + if (ct < dt || save == NULL) { + save = dm; + dt = ct; + } + dm = dm->link.le_next; + } + /* + * Did we do better than the current mode? + */ + if ((save != NULL) && (curr_mode != NULL)) { + dx = abs(curr_mode->size.width - dim->width); + dy = abs(curr_mode->size.height - dim->height); + ct = dx + dy; + if (ct <= dt) + return (NULL); + } + return (save); +} diff --git a/sys/arch/atari/dev/grfabs_fal.c b/sys/arch/atari/dev/grfabs_fal.c new file mode 100644 index 00000000000..72b9f9da5a6 --- /dev/null +++ b/sys/arch/atari/dev/grfabs_fal.c @@ -0,0 +1,424 @@ +/* $NetBSD: grfabs_fal.c,v 1.1 1995/08/20 18:17:32 leo Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman. + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Leo Weppelman. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifdef FALCON_VIDEO +/* + * atari abstract graphics driver: Falcon-interface + */ +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/malloc.h> +#include <sys/device.h> + +#include <machine/iomap.h> +#include <machine/video.h> +#include <machine/mfp.h> +#include <atari/atari/device.h> +#include <atari/dev/grfabs_reg.h> + +/* + * Function decls + */ +static void init_view __P((view_t *, bmap_t *, dmode_t *, box_t *)); +static bmap_t *alloc_bitmap __P((u_long, u_long, u_char)); +static colormap_t *alloc_colormap __P((dmode_t *)); +static void free_bitmap __P((bmap_t *)); +static void falcon_display_view __P((view_t *)); +static view_t *falcon_alloc_view __P((dmode_t *, dimen_t *, u_char)); +static void falcon_free_view __P((view_t *)); +static void falcon_remove_view __P((view_t *)); +static int falcon_use_colormap __P((view_t *, colormap_t *)); +static void falcon_dedect __P((dmode_t *)); + +/* + * Our function switch table + */ +struct grfabs_sw fal_vid_sw = { + falcon_display_view, + falcon_alloc_view, + falcon_free_view, + falcon_remove_view, + falcon_use_colormap +}; + +static dmode_t vid_modes[] = { + { { NULL, NULL }, "falauto",{ 0, 0 }, 0, RES_FALAUTO ,&fal_vid_sw}, + { { NULL, NULL }, "sthigh", { 640, 400 }, 1, RES_FAL_STHIGH ,&fal_vid_sw}, + { { NULL, NULL }, "stmid", { 640, 200 }, 2, RES_FAL_STMID ,&fal_vid_sw}, + { { NULL, NULL }, "stlow", { 320, 200 }, 4, RES_FAL_STLOW ,&fal_vid_sw}, + { { NULL, NULL }, "ttlow", { 320, 480 }, 8, RES_FAL_TTLOW ,&fal_vid_sw}, + { { NULL, NULL }, "vga2", { 640, 480 }, 1, RES_VGA2 ,&fal_vid_sw}, + { { NULL, NULL }, "vga4", { 640, 480 }, 2, RES_VGA4 ,&fal_vid_sw}, + { { NULL, NULL }, "vga16", { 640, 480 }, 4, RES_VGA16 ,&fal_vid_sw}, + { { NULL, NULL }, "vga256", { 640, 480 }, 8, RES_VGA256 ,&fal_vid_sw}, + { { NULL, NULL }, "highcol",{ 320, 200 }, 16, RES_DIRECT ,&fal_vid_sw}, + { { NULL, NULL }, NULL, } +}; + +/* + * XXX: called from ite console init routine. + * Initialize list of posible video modes. + */ +void +falcon_probe_video(modelp) +MODES *modelp; +{ + dmode_t *dm; + int i; + + /* Currently we support only one mode of the falcon video system. + * This is the mode that is initialized before NetBSD starts. This + * is possible since the bios has already done that work. + */ + + for (i = 0; (dm = &vid_modes[i])->name != NULL; i++) { + if (dm->vm_reg == RES_FALAUTO) { + falcon_dedect(dm); + LIST_INSERT_HEAD(modelp, dm, link); + } + } + + /* + * This seems to prevent bordered screens. + */ + for (i=0; i < 16; i++) + VIDEO->vd_fal_rgb[i] = CM_L2FAL(gra_def_color16[i]); +} + +static void +falcon_dedect(dm) +dmode_t *dm; +{ + u_short falshift, stshift; + short interlace, doublescan; + + interlace = (VIDEO->vd_fal_ctrl & 0x2) >>1; + doublescan = VIDEO->vd_fal_ctrl & 0x1; + + /* + * Calculate the depth of the screen + */ + + falshift = VIDEO->vd_fal_res; + stshift = VIDEO->vd_st_res; + + if (falshift & 0x400) /* 2 color */ + dm->depth = 1; + else if (falshift & 0x100) /* high color, direct */ + dm->depth = 16; + else if (falshift & 0x10) /* 256 color */ + dm->depth = 8; + else if (stshift == 0) /* 16 color */ + dm->depth = 4; + else if (stshift == 1) /* 4 color */ + dm->depth = 2; + else dm->depth = 1; /* 2 color */ + + /* + * Now calculate the screen hight + */ + + dm->size.height = VIDEO->vd_v_dis_end - VIDEO->vd_v_dis_beg; + if (!interlace) dm->size.height >>=1; + if (doublescan) dm->size.height >>=1; + + /* + * And the width + */ + + dm->size.width = VIDEO->vd_vert_wrap * 16 / dm->depth; +} + +static void +falcon_display_view(v) +view_t *v; +{ + dmode_t *dm = v->mode; + bmap_t *bm = v->bitmap; + + if (dm->current_view) { + /* + * Mark current view for this mode as no longer displayed + */ + dm->current_view->flags &= ~VF_DISPLAY; + } + dm->current_view = v; + v->flags |= VF_DISPLAY; + + falcon_use_colormap(v, v->colormap); + + /* XXX: should use vbl for this */ + /* + * Falcon: here should set the videl to switch the video mode. + * This will be added later. + * At the moment we set only the video base. + */ + VIDEO->vd_raml = (u_long)bm->hw_address & 0xff; + VIDEO->vd_ramm = ((u_long)bm->hw_address >> 8) & 0xff; + VIDEO->vd_ramh = ((u_long)bm->hw_address >> 16) & 0xff; +} + +static void +falcon_remove_view(v) +view_t *v; +{ + dmode_t *mode = v->mode; + + if (mode->current_view == v) { +#if 0 + if (v->flags & VF_DISPLAY) + panic("Cannot shutdown display\n"); /* XXX */ +#endif + mode->current_view = NULL; + } + v->flags &= ~VF_DISPLAY; +} + +static void +falcon_free_view(v) +view_t *v; +{ + if (v) { + dmode_t *md = v->mode; + + falcon_remove_view(v); + if (v->colormap != &gra_con_cmap) + free(v->colormap, M_DEVBUF); + free_bitmap(v->bitmap); + if (v != &gra_con_view) + free(v, M_DEVBUF); + } +} + +static int +falcon_use_colormap(v, cm) +view_t *v; +colormap_t *cm; +{ + dmode_t *dm; + volatile u_short *creg; + volatile u_long *fcreg; + u_long *src; + colormap_t *vcm; + u_long *vcreg; + u_short ncreg; + int i; + + dm = v->mode; + vcm = v->colormap; + + /* + * I guess it seems reasonable to require the maps to be + * of the same type... + */ + if (cm->type != vcm->type) + return (EINVAL); + + /* + * First get the colormap addresses an calculate + * howmany colors are in it. + */ + if (dm->depth == 16) /* direct color, no colormap; + but also not (yet) supported */ + return(0); + fcreg = &VIDEO->vd_fal_rgb[0]; + creg = &VIDEO->vd_st_rgb[0]; + ncreg = 1 << dm->depth; + + /* If first entry specified beyond capabilities -> error */ + if (cm->first >= ncreg) + return (EINVAL); + + /* + * A little tricky, the actual colormap pointer will be NULL + * when view is not displaying, valid otherwise. + */ + if (v->flags & VF_DISPLAY) + creg = &creg[cm->first]; + else creg = NULL; + + vcreg = &vcm->entry[cm->first]; + ncreg -= cm->first; + if (cm->size > ncreg) + return (EINVAL); + ncreg = cm->size; + + for (i = 0, src = cm->entry; i < ncreg; i++, vcreg++) { + *vcreg = *src++; + + /* + * If displaying, also update actual color register. + */ + if (creg != NULL) { + *fcreg++ = CM_L2FAL(*vcreg); + if (i < 16 ) + *creg++ = CM_L2ST(*vcreg); + } + } + return (0); +} + +static view_t * +falcon_alloc_view(mode, dim, depth) +dmode_t *mode; +dimen_t *dim; +u_char depth; +{ + view_t *v; + bmap_t *bm; + + if (!atari_realconfig) + v = &gra_con_view; + else v = malloc(sizeof(*v), M_DEVBUF, M_NOWAIT); + if (v == NULL) + return(NULL); + + bm = alloc_bitmap(mode->size.width, mode->size.height, mode->depth); + if (bm) { + box_t box; + + v->colormap = alloc_colormap(mode); + if (v->colormap) { + INIT_BOX(&box,0,0,mode->size.width,mode->size.height); + init_view(v, bm, mode, &box); + return(v); + } + free_bitmap(bm); + } + if (v != &gra_con_view) + free(v, M_DEVBUF); + return (NULL); +} + +static void +init_view(v, bm, mode, dbox) +view_t *v; +bmap_t *bm; +dmode_t *mode; +box_t *dbox; +{ + v->bitmap = bm; + v->mode = mode; + v->flags = 0; + bcopy(dbox, &v->display, sizeof(box_t)); +} + +/* bitmap functions */ + +static bmap_t * +alloc_bitmap(width, height, depth) +u_long width, height; +u_char depth; +{ + int i; + u_long total_size, bm_size; + void *hw_address; + bmap_t *bm; + + /* + * Sigh, it seems for mapping to work we need the bitplane data to + * 1: be aligned on a page boundry. + * 2: be n pages large. + * + * why? because the user gets a page aligned address, if this is before + * your allocation, too bad. Also it seems that the mapping routines + * do not watch to closely to the allowable length. so if you go over + * n pages by less than another page, the user gets to write all over + * the entire page. Since you did not allocate up to a page boundry + * (or more) the user writes into someone elses memory. -ch + */ + bm_size = atari_round_page((width * height * depth) / NBBY); + total_size = bm_size + sizeof(bmap_t) + NBPG; + + if ((bm = (bmap_t*)alloc_stmem(total_size, &hw_address)) == NULL) + return(NULL); + + bm->plane = (u_char*)bm + sizeof(bmap_t); + bm->plane = (u_char*)atari_round_page(bm->plane); + bm->hw_address = (u_char*)hw_address + sizeof(bmap_t); + bm->hw_address = (u_char*)atari_round_page(bm->hw_address); + bm->bytes_per_row = (width * depth) / NBBY; + bm->rows = height; + bm->depth = depth; + + bzero(bm->plane, bm_size); + return (bm); +} + +static void +free_bitmap(bm) +bmap_t *bm; +{ + if (bm) + free_stmem(bm); +} + +static colormap_t * +alloc_colormap(dm) +dmode_t *dm; +{ + int nentries, i; + colormap_t *cm; + u_char type = CM_COLOR; + + if (dm->depth == 16) /* direct color, no colormap; + not (yet) supported */ + nentries = 0; + else + nentries = 1 << dm->depth; + + if (!atari_realconfig) { + cm = &gra_con_cmap; + cm->entry = gra_con_colors; + } + else { + int size; + + size = sizeof(*cm) + (nentries * sizeof(cm->entry[0])); + cm = malloc(size, M_DEVBUF, M_NOWAIT); + if (cm == NULL) + return(NULL); + cm->entry = (long *)&cm[1]; + + } + + if ((cm->type = type) == CM_COLOR) + cm->red_mask = cm->green_mask = cm->blue_mask = 0x3f; + + cm->first = 0; + cm->size = nentries; + + for (i = 0; i < nentries; i++) + cm->entry[i] = gra_def_color16[i % 16]; + return (cm); +} +#endif /* FALCON_VIDEO */ diff --git a/sys/arch/atari/dev/grfabs_reg.h b/sys/arch/atari/dev/grfabs_reg.h new file mode 100644 index 00000000000..1377d2aee84 --- /dev/null +++ b/sys/arch/atari/dev/grfabs_reg.h @@ -0,0 +1,219 @@ +/* $NetBSD: grfabs_reg.h,v 1.5 1995/09/04 19:41:41 leo Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman + * Copyright (c) 1994 Christian E. Hopps + * All rights reserved. + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christian E. Hopps. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef _GRFABS_REG_H +#define _GRFABS_REG_H + +struct point { + long x; + long y; +}; +typedef struct point point_t; + +struct dimension { + u_long width; + u_long height; +}; +typedef struct dimension dimen_t; + +struct box { + long x; + long y; + u_long width; + u_long height; +}; +typedef struct box box_t; + +struct rectangle { + long left; + long top; + long right; + long bottom; +}; +typedef struct rectangle rect_t; + +typedef struct bitmap bmap_t; +typedef struct colormap colormap_t; +typedef struct display_mode dmode_t; + +/* + * View stuff. + */ + +struct view { + bmap_t *bitmap; /* bitmap. */ + box_t display; /* viewable area. */ + dmode_t *mode; /* the mode for this view */ + colormap_t *colormap; /* the colormap for this view */ + int flags; +}; +typedef struct view view_t; + +/* View-flags: */ +#define VF_DISPLAY 1 /* view is on the air now */ + +/* + * Bitmap stuff. + */ +struct bitmap { + u_short bytes_per_row; /* number of bytes per display row. */ + u_short rows; /* number of display rows. */ + u_short depth; /* depth of bitmap. */ + u_char *plane; /* plane data for bitmap. */ + u_char *hw_address; /* mappable bitplane pointer. */ +}; + +/* + * Colormap stuff. + */ +struct colormap { + u_char type; /* what type of entries these are. */ + union { + u_char grey; /* CM_GREYSCALE */ + struct { /* CM_COLOR */ + u_char red; + u_char green; + u_char blue; + } rgb_mask; + } valid_mask; + u_short first; /* color register entry[0] refers to */ + u_short size; /* number of entries */ + u_long *entry; /* the table of actual color values */ +}; + +/* + * Mask short-hands + */ +#define grey_mask valid_mask.grey +#define red_mask valid_mask.rgb_mask.red +#define green_mask valid_mask.rgb_mask.green +#define blue_mask valid_mask.rgb_mask.blue + +enum colormap_type { + CM_MONO, /* only on or off allowed */ + CM_GREYSCALE, /* grey values */ + CM_COLOR /* RGB values */ +}; + +#define MAX_CENTRIES 256 /* that all there is */ +/* + * Create a colormap entry + */ +#define MAKE_COLOR_ENTRY(r,g,b) (((r & 0xff)<<16)|((g & 0xff)<<8)|(b & 0xff)) +#define MAKE_MONO_ENTRY(x) ((x) ? 1 : 0) +#define MAKE_GREY_ENTRY(l) (l & 0xff) + +#define CM_L2TT(v) \ + (((0x000f0000 & (v)) >> 8) | ((0x00000f00 & (v)) >> 4) |\ + (0x0000000f & (v))) +#define CM_TT2L(v) \ + ((((0x00000f00 & (v)) * 0xff / 0xf) << 8) |\ + (((0x000000f0 & (v)) * 0xff / 0xf) << 4) |\ + (0x0000000f & (v)) * 0xff / 0xf) +#define CM_L2FAL(v) \ + (((0x003f0000 & (v)) << 10) | ((0x00003f00 & (v)) << 10) |\ + (0x0000003f & (v)) << 2) +#define CM_FAL2L(v) \ + (((((0xfc000000 & (v)) >> 10) * 0xff / 0x3f) & 0x00ff0000) |\ + ((((0x00fc0000 & (v)) >> 10) * 0xff / 0x3f) & 0x0000ff00) |\ + ((0x000000fc & (v)) >> 2) * 0xff / 0x3f) +#define CM_L2ST(v) \ + (((0x000e0000 & (v)) >> 9) | ((0x00000e00 & (v)) >> 5) |\ + (0x0000000e & (v)) >> 1) +#define CM_ST2L(v) \ + (((((0x00000700 & (v)) * 0xff / 0x7) << 8) & 0x00ff0000) |\ + ((((0x00000070 & (v)) * 0xff / 0x7) << 4) & 0x0000ff00) |\ + (0x00000007 & (v)) * 0xff / 0x7) + +struct grfabs_sw { + void (*display_view) __P((view_t*)); + view_t * (*alloc_view) __P((dmode_t *, dimen_t *, u_char)); + void (*free_view) __P((view_t *)); + void (*remove_view) __P((view_t *)); + int (*use_colormap) __P((view_t *, colormap_t *)); +}; + +/* display mode */ +struct display_mode { + LIST_ENTRY(display_mode) link; + u_char *name; /* logical name for mode. */ + dimen_t size; /* screen size */ + u_char depth; /* screen depth */ + u_short vm_reg; /* video mode register */ + struct grfabs_sw *grfabs_funcs; /* hardware switch table */ + view_t *current_view; /* view displaying me */ +}; + +/* + * Definition of available graphic mode list. + */ +typedef LIST_HEAD(modelist, display_mode) MODES; + +/* + * Misc draw related macros. + */ +#define INIT_BOX(b,xx,yy,ww,hh) \ + do { \ + (b)->x = xx; \ + (b)->y = yy; \ + (b)->width = ww; \ + (b)->height = hh; \ + } while(0) + + +/* + * Common variables + */ +extern view_t gra_con_view; +extern colormap_t gra_con_cmap; +extern long gra_con_colors[MAX_CENTRIES]; +extern u_long gra_def_color16[16]; + +/* + * Prototypes: + */ +#ifdef FALCON_VIDEO +void falcon_probe_video __P((MODES *)); +#endif /* FALCON_VIDEO */ +#ifdef TT_VIDEO +void tt_probe_video __P((MODES *)); +#endif /* TT_VIDEO */ + +view_t *grf_alloc_view __P((dmode_t *d, dimen_t *dim, u_char depth)); +dmode_t *grf_get_best_mode __P((dimen_t *dim, u_char depth)); +void grf_display_view __P((view_t *v)); +void grf_remove_view __P((view_t *v)); +void grf_free_view __P((view_t *v)); +int grf_get_colormap __P((view_t *, colormap_t *)); +int grf_use_colormap __P((view_t *, colormap_t *)); + +#endif /* _GRFABS_REG_H */ diff --git a/sys/arch/atari/dev/grfabs_tt.c b/sys/arch/atari/dev/grfabs_tt.c new file mode 100644 index 00000000000..65d2a871585 --- /dev/null +++ b/sys/arch/atari/dev/grfabs_tt.c @@ -0,0 +1,402 @@ +/* $NetBSD: grfabs_tt.c,v 1.1 1995/08/20 18:17:34 leo Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman. + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Leo Weppelman. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifdef TT_VIDEO +/* + * atari abstract graphics driver: TT-interface + */ +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/malloc.h> +#include <sys/device.h> + +#include <machine/iomap.h> +#include <machine/video.h> +#include <machine/mfp.h> +#include <atari/atari/device.h> +#include <atari/dev/grfabs_reg.h> + +/* + * Function decls + */ +static void init_view __P((view_t *, bmap_t *, dmode_t *, box_t *)); +static bmap_t *alloc_bitmap __P((u_long, u_long, u_char)); +static colormap_t *alloc_colormap __P((dmode_t *)); +static void free_bitmap __P((bmap_t *)); +static void tt_display_view __P((view_t *)); +static view_t *tt_alloc_view __P((dmode_t *, dimen_t *, u_char)); +static void tt_free_view __P((view_t *)); +static void tt_remove_view __P((view_t *)); +static int tt_use_colormap __P((view_t *, colormap_t *)); + +/* + * Our function switch table + */ +struct grfabs_sw tt_vid_sw = { + tt_display_view, + tt_alloc_view, + tt_free_view, + tt_remove_view, + tt_use_colormap +}; + +static dmode_t vid_modes[] = { + { { NULL, NULL }, "sthigh", { 640, 400 }, 1, RES_STHIGH, &tt_vid_sw }, + { { NULL, NULL }, "tthigh", { 1280, 960 }, 1, RES_TTHIGH, &tt_vid_sw }, + { { NULL, NULL }, "stmid", { 640, 200 }, 2, RES_STMID , &tt_vid_sw }, + { { NULL, NULL }, "stlow", { 320, 200 }, 4, RES_STLOW , &tt_vid_sw }, + { { NULL, NULL }, "ttmid", { 640, 480 }, 4, RES_TTMID , &tt_vid_sw }, + { { NULL, NULL }, "ttlow", { 320, 480 }, 8, RES_TTLOW , &tt_vid_sw }, + { { NULL, NULL }, NULL, } +}; + +/* + * XXX: called from ite console init routine. + * Initialize list of posible video modes. + */ +void +tt_probe_video(modelp) +MODES *modelp; +{ + dmode_t *dm; + int i; + int has_mono; + + /* + * First find out what kind of monitor is attached. Dma-sound + * should be off because the 'sound-done' and 'monochrome-detect' + * are xor-ed together. I think that shutting it down here is the + * wrong place. + */ + has_mono = (MFP->mf_gpip & IA_MONO) == 0; + + for (i = 0; (dm = &vid_modes[i])->name != NULL; i++) { + if (has_mono && (dm->vm_reg != RES_TTHIGH)) + continue; + if (!has_mono && (dm->vm_reg == RES_TTHIGH)) + continue; + LIST_INSERT_HEAD(modelp, dm, link); + } + + for (i=0; i < 16; i++) + VIDEO->vd_tt_rgb[i] = CM_L2TT(gra_def_color16[i]); +} + +static void +tt_display_view(v) +view_t *v; +{ + dmode_t *dm = v->mode; + bmap_t *bm = v->bitmap; + + if (dm->current_view) { + /* + * Mark current view for this mode as no longer displayed + */ + dm->current_view->flags &= ~VF_DISPLAY; + } + dm->current_view = v; + v->flags |= VF_DISPLAY; + + tt_use_colormap(v, v->colormap); + + /* XXX: should use vbl for this */ + VIDEO->vd_tt_res = dm->vm_reg; + VIDEO->vd_raml = (u_long)bm->hw_address & 0xff; + VIDEO->vd_ramm = ((u_long)bm->hw_address >> 8) & 0xff; + VIDEO->vd_ramh = ((u_long)bm->hw_address >> 16) & 0xff; +} + +void +tt_remove_view(v) +view_t *v; +{ + dmode_t *mode = v->mode; + + if (mode->current_view == v) { +#if 0 + if (v->flags & VF_DISPLAY) + panic("Cannot shutdown display\n"); /* XXX */ +#endif + mode->current_view = NULL; + } + v->flags &= ~VF_DISPLAY; +} + +void +tt_free_view(v) +view_t *v; +{ + if(v) { + dmode_t *md = v->mode; + + tt_remove_view(v); + if (v->colormap != &gra_con_cmap) + free(v->colormap, M_DEVBUF); + free_bitmap(v->bitmap); + if (v != &gra_con_view) + free(v, M_DEVBUF); + } +} + +static int +tt_use_colormap(v, cm) +view_t *v; +colormap_t *cm; +{ + dmode_t *dm; + volatile u_short *creg; + u_long *src; + colormap_t *vcm; + u_long *vcreg; + u_short ncreg; + int i; + + dm = v->mode; + vcm = v->colormap; + + /* + * I guess it seems reasonable to require the maps to be + * of the same type... + */ + if (cm->type != vcm->type) + return(EINVAL); + + /* + * First figure out where the actual colormap resides and + * howmany colors are in it. + */ + switch (dm->vm_reg) { + case RES_STLOW: + creg = &VIDEO->vd_tt_rgb[0]; + ncreg = 16; + break; + case RES_STMID: + creg = &VIDEO->vd_tt_rgb[0]; + ncreg = 4; + break; + case RES_STHIGH: + creg = &VIDEO->vd_tt_rgb[254]; + ncreg = 2; + break; + case RES_TTLOW: + creg = &VIDEO->vd_tt_rgb[0]; + ncreg = 256; + break; + case RES_TTMID: + creg = &VIDEO->vd_tt_rgb[0]; + ncreg = 16; + break; + case RES_TTHIGH: + return(0); /* No colors */ + default: + panic("grf_tt:use_colormap: wrong mode!?"); + } + + /* If first entry specified beyond capabilities -> error */ + if (cm->first >= ncreg) + return(EINVAL); + + /* + * A little tricky, the actual colormap pointer will be NULL + * when view is not displaying, valid otherwise. + */ + if (v->flags & VF_DISPLAY) + creg = &creg[cm->first]; + else creg = NULL; + + vcreg = &vcm->entry[cm->first]; + ncreg -= cm->first; + if (cm->size > ncreg) + return(EINVAL); + ncreg = cm->size; + + for (i = 0, src = cm->entry; i < ncreg; i++, vcreg++) { + *vcreg = *src++; + + /* + * If displaying, also update actual color registers. + */ + if (creg != NULL) + *creg++ = CM_L2TT(*vcreg); + } + return (0); +} + +static view_t * +tt_alloc_view(mode, dim, depth) +dmode_t *mode; +dimen_t *dim; +u_char depth; +{ + view_t *v; + bmap_t *bm; + + if (!atari_realconfig) + v = &gra_con_view; + else v = malloc(sizeof(*v), M_DEVBUF, M_NOWAIT); + if(v == NULL) + return (NULL); + + bm = alloc_bitmap(mode->size.width, mode->size.height, mode->depth); + if (bm) { + box_t box; + + v->colormap = alloc_colormap(mode); + if (v->colormap) { + INIT_BOX(&box,0,0,mode->size.width,mode->size.height); + init_view(v, bm, mode, &box); + return (v); + } + free_bitmap(bm); + } + if (v != &gra_con_view) + free(v, M_DEVBUF); + return (NULL); +} + +static void +init_view(v, bm, mode, dbox) +view_t *v; +bmap_t *bm; +dmode_t *mode; +box_t *dbox; +{ + v->bitmap = bm; + v->mode = mode; + v->flags = 0; + bcopy(dbox, &v->display, sizeof(box_t)); +} + +/* bitmap functions */ + +static bmap_t * +alloc_bitmap(width, height, depth) +u_long width, height; +u_char depth; +{ + int i; + u_long total_size, bm_size; + void *hw_address; + bmap_t *bm; + + /* + * Sigh, it seems for mapping to work we need the bitplane data to + * 1: be aligned on a page boundry. + * 2: be n pages large. + * + * why? because the user gets a page aligned address, if this is before + * your allocation, too bad. Also it seems that the mapping routines + * do not watch to closely to the allowable length. so if you go over + * n pages by less than another page, the user gets to write all over + * the entire page. Since you did not allocate up to a page boundry + * (or more) the user writes into someone elses memory. -ch + */ + bm_size = atari_round_page((width * height * depth) / NBBY); + total_size = bm_size + sizeof(bmap_t) + NBPG; + + if ((bm = (bmap_t*)alloc_stmem(total_size, &hw_address)) == NULL) + return(NULL); + + bm->plane = (u_char*)bm + sizeof(bmap_t); + bm->plane = (u_char*)atari_round_page(bm->plane); + bm->hw_address = (u_char*)hw_address + sizeof(bmap_t); + bm->hw_address = (u_char*)atari_round_page(bm->hw_address); + bm->bytes_per_row = (width * depth) / NBBY; + bm->rows = height; + bm->depth = depth; + + bzero(bm->plane, bm_size); + return (bm); +} + +static void +free_bitmap(bm) +bmap_t *bm; +{ + if (bm) + free_stmem(bm); +} + +static colormap_t * +alloc_colormap(dm) +dmode_t *dm; +{ + int nentries, i; + colormap_t *cm; + u_char type = CM_COLOR; + + switch (dm->vm_reg) { + case RES_STLOW: + case RES_TTMID: + nentries = 16; + break; + case RES_STMID: + nentries = 4; + break; + case RES_STHIGH: + nentries = 2; + break; + case RES_TTLOW: + nentries = 256; + break; + case RES_TTHIGH: + type = CM_MONO; + nentries = 0; + break; + default: + panic("grf_tt:alloc_colormap: wrong mode!?"); + } + if (!atari_realconfig) { + cm = &gra_con_cmap; + cm->entry = gra_con_colors; + } + else { + int size; + + size = sizeof(*cm) + (nentries * sizeof(cm->entry[0])); + cm = malloc(size, M_DEVBUF, M_NOWAIT); + if (cm == NULL) + return (NULL); + cm->entry = (long *)&cm[1]; + + } + if ((cm->type = type) == CM_COLOR) + cm->red_mask = cm->green_mask = cm->blue_mask = 0xf; + cm->first = 0; + cm->size = nentries; + + for (i = 0; i < nentries; i++) + cm->entry[i] = gra_def_color16[i % 16]; + return (cm); +} +#endif /* TT_VIDEO */ diff --git a/sys/arch/atari/dev/grfioctl.h b/sys/arch/atari/dev/grfioctl.h new file mode 100644 index 00000000000..fb5b32571c3 --- /dev/null +++ b/sys/arch/atari/dev/grfioctl.h @@ -0,0 +1,212 @@ +/* $NetBSD: grfioctl.h,v 1.1.1.1 1995/03/26 07:12:12 leo Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1990 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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: grfioctl.h 1.1 90/07/09$ + * + * @(#)grfioctl.h 7.2 (Berkeley) 11/4/90 + */ + + +/* these are changeable values, encapsulated in their own structure, so + no the whole thing has to be copied when setting parameters. */ +struct grfdyninfo { + int gdi_fbx; /* frame buffer x offset */ + int gdi_fby; /* frame buffer y offset */ + int gdi_dwidth; /* displayed part width */ + int gdi_dheight; /* displayed part height */ + int gdi_dx; /* displayed part x offset */ + int gdi_dy; /* displayed part y offset */ +}; + +struct grfinfo { + caddr_t gd_fbaddr; /* frame buffer physaddr */ + int gd_fbsize; /* frame buffer size */ + short gd_colors; /* number of colors */ + short gd_planes; /* number of planes */ + + int gd_fbwidth; /* frame buffer width */ + int gd_fbheight; /* frame buffer height */ + + struct grfdyninfo gd_dyn; /* everything changable by GRFIOCSINFO */ +/* compatibility... */ +#define gd_fbx gd_dyn.gdi_fbx +#define gd_fby gd_dyn.gdi_fby +#define gd_dwidth gd_dyn.gdi_dwidth +#define gd_dheight gd_dyn.gdi_dheight +#define gd_dx gd_dyn.gdi_dx +#define gd_dy gd_dyn.gdi_dy + + /* new for banked pager support */ + int gd_bank_size; /* size of a bank (or 0) */ +}; + + +/* video mode, should be display-independant, but it might need + modifications in the future to really become hardware-independant. */ + +struct grfvideo_mode { + u_char mode_num; /* index in mode table */ + char mode_descr[80]; /* description of mode */ + u_long pixel_clock; /* in Hz. */ + u_short disp_width; /* width of displayed video (incl overscan) */ + u_short disp_height; /* height "" */ + u_short depth; /* number of bitplanes resp. bits per pixel */ + u_short hblank_start; + u_short hblank_stop; + u_short hsync_start; /* video-parameters, take care not to */ + u_short hsync_stop; /* use parameters that violete specs of */ + u_short htotal; /* your monitor ! */ + u_short vblank_start; + u_short vblank_stop; + u_short vsync_start; + u_short vsync_stop; + u_short vtotal; +}; + + +/* + * BSD ioctls + */ +#define OGRFIOCGINFO 0x40344700 /* to keep compat for a while... */ +#define GRFIOCGINFO _IOR('G', 0, struct grfinfo) /* get info on device */ +#define GRFIOCON _IO('G', 1) /* turn graphics on */ +#define GRFIOCOFF _IO('G', 2) /* turn graphics off */ +#define GRFIOCMAP _IOWR('G', 5, int) /* map in regs+framebuffer */ +#define GRFIOCUNMAP _IOW('G', 6, int) /* unmap regs+framebuffer */ + +/* amiga addons */ + /* set info on device */ +#define GRFIOCSINFO _IOW('G', 40, struct grfdyninfo) + /* get video_mode. mode_num==0 gets current mode. */ +#define GRFGETVMODE _IOWR('G', 41, struct grfvideo_mode) + /* set video_mode. */ +#define GRFSETVMODE _IOW('G', 42, int) + /* get number of configured video modes */ +#define GRFGETNUMVM _IOR('G', 43, int) + + +/* + * generic framebuffer-related ioctls. These are somewhat + * similar to SunOS fb-ioctls since I liked them reading + * thru the X11-server code. + */ + +/* + * colormap related information. Every grf has an associated + * colormap. Depending on the capabilities of the hardware, more + * or less of the information provided may be used. + * Maxium value of "index" can be deduced from grfinfo->gd_colors. + */ +struct grf_colormap { + int index; /* start at red[index],green[index],blue[index] */ + int count; /* till < red[index+count],... */ + u_char *red; + u_char *green; + u_char *blue; +}; + +/* write the selected slots into the active colormap */ +#define GRFIOCPUTCMAP _IOW('G', 50, struct grf_colormap) + +/* retrieve the selected slots from the active colormap */ +#define GRFIOCGETCMAP _IOWR('G', 51, struct grf_colormap) + + +/* + * support a possibly available hardware sprite. calls just fail + * if a given grf doesn't implement hardware sprites. + */ +struct grf_position { + u_short x, y; /* 0,0 is upper left corner */ +}; +#define GRFIOCSSPRITEPOS _IOW('G', 52, struct grf_position) +#define GRFIOCGSPRITEPOS _IOR('G', 53, struct grf_position) + +struct grf_spriteinfo { + u_short set; +#define GRFSPRSET_ENABLE (1<<0) +#define GRFSPRSET_POS (1<<1) +#define GRFSPRSET_HOT (1<<2) +#define GRFSPRSET_CMAP (1<<3) +#define GRFSPRSET_SHAPE (1<<4) +#define GRFSPRSET_ALL 0x1f + u_short enable; /* sprite is displayed if == 1 */ + struct grf_position pos; /* sprite location */ + struct grf_position hot; /* sprite hot spot */ + struct grf_colormap cmap; /* colormap for the sprite. */ + struct grf_position size; /* x == width, y == height */ + u_char *image, *mask; /* sprite bitmap and mask */ +}; + +#define GRFIOCSSPRITEINF _IOW('G', 54, struct grf_spriteinfo) +#define GRFIOCGSPRITEINF _IOR('G', 55, struct grf_spriteinfo) + +/* get maximum sprite size hardware can display */ +#define GRFIOCGSPRITEMAX _IOR('G', 56, struct grf_position) + + +/* support for a BitBlt operation. The op-codes are identical + to X11 GCs */ +#define GRFBBOPclear 0x0 /* 0 */ +#define GRFBBOPand 0x1 /* src AND dst */ +#define GRFBBOPandReverse 0x2 /* src AND NOT dst */ +#define GRFBBOPcopy 0x3 /* src */ +#define GRFBBOPandInverted 0x4 /* NOT src AND dst */ +#define GRFBBOPnoop 0x5 /* dst */ +#define GRFBBOPxor 0x6 /* src XOR dst */ +#define GRFBBOPor 0x7 /* src OR dst */ +#define GRFBBOPnor 0x8 /* NOT src AND NOT dst */ +#define GRFBBOPequiv 0x9 /* NOT src XOR dst */ +#define GRFBBOPinvert 0xa /* NOT dst */ +#define GRFBBOPorReverse 0xb /* src OR NOT dst */ +#define GRFBBOPcopyInverted 0xc /* NOT src */ +#define GRFBBOPorInverted 0xd /* NOT src OR dst */ +#define GRFBBOPnand 0xe /* NOT src OR NOT dst */ +#define GRFBBOPset 0xf /* 1 */ + +struct grf_bitblt { + u_short op; /* see above */ + u_short src_x, src_y; /* upper left corner of source-region */ + u_short dst_x, dst_y; /* upper left corner of dest-region */ + u_short w, h; /* width, height of region */ + u_short mask; /* bitmask to apply */ +}; + +#define GRFIOCBITBLT _IOR('G', 57, struct grf_bitblt) + diff --git a/sys/arch/atari/dev/grfvar.h b/sys/arch/atari/dev/grfvar.h new file mode 100644 index 00000000000..121fd265bca --- /dev/null +++ b/sys/arch/atari/dev/grfvar.h @@ -0,0 +1,97 @@ +/* $NetBSD: grfvar.h,v 1.2 1995/05/28 19:45:38 leo Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1990 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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: grfvar.h 1.9 91/01/21$ + * + * @(#)grfvar.h 7.3 (Berkeley) 5/7/91 + */ + +struct ite_softc; + +/* + * this struct is owned by the driver (grfcc) + * and is passed to grf when grf is configed. The ite also + * uses it... + */ +struct grf_softc { + struct device g_device; /* config sets this up. */ + struct grfinfo g_display; /* hardware descr. (for ioctl) */ + int g_flags; /* software flags */ + int g_unit; /* grf unit we want/have */ + dev_t g_itedev; /* ite device number */ + dev_t g_grfdev; /* grf device number */ + dev_t g_viewdev; /* view device number */ + caddr_t g_data; /* device dependent data */ + int (*g_mode)(); + int g_conpri; /* priority of ite as console */ + void (*g_iteinit)(); + void (*g_itedeinit)(); + void (*g_iteclear)(); + void (*g_iteputc)(); + void (*g_itecursor)(); + void (*g_itescroll)(); +}; + +/* flags */ +#define GF_ALIVE 0x01 +#define GF_OPEN 0x02 +#define GF_EXCLUDE 0x04 +#define GF_WANTED 0x08 +#define GF_GRFON 0x10 + +/* software ids defined in grfioctl.h */ + +/* requests to mode routine (g_mode())*/ +#define GM_GRFON 1 +#define GM_GRFOFF 2 +#define GM_GRFOVON 3 +#define GM_GRFOVOFF 4 +#define GM_GRFCONFIG 5 +#define GM_GRFGETVMODE 6 +#define GM_GRFSETVMODE 7 +#define GM_GRFGETNUMVM 8 +#define GM_GRFGETBANK 9 +#define GM_GRFSETBANK 10 +#define GM_GRFGETCURBANK 11 +#define GM_GRFIOCTL 12 + +/* minor device interpretation */ +#define GRFOVDEV 0x10 /* XXX no driver uses yet, overlay planes */ +#define GRFIMDEV 0x20 /* XXX no driver uses yet, images planes */ +#define GRFUNIT(d) ((d) & 0x7) diff --git a/sys/arch/atari/dev/ite.c b/sys/arch/atari/dev/ite.c new file mode 100644 index 00000000000..3d29cc47bbe --- /dev/null +++ b/sys/arch/atari/dev/ite.c @@ -0,0 +1,2348 @@ +/* $NetBSD: ite.c,v 1.7 1995/09/04 19:39:21 leo Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1990 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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.1 90/07/09 + * from: @(#)ite.c 7.6 (Berkeley) 5/16/91 + */ + +/* + * ite - bitmapped terminal. + * Supports VT200, a few terminal features will be unavailable until + * the system actually probes the device (i.e. not after consinit()) + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/conf.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +#include <sys/termios.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <dev/cons.h> + +#include <atari/atari/kdassert.h> +#include <atari/dev/kbdmap.h> +#include <atari/dev/iteioctl.h> +#include <atari/dev/itevar.h> +#include <atari/dev/grfioctl.h> +#include <atari/dev/grfabs_reg.h> +#include <atari/dev/grfvar.h> +#include <atari/dev/viewioctl.h> +#include <atari/dev/viewvar.h> + +#define ITEUNIT(dev) (minor(dev)) + +#define SUBR_INIT(ip) (ip)->grf->g_iteinit(ip) +#define SUBR_DEINIT(ip) (ip)->grf->g_itedeinit(ip) +#define SUBR_PUTC(ip,c,dy,dx,m) (ip)->grf->g_iteputc(ip,c,dy,dx,m) +#define SUBR_CURSOR(ip,flg) (ip)->grf->g_itecursor(ip,flg) +#define SUBR_CLEAR(ip,sy,sx,h,w) (ip)->grf->g_iteclear(ip,sy,sx,h,w) +#define SUBR_SCROLL(ip,sy,sx,cnt,dir) (ip)->grf->g_itescroll(ip,sy,sx,cnt,dir) + +u_int ite_confunits; /* configured units */ + +int start_repeat_timeo = 30; /* first repeat after x s/100 */ +int next_repeat_timeo = 10; /* next repeat after x s/100 */ + +int ite_default_wrap = 1; /* you want vtxxx-nam, binpatch */ + +struct ite_softc con_itesoftc; +u_char cons_tabs[MAX_TABS]; + +struct ite_softc *kbd_ite; +int kbd_init; + +static char *index __P((const char *, int)); +static int inline atoi __P((const char *)); +static void ite_switch __P((int)); +void iteputchar __P((int c, struct ite_softc *ip)); +void ite_putstr __P((const u_char * s, int len, dev_t dev)); +void iteattach __P((struct device *, struct device *, void *)); +int itematch __P((struct device *, struct cfdata *, void *)); + +struct cfdriver itecd = { + NULL, "ite", (cfmatch_t)itematch, iteattach, DV_DULL, + sizeof(struct ite_softc), NULL, 0 }; + +int +itematch(pdp, cdp, auxp) + struct device *pdp; + struct cfdata *cdp; + void *auxp; +{ + struct grf_softc *gp; + int maj; + + gp = auxp; + + /* ite0 should be at grf0 */ + if(cdp->cf_unit != gp->g_unit) + return(0); + + /* + * all that our mask allows (more than enough no one + * has > 32 monitors for text consoles on one machine) + */ + if (cdp->cf_unit >= sizeof(ite_confunits) * NBBY) + return(0); + /* + * XXX + * normally this would be done in attach, however + * during early init we do not have a device pointer + * and thus no unit number. + */ + for(maj = 0; maj < nchrdev; maj++) + if (cdevsw[maj].d_open == iteopen) + break; + gp->g_itedev = makedev(maj, cdp->cf_unit); + return(1); +} + +void +iteattach(pdp, dp, auxp) +struct device *pdp, *dp; +void *auxp; +{ + extern int hz; + struct grf_softc *gp; + struct ite_softc *ip; + int s; + + gp = (struct grf_softc *)auxp; + + /* + * mark unit as attached (XXX see itematch) + */ + ite_confunits |= 1 << ITEUNIT(gp->g_itedev); + + if(dp) { + ip = (struct ite_softc *)dp; + + s = spltty(); + if(con_itesoftc.grf != NULL + && con_itesoftc.grf->g_unit == gp->g_unit) { + /* + * console reinit copy params over. + * and console always gets keyboard + */ + bcopy(&con_itesoftc.grf, &ip->grf, + (char *)&ip[1] - (char *)&ip->grf); + con_itesoftc.grf = NULL; + kbd_ite = ip; + } + ip->grf = gp; + splx(s); + + iteinit(gp->g_itedev); + printf(": rows %d cols %d", ip->rows, ip->cols); + printf(" repeat at (%d/100)s next at (%d/100)s", + start_repeat_timeo, next_repeat_timeo); + + if (kbd_ite == NULL) + kbd_ite = ip; + if (kbd_ite == ip) + printf(" has keyboard"); + printf("\n"); + } else { + if (con_itesoftc.grf != NULL && + con_itesoftc.grf->g_conpri > gp->g_conpri) + return; + con_itesoftc.grf = gp; + con_itesoftc.tabs = cons_tabs; + } +} + +struct ite_softc * +getitesp(dev) + dev_t dev; +{ + extern int atari_realconfig; + + if(atari_realconfig && (con_itesoftc.grf == NULL)) + return(itecd.cd_devs[ITEUNIT(dev)]); + + if(con_itesoftc.grf == NULL) + panic("no ite_softc for console"); + return(&con_itesoftc); +} + +/* + * cons.c entry points into ite device. + */ + +/* + * Return a priority in consdev->cn_pri field highest wins. This function + * is called before any devices have been probed. + */ +void +itecnprobe(cd) + struct consdev *cd; +{ + /* + * bring graphics layer up. + */ + config_console(); + + /* + * return priority of the best ite (already picked from attach) + * or CN_DEAD. + */ + if (con_itesoftc.grf == NULL) + cd->cn_pri = CN_DEAD; + else { + cd->cn_pri = con_itesoftc.grf->g_conpri; + cd->cn_dev = con_itesoftc.grf->g_itedev; + } +} + +void +itecninit(cd) + struct consdev *cd; +{ + struct ite_softc *ip; + + ip = getitesp(cd->cn_dev); + ip->flags |= ITE_ISCONS; + iteinit(cd->cn_dev); + ip->flags |= ITE_ACTIVE | ITE_ISCONS; +} + +/* + * ite_cnfinish() is called in ite_init() when the device is + * being probed in the normal fasion, thus we can finish setting + * up this ite now that the system is more functional. + */ +void +ite_cnfinish(ip) + struct ite_softc *ip; +{ + static int done; + + if (done) + return; + done = 1; +} + +int +itecngetc(dev) + dev_t dev; +{ + int c; + + /* XXX this should be moved */ + if (!kbd_init) { + kbd_init = 1; + kbdenable(); + } + do { + c = kbdgetcn(); + c = ite_cnfilter(c, ITEFILT_CONSOLE); + } while (c == -1); + return (c); +} + +void +itecnputc(dev, c) + dev_t dev; + int c; +{ + static int paniced; + struct ite_softc *ip; + char ch; + + ip = getitesp(dev); + ch = c; + + if (panicstr && !paniced && + (ip->flags & (ITE_ACTIVE | ITE_INGRF)) != ITE_ACTIVE) { + (void)ite_on(dev, 3); + paniced = 1; + } + iteputchar(ch, ip); +} + +/* + * standard entry points to the device. + */ + +/* + * iteinit() is the standard entry point for initialization of + * an ite device, it is also called from itecninit(). + * + */ +void +iteinit(dev) + dev_t dev; +{ + extern int atari_realconfig; + struct ite_softc *ip; + + ip = getitesp(dev); + if (ip->flags & ITE_INITED) + return; + if (atari_realconfig) { + if (ip->kbdmap && ip->kbdmap != &ascii_kbdmap) + free(ip->kbdmap, M_DEVBUF); + ip->kbdmap = malloc(sizeof(struct kbdmap), M_DEVBUF, M_WAITOK); + bcopy(&ascii_kbdmap, ip->kbdmap, sizeof(struct kbdmap)); + } + else ip->kbdmap = &ascii_kbdmap; + + ip->cursorx = 0; + ip->cursory = 0; + SUBR_INIT(ip); + SUBR_CURSOR(ip, DRAW_CURSOR); + if (ip->tabs == NULL) + ip->tabs = malloc(MAX_TABS * sizeof(u_char),M_DEVBUF,M_WAITOK); + ite_reset(ip); + ip->flags |= ITE_INITED; +} + +int +iteopen(dev, mode, devtype, p) + dev_t dev; + int mode, devtype; + struct proc *p; +{ + struct ite_softc *ip; + struct tty *tp; + int error, first, unit; + + unit = ITEUNIT(dev); + first = 0; + + if (((1 << unit) & ite_confunits) == 0) + return (ENXIO); + + ip = getitesp(dev); + + if (ip->tp == NULL) + tp = ip->tp = ttymalloc(); + else + tp = ip->tp; + if ((tp->t_state & (TS_ISOPEN | TS_XCLUDE)) == (TS_ISOPEN | TS_XCLUDE) + && p->p_ucred->cr_uid != 0) + return (EBUSY); + if ((ip->flags & ITE_ACTIVE) == 0) { + error = ite_on(dev, 0); + if (error) + return (error); + first = 1; + } + tp->t_oproc = itestart; + tp->t_param = ite_param; + tp->t_dev = dev; + if ((tp->t_state & TS_ISOPEN) == 0) { + ttychars(tp); + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_cflag = TTYDEF_CFLAG; + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; + tp->t_state = TS_WOPEN | TS_CARR_ON; + ttsetwater(tp); + } + error = (*linesw[tp->t_line].l_open) (dev, tp); + if (error == 0) { + tp->t_winsize.ws_row = ip->rows; + tp->t_winsize.ws_col = ip->cols; + if (!kbd_init) { + kbd_init = 1; + kbdenable(); + } + } else if (first) + ite_off(dev, 0); + return (error); +} + +int +iteclose(dev, flag, mode, p) + dev_t dev; + int flag, mode; + struct proc *p; +{ + struct tty *tp; + + tp = getitesp(dev)->tp; + + KDASSERT(tp); + (*linesw[tp->t_line].l_close) (tp, flag); + ttyclose(tp); + ite_off(dev, 0); + return (0); +} + +int +iteread(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct tty *tp; + + tp = getitesp(dev)->tp; + + KDASSERT(tp); + return ((*linesw[tp->t_line].l_read) (tp, uio, flag)); +} + +int +itewrite(dev, uio, flag) + dev_t dev; + struct uio *uio; + int flag; +{ + struct tty *tp; + + tp = getitesp(dev)->tp; + + KDASSERT(tp); + return ((*linesw[tp->t_line].l_write) (tp, uio, flag)); +} + +int +itestop(tp, flag) + struct tty *tp; + int flag; +{ + +} + +struct tty * +itetty(dev) + dev_t dev; +{ + return(getitesp(dev)->tp); +} + +int +iteioctl(dev, cmd, addr, flag, p) + dev_t dev; + u_long cmd; + int flag; + caddr_t addr; + struct proc *p; +{ + struct iterepeat *irp; + struct ite_softc *ip; + struct tty *tp; + int error; + + ip = getitesp(dev); + tp = ip->tp; + + KDASSERT(tp); + + error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, addr, flag, p); + if(error >= 0) + return (error); + error = ttioctl(tp, cmd, addr, flag, p); + if (error >= 0) + return (error); + + switch (cmd) { + case ITEIOCSKMAP: + if (addr == 0) + return(EFAULT); + bcopy(addr, ip->kbdmap, sizeof(struct kbdmap)); + return(0); + case ITEIOCSSKMAP: + if (addr == 0) + return(EFAULT); + bcopy(addr, &ascii_kbdmap, sizeof(struct kbdmap)); + return(0); + case ITEIOCGKMAP: + if (addr == NULL) + return(EFAULT); + bcopy(ip->kbdmap, addr, sizeof(struct kbdmap)); + return(0); + case ITEIOCGREPT: + irp = (struct iterepeat *)addr; + irp->start = start_repeat_timeo; + irp->next = next_repeat_timeo; + return(0); + case ITEIOCSREPT: + irp = (struct iterepeat *)addr; + if (irp->start < ITEMINREPEAT || irp->next < ITEMINREPEAT) + return(EINVAL); + start_repeat_timeo = irp->start; + next_repeat_timeo = irp->next; + return(0); + } + error = ite_grf_ioctl(ip, cmd, addr, flag, p); + if(error >= 0) + return(error); + return (ENOTTY); +} + +void +itestart(tp) + struct tty *tp; +{ + struct clist *rbp; + struct ite_softc *ip; + u_char buf[ITEBURST]; + int s, len, n; + + ip = getitesp(tp->t_dev); + + KDASSERT(tp); + + s = spltty(); { + if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) + goto out; + + tp->t_state |= TS_BUSY; + rbp = &tp->t_outq; + + len = q_to_b(rbp, buf, ITEBURST); + } splx(s); + + /* Here is a really good place to implement pre/jumpscroll() */ + ite_putstr((char *)buf, len, tp->t_dev); + + s = spltty(); { + tp->t_state &= ~TS_BUSY; + /* we have characters remaining. */ + if (rbp->c_cc) { + tp->t_state |= TS_TIMEOUT; + timeout(ttrstrt, tp, 1); + } + /* wakeup we are below */ + if (rbp->c_cc <= tp->t_lowat) { + if (tp->t_state & TS_ASLEEP) { + tp->t_state &= ~TS_ASLEEP; + wakeup((caddr_t) rbp); + } + selwakeup(&tp->t_wsel); + } + out: ; + } splx(s); +} + +int +ite_on(dev, flag) + dev_t dev; + int flag; +{ + struct ite_softc *ip; + int unit; + + unit = ITEUNIT(dev); + if (((1 << unit) & ite_confunits) == 0) + return (ENXIO); + + ip = getitesp(dev); + + /* force ite active, overriding graphics mode */ + if (flag & 1) { + ip->flags |= ITE_ACTIVE; + ip->flags &= ~(ITE_INGRF | ITE_INITED); + } + /* leave graphics mode */ + if (flag & 2) { + ip->flags &= ~ITE_INGRF; + if ((ip->flags & ITE_ACTIVE) == 0) + return (0); + } + ip->flags |= ITE_ACTIVE; + if (ip->flags & ITE_INGRF) + return (0); + iteinit(dev); + return (0); +} + +int +ite_off(dev, flag) +dev_t dev; +int flag; +{ + struct ite_softc *ip; + + ip = getitesp(dev); + if (flag & 2) + ip->flags |= ITE_INGRF; + if ((ip->flags & ITE_ACTIVE) == 0) + return; + if ((flag & 1) || + (ip->flags & (ITE_INGRF | ITE_ISCONS | ITE_INITED)) == ITE_INITED) + SUBR_DEINIT(ip); + if ((flag & 2) == 0) /* XXX hmm grfon() I think wants this to go inactive. */ + ip->flags &= ~ITE_ACTIVE; +} + +static void +ite_switch(unit) +int unit; +{ + struct ite_softc *ip; + + if(!(ite_confunits & (1 << unit))) + return; /* Don't try unconfigured units */ + ip = getitesp(unit); + if(!(ip->flags & ITE_INITED)) + return; + + /* + * If switching to an active ite, also switch the keyboard. + */ + if(ip->flags & ITE_ACTIVE) + kbd_ite = ip; + + /* + * Now make it visible + */ + viewioctl(ip->grf->g_viewdev, VIOCDISPLAY, NULL, 0, -1); +} + +/* XXX called after changes made in underlying grf layer. */ +/* I want to nuke this */ +void +ite_reinit(dev) + dev_t dev; +{ + struct ite_softc *ip; + + ip = getitesp(dev); + ip->flags &= ~ITE_INITED; + iteinit(dev); +} + +int +ite_param(tp, t) + struct tty *tp; + struct termios *t; +{ + tp->t_ispeed = t->c_ispeed; + tp->t_ospeed = t->c_ospeed; + tp->t_cflag = t->c_cflag; + return (0); +} + +void +ite_reset(ip) + struct ite_softc *ip; +{ + int i; + + ip->curx = 0; + ip->cury = 0; + ip->attribute = ATTR_NOR; + ip->save_curx = 0; + ip->save_cury = 0; + ip->save_attribute = ATTR_NOR; + ip->ap = ip->argbuf; + ip->emul_level = 0; + ip->eightbit_C1 = 0; + ip->top_margin = 0; + ip->bottom_margin = ip->rows - 1; + ip->inside_margins = 0; + ip->linefeed_newline = 0; + ip->auto_wrap = ite_default_wrap; + ip->cursor_appmode = 0; + ip->keypad_appmode = 0; + ip->imode = 0; + ip->key_repeat = 1; + bzero(ip->tabs, ip->cols); + for (i = 0; i < ip->cols; i++) + ip->tabs[i] = ((i & 7) == 0); +} + +/* + * has to be global becuase of the shared filters. + */ +static u_char key_mod; +static u_char last_dead; + +/* Used in console at startup only */ +int +ite_cnfilter(c, caller) +u_int c; +enum caller caller; +{ + struct key key; + struct kbdmap *kbdmap; + u_char code, up, mask; + int s; + + up = KBD_RELEASED(c); + c = KBD_SCANCODE(c); + code = 0; + mask = 0; + kbdmap = (kbd_ite == NULL) ? &ascii_kbdmap : kbd_ite->kbdmap; + + s = spltty(); + + /* + * Handle special keys + */ + switch(c) { + case KBD_LEFT_SHIFT: + mask = KBD_MOD_LSHIFT; + break; + case KBD_RIGHT_SHIFT: + mask = KBD_MOD_RSHIFT; + break; + case KBD_CTRL: + mask = KBD_MOD_CTRL; + break; + case KBD_ALT: + mask = KBD_MOD_ALT; + break; + case KBD_CAPS_LOCK: + /* CAPSLOCK is a toggle */ + if(!up) + key_mod ^= KBD_MOD_CAPS; + splx(s); + return; + break; + } + if(mask) { + if(up) + key_mod &= ~mask; + else + key_mod |= mask; + splx(s); + return -1; + } + + /* + * No special action if key released + */ + if(up) { + splx(s); + return -1; + } + + /* translate modifiers */ + if(key_mod & KBD_MOD_SHIFT) { + if(key_mod & KBD_MOD_ALT) + key = kbdmap->alt_shift_keys[c]; + else key = kbdmap->shift_keys[c]; + } + else if(key_mod & KBD_MOD_ALT) + key = kbdmap->alt_keys[c]; + else { + key = kbdmap->keys[c]; + /* + * If CAPS and key is CAPable (no pun intended) + */ + if((key_mod & KBD_MOD_CAPS) && (key.mode & KBD_MODE_CAPS)) + key = kbdmap->shift_keys[c]; + } + code = key.code; + +#ifdef notyet /* LWP: Didn't have time to look at this yet */ + /* + * If string return simple console filter + */ + if(key->mode & (KBD_MODE_STRING | KBD_MODE_KPAD)) { + splx(s); + return -1; + } + /* handle dead keys */ + if(key->mode & KBD_MODE_DEAD) { + /* if entered twice, send accent itself */ + if (last_dead == key->mode & KBD_MODE_ACCMASK) + last_dead = 0; + else { + last_dead = key->mode & KBD_MODE_ACCMASK; + splx(s); + return -1; + } + } + if(last_dead) { + /* can't apply dead flag to string-keys */ + if (code >= '@' && code < 0x7f) + code = + acctable[KBD_MODE_ACCENT(last_dead)][code - '@']; + last_dead = 0; + } +#endif + if(key_mod & KBD_MOD_CTRL) + code &= 0x1f; + + /* + * Do console mapping. + */ + code = code == '\r' ? '\n' : code; + + splx(s); + return (code); +} + +/* And now the old stuff. */ + +/* these are used to implement repeating keys.. */ +static u_char last_char; +static u_char tout_pending; + +/*ARGSUSED*/ +static void + +repeat_handler(arg) +void *arg; +{ + tout_pending = 0; + if(last_char) + add_sicallback(ite_filter, last_char, ITEFILT_REPEATER); +} + +void +ite_filter(c, caller) +u_int c; +enum caller caller; +{ + struct tty *kbd_tty; + struct kbdmap *kbdmap; + u_char code, *str, up, mask; + struct key key; + int s, i; + + if(kbd_ite == NULL) + return; + + kbd_tty = kbd_ite->tp; + kbdmap = kbd_ite->kbdmap; + + up = KBD_RELEASED(c); + c = KBD_SCANCODE(c); + code = 0; + mask = 0; + + /* have to make sure we're at spltty in here */ + s = spltty(); + + /* + * keyboard interrupts come at priority 2, while softint + * generated keyboard-repeat interrupts come at level 1. So, + * to not allow a key-up event to get thru before a repeat for + * the key-down, we remove any outstanding callout requests.. + */ + rem_sicallback(ite_filter); + + + /* + * Handle special keys + */ + switch(c) { + case KBD_LEFT_SHIFT: + mask = KBD_MOD_LSHIFT; + break; + case KBD_RIGHT_SHIFT: + mask = KBD_MOD_RSHIFT; + break; + case KBD_CTRL: + mask = KBD_MOD_CTRL; + break; + case KBD_ALT: + mask = KBD_MOD_ALT; + break; + case KBD_CAPS_LOCK: + /* CAPSLOCK is a toggle */ + if(!up) + key_mod ^= KBD_MOD_CAPS; + splx(s); + return; + break; + } + if(mask) { + if(up) + key_mod &= ~mask; + else + key_mod |= mask; + splx(s); + return; + } + + /* + * Stop repeating on up event + */ + if (up) { + if(tout_pending) { + untimeout(repeat_handler, 0); + tout_pending = 0; + last_char = 0; + } + splx(s); + return; + } + else if(tout_pending && last_char != c) { + /* + * Different character, stop also + */ + untimeout(repeat_handler, 0); + tout_pending = 0; + last_char = 0; + } + + /* + * Handle ite-switching ALT + Fx + */ + if((key_mod == KBD_MOD_ALT) && (c >= 0x3b) && (c <= 0x44)) { + ite_switch(c - 0x3b); + splx(s); + return; + } + /* + * Safety button, switch back to ascii keymap. + */ + if(key_mod == (KBD_MOD_ALT | KBD_MOD_LSHIFT) && c == 0x3b) { + /* ALT + LSHIFT + F1 */ + bcopy(&ascii_kbdmap, kbdmap, sizeof(struct kbdmap)); + splx(s); + return; +#ifdef DDB + } + else if(key_mod == (KBD_MOD_ALT | KBD_MOD_LSHIFT) && c == 0x43) { + /* ALT + LSHIFT + F9 */ + extern int Debugger(); + Debugger(); + splx(s); + return; +#endif + } + + /* + * The rest of the code is senseless when the device is not open. + */ + if(kbd_tty == NULL) { + splx(s); + return; + } + + /* + * Translate modifiers + */ + if(key_mod & KBD_MOD_SHIFT) { + if(key_mod & KBD_MOD_ALT) + key = kbdmap->alt_shift_keys[c]; + else key = kbdmap->shift_keys[c]; + } + else if(key_mod & KBD_MOD_ALT) + key = kbdmap->alt_keys[c]; + else { + key = kbdmap->keys[c]; + /* + * If CAPS and key is CAPable (no pun intended) + */ + if((key_mod & KBD_MOD_CAPS) && (key.mode & KBD_MODE_CAPS)) + key = kbdmap->shift_keys[c]; + } + code = key.code; + + /* + * Arrange to repeat the keystroke. By doing this at the level + * of scan-codes, we can have function keys, and keys that + * send strings, repeat too. This also entitles an additional + * overhead, since we have to do the conversion each time, but + * I guess that's ok. + */ + if(!tout_pending && caller == ITEFILT_TTY && kbd_ite->key_repeat) { + tout_pending = 1; + last_char = c; + timeout(repeat_handler, 0, start_repeat_timeo * hz / 100); + } + else if(!tout_pending && caller==ITEFILT_REPEATER + && kbd_ite->key_repeat) { + tout_pending = 1; + last_char = c; + timeout(repeat_handler, 0, next_repeat_timeo * hz / 100); + } + /* handle dead keys */ + if (key.mode & KBD_MODE_DEAD) { + /* if entered twice, send accent itself */ + if (last_dead == key.mode & KBD_MODE_ACCMASK) + last_dead = 0; + else { + last_dead = key.mode & KBD_MODE_ACCMASK; + splx(s); + return; + } + } + if (last_dead) { + /* can't apply dead flag to string-keys */ + if (!(key.mode & KBD_MODE_STRING) && code >= '@' && + code < 0x7f) + code = acctable[KBD_MODE_ACCENT(last_dead)][code - '@']; + last_dead = 0; + } + + /* + * If not string, apply CTRL modifiers + */ + if(!(key.mode & KBD_MODE_STRING) + && (!(key.mode & KBD_MODE_KPAD) + || (kbd_ite && !kbd_ite->keypad_appmode))) { + if(key_mod & KBD_MOD_CTRL) + code &= 0x1f; + } + else if((key.mode & KBD_MODE_KPAD) + && (kbd_ite && kbd_ite->keypad_appmode)) { + static char *in = "0123456789-+.\r()/*"; + static char *out = "pqrstuvwxymlnMPQRS"; + char *cp = index(in, code); + + /* + * keypad-appmode sends SS3 followed by the above + * translated character + */ + (*linesw[kbd_tty->t_line].l_rint) (27, kbd_tty); + (*linesw[kbd_tty->t_line].l_rint) ('O', kbd_tty); + (*linesw[kbd_tty->t_line].l_rint) (out[cp - in], kbd_tty); + splx(s); + return; + } else { + /* *NO* I don't like this.... */ + static u_char app_cursor[] = + { + 3, 27, 'O', 'A', + 3, 27, 'O', 'B', + 3, 27, 'O', 'C', + 3, 27, 'O', 'D'}; + + str = kbdmap->strings + code; + /* + * if this is a cursor key, AND it has the default + * keymap setting, AND we're in app-cursor mode, switch + * to the above table. This is *nasty* ! + */ + if(((c == 0x48) || (c == 0x4b) || (c == 0x4d) || (c == 0x50)) + && kbd_ite->cursor_appmode + && !bcmp(str, "\x03\x1b[", 3) && + index("ABCD", str[3])) + str = app_cursor + 4 * (str[3] - 'A'); + + /* + * using a length-byte instead of 0-termination allows + * to embed \0 into strings, although this is not used + * in the default keymap + */ + for (i = *str++; i; i--) + (*linesw[kbd_tty->t_line].l_rint) (*str++, kbd_tty); + splx(s); + return; + } + (*linesw[kbd_tty->t_line].l_rint) (code, kbd_tty); + + splx(s); + return; +} + +/* helper functions, makes the code below more readable */ +static void inline +ite_sendstr(str) + char *str; +{ + struct tty *kbd_tty; + + kbd_tty = kbd_ite->tp; + KDASSERT(kbd_tty); + while (*str) + (*linesw[kbd_tty->t_line].l_rint) (*str++, kbd_tty); +} + +static void +alignment_display(ip) + struct ite_softc *ip; +{ + int i, j; + + for (j = 0; j < ip->rows; j++) + for (i = 0; i < ip->cols; i++) + SUBR_PUTC(ip, 'E', j, i, ATTR_NOR); + attrclr(ip, 0, 0, ip->rows, ip->cols); + SUBR_CURSOR(ip, DRAW_CURSOR); +} + +static void inline +snap_cury(ip) + struct ite_softc *ip; +{ + if (ip->inside_margins) + { + if (ip->cury < ip->top_margin) + ip->cury = ip->top_margin; + if (ip->cury > ip->bottom_margin) + ip->cury = ip->bottom_margin; + } +} + +static void inline +ite_dnchar(ip, n) + struct ite_softc *ip; + int n; +{ + n = min(n, ip->cols - ip->curx); + if (n < ip->cols - ip->curx) + { + SUBR_SCROLL(ip, ip->cury, ip->curx + n, n, SCROLL_LEFT); + attrmov(ip, ip->cury, ip->curx + n, ip->cury, ip->curx, + 1, ip->cols - ip->curx - n); + attrclr(ip, ip->cury, ip->cols - n, 1, n); + } + while (n-- > 0) + SUBR_PUTC(ip, ' ', ip->cury, ip->cols - n - 1, ATTR_NOR); + SUBR_CURSOR(ip, DRAW_CURSOR); +} + +static void inline +ite_inchar(ip, n) + struct ite_softc *ip; + int n; +{ + n = min(n, ip->cols - ip->curx); + if (n < ip->cols - ip->curx) + { + SUBR_SCROLL(ip, ip->cury, ip->curx, n, SCROLL_RIGHT); + attrmov(ip, ip->cury, ip->curx, ip->cury, ip->curx + n, + 1, ip->cols - ip->curx - n); + attrclr(ip, ip->cury, ip->curx, 1, n); + } + while (n--) + SUBR_PUTC(ip, ' ', ip->cury, ip->curx + n, ATTR_NOR); + SUBR_CURSOR(ip, DRAW_CURSOR); +} + +static void inline +ite_clrtoeol(ip) + struct ite_softc *ip; +{ + int y = ip->cury, x = ip->curx; + if (ip->cols - x > 0) + { + SUBR_CLEAR(ip, y, x, 1, ip->cols - x); + attrclr(ip, y, x, 1, ip->cols - x); + SUBR_CURSOR(ip, DRAW_CURSOR); + } +} + +static void inline +ite_clrtobol(ip) + struct ite_softc *ip; +{ + int y = ip->cury, x = min(ip->curx + 1, ip->cols); + SUBR_CLEAR(ip, y, 0, 1, x); + attrclr(ip, y, 0, 1, x); + SUBR_CURSOR(ip, DRAW_CURSOR); +} + +static void inline +ite_clrline(ip) + struct ite_softc *ip; +{ + int y = ip->cury; + SUBR_CLEAR(ip, y, 0, 1, ip->cols); + attrclr(ip, y, 0, 1, ip->cols); + SUBR_CURSOR(ip, DRAW_CURSOR); +} + + + +static void inline +ite_clrtoeos(ip) + struct ite_softc *ip; +{ + ite_clrtoeol(ip); + if (ip->cury < ip->rows - 1) + { + SUBR_CLEAR(ip, ip->cury + 1, 0, ip->rows - 1 - ip->cury, ip->cols); + attrclr(ip, ip->cury, 0, ip->rows - ip->cury, ip->cols); + SUBR_CURSOR(ip, DRAW_CURSOR); + } +} + +static void inline +ite_clrtobos(ip) + struct ite_softc *ip; +{ + ite_clrtobol(ip); + if (ip->cury > 0) + { + SUBR_CLEAR(ip, 0, 0, ip->cury, ip->cols); + attrclr(ip, 0, 0, ip->cury, ip->cols); + SUBR_CURSOR(ip, DRAW_CURSOR); + } +} + +static void inline +ite_clrscreen(ip) + struct ite_softc *ip; +{ + SUBR_CLEAR(ip, 0, 0, ip->rows, ip->cols); + attrclr(ip, 0, 0, ip->rows, ip->cols); + SUBR_CURSOR(ip, DRAW_CURSOR); +} + + + +static void inline +ite_dnline(ip, n) + struct ite_softc *ip; + int n; +{ + /* interesting.. if the cursor is outside the scrolling + region, this command is simply ignored.. */ + if (ip->cury < ip->top_margin || ip->cury > ip->bottom_margin) + return; + + n = min(n, ip->bottom_margin + 1 - ip->cury); + if (n <= ip->bottom_margin - ip->cury) + { + SUBR_SCROLL(ip, ip->cury + n, 0, n, SCROLL_UP); + attrmov(ip, ip->cury + n, 0, ip->cury, 0, + ip->bottom_margin + 1 - ip->cury - n, ip->cols); + } + SUBR_CLEAR(ip, ip->bottom_margin - n + 1, 0, n, ip->cols); + attrclr(ip, ip->bottom_margin - n + 1, 0, n, ip->cols); + SUBR_CURSOR(ip, DRAW_CURSOR); +} + +static void inline +ite_inline(ip, n) + struct ite_softc *ip; + int n; +{ + /* interesting.. if the cursor is outside the scrolling + region, this command is simply ignored.. */ + if (ip->cury < ip->top_margin || ip->cury > ip->bottom_margin) + return; + + n = min(n, ip->bottom_margin + 1 - ip->cury); + if (n <= ip->bottom_margin - ip->cury) + { + SUBR_SCROLL(ip, ip->cury, 0, n, SCROLL_DOWN); + attrmov(ip, ip->cury, 0, ip->cury + n, 0, + ip->bottom_margin + 1 - ip->cury - n, ip->cols); + } + SUBR_CLEAR(ip, ip->cury, 0, n, ip->cols); + attrclr(ip, ip->cury, 0, n, ip->cols); + SUBR_CURSOR(ip, DRAW_CURSOR); +} + +static void inline +ite_lf (ip) + struct ite_softc *ip; +{ + ++ip->cury; + if ((ip->cury == ip->bottom_margin+1) || (ip->cury == ip->rows)) + { + ip->cury--; + SUBR_SCROLL(ip, ip->top_margin + 1, 0, 1, SCROLL_UP); + ite_clrline(ip); + } + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr(ip, ATTR_INV); +} + +static void inline +ite_crlf (ip) + struct ite_softc *ip; +{ + ip->curx = 0; + ite_lf (ip); +} + +static void inline +ite_cr (ip) + struct ite_softc *ip; +{ + if (ip->curx) + { + ip->curx = 0; + SUBR_CURSOR(ip, MOVE_CURSOR); + } +} + +static void inline +ite_rlf (ip) + struct ite_softc *ip; +{ + ip->cury--; + if ((ip->cury < 0) || (ip->cury == ip->top_margin - 1)) + { + ip->cury++; + SUBR_SCROLL(ip, ip->top_margin, 0, 1, SCROLL_DOWN); + ite_clrline(ip); + } + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr(ip, ATTR_INV); +} + +static int inline +atoi (cp) + const char *cp; +{ + int n; + + for (n = 0; *cp && *cp >= '0' && *cp <= '9'; cp++) + n = n * 10 + *cp - '0'; + + return n; +} + +static char * +index (cp, ch) + const char *cp; + int ch; +{ + while (*cp && *cp != ch) cp++; + return *cp ? (char *) cp : 0; +} + + + +static int inline +ite_argnum (ip) + struct ite_softc *ip; +{ + char ch; + int n; + + /* convert argument string into number */ + if (ip->ap == ip->argbuf) + return 1; + ch = *ip->ap; + *ip->ap = 0; + n = atoi (ip->argbuf); + *ip->ap = ch; + + return n; +} + +static int inline +ite_zargnum (ip) + struct ite_softc *ip; +{ + char ch, *cp; + int n; + + /* convert argument string into number */ + if (ip->ap == ip->argbuf) + return 0; + ch = *ip->ap; + *ip->ap = 0; + n = atoi (ip->argbuf); + *ip->ap = ch; + + return n; /* don't "n ? n : 1" here, <CSI>0m != <CSI>1m ! */ +} + +static int inline +strncmp (a, b, l) + const char *a, *b; + int l; +{ + for (;l--; a++, b++) + if (*a != *b) + return *a - *b; + return 0; +} + +void +ite_putstr(s, len, dev) + const u_char *s; + int len; + dev_t dev; +{ + struct ite_softc *ip; + int i; + + ip = getitesp(dev); + + /* XXX avoid problems */ + if ((ip->flags & (ITE_ACTIVE|ITE_INGRF)) != ITE_ACTIVE) + return; + + SUBR_CURSOR(ip, START_CURSOROPT); + for (i = 0; i < len; i++) + if (s[i]) + iteputchar(s[i], ip); + SUBR_CURSOR(ip, END_CURSOROPT); +} + + +void +iteputchar(c, ip) + register int c; + struct ite_softc *ip; +{ + struct tty *kbd_tty; + int n, x, y; + char *cp; + + if (kbd_ite == NULL) + kbd_tty = NULL; + else + kbd_tty = kbd_ite->tp; + + if (ip->escape) + { +doesc: + switch (ip->escape) + { + case ESC: + switch (c) + { + /* first 7bit equivalents for the 8bit control characters */ + + case 'D': + c = IND; + ip->escape = 0; + break; /* and fall into the next switch below (same for all `break') */ + + case 'E': + c = NEL; + ip->escape = 0; + break; + + case 'H': + c = HTS; + ip->escape = 0; + break; + + case 'M': + c = RI; + ip->escape = 0; + break; + + case 'N': + c = SS2; + ip->escape = 0; + break; + + case 'O': + c = SS3; + ip->escape = 0; + break; + + case 'P': + c = DCS; + ip->escape = 0; + break; + + case '[': + c = CSI; + ip->escape = 0; + break; + + case '\\': + c = ST; + ip->escape = 0; + break; + + case ']': + c = OSC; + ip->escape = 0; + break; + + case '^': + c = PM; + ip->escape = 0; + break; + + case '_': + c = APC; + ip->escape = 0; + break; + + + /* introduces 7/8bit control */ + case ' ': + /* can be followed by either F or G */ + ip->escape = ' '; + break; + + + /* a lot of character set selections, not yet used... + 94-character sets: */ + case '(': /* G0 */ + case ')': /* G1 */ + ip->escape = c; + return; + + case '*': /* G2 */ + case '+': /* G3 */ + case 'B': /* ASCII */ + case 'A': /* ISO latin 1 */ + case '<': /* user preferred suplemental */ + case '0': /* dec special graphics */ + + /* 96-character sets: */ + case '-': /* G1 */ + case '.': /* G2 */ + case '/': /* G3 */ + + /* national character sets: */ + case '4': /* dutch */ + case '5': + case 'C': /* finnish */ + case 'R': /* french */ + case 'Q': /* french canadian */ + case 'K': /* german */ + case 'Y': /* italian */ + case '6': /* norwegian/danish */ + /* note: %5 and %6 are not supported (two chars..) */ + + ip->escape = 0; + /* just ignore for now */ + return; + + + /* locking shift modes (as you might guess, not yet supported..) */ + case '`': + ip->GR = ip->G1; + ip->escape = 0; + return; + + case 'n': + ip->GL = ip->G2; + ip->escape = 0; + return; + + case '}': + ip->GR = ip->G2; + ip->escape = 0; + return; + + case 'o': + ip->GL = ip->G3; + ip->escape = 0; + return; + + case '|': + ip->GR = ip->G3; + ip->escape = 0; + return; + + + /* font width/height control */ + case '#': + ip->escape = '#'; + return; + + + /* hard terminal reset .. */ + case 'c': + ite_reset (ip); + SUBR_CURSOR(ip, MOVE_CURSOR); + ip->escape = 0; + return; + + + case '7': + ip->save_curx = ip->curx; + ip->save_cury = ip->cury; + ip->save_attribute = ip->attribute; + ip->escape = 0; + return; + + case '8': + ip->curx = ip->save_curx; + ip->cury = ip->save_cury; + ip->attribute = ip->save_attribute; + SUBR_CURSOR(ip, MOVE_CURSOR); + ip->escape = 0; + return; + + case '=': + ip->keypad_appmode = 1; + ip->escape = 0; + return; + + case '>': + ip->keypad_appmode = 0; + ip->escape = 0; + return; + + case 'Z': /* request ID */ + if (ip->emul_level == EMUL_VT100) + ite_sendstr ("\033[?61;0c"); /* XXX not clean */ + else + ite_sendstr ("\033[?63;0c"); /* XXX not clean */ + ip->escape = 0; + return; + + /* default catch all for not recognized ESC sequences */ + default: + ip->escape = 0; + return; + } + break; + + + case '(': + case ')': + ip->escape = 0; + return; + + + case ' ': + switch (c) + { + case 'F': + ip->eightbit_C1 = 0; + ip->escape = 0; + return; + + case 'G': + ip->eightbit_C1 = 1; + ip->escape = 0; + return; + + default: + /* not supported */ + ip->escape = 0; + return; + } + break; + + + case '#': + switch (c) + { + case '5': + /* single height, single width */ + ip->escape = 0; + return; + + case '6': + /* double width, single height */ + ip->escape = 0; + return; + + case '3': + /* top half */ + ip->escape = 0; + return; + + case '4': + /* bottom half */ + ip->escape = 0; + return; + + case '8': + /* screen alignment pattern... */ + alignment_display (ip); + ip->escape = 0; + return; + + default: + ip->escape = 0; + return; + } + break; + + + + case CSI: + /* the biggie... */ + switch (c) + { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case ';': case '\"': case '$': case '>': + if (ip->ap < ip->argbuf + MAX_ARGSIZE) + *ip->ap++ = c; + return; + + case BS: + /* you wouldn't believe such perversion is possible? + it is.. BS is allowed in between cursor sequences + (at least), according to vttest.. */ + if (--ip->curx < 0) + ip->curx = 0; + else + SUBR_CURSOR(ip, MOVE_CURSOR); + break; + + case 'p': + *ip->ap = 0; + if (! strncmp (ip->argbuf, "61\"", 3)) + ip->emul_level = EMUL_VT100; + else if (! strncmp (ip->argbuf, "63;1\"", 5) + || ! strncmp (ip->argbuf, "62;1\"", 5)) + ip->emul_level = EMUL_VT300_7; + else + ip->emul_level = EMUL_VT300_8; + ip->escape = 0; + return; + + + case '?': + *ip->ap = 0; + ip->escape = '?'; + ip->ap = ip->argbuf; + return; + + + case 'c': + *ip->ap = 0; + if (ip->argbuf[0] == '>') + { + ite_sendstr ("\033[>24;0;0;0c"); + } + else switch (ite_zargnum(ip)) + { + case 0: + /* primary DA request, send primary DA response */ + if (ip->emul_level == EMUL_VT100) + ite_sendstr ("\033[?1;1c"); + else + ite_sendstr ("\033[?63;1c"); + break; + } + ip->escape = 0; + return; + + case 'n': + switch (ite_zargnum(ip)) + { + case 5: + ite_sendstr ("\033[0n"); /* no malfunction */ + break; + case 6: + /* cursor position report */ + sprintf (ip->argbuf, "\033[%d;%dR", + ip->cury + 1, ip->curx + 1); + ite_sendstr (ip->argbuf); + break; + } + ip->escape = 0; + return; + + + case 'x': + switch (ite_zargnum(ip)) + { + case 0: + /* Fake some terminal parameters. */ + ite_sendstr ("\033[2;1;1;112;112;1;0x"); + break; + case 1: + ite_sendstr ("\033[3;1;1;112;112;1;0x"); + break; + } + ip->escape = 0; + return; + + + case 'g': + switch (ite_zargnum(ip)) + { + case 0: + if (ip->curx < ip->cols) + ip->tabs[ip->curx] = 0; + break; + case 3: + for (n = 0; n < ip->cols; n++) + ip->tabs[n] = 0; + break; + } + ip->escape = 0; + return; + + + case 'h': case 'l': + n = ite_zargnum (ip); + switch (n) + { + case 4: + ip->imode = (c == 'h'); /* insert/replace mode */ + break; + case 20: + ip->linefeed_newline = (c == 'h'); + break; + } + ip->escape = 0; + return; + + + case 'M': + ite_dnline (ip, ite_argnum (ip)); + ip->escape = 0; + return; + + + case 'L': + ite_inline (ip, ite_argnum (ip)); + ip->escape = 0; + return; + + + case 'P': + ite_dnchar (ip, ite_argnum (ip)); + ip->escape = 0; + return; + + + case '@': + ite_inchar (ip, ite_argnum (ip)); + ip->escape = 0; + return; + + + case 'G': + /* this one was *not* in my vt320 manual but in + a vt320 termcap entry.. who is right? + It's supposed to set the horizontal cursor position. */ + *ip->ap = 0; + x = atoi (ip->argbuf); + if (x) x--; + ip->curx = min(x, ip->cols - 1); + ip->escape = 0; + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr (ip, ATTR_INV); + return; + + + case 'd': + /* same thing here, this one's for setting the absolute + vertical cursor position. Not documented... */ + *ip->ap = 0; + y = atoi (ip->argbuf); + if (y) y--; + if (ip->inside_margins) + y += ip->top_margin; + ip->cury = min(y, ip->rows - 1); + ip->escape = 0; + snap_cury(ip); + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr (ip, ATTR_INV); + return; + + + case 'H': + case 'f': + *ip->ap = 0; + y = atoi (ip->argbuf); + x = 0; + cp = index (ip->argbuf, ';'); + if (cp) + x = atoi (cp + 1); + if (x) x--; + if (y) y--; + if (ip->inside_margins) + y += ip->top_margin; + ip->cury = min(y, ip->rows - 1); + ip->curx = min(x, ip->cols - 1); + ip->escape = 0; + snap_cury(ip); + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr (ip, ATTR_INV); + return; + + case 'A': + n = ite_argnum (ip); + n = ip->cury - (n ? n : 1); + if (n < 0) n = 0; + if (ip->inside_margins) + n = max(ip->top_margin, n); + else if (n == ip->top_margin - 1) + /* allow scrolling outside region, but don't scroll out + of active region without explicit CUP */ + n = ip->top_margin; + ip->cury = n; + ip->escape = 0; + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr (ip, ATTR_INV); + return; + + case 'B': + n = ite_argnum (ip); + n = ip->cury + (n ? n : 1); + n = min(ip->rows - 1, n); + if (ip->inside_margins) + n = min(ip->bottom_margin, n); + else if (n == ip->bottom_margin + 1) + /* allow scrolling outside region, but don't scroll out + of active region without explicit CUP */ + n = ip->bottom_margin; + ip->cury = n; + ip->escape = 0; + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr (ip, ATTR_INV); + return; + + case 'C': + n = ite_argnum (ip); + n = n ? n : 1; + ip->curx = min(ip->curx + n, ip->cols - 1); + ip->escape = 0; + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr (ip, ATTR_INV); + return; + + case 'D': + n = ite_argnum (ip); + n = n ? n : 1; + n = ip->curx - n; + ip->curx = n >= 0 ? n : 0; + ip->escape = 0; + SUBR_CURSOR(ip, MOVE_CURSOR); + clr_attr (ip, ATTR_INV); + return; + + + + + case 'J': + *ip->ap = 0; + n = ite_zargnum (ip); + if (n == 0) + ite_clrtoeos(ip); + else if (n == 1) + ite_clrtobos(ip); + else if (n == 2) + ite_clrscreen(ip); + ip->escape = 0; + return; + + + case 'K': + n = ite_zargnum (ip); + if (n == 0) + ite_clrtoeol(ip); + else if (n == 1) + ite_clrtobol(ip); + else if (n == 2) + ite_clrline(ip); + ip->escape = 0; + return; + + + case 'X': + n = ite_argnum(ip) - 1; + n = min(n, ip->cols - 1 - ip->curx); + for (; n >= 0; n--) + { + attrclr(ip, ip->cury, ip->curx + n, 1, 1); + SUBR_PUTC(ip, ' ', ip->cury, ip->curx + n, ATTR_NOR); + } + ip->escape = 0; + return; + + + case '}': case '`': + /* status line control */ + ip->escape = 0; + return; + + + case 'r': + *ip->ap = 0; + x = atoi (ip->argbuf); + x = x ? x : 1; + y = ip->rows; + cp = index (ip->argbuf, ';'); + if (cp) + { + y = atoi (cp + 1); + y = y ? y : ip->rows; + } + if (y - x < 2) + { + /* if illegal scrolling region, reset to defaults */ + x = 1; + y = ip->rows; + } + x--; + y--; + ip->top_margin = min(x, ip->rows - 1); + ip->bottom_margin = min(y, ip->rows - 1); + if (ip->inside_margins) + { + ip->cury = ip->top_margin; + ip->curx = 0; + SUBR_CURSOR(ip, MOVE_CURSOR); + } + ip->escape = 0; + return; + + + case 'm': + /* big attribute setter/resetter */ + { + char *cp; + *ip->ap = 0; + /* kludge to make CSIm work (== CSI0m) */ + if (ip->ap == ip->argbuf) + ip->ap++; + for (cp = ip->argbuf; cp < ip->ap; ) + { + switch (*cp) + { + case 0: + case '0': + clr_attr (ip, ATTR_ALL); + cp++; + break; + + case '1': + set_attr (ip, ATTR_BOLD); + cp++; + break; + + case '2': + switch (cp[1]) + { + case '2': + clr_attr (ip, ATTR_BOLD); + cp += 2; + break; + + case '4': + clr_attr (ip, ATTR_UL); + cp += 2; + break; + + case '5': + clr_attr (ip, ATTR_BLINK); + cp += 2; + break; + + case '7': + clr_attr (ip, ATTR_INV); + cp += 2; + break; + + default: + cp++; + break; + } + break; + + case '4': + set_attr (ip, ATTR_UL); + cp++; + break; + + case '5': + set_attr (ip, ATTR_BLINK); + cp++; + break; + + case '7': + set_attr (ip, ATTR_INV); + cp++; + break; + + default: + cp++; + break; + } + } + + } + ip->escape = 0; + return; + + + case 'u': + /* DECRQTSR */ + ite_sendstr ("\033P\033\\"); + ip->escape = 0; + return; + + + + default: + ip->escape = 0; + return; + } + break; + + + + case '?': /* CSI ? */ + switch (c) + { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case ';': case '\"': case '$': + /* Don't fill the last character; it's needed. */ + /* XXX yeah, where ?? */ + if (ip->ap < ip->argbuf + MAX_ARGSIZE - 1) + *ip->ap++ = c; + return; + + + case 'n': + *ip->ap = 0; + if (ip->ap == &ip->argbuf[2]) + { + if (! strncmp (ip->argbuf, "15", 2)) + /* printer status: no printer */ + ite_sendstr ("\033[13n"); + + else if (! strncmp (ip->argbuf, "25", 2)) + /* udk status */ + ite_sendstr ("\033[20n"); + + else if (! strncmp (ip->argbuf, "26", 2)) + /* keyboard dialect: US */ + ite_sendstr ("\033[27;1n"); + } + ip->escape = 0; + return; + + + case 'h': case 'l': + n = ite_zargnum (ip); + switch (n) + { + case 1: + ip->cursor_appmode = (c == 'h'); + break; + + case 3: + /* 132/80 columns (132 == 'h') */ + break; + + case 4: /* smooth scroll */ + break; + + case 5: + /* light background (=='h') /dark background(=='l') */ + break; + + case 6: /* origin mode */ + ip->inside_margins = (c == 'h'); + ip->curx = 0; + ip->cury = ip->inside_margins ? ip->top_margin : 0; + SUBR_CURSOR(ip, MOVE_CURSOR); + break; + + case 7: /* auto wraparound */ + ip->auto_wrap = (c == 'h'); + break; + + case 8: /* keyboard repeat */ + ip->key_repeat = (c == 'h'); + break; + + case 20: /* newline mode */ + ip->linefeed_newline = (c == 'h'); + break; + + case 25: /* cursor on/off */ + SUBR_CURSOR(ip, (c == 'h') ? DRAW_CURSOR : ERASE_CURSOR); + break; + } + ip->escape = 0; + return; + + default: + ip->escape = 0; + return; + } + break; + + + default: + ip->escape = 0; + return; + } + } + + switch (c) { + + case VT: /* VT is treated like LF */ + case FF: /* so is FF */ + case LF: + /* cr->crlf distinction is done here, on output, + not on input! */ + if (ip->linefeed_newline) + ite_crlf (ip); + else + ite_lf (ip); + break; + + case CR: + ite_cr (ip); + break; + + case BS: + if (--ip->curx < 0) + ip->curx = 0; + else + SUBR_CURSOR(ip, MOVE_CURSOR); + break; + + case HT: + for (n = ip->curx + 1; n < ip->cols; n++) { + if (ip->tabs[n]) { + ip->curx = n; + SUBR_CURSOR(ip, MOVE_CURSOR); + break; + } + } + break; + + case BEL: + if(kbd_tty && kbd_ite && kbd_ite->tp == kbd_tty) + kbdbell(); + break; + + case SO: + ip->GL = ip->G1; + break; + + case SI: + ip->GL = ip->G0; + break; + + case ENQ: + /* send answer-back message !! */ + break; + + case CAN: + ip->escape = 0; /* cancel any escape sequence in progress */ + break; + + case SUB: + ip->escape = 0; /* dito, but see below */ + /* should also display a reverse question mark!! */ + break; + + case ESC: + ip->escape = ESC; + break; + + + /* now it gets weird.. 8bit control sequences.. */ + case IND: /* index: move cursor down, scroll */ + ite_lf (ip); + break; + + case NEL: /* next line. next line, first pos. */ + ite_crlf (ip); + break; + + case HTS: /* set horizontal tab */ + if (ip->curx < ip->cols) + ip->tabs[ip->curx] = 1; + break; + + case RI: /* reverse index */ + ite_rlf (ip); + break; + + case SS2: /* go into G2 for one character */ + /* not yet supported */ + break; + + case SS3: /* go into G3 for one character */ + break; + + case DCS: /* device control string introducer */ + ip->escape = DCS; + ip->ap = ip->argbuf; + break; + + case CSI: /* control sequence introducer */ + ip->escape = CSI; + ip->ap = ip->argbuf; + break; + + case ST: /* string terminator */ + /* ignore, if not used as terminator */ + break; + + case OSC: /* introduces OS command. Ignore everything upto ST */ + ip->escape = OSC; + break; + + case PM: /* privacy message, ignore everything upto ST */ + ip->escape = PM; + break; + + case APC: /* application program command, ignore everything upto ST */ + ip->escape = APC; + break; + + default: + if (c < ' ' || c == DEL) + break; + if (ip->imode) + ite_inchar(ip, 1); + iteprecheckwrap(ip); +#ifdef DO_WEIRD_ATTRIBUTES + if ((ip->attribute & ATTR_INV) || attrtest(ip, ATTR_INV)) { + attrset(ip, ATTR_INV); + SUBR_PUTC(ip, c, ip->cury, ip->curx, ATTR_INV); + } + else + SUBR_PUTC(ip, c, ip->cury, ip->curx, ATTR_NOR); +#else + SUBR_PUTC(ip, c, ip->cury, ip->curx, ip->attribute); +#endif + SUBR_CURSOR(ip, DRAW_CURSOR); + itecheckwrap(ip); + break; + } +} + +iteprecheckwrap(ip) + struct ite_softc *ip; +{ + if (ip->auto_wrap && ip->curx == ip->cols) { + ip->curx = 0; + clr_attr(ip, ATTR_INV); + if (++ip->cury >= ip->bottom_margin + 1) { + ip->cury = ip->bottom_margin; + SUBR_CURSOR(ip, MOVE_CURSOR); + SUBR_SCROLL(ip, ip->top_margin + 1, 0, 1, SCROLL_UP); + ite_clrtoeol(ip); + } else + SUBR_CURSOR(ip, MOVE_CURSOR); + } +} + +itecheckwrap(ip) + struct ite_softc *ip; +{ + if (ip->curx < ip->cols) { + ip->curx++; + SUBR_CURSOR(ip, MOVE_CURSOR); + } +} diff --git a/sys/arch/atari/dev/ite_cc.c b/sys/arch/atari/dev/ite_cc.c new file mode 100644 index 00000000000..676c499e061 --- /dev/null +++ b/sys/arch/atari/dev/ite_cc.c @@ -0,0 +1,671 @@ +/* $NetBSD: ite_cc.c,v 1.4 1995/05/28 19:45:39 leo Exp $ */ + +/* + * Copyright (c) 1994 Christian E. Hopps + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christian E. Hopps. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include "grf.h" +#if NGRF > 0 + +#include <sys/param.h> +#include <sys/conf.h> +#include <sys/proc.h> +#include <sys/device.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +#include <sys/systm.h> +#include <sys/queue.h> +#include <sys/termios.h> +#include <sys/malloc.h> +#include <dev/cons.h> +#include <machine/cpu.h> +#include <atari/dev/itevar.h> +#include <atari/dev/iteioctl.h> +#include <atari/dev/grfioctl.h> +#include <atari/dev/grfabs_reg.h> +#include <atari/dev/grfvar.h> +#include <atari/dev/font.h> +#include <atari/dev/viewioctl.h> +#include <atari/dev/viewvar.h> + +/* + * This is what ip->priv points to; + * it contains local variables for custom-chip ites. + */ +struct ite_priv { + u_char **row_ptr; /* array of pointers into the bitmap */ + u_long row_bytes; + u_long cursor_opt; + u_short *column_offset; /* array of offsets for columns */ + u_int row_offset; /* the row offset */ + u_short width; /* the bitmap width */ + u_short underline; /* where the underline goes */ + u_short ft_x; /* the font width */ + u_short ft_y; /* the font height */ + u_char *font_cell[256];/* the font pointer */ +}; +typedef struct ite_priv ipriv_t; + +/* + * We need the following space to get an ite-console setup before + * the VM-system is brought up. We setup for a 1280x960 monitor with + * an 8x8 font. + */ +extern int atari_realconfig; + +#define CONS_MAXROW 120 /* Max. number of rows on console */ +#define CONS_MAXCOL 160 /* Max. number of columns on console */ +static u_short con_columns[CONS_MAXCOL]; +static u_char *con_rows[CONS_MAXROW]; +static ipriv_t con_ipriv; + +extern font_info font_info_8x8; +extern font_info font_info_8x16; + +static void view_init __P((struct ite_softc *)); +static void view_deinit __P((struct ite_softc *)); +static int ite_newsize __P((struct ite_softc *, struct itewinsize *)); +static void cursor32 __P((struct ite_softc *, int)); +static void putc8 __P((struct ite_softc *, int, int, int, int)); +static void clear8 __P((struct ite_softc *, int, int, int, int)); +static void scroll8 __P((struct ite_softc *, int, int, int, int)); +static void scrollbmap __P((bmap_t *, u_short, u_short, u_short, u_short, + short, short)); + +/* + * Patchable + */ +int ite_default_x = 0; /* def leftedge offset */ +int ite_default_y = 0; /* def topedge offset */ +int ite_default_width = 640; /* def width */ +int ite_default_depth = 1; /* def depth */ +int ite_default_height = 400; /* def height */ + +/* + * called from grf_cc to return console priority + */ +int +grfcc_cnprobe() +{ + return(CN_INTERNAL); +} +/* + * called from grf_cc to init ite portion of + * grf_softc struct + */ +void +grfcc_iteinit(gp) +struct grf_softc *gp; +{ + + gp->g_itecursor = cursor32; + gp->g_iteputc = putc8; + gp->g_iteclear = clear8; + gp->g_itescroll = scroll8; + gp->g_iteinit = view_init; + gp->g_itedeinit = view_deinit; +} + +static void +view_deinit(ip) +struct ite_softc *ip; +{ + ip->flags &= ~ITE_INITED; +} + +static void +view_init(ip) +register struct ite_softc *ip; +{ + struct itewinsize wsz; + ipriv_t *cci; + + if(cci = ip->priv) + return; + +#if defined(KFONT_8X8) + ip->font = font_info_8x8; +#else + ip->font = font_info_8x16; +#endif + + /* Find the correct set of rendering routines for this font. */ + if(ip->font.width != 8) + panic("kernel font size not supported"); + + if(!atari_realconfig) + ip->priv = cci = &con_ipriv; + else ip->priv = cci = (ipriv_t*)malloc(sizeof(*cci), M_DEVBUF,M_WAITOK); + if(cci == NULL) + panic("No memory for ite-view"); + bzero(cci, sizeof(*cci)); + + cci->cursor_opt = 0; + cci->row_ptr = NULL; + cci->column_offset = NULL; + + wsz.x = ite_default_x; + wsz.y = ite_default_y; + wsz.width = ite_default_width; + wsz.height = ite_default_height; + wsz.depth = ite_default_depth; + + ite_newsize (ip, &wsz); + + /* + * Only console will be turned on by default.. + */ + if(ip->flags & ITE_ISCONS) + ip->grf->g_mode(ip->grf, GM_GRFON, NULL, 0, 0); +} + +static int +ite_newsize(ip, winsz) +struct ite_softc *ip; +struct itewinsize *winsz; +{ + struct view_size vs; + ipriv_t *cci = ip->priv; + u_long fbp, i, j; + int error = 0; + view_t *view; + + vs.x = winsz->x; + vs.y = winsz->y; + vs.width = winsz->width; + vs.height = winsz->height; + vs.depth = winsz->depth; + + error = viewioctl(ip->grf->g_viewdev, VIOCSSIZE, &vs, 0, -1); + view = viewview(ip->grf->g_viewdev); + + /* + * Reinitialize our structs + */ + ip->cols = view->display.width / ip->font.width; + ip->rows = view->display.height / ip->font.height; + + /* + * save new values so that future opens use them + * this may not be correct when we implement Virtual Consoles + */ + ite_default_height = view->display.height; + ite_default_width = view->display.width; + ite_default_x = view->display.x; + ite_default_y = view->display.y; + ite_default_depth = view->bitmap->depth; + + if(cci->row_ptr && (cci->row_ptr != con_rows)) { + free(cci->row_ptr, M_DEVBUF); + cci->row_ptr = NULL; + } + if(cci->column_offset && (cci->column_offset != con_columns)) { + free(cci->column_offset, M_DEVBUF); + cci->column_offset = NULL; + } + + if(!atari_realconfig) { + cci->row_ptr = con_rows; + cci->column_offset = con_columns; + } + else { + cci->row_ptr = malloc(sizeof(u_char *) * ip->rows,M_DEVBUF,M_NOWAIT); + cci->column_offset = malloc(sizeof(u_int)*ip->cols,M_DEVBUF,M_NOWAIT); + } + + if(!cci->row_ptr || !cci->column_offset) + panic("No memory for ite-view"); + + cci->width = view->bitmap->bytes_per_row << 3; + cci->underline = ip->font.baseline + 1; + cci->row_offset = view->bitmap->bytes_per_row; + cci->ft_x = ip->font.width; + cci->ft_y = ip->font.height; + cci->row_bytes = cci->row_offset * cci->ft_y; + cci->row_ptr[0] = view->bitmap->plane; + for(i = 1; i < ip->rows; i++) + cci->row_ptr[i] = cci->row_ptr[i-1] + cci->row_bytes; + + /* + * Initialize the column offsets to point at the correct location + * in the first plane. This definitely assumes a font width of 8! + */ + j = view->bitmap->depth * 2; + cci->column_offset[0] = 0; + for(i = 1; i < ip->cols; i++) + cci->column_offset[i] = ((i >> 1) * j) + (i & 1); + + /* initialize the font cell pointers */ + cci->font_cell[ip->font.font_lo] = ip->font.font_p; + for(i = ip->font.font_lo+1; i <= ip->font.font_hi; i++) + cci->font_cell[i] = cci->font_cell[i-1] + ip->font.height; + + return(error); +} + +int +ite_grf_ioctl(ip, cmd, addr, flag, p) +struct ite_softc *ip; +u_long cmd; +caddr_t addr; +int flag; +struct proc *p; +{ + struct winsize ws; + struct itewinsize *is; + struct itebell *ib; + int error = 0; + ipriv_t *cci = ip->priv; + view_t *view = viewview(ip->grf->g_viewdev); + + switch (cmd) { + case ITEIOCGWINSZ: + is = (struct itewinsize *)addr; + is->x = view->display.x; + is->y = view->display.y; + is->width = view->display.width; + is->height = view->display.height; + is->depth = view->bitmap->depth; + break; + case ITEIOCSWINSZ: + is = (struct itewinsize *)addr; + + if(ite_newsize(ip, is)) + error = ENOMEM; + else { + view = viewview(ip->grf->g_viewdev); + ws.ws_row = ip->rows; + ws.ws_col = ip->cols; + ws.ws_xpixel = view->display.width; + ws.ws_ypixel = view->display.height; + ite_reset(ip); + /* + * XXX tell tty about the change + * XXX this is messy, but works + */ + iteioctl(ip->grf->g_itedev,TIOCSWINSZ,(caddr_t)&ws,0,p); + } + break; + case ITEIOCDSPWIN: + ip->grf->g_mode(ip->grf, GM_GRFON, NULL, 0, 0); + break; + case ITEIOCREMWIN: + ip->grf->g_mode(ip->grf, GM_GRFOFF, NULL, 0, 0); + break; + case ITEIOCGBELL: +#if 0 /* LWP */ + /* XXX This won't work now */ + /* XXX Should the bell be device dependent? */ + ib = (struct itebell *)addr; + ib->volume = bvolume; + ib->pitch = bpitch; + ib->msec = bmsec; +#endif + break; + case ITEIOCSBELL: +#if 0 /* LWP */ + /* XXX See above */ + ib = (struct itebell *)addr; + /* bounds check */ + if(ib->pitch > MAXBPITCH || ib->pitch < MINBPITCH || + ib->volume > MAXBVOLUME || ib->msec > MAXBTIME) + error = EINVAL; + else { + bvolume = ib->volume; + bpitch = ib->pitch; + bmsec = ib->msec; + } +#endif + break; + case VIOCSCMAP: + case VIOCGCMAP: + /* + * XXX watchout for that -1 its not really the kernel talking + * XXX these two commands don't use the proc pointer though + */ + error = viewioctl(ip->grf->g_viewdev, cmd, addr, flag, -1); + break; + default: + error = -1; + break; + } + return (error); +} + +static void +cursor32(struct ite_softc *ip, int flag) +{ + int cend; + u_char *pl; + ipriv_t *cci; + + cci = ip->priv; + + if(flag == END_CURSOROPT) + cci->cursor_opt--; + else if(flag == START_CURSOROPT) { + if(!cci->cursor_opt) + cursor32(ip, ERASE_CURSOR); + cci->cursor_opt++; + return; /* if we are already opted. */ + } + + if(cci->cursor_opt) + return; /* if we are still nested. */ + /* else we draw the cursor. */ + + if(flag != DRAW_CURSOR && flag != END_CURSOROPT) { + /* + * erase the cursor + */ + cend = ip->font.height-1; + pl = cci->column_offset[ip->cursorx] + + cci->row_ptr[ip->cursory]; + __asm__ __volatile__ + ("1: notb %0@ ; addaw %4,%0\n\t" + "dbra %1,1b" + : "=a" (pl), "=d" (cend) + : "0" (pl), "1" (cend), + "d" (cci->row_offset) + ); + } + + if(flag != DRAW_CURSOR && flag != MOVE_CURSOR && flag != END_CURSOROPT) + return; + + /* + * draw the cursor + */ + ip->cursorx = min(ip->curx, ip->cols-1); + ip->cursory = ip->cury; + cend = ip->font.height-1; + pl = cci->column_offset[ip->cursorx] + + cci->row_ptr[ip->cursory]; + + __asm__ __volatile__ + ("1: notb %0@ ; addaw %4,%0\n\t" + "dbra %1,1b" + : "=a" (pl), "=d" (cend) + : "0" (pl), "1" (cend), + "d" (cci->row_offset) + ); +} + +static void +putc8(struct ite_softc *ip, int c, int dy, int dx, int mode) +{ + register ipriv_t *cci = (ipriv_t *)ip->priv; + register u_char *pl = cci->column_offset[dx] + cci->row_ptr[dy]; + register u_int fh = cci->ft_y; + register u_int ro = cci->row_offset; + register u_char eor_mask; + register u_char bl, tmp, ul; + register u_char *ft; + + if(c < ip->font.font_lo || c > ip->font.font_hi) + return; + + ft = cci->font_cell[c]; + + if(!mode) { + while(fh--) { + *pl = *ft++; pl += ro; + } + return; + } + + eor_mask = (mode & ATTR_INV) ? 0xff : 0x00; + bl = (mode & ATTR_BOLD) ? 1 : 0; + ul = (mode & ATTR_UL) ? fh - cci->underline : fh; + for(; fh--; pl += ro) { + if(fh != ul) { + tmp = *ft++; + if(bl) + tmp |= (tmp >> 1); + *pl = tmp ^ eor_mask; + } + else { + *pl = 0xff ^ eor_mask; + ft++; + } + } +} + +static void +clear8(struct ite_softc *ip, int sy, int sx, int h, int w) +{ + ipriv_t *cci = (ipriv_t *) ip->priv; + view_t *v = viewview(ip->grf->g_viewdev); + bmap_t *bm = v->bitmap; + + if((sx == 0) && (w == ip->cols)) { + /* common case: clearing whole lines */ + while (h--) { + int i; + u_char *ptr = cci->row_ptr[sy]; + for(i = 0; i < ip->font.height; i++) { + bzero(ptr, bm->bytes_per_row); + ptr += bm->bytes_per_row; + } + sy++; + } + } + else { + /* + * clearing only part of a line + * XXX could be optimized MUCH better, but is it worth the + * trouble? + */ + + int i; + u_char *pls, *ple; + + pls = cci->row_ptr[sy]; + ple = pls + cci->column_offset[sx + w-1]; + pls = pls + cci->column_offset[sx]; + + for(i = ((ip->font.height) * h)-1; i >= 0; i--) { + u_char *p = pls; + while(p <= ple) + *p++ = 0; + pls += bm->bytes_per_row; + ple += bm->bytes_per_row; + } + } +} + +/* Note: sx is only relevant for SCROLL_LEFT or SCROLL_RIGHT. */ +static void +scroll8(ip, sy, sx, count, dir) +register struct ite_softc *ip; +register int sy; +int dir, sx, count; +{ + bmap_t *bm = viewview(ip->grf->g_viewdev)->bitmap; + u_char *pl = ((ipriv_t *)ip->priv)->row_ptr[sy]; + + if(dir == SCROLL_UP) { + int dy = sy - count; + int height = ip->bottom_margin - sy + 1; + int i; + + cursor32(ip, ERASE_CURSOR); + scrollbmap(bm, 0, dy*ip->font.height, bm->bytes_per_row >> 3, + (ip->bottom_margin-dy+1)*ip->font.height, + 0, -(count*ip->font.height)); + } + else if(dir == SCROLL_DOWN) { + int dy = sy + count; + int height = ip->bottom_margin - dy + 1; + int i; + + cursor32(ip, ERASE_CURSOR); + scrollbmap(bm, 0, sy*ip->font.height, bm->bytes_per_row >> 3, + (ip->bottom_margin-sy+1)*ip->font.height, + 0, count*ip->font.height); + } + else if(dir == SCROLL_RIGHT) { + int sofs = (ip->cols - count) * ip->font.width; + int dofs = (ip->cols) * ip->font.width; + int i, j; + + cursor32(ip, ERASE_CURSOR); + for(j = ip->font.height-1; j >= 0; j--) { + int sofs2 = sofs, dofs2 = dofs; + for (i = (ip->cols - (sx + count))-1; i >= 0; i--) { + int t; + sofs2 -= ip->font.width; + dofs2 -= ip->font.width; + asm("bfextu %1@{%2:%3},%0" : "=d" (t) + : "a" (pl), "d" (sofs2), "d" (ip->font.width)); + asm("bfins %3,%0@{%1:%2}" : + : "a" (pl), "d" (dofs2), "d" (ip->font.width), + "d" (t)); + } + pl += bm->bytes_per_row; + } + } + else { /* SCROLL_LEFT */ + int sofs = (sx) * ip->font.width; + int dofs = (sx - count) * ip->font.width; + int i, j; + + cursor32(ip, ERASE_CURSOR); + for(j = ip->font.height-1; j >= 0; j--) { + int sofs2 = sofs, dofs2 = dofs; + for(i = (ip->cols - sx)-1; i >= 0; i--) { + int t; + + asm("bfextu %1@{%2:%3},%0" : "=d" (t) + : "a" (pl), "d" (sofs2), "d" (ip->font.width)); + asm("bfins %3,%0@{%1:%2}" + : : "a" (pl), "d" (dofs2),"d" (ip->font.width), + "d" (t)); + sofs2 += ip->font.width; + dofs2 += ip->font.width; + } + pl += bm->bytes_per_row; + } + } +} + +static void +scrollbmap (bmap_t *bm, u_short x, u_short y, u_short width, u_short height, short dx, short dy) +{ + u_short depth = bm->depth; + u_short lwpr = bm->bytes_per_row >> 2; + + if(dx) { + /* FIX: */ panic ("delta x not supported in scroll bitmap yet."); + } + + if(dy == 0) { + return; + } + if(dy > 0) { + u_long *pl = (u_long *)bm->plane; + u_long *src_y = pl + (lwpr*y); + u_long *dest_y = pl + (lwpr*(y+dy)); + u_long count = lwpr*(height-dy); + u_long *clr_y = src_y; + u_long clr_count = dest_y - src_y; + u_long bc, cbc; + + src_y += count - 1; + dest_y += count - 1; + + bc = count >> 4; + count &= 0xf; + + while (bc--) { + *dest_y-- = *src_y--; *dest_y-- = *src_y--; + *dest_y-- = *src_y--; *dest_y-- = *src_y--; + *dest_y-- = *src_y--; *dest_y-- = *src_y--; + *dest_y-- = *src_y--; *dest_y-- = *src_y--; + *dest_y-- = *src_y--; *dest_y-- = *src_y--; + *dest_y-- = *src_y--; *dest_y-- = *src_y--; + *dest_y-- = *src_y--; *dest_y-- = *src_y--; + *dest_y-- = *src_y--; *dest_y-- = *src_y--; + } + while (count--) + *dest_y-- = *src_y--; + + cbc = clr_count >> 4; + clr_count &= 0xf; + + while (cbc--) { + *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; + *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; + *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; + *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; + } + while(clr_count--) + *clr_y++ = 0; + } + else { + u_long *pl = (u_long *)bm->plane; + u_long *src_y = pl + (lwpr*(y-dy)); + u_long *dest_y = pl + (lwpr*y); + long count = lwpr*(height + dy); + u_long *clr_y = dest_y + count; + u_long clr_count = src_y - dest_y; + u_long bc, cbc; + + bc = count >> 4; + count &= 0xf; + + while(bc--) { + *dest_y++ = *src_y++; *dest_y++ = *src_y++; + *dest_y++ = *src_y++; *dest_y++ = *src_y++; + *dest_y++ = *src_y++; *dest_y++ = *src_y++; + *dest_y++ = *src_y++; *dest_y++ = *src_y++; + *dest_y++ = *src_y++; *dest_y++ = *src_y++; + *dest_y++ = *src_y++; *dest_y++ = *src_y++; + *dest_y++ = *src_y++; *dest_y++ = *src_y++; + *dest_y++ = *src_y++; *dest_y++ = *src_y++; + } + while(count--) + *dest_y++ = *src_y++; + + cbc = clr_count >> 4; + clr_count &= 0xf; + + while (cbc--) { + *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; + *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; + *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; + *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; *clr_y++ = 0; + } + while (clr_count--) + *clr_y++ = 0; + } +} +#else +#error Must be defined +#endif /* NGRF */ diff --git a/sys/arch/atari/dev/iteioctl.h b/sys/arch/atari/dev/iteioctl.h new file mode 100644 index 00000000000..b1555bfd772 --- /dev/null +++ b/sys/arch/atari/dev/iteioctl.h @@ -0,0 +1,83 @@ +/* $NetBSD: iteioctl.h,v 1.2 1995/07/24 05:56:12 leo Exp $ */ + +/* + * Copyright (c) 1988 University of Utah. + * Copyright (c) 1990 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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: iteioctl.h 1.1 90/07/09$ + * + * @(#)iteioctl.h 7.2 (Berkeley) 11/4/90 + */ + +struct itewinsize { + int x; /* leftedge offset to the right */ + int y; /* topedge offset down */ + u_int width; /* width of ite display */ + u_int height; /* height of ite display */ + u_int depth; /* depth of ite display */ +}; + +struct itebell { + u_int volume; /* volume of bell (0-64) */ + u_int pitch; /* pitch of bell (10-2000) */ + u_int msec; /* duration of bell */ +}; +#define MAXBVOLUME (63) +#define MAXBPITCH (2000) +#define MINBPITCH (10) +#define MAXBTIME (5000) /* 5 seconds */ + +struct iterepeat { + int start; /* number of 100/s before repeat start */ + int next; /* number of 100/s before next repeat */ +}; +#define ITEMINREPEAT 5 /* mininum number of 100/s for key repeat */ + +#define ITEIOCSKMAP _IOW('Z',0x70, struct kbdmap) +#define ITEIOCSSKMAP _IOW('Z',0x68, struct kbdmap) +#define ITEIOCGKMAP _IOR('Z',0x71, struct kbdmap) +#define ITEIOCGWINSZ _IOR('Z',0x72, struct itewinsize) +#define ITEIOCSWINSZ _IOW('Z',0x73, struct itewinsize) +#define ITEIOCDSPWIN _IO('Z', 0x74) +#define ITEIOCREMWIN _IO('Z', 0x75) +#define ITEIOCGBELL _IOR('Z', 0x76, struct itebell) +#define ITEIOCSBELL _IOW('Z', 0x77, struct itebell) +#define ITEIOCGREPT _IOR('Z', 0x78, struct iterepeat) +#define ITEIOCSREPT _IOW('Z', 0x79, struct iterepeat) + + +#define ITESWITCH _IOW('Z',0x69, int) /* XXX */ + diff --git a/sys/arch/atari/dev/itevar.h b/sys/arch/atari/dev/itevar.h new file mode 100644 index 00000000000..1607302db84 --- /dev/null +++ b/sys/arch/atari/dev/itevar.h @@ -0,0 +1,200 @@ +/* $NetBSD: itevar.h,v 1.2 1995/07/25 13:49:26 leo Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman (Atari modifications) + * Copyright (c) 1994 Christian E. Hopps + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christian E. Hopps. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef _ITEVAR_H +#define _ITEVAR_H + +#include <atari/dev/font.h> + +enum ite_arraymaxs { + MAX_ARGSIZE = 256, + MAX_TABS = 256, +}; + +enum ite_attr { + ATTR_NOR = 0, + ATTR_INV = 1, + ATTR_UL = 2, + ATTR_BOLD = 4, + ATTR_BLINK = 8, + ATTR_ALL = 16-1, + + ATTR_KEYPAD = 0x80 /* XXX */ +}; + +struct ite_softc { + struct device device; /* _Must_ be first */ + char argbuf[MAX_ARGSIZE]; + struct grf_softc *grf; /* XXX */ + char *ap; + struct tty *tp; + void *priv; + font_info font; + u_char *tabs; + struct kbdmap *kbdmap; + int flags; + short cursorx; + short cursory; + short rows; + short cols; + u_char *cursor; + char imode; + u_char escape; + u_char cursor_opt; + u_char key_repeat; + char GL; + char GR; + char G0; + char G1; + char G2; + char G3; + char linefeed_newline; + char auto_wrap; + char cursor_appmode; + char keypad_appmode; + short top_margin; + short bottom_margin; + short inside_margins; + short eightbit_C1; + short emul_level; + enum ite_attr attribute; + enum ite_attr save_attribute; + int curx; + int save_curx; + int cury; + int save_cury; +}; + +enum ite_flags { + ITE_ALIVE = 0x1, /* grf layer is configed */ + ITE_ISCONS = 0x2, /* ite is acting console. */ + ITE_INITED = 0x4, /* ite has been inited. */ + ITE_ISOPEN = 0x8, /* ite has been opened */ + ITE_INGRF = 0x10, /* ite is in graphics mode */ + ITE_ACTIVE = 0x20, /* ite is an active terminal */ +}; + +enum ite_replrules { + RR_CLEAR = 0, + RR_COPY = 0x3, + RR_XOR = 0x6, + RR_COYINVERTED = 0xC +}; + +enum ite_scrolldir { + SCROLL_UP = 1, + SCROLL_DOWN, + SCROLL_LEFT, + SCROLL_RIGHT, +}; + +enum ite_cursact { + DRAW_CURSOR = 5, + ERASE_CURSOR, + MOVE_CURSOR, + START_CURSOROPT, + END_CURSOROPT +}; + +enum ite_special_keycodes { + KBD_LEFT_SHIFT = 0x2a, + KBD_RIGHT_SHIFT = 0x36, + KBD_CAPS_LOCK = 0x3a, + KBD_CTRL = 0x1d, + KBD_ALT = 0x38 +}; + +enum ite_modifiers { + KBD_MOD_LSHIFT = 0x01, + KBD_MOD_RSHIFT = 0x02, + KBD_MOD_CTRL = 0x04, + KBD_MOD_ALT = 0x08, + KBD_MOD_CAPS = 0x10, + KBD_MOD_SHIFT = (KBD_MOD_LSHIFT | KBD_MOD_RSHIFT) +}; + +enum caller { + ITEFILT_TTY, + ITEFILT_CONSOLE, + ITEFILT_REPEATER +}; + +enum emul_level { + EMUL_VT100 = 1, + EMUL_VT300_8, + EMUL_VT300_7 +}; + +enum ite_max_getsize { ITEBURST = 64 }; + +enum tab_size { TABSIZE = 8 }; +#define TABEND(u) (ite_tty[u]->t_windsize.ws_col - TABSIZE) /* XXX */ + +#define set_attr(ip, attr) ((ip)->attribute |= (attr)) +#define clr_attr(ip, attr) ((ip)->attribute &= ~(attr)) +#define attrloc(ip, y, x) 0 +#define attrclr(ip, sy, sx, h, w) +#define attrmov(ip, sy, sx, dy, dx, h, w) +#define attrtest(ip, attr) 0 +#define attrset(ip, attr) + +struct proc; +struct consdev; +struct termios; + +/* console related function */ +void ite_cnprobe __P((struct consdev *)); +void ite_cninit __P((struct consdev *)); +int ite_cngetc __P((dev_t)); +void ite_cnputc __P((dev_t, int)); +void ite_cnfinish __P((struct ite_softc *)); + +/* standard ite device entry points. */ +void iteinit __P((dev_t)); +int iteopen __P((dev_t, int, int, struct proc *)); +int iteclose __P((dev_t, int, int, struct proc *)); +int iteread __P((dev_t, struct uio *, int)); +int itewrite __P((dev_t, struct uio *, int)); +int iteioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); +void itestart __P((struct tty *)); + +/* ite functions */ +int ite_on __P((dev_t, int)); +int ite_off __P((dev_t, int)); +void ite_reinit __P((dev_t)); +int ite_param __P((struct tty *, struct termios *)); +void ite_reset __P((struct ite_softc *)); +int ite_cnfilter __P((u_int, enum caller)); +void ite_filter __P((u_int ,enum caller)); + +#endif /* _ITEVAR_H */ diff --git a/sys/arch/atari/dev/kbd.c b/sys/arch/atari/dev/kbd.c new file mode 100644 index 00000000000..32a80018a25 --- /dev/null +++ b/sys/arch/atari/dev/kbd.c @@ -0,0 +1,563 @@ +/* $NetBSD: kbd.c,v 1.5 1995/06/26 14:31:27 leo Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman + * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +#include <sys/proc.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/kernel.h> +#include <sys/syslog.h> +#include <dev/cons.h> +#include <machine/cpu.h> +#include <machine/iomap.h> +#include <machine/mfp.h> +#include <machine/acia.h> +#include <machine/video.h> +#include <atari/dev/itevar.h> +#include <atari/dev/kbdreg.h> +#include <atari/dev/event_var.h> +#include <atari/dev/vuid_event.h> + +#include "mouse.h" + +/* + * The ringbuffer is the interface between the hard and soft interrupt handler. + * The hard interrupt runs straight from the MFP interrupt. + */ +#define KBD_RING_SIZE 256 /* Sz of input ring buffer, must be power of 2 */ +#define KBD_RING_MASK 255 /* Modulo mask for above */ + +static u_char kbd_ring[KBD_RING_SIZE]; +static volatile u_int kbd_rbput = 0; /* 'put' index */ +static u_int kbd_rbget = 0; /* 'get' index */ +static u_char kbd_soft = 0; /* 1: Softint has been scheduled*/ + +struct kbd_softc { + int k_event_mode; /* if 1, collect events, */ + /* else pass to ite */ + struct evvar k_events; /* event queue state */ + u_char k_soft_cs; /* control-reg. copy */ + u_char k_package[20]; /* XXX package being build */ + u_char k_pkg_size; /* Size of the package */ + u_char k_pkg_idx; + u_char *k_sendp; /* Output pointer */ + int k_send_cnt; /* Chars left for output */ +}; + +static struct kbd_softc kbd_softc; + +void kbd_write __P((u_char *, int)); + +static void kbdsoft __P((void)); +static void kbdattach __P((struct device *, struct device *, void *)); +static int kbdmatch __P((struct device *, struct cfdata *, void *)); +static int kbd_write_poll __P((u_char *, int)); +static void kbd_pkg_start __P((struct kbd_softc *, u_char)); + +struct cfdriver kbdcd = { + NULL, "kbd", (cfmatch_t)kbdmatch, kbdattach, + DV_DULL, sizeof(struct device), NULL, 0 }; + + +/*ARGSUSED*/ +static int +kbdmatch(pdp, cfp, auxp) +struct device *pdp; +struct cfdata *cfp; +void *auxp; +{ + if (!strcmp((char *)auxp, "kbd")) + return (1); + return (0); +} + +/*ARGSUSED*/ +static void +kbdattach(pdp, dp, auxp) +struct device *pdp, *dp; +void *auxp; +{ + int timeout; + u_char kbd_rst[] = { 0x80, 0x01 }; + u_char kbd_icmd[] = { 0x12, 0x15 }; + + /* + * Disable keyboard interrupts from MFP + */ + MFP->mf_ierb &= ~IB_AINT; + + /* + * Reset ACIA and intialize to: + * divide by 16, 8 data, 1 stop, no parity, enable RX interrupts + */ + KBD->ac_cs = A_RESET; + delay(100); /* XXX: enough? */ + KBD->ac_cs = kbd_softc.k_soft_cs = KBD_INIT | A_RXINT; + + /* + * Clear error conditions + */ + while (KBD->ac_cs & (A_IRQ|A_RXRDY)) + timeout = KBD->ac_da; + + /* + * Now send the reset string, and read+ignore it's response + */ + if (!kbd_write_poll(kbd_rst, 2)) + printf("kbd: error cannot reset keyboard\n"); + for (timeout = 1000; timeout > 0; timeout--) { + if (KBD->ac_cs & (A_IRQ|A_RXRDY)) { + timeout = KBD->ac_da; + timeout = 100; + } + delay(100); + } + /* + * Send init command: disable mice & joysticks + */ + kbd_write_poll(kbd_icmd, sizeof(kbd_icmd)); + + printf("\n"); +} + +/* definitions for atari keyboard encoding. */ +#define KEY_CODE(c) ((u_char)(c) & 0x7f) +#define KEY_UP(c) ((u_char)(c) & 0x80) +#define IS_KEY(c) ((u_char)(c) < 0xf6) + +void +kbdenable() +{ + int s, code; + + s = spltty(); + + /* + * Clear error conditions... + */ + while (KBD->ac_cs & (A_IRQ|A_RXRDY)) + code = KBD->ac_da; + /* + * Enable interrupts from MFP + */ + MFP->mf_iprb &= ~IB_AINT; + MFP->mf_ierb |= IB_AINT; + MFP->mf_imrb |= IB_AINT; + + kbd_softc.k_event_mode = 0; + kbd_softc.k_events.ev_io = 0; + kbd_softc.k_pkg_size = 0; + splx(s); +} + +int kbdopen(dev_t dev, int flags, int mode, struct proc *p) +{ + int s, error; + + if (kbd_softc.k_events.ev_io) + return EBUSY; + + kbd_softc.k_events.ev_io = p; + ev_init(&kbd_softc.k_events); + return (0); +} + +int +kbdclose(dev_t dev, int flags, int mode, struct proc *p) +{ + /* Turn off event mode, dump the queue */ + kbd_softc.k_event_mode = 0; + ev_fini(&kbd_softc.k_events); + kbd_softc.k_events.ev_io = NULL; + return (0); +} + +int +kbdread(dev_t dev, struct uio *uio, int flags) +{ + return ev_read(&kbd_softc.k_events, uio, flags); +} + +int +kbdioctl(dev_t dev,u_long cmd,register caddr_t data,int flag,struct proc *p) +{ + register struct kbd_softc *k = &kbd_softc; + + switch (cmd) { + case KIOCTRANS: + if (*(int *)data == TR_UNTRANS_EVENT) + return 0; + break; + + case KIOCGTRANS: + /* + * Get translation mode + */ + *(int *)data = TR_UNTRANS_EVENT; + return 0; + + case KIOCSDIRECT: + k->k_event_mode = *(int *)data; + return 0; + + case FIONBIO: /* we will remove this someday (soon???) */ + return 0; + + case FIOASYNC: + k->k_events.ev_async = *(int *)data != 0; + return 0; + + case TIOCSPGRP: + if (*(int *)data != k->k_events.ev_io->p_pgid) + return EPERM; + return 0; + + default: + return ENOTTY; + } + + /* + * We identified the ioctl, but we do not handle it. + */ + return EOPNOTSUPP; /* misuse, but what the heck */ +} + +int +kbdselect (dev_t dev, int rw, struct proc *p) +{ + return ev_select (&kbd_softc.k_events, rw, p); +} + +/* + * Keyboard interrupt handler called straight from MFP at spl6. + */ +int +kbdintr(sr) +int sr; /* sr at time of interrupt */ +{ + int code; + int got_char = 0; + + /* + * There may be multiple keys available. Read them all. + */ + while (KBD->ac_cs & (A_RXRDY|A_OE|A_PE)) { + got_char = 1; + if (KBD->ac_cs & (A_OE|A_PE)) { + code = KBD->ac_da; /* Silently ignore errors */ + continue; + } + kbd_ring[kbd_rbput++ & KBD_RING_MASK] = KBD->ac_da; + } + + /* + * If characters are waiting for transmit, send them. + */ + if ((kbd_softc.k_soft_cs & A_TXINT) && (KBD->ac_cs & A_TXRDY)) { + if (kbd_softc.k_sendp != NULL) + KBD->ac_da = *kbd_softc.k_sendp++; + if (--kbd_softc.k_send_cnt <= 0) { + /* + * The total package has been transmitted, + * wakeup anyone waiting for it. + */ + KBD->ac_cs = (kbd_softc.k_soft_cs &= ~A_TXINT); + kbd_softc.k_sendp = NULL; + kbd_softc.k_send_cnt = 0; + wakeup((caddr_t)&kbd_softc.k_send_cnt); + } + } + + /* + * Activate software-level to handle possible input. + */ + if (got_char) { + if (!BASEPRI(sr)) { + if (!kbd_soft++) + add_sicallback(kbdsoft, 0, 0); + } else { + spl1(); + kbdsoft(); + } + } +} + +/* + * Keyboard soft interrupt handler + */ +void +kbdsoft() +{ + int s; + u_char code; + struct kbd_softc *k = &kbd_softc; + struct firm_event *fe; + int put; + int n, get; + + kbd_soft = 0; + get = kbd_rbget; + + for (;;) { + n = kbd_rbput; + if (get == n) /* We're done */ + break; + n -= get; + if (n > KBD_RING_SIZE) { /* Ring buffer overflow */ + get += n - KBD_RING_SIZE; + n = KBD_RING_SIZE; + } + while (--n >= 0) { + code = kbd_ring[get++ & KBD_RING_MASK]; + + /* + * If collecting a package, stuff it in and + * continue. + */ + if (k->k_pkg_size && (k->k_pkg_idx < k->k_pkg_size)) { + k->k_package[k->k_pkg_idx++] = code; + if (k->k_pkg_idx == k->k_pkg_size) { + k->k_pkg_size = 0; +#if NMOUSE > 0 + /* + * Package is complete, we can now + * send it to the mouse driver... + */ + mouse_soft(k->k_package, k->k_pkg_size); +#endif /* NMOUSE */ + } + continue; + } + /* + * If this is a package header, init pkg. handling. + */ + if (!IS_KEY(code)) { + kbd_pkg_start(k, code); + continue; + } + /* + * if not in event mode, deliver straight to ite to + * process key stroke + */ + if (!k->k_event_mode) { + /* Gets to spltty() by itself */ + ite_filter(code, ITEFILT_TTY); + continue; + } + + /* + * Keyboard is generating events. Turn this keystroke + * into an event and put it in the queue. If the queue + * is full, the keystroke is lost (sorry!). + */ + s = spltty(); + put = k->k_events.ev_put; + fe = &k->k_events.ev_q[put]; + put = (put + 1) % EV_QSIZE; + if (put == k->k_events.ev_get) { + log(LOG_WARNING, + "keyboard event queue overflow\n"); + splx(s); + continue; + } + fe->id = KEY_CODE(code); + fe->value = KEY_UP(code) ? VKEY_UP : VKEY_DOWN; + fe->time = time; + k->k_events.ev_put = put; + EV_WAKEUP(&k->k_events); + splx(s); + } + kbd_rbget = get; + } +} + +static char sound[] = { + 0xA8,0x01,0xA9,0x01,0xAA,0x01,0x00, + 0xF8,0x10,0x10,0x10,0x00,0x20,0x03 +}; + +int +kbdbell() +{ + register int i, sps; + + sps = spltty(); + for (i = 0; i < sizeof(sound); i++) { + SOUND->sd_selr = i; + SOUND->sd_wdat = sound[i]; + } + splx(sps); +} + +int +kbdgetcn() +{ + u_char code; + int s = spltty(); + int ints_active; + + ints_active = 0; + if (MFP->mf_imrb & IB_AINT) { + ints_active = 1; + MFP->mf_imrb &= ~IB_AINT; + } + for (;;) { + while (!((KBD->ac_cs & (A_IRQ|A_RXRDY)) == (A_IRQ|A_RXRDY))) + ; /* Wait for key */ + if (KBD->ac_cs & (A_OE|A_PE)) { + code = KBD->ac_da; /* Silently ignore errors */ + continue; + } + break; + } + + code = KBD->ac_da; + if (ints_active) { + MFP->mf_iprb &= ~IB_AINT; + MFP->mf_imrb |= IB_AINT; + } + + splx (s); + return code; +} + +/* + * Write a command to the keyboard in 'polled' mode. + */ +static int +kbd_write_poll(cmd, len) +u_char *cmd; +int len; +{ + int timeout; + + while (len-- > 0) { + KBD->ac_da = *cmd++; + for (timeout = 100; !(KBD->ac_cs & A_TXRDY); timeout--) + delay(10); + if (!(KBD->ac_cs & A_TXRDY)) + return (0); + } + return (1); +} + +/* + * Write a command to the keyboard. Return when command is send. + */ +void +kbd_write(cmd, len) +u_char *cmd; +int len; +{ + struct kbd_softc *k = &kbd_softc; + int sps; + + /* + * Get to splhigh, 'real' interrupts arrive at spl6! + */ + sps = splhigh(); + + /* + * Make sure any privious write has ended... + */ + while (k->k_sendp != NULL) + tsleep((caddr_t)&k->k_sendp, TTOPRI, "kbd_write1", 0); + + /* + * If the KBD-acia is not currently busy, send the first + * character now. + */ + KBD->ac_cs = (k->k_soft_cs |= A_TXINT); + if (KBD->ac_cs & A_TXRDY) { + KBD->ac_da = *cmd++; + len--; + } + + /* + * If we're not yet done, wait until all characters are send. + */ + if (len > 0) { + k->k_sendp = cmd; + k->k_send_cnt = len; + tsleep((caddr_t)&k->k_send_cnt, TTOPRI, "kbd_write2", 0); + } + splx(sps); + + /* + * Wakeup all procs waiting for us. + */ + wakeup((caddr_t)&k->k_sendp); +} + +/* + * Setup softc-fields to assemble a keyboard package. + */ +static void +kbd_pkg_start(kp, msg_start) +struct kbd_softc *kp; +u_char msg_start; +{ + kp->k_pkg_idx = 1; + kp->k_package[0] = msg_start; + switch (msg_start) { + case 0xf6: + kp->k_pkg_size = 8; + break; + case 0xf7: + kp->k_pkg_size = 6; + break; + case 0xf8: + case 0xf9: + case 0xfa: + case 0xfb: + kp->k_pkg_size = 3; + break; + case 0xfc: + kp->k_pkg_size = 7; + break; + case 0xfe: + case 0xff: + kp->k_pkg_size = 2; + break; + default: + printf("kbd: Unknown packet 0x%x\n", msg_start); + break; + } +} diff --git a/sys/arch/atari/dev/kbdmap.c b/sys/arch/atari/dev/kbdmap.c new file mode 100644 index 00000000000..26d1f936728 --- /dev/null +++ b/sys/arch/atari/dev/kbdmap.c @@ -0,0 +1,207 @@ +/* $NetBSD: kbdmap.c,v 1.2 1995/07/24 05:56:14 leo Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman. + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Leo Weppelman. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include <atari/dev/kbdmap.h> + +/* define a default keymap. This can be changed by keyboard ioctl's + (later at least..) */ + +/* mode shortcuts: */ +#define S KBD_MODE_STRING +#define C KBD_MODE_CAPS +#define K KBD_MODE_KPAD + +struct kbdmap ascii_kbdmap = { + /* normal map */ + { +/* 0x00 */ 0, 0, 0, ESC, 0, '1', 0, '2', +/* 0x04 */ 0, '3', 0, '4', 0, '5', 0, '6', +/* 0x08 */ 0, '7', 0, '8', 0, '9', 0, '0', +/* 0x0c */ 0, '-', 0, '=', 0, '\b', 0, '\t', +/* 0x10 */ C, 'q', C, 'w', C, 'e', C, 'r', +/* 0x14 */ C, 't', C, 'y', C, 'u', C, 'i', +/* 0x18 */ C, 'o', C, 'p', 0, '[', 0, ']', +/* 0x1c */ 0, '\r', 0, 0, C, 'a', C, 's', +/* 0x20 */ C, 'd', C, 'f', C, 'g', C, 'h', +/* 0x24 */ C, 'j', C, 'k', C, 'l', 0, ';', +#ifdef US_KBD +/* 0x28 */ 0, '\'', 0, '`', 0, 0, 0, '\\', +#else +/* 0x28 */ 0, '\'', 0, '`', 0, 0, 0, '#', +#endif +/* 0x2c */ C, 'z', C, 'x', C, 'c', C, 'v', +/* 0x30 */ C, 'b', C, 'n', C, 'm', 0, ',', +/* 0x34 */ 0, '.', 0, '/', 0, 0, 0, 0, +/* 0x38 */ 0, 0, 0, ' ', 0, 0, S, 0x10, +/* 0x3c */ S, 0x15, S, 0x1A, S, 0x1F, S, 0x24, +/* 0x40 */ S, 0x29, S, 0x2E, S, 0x33, S, 0x38, +/* 0x44 */ S, 0x3D, 0, 0, 0, 0, 0, 0, +/* 0x48 */ S, 0x00, 0, 0, 0, '-', S, 0x0C, +/* 0x4c */ 0, 0, S, 0x08, 0, '+', 0, 0, +/* 0x50 */ S, 0x04, 0, 0, 0, 0, 0, DEL, +/* 0x54 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 0x58 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 0x5c */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 0x60 */ +#ifdef US_KBD +/* 0x60 */ 0, 0, 0, 0, 0, 0, 0, '(', +#else +/* 0x60 */ 0, '\\', 0, 0, 0, 0, 0, '(', +#endif +/* 0x64 */ 0, ')', 0, '/', 0, '*', K, '7', +/* 0x68 */ K, '8', K, '9', K, '4', K, '5', +/* 0x6c */ K, '6', K, '1', K, '2', K, '3', +/* 0x70 */ K, '0', K, '.', K, '\r', 0, 0, +/* 0x74 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 0x78 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 0x7c */ 0, 0, 0, 0, 0, 0, 0, 0 +}, + /* shifted map */ + { +#ifdef US_KBD +/* 0x00 */ 0, 0, 0, ESC, 0, '!', 0, '@', +#else +/* 0x00 */ 0, 0, 0, ESC, 0, '!', 0, '"', +#endif +/* 0x04 */ 0, '#', 0, '$', 0, '%', 0, '^', +/* 0x08 */ 0, '&', 0, '*', 0, '(', 0, ')', +/* 0x0c */ 0, '_', 0, '+', 0, '\b', 0, '\t', +/* 0x10 */ C, 'Q', C, 'W', C, 'E', C, 'R', +/* 0x14 */ C, 'T', C, 'Y', C, 'U', C, 'I', +/* 0x18 */ C, 'O', C, 'P', 0, '{', 0, '}', +/* 0x1c */ 0, '\r', 0, 0, C, 'A', C, 'S', +/* 0x20 */ C, 'D', C, 'F', C, 'G', C, 'H', +/* 0x24 */ C, 'J', C, 'K', C, 'L', 0, ':', +#ifdef US_KBD +/* 0x28 */ 0, '"', 0, '~', 0, 0, 0, '|', +#else +/* 0x28 */ 0, '@', 0, '_', 0, 0, 0, '~', +#endif +/* 0x2c */ C, 'Z', C, 'X', C, 'C', C, 'V', +/* 0x30 */ C, 'B', C, 'N', C, 'M', 0, '<', +/* 0x34 */ 0, '>', 0, '?', 0, 0, 0, 0, +/* 0x38 */ 0, 0, 0, ' ', 0, 0, S, 0x5d, +/* 0x3c */ S, 0x63, S, 0x69, S, 0x6F, S, 0x75, +/* 0x40 */ S, 0x7b, S, 0x81, S, 0x87, S, 0x8d, +/* 0x44 */ S, 0x93, 0, 0, 0, 0, 0, 0, +/* 0x48 */ S, 0x47, 0, 0, 0, '-', S, 0x57, +/* 0x4c */ 0, 0, S, 0x51, 0, '+', 0, 0, +/* 0x50 */ S, 0x4c, 0, 0, 0, 0, 0, DEL, +/* 0x54 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 0x58 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 0x5c */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 0x60 */ +#ifdef US_KBD +/* 0x60 */ 0, 0, 0, 0, 0, 0, 0, '(', +#else +/* 0x60 */ 0, '|', 0, 0, 0, 0, 0, '(', +#endif +/* 0x64 */ 0, ')', 0, '/', 0, '*', K, '7', +/* 0x68 */ K, '8', K, '9', K, '4', K, '5', +/* 0x6c */ K, '6', K, '1', K, '2', K, '3', +/* 0x70 */ K, '0', K, '.', K, '\r', 0, 0, +/* 0x74 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 0x78 */ 0, 0, 0, 0, 0, 0, 0, 0, +/* 0x7c */ 0, 0, 0, 0, 0, 0, 0, 0 + }, + + /* alt map FIXME: No altmap yet.. */ + { + 0, 0 + }, + + /* shift alt map FIXME: No shift altmap yet... */ + { + 0, 0 + }, + + { + /* string table. If there's a better way to get the offsets into the + above table, please tell me.. + + NOTE: save yourself and others a lot of grief by *not* using + CSI == 0x9b, using the two-character sequence gives + much less trouble, especially in GNU-Emacs.. */ + + 3, ESC, '[', 'A', /* 0x00: CRSR UP */ + 3, ESC, '[', 'B', /* 0x04: CRSR DOWN */ + 3, ESC, '[', 'C', /* 0x08: CRSR RIGHT */ + 3, ESC, '[', 'D', /* 0x0C: CRSR LEFT */ + 4, ESC, '[', '0', '~', /* 0x10: F1 */ + 4, ESC, '[', '1', '~', /* 0x15: F2 */ + 4, ESC, '[', '2', '~', /* 0x1A: F3 */ + 4, ESC, '[', '3', '~', /* 0x1F: F4 */ + 4, ESC, '[', '4', '~', /* 0x24: F5 */ + 4, ESC, '[', '5', '~', /* 0x29: F6 */ + 4, ESC, '[', '6', '~', /* 0x2E: F7 */ + 4, ESC, '[', '7', '~', /* 0x33: F8 */ + 4, ESC, '[', '8', '~', /* 0x38: F9 */ + 4, ESC, '[', '9', '~', /* 0x3D: F10 */ + 4, ESC, '[', '?', '~', /* 0x42: HELP */ + + 4, ESC, '[', 'T', '~', /* 0x47: shift CRSR UP */ + 4, ESC, '[', 'S', '~', /* 0x4C: shift CRSR DOWN */ + 5, ESC, '[', ' ', '@', '~', /* 0x51: shift CRSR RIGHT */ + 5, ESC, '[', ' ', 'A', '~', /* 0x57: shift CRSR LEFT */ + 5, ESC, '[', '1', '0', '~', /* 0x5D: shift F1 */ + 5, ESC, '[', '1', '1', '~', /* 0x63: shift F2 */ + 5, ESC, '[', '1', '2', '~', /* 0x69: shift F3 */ + 5, ESC, '[', '1', '3', '~', /* 0x6F: shift F4 */ + 5, ESC, '[', '1', '4', '~', /* 0x75: shift F5 */ + 5, ESC, '[', '1', '5', '~', /* 0x7B: shift F6 */ + 5, ESC, '[', '1', '6', '~', /* 0x81: shift F7 */ + 5, ESC, '[', '1', '7', '~', /* 0x87: shift F8 */ + 5, ESC, '[', '1', '8', '~', /* 0x8D: shift F9 */ + 5, ESC, '[', '1', '9', '~', /* 0x93: shift F10 */ + 3, ESC, '[', 'Z', /* 0x99: shift TAB */ + 2, ESC, '[', /* 0x9d: alt ESC == CSI */ + }, +}; + +unsigned char acctable[KBD_NUM_ACC][64] = { + { "@ÀBCDÈFGHÌJKLMNÒPQRSTÙVWXYZ[\\]^_" + "`àbcdèfghìjklmnòpqrstùvwxyz{|}~\177"}, /* KBD_ACC_GRAVE */ + + { "@ÁBCDÉFGHÍJKLMNÓPQRSTÚVWXYZ[\\]^_" + "`ábcdéfghíjklmnópqrstúvwxyz{|}~\177"}, /* KBD_ACC_ACUTE */ + + { "@ÂBCDÊFGHÎJKLMNÔPQRSTÛVWXYZ[\\]^_" + "`âbcdêfghîjklmnôpqrstûvwxyz{|}~\177"}, /* KBD_ACC_CIRC */ + + { "@ÃBCDEFGHIJKLMÑÕPQRSTUVWXYZ[\\]^_" + "`ãbcdefghijklmñÕpqrstuvwxyz{|}~\177"}, /* KBD_ACC_TILDE */ + + { "@ÄBCDËFGHÏJKLMNÖPQRSTÜVWXYZ[\\]^_" + "`äbcdëfghïjklmnöpqrstüvwxyz{|}~\177"}, /* KBD_ACC_DIER */ +}; + + diff --git a/sys/arch/atari/dev/kbdmap.h b/sys/arch/atari/dev/kbdmap.h new file mode 100644 index 00000000000..b75795cbfb1 --- /dev/null +++ b/sys/arch/atari/dev/kbdmap.h @@ -0,0 +1,144 @@ +/* $NetBSD: kbdmap.h,v 1.3 1995/07/24 05:56:17 leo Exp $ */ + +/* + * Copyright (c) 1993 Markus Wild + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Markus Wild. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#define NUL 0 +#define SOH 1 +#define STX 2 +#define ETX 3 +#define EOT 4 +#define ENQ 5 +#define ACK 6 +#define BEL 7 +#define BS 8 +#define HT 9 +#define LF 10 +#define VT 11 +#define FF 12 +#define CR 13 +#define SO 14 +#define SI 15 +#define DLE 16 +#define DC1 17 +#define DC2 18 +#define DC3 19 +#define DC4 20 +#define NAK 21 +#define SYN 22 +#define ETB 23 +#define CAN 24 +#define EM 25 +#define SUB 26 +#define ESC 27 +#define FS 28 +#define GS 29 +#define RS 30 +#define US 31 +#define DEL 127 +#define IND 132 +#define NEL 133 +#define SSA 134 +#define ESA 135 +#define HTS 136 +#define HTJ 137 +#define VTS 138 +#define PLD 139 +#define PLU 140 +#define RI 141 +#define SS2 142 +#define SS3 143 +#define DCS 144 +#define PU1 145 +#define PU2 146 +#define STS 147 +#define CCH 148 +#define MW 149 +#define SPA 150 +#define EPA 151 +#define CSI 155 +#define ST 156 +#define OSC 157 +#define PM 158 +#define APC 159 + + +/* + * A total of 0x80 scancode are defined for the atari keyboard. + */ +#define KBD_NUM_KEYS 0x80 + +/* size of string table */ +#define KBD_STRTAB_SIZE 255 + +/* for dead keys, index into acctable */ +/* FIXME: What the hell are dead keys?? */ +#define KBD_ACC_GRAVE 0 +#define KBD_ACC_ACUTE 1 +#define KBD_ACC_CIRC 2 +#define KBD_ACC_TILDE 3 +#define KBD_ACC_DIER 4 +#define KBD_NUM_ACC 5 + + +struct key { + unsigned char mode; /* see possible values below */ + unsigned char code; +}; + +#define KBD_MODE_STRING (0x01) /* code is index into strings[] */ +#define KBD_MODE_DEAD (0x02) /* acc-index in upper nibble, code = plain acc */ +#define KBD_MODE_CAPS (0x04) /* key is capsable. Only in non-shifted maps */ +#define KBD_MODE_KPAD (0x08) /* key is on keypad */ +#define KBD_MODE_GRAVE (KBD_ACC_GRAVE << 4) +#define KBD_MODE_ACUTE (KBD_ACC_ACUTE << 4) +#define KBD_MODE_CIRC (KBD_ACC_CIRC << 4) +#define KBD_MODE_TILDE (KBD_ACC_TILDE << 4) +#define KBD_MODE_DIER (KBD_ACC_DIER << 4) +#define KBD_MODE_ACCENT(m) ((m) >> 4) /* get accent from mode */ +#define KBD_MODE_ACCMASK (0xf0) + +#define KBD_SCANCODE(code) (code & 0x7f) +#define KBD_RELEASED(code) (code & 0x80 ? 1 : 0) + +struct kbdmap { + struct key keys[KBD_NUM_KEYS], + shift_keys[KBD_NUM_KEYS], + alt_keys[KBD_NUM_KEYS], + alt_shift_keys[KBD_NUM_KEYS]; + unsigned char strings[KBD_STRTAB_SIZE]; +}; + + +#ifdef _KERNEL +/* XXX: ITE interface */ +extern struct kbdmap ascii_kbdmap; +extern unsigned char acctable[KBD_NUM_ACC][64]; +#endif diff --git a/sys/arch/atari/dev/kbdreg.h b/sys/arch/atari/dev/kbdreg.h new file mode 100644 index 00000000000..84301c4fda2 --- /dev/null +++ b/sys/arch/atari/dev/kbdreg.h @@ -0,0 +1,54 @@ +/* $NetBSD: kbdreg.h,v 1.1.1.1 1995/03/26 07:12:12 leo Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + * + * @(#)kbio.h 8.1 (Berkeley) 6/11/93 + * + * from: Header: kbio.h,v 1.4 92/11/26 01:16:32 torek Exp (LBL) + */ + +#define KIOCTRANS _IOW('k', 0, int) /* set translation mode */ + /* (we only accept TR_UNTRANS_EVENT) */ +#define KIOCGTRANS _IOR('k', 5, int) /* get translation mode */ +#define KIOCSDIRECT _IOW('k', 10, int) /* keys to console? */ + +#define TR_UNTRANS_EVENT 3 diff --git a/sys/arch/atari/dev/ms.c b/sys/arch/atari/dev/ms.c new file mode 100644 index 00000000000..5d5c647c0ee --- /dev/null +++ b/sys/arch/atari/dev/ms.c @@ -0,0 +1,397 @@ +/* $NetBSD: ms.c,v 1.3 1995/07/27 06:35:46 leo Exp $ + +/* + * Copyright (c) 1995 Leo Weppelman. + * All rights reserved. + * + * based on: + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + * + * @(#)ms.c 8.1 (Berkeley) 6/11/93 + * + * Header: ms.c,v 1.5 92/11/26 01:28:47 torek Exp (LBL) + */ + +/* + * Mouse driver. + */ + +#include <sys/param.h> +#include <sys/conf.h> +#include <sys/ioctl.h> +#include <sys/kernel.h> +#include <sys/proc.h> +#include <sys/systm.h> +#include <sys/tty.h> + +#include <atari/dev/event_var.h> +#include <atari/dev/vuid_event.h> + +#include "mouse.h" +#if NMOUSE > 0 + +/* there's really no more physical ports on an atari. */ +#if NMOUSE > 1 +#undef NMOUSE +#define NMOUSE 1 +#endif + +typedef void (*FPV)(); + +/* + * Mouse specific packages produced by the keyboard. Currently, we only + * define the REL_MOUSE package, as this is the only one used. + */ +typedef struct { + u_char id; + char dx; + char dy; +} REL_MOUSE; + +#define IS_REL_MOUSE(id) (((u_int)(id) & 0xF8) == 0xF8) +#define TIMEOUT_ID (0xFC) + +static struct ms_softc { + u_char ms_buttons; /* button states */ + struct evvar ms_events; /* event queue state */ + int ms_dx; /* accumulated dx */ + int ms_dy; /* accumulated dy */ + struct firm_event ms_bq[2]; /* Button queue */ + int ms_bq_idx; /* Button queue index */ +} ms_softc[NMOUSE]; + +static void ms_3b_delay __P((struct ms_softc *)); + void mouse_soft __P((REL_MOUSE *, int)); + +int +mouseattach(cnt) + int cnt; +{ + printf("1 mouse configured\n"); + return(NMOUSE); +} + +static void +ms_3b_delay(ms) +struct ms_softc *ms; +{ + REL_MOUSE rel_ms; + + rel_ms.id = TIMEOUT_ID; + rel_ms.dx = rel_ms.dy = 0; + mouse_soft(&rel_ms, sizeof(rel_ms)); +} +/* + * Note that we are called from the keyboard software interrupt! + */ +void +mouse_soft(rel_ms, size) +REL_MOUSE *rel_ms; +int size; +{ + struct ms_softc *ms = &ms_softc[0]; + struct firm_event *fe, *fe2; + int get, put; + int sps; + u_char mbut, bmask; + int is_timeout; + int flush_buttons; + int id; + + if (!IS_REL_MOUSE(rel_ms->id)) + return; /* Probably some other message */ + if (ms->ms_events.ev_io == NULL) + return; + + sps = splev(); + get = ms->ms_events.ev_get; + put = ms->ms_events.ev_put; + fe = &ms->ms_events.ev_q[put]; + + if (rel_ms->id == TIMEOUT_ID) { + is_timeout = 1; + id = ms->ms_buttons; + } + else { + is_timeout = 0; + id = (rel_ms->id & 3) | (ms->ms_buttons & 4); + } + + if (!is_timeout && ms->ms_bq_idx) + untimeout((FPV)ms_3b_delay, (void *)ms); + + /* + * Button states are encoded in the lower 2 bits of 'id' + */ + if (!(mbut = (id ^ ms->ms_buttons)) && (put != get)) { + /* + * Compact dx/dy messages. Always generate an event when + * a button is pressed or the event queue is empty. + */ + ms->ms_dx += rel_ms->dx; + ms->ms_dy += rel_ms->dy; + goto out; + } + rel_ms->dx += ms->ms_dx; + rel_ms->dy += ms->ms_dy; + ms->ms_dx = ms->ms_dy = 0; + + /* + * Output location events _before_ button events ie. make sure + * the button is pressed at the correct location. + */ + if (rel_ms->dx) { + if ((++put) % EV_QSIZE == get) { + put--; + goto out; + } + fe->id = LOC_X_DELTA; + fe->value = rel_ms->dx; + fe->time = time; + if (put >= EV_QSIZE) { + put = 0; + fe = &ms->ms_events.ev_q[0]; + } + else fe++; + } + if (rel_ms->dy) { + if ((++put) % EV_QSIZE == get) { + put--; + goto out; + } + fe->id = LOC_Y_DELTA; + fe->value = rel_ms->dy; + fe->time = time; + if (put >= EV_QSIZE) { + put = 0; + fe = &ms->ms_events.ev_q[0]; + } + else fe++; + } + if (mbut && !is_timeout) { + for (bmask = 1; bmask < 0x04; bmask <<= 1) { + if (!(mbut & bmask)) + continue; + fe2 = &ms->ms_bq[ms->ms_bq_idx++]; + fe2->id = bmask & 1 ? MS_RIGHT : MS_LEFT; + fe2->value = id & bmask ? VKEY_DOWN : VKEY_UP; + fe2->time = time; + } + } + if (ms->ms_bq_idx) { + /* + * We have at least one button, handle it. + */ + flush_buttons = (is_timeout) ? 1 : 0; + if (ms->ms_bq_idx == 2) { + if (ms->ms_bq[0].value == ms->ms_bq[1].value) { + /* Must be 2 button presses! */ + if (ms->ms_bq[0].id != ms->ms_bq[1].id) { + ms->ms_bq[0].id = MS_MIDDLE; + ms->ms_bq_idx = 1; + id = 7; + } + } + flush_buttons = 1; + } + else { + if (ms->ms_bq[0].value == VKEY_UP) { + /* + * Release of a button is always flushed + * immediately. If the middle button is + * active, the release event is his. Mark + * all buttons released, this also surpresses + * a spurious release event of the not-yet- + * released button. + */ + if( id & 4) { + ms->ms_bq[0].id = MS_MIDDLE; + id = 0; + } + flush_buttons = 1; + } + else if (!is_timeout) { + timeout((FPV)ms_3b_delay, (void *)ms, 10); + goto out; + } + } + if (flush_buttons) { + int i; + + for (i = 0; i < ms->ms_bq_idx; i++) { + if ((++put) % EV_QSIZE == get) { + ms->ms_bq_idx = 0; + put--; + goto out; + } + *fe = ms->ms_bq[i]; + if (put >= EV_QSIZE) { + put = 0; + fe = &ms->ms_events.ev_q[0]; + } + else fe++; + } + ms->ms_bq_idx = 0; + } + } + +out: + ms->ms_events.ev_put = put; + ms->ms_buttons = id; + splx(sps); + EV_WAKEUP(&ms->ms_events); +} + +int +msopen(dev, flags, mode, p) +dev_t dev; +int flags, mode; +struct proc *p; +{ + u_char report_ms[] = { 0x08 }; + struct ms_softc *ms; + int unit; + + unit = minor(dev); + ms = &ms_softc[unit]; + + if (unit >= NMOUSE) + return(EXDEV); + + if (ms->ms_events.ev_io) + return(EBUSY); + + ms->ms_events.ev_io = p; + ms->ms_dx = ms->ms_dy = 0; + ms->ms_buttons = 0; + ms->ms_bq[0].id = ms->ms_bq[1].id = 0; + ms->ms_bq_idx = 0; + ev_init(&ms->ms_events); /* may cause sleep */ + + /* + * Enable mouse reporting. + */ + kbd_write(report_ms, sizeof(report_ms)); + return(0); +} + +int +msclose(dev, flags, mode, p) +dev_t dev; +int flags, mode; +struct proc *p; +{ + u_char disable_ms[] = { 0x12 }; + int unit; + struct ms_softc *ms; + + unit = minor (dev); + ms = &ms_softc[unit]; + + /* + * Turn off mouse interrogation. + */ + kbd_write(disable_ms, sizeof(disable_ms)); + ev_fini(&ms->ms_events); + ms->ms_events.ev_io = NULL; + return(0); +} + +int +msread(dev, uio, flags) +dev_t dev; +struct uio *uio; +int flags; +{ + struct ms_softc *ms; + + ms = &ms_softc[minor(dev)]; + return(ev_read(&ms->ms_events, uio, flags)); +} + +int +msioctl(dev, cmd, data, flag, p) +dev_t dev; +u_long cmd; +register caddr_t data; +int flag; +struct proc *p; +{ + struct ms_softc *ms; + int unit; + + unit = minor(dev); + ms = &ms_softc[unit]; + + switch (cmd) { + case FIONBIO: /* we will remove this someday (soon???) */ + return(0); + case FIOASYNC: + ms->ms_events.ev_async = *(int *)data != 0; + return(0); + case TIOCSPGRP: + if (*(int *)data != ms->ms_events.ev_io->p_pgid) + return(EPERM); + return(0); + case VUIDGFORMAT: /* we only do firm_events */ + *(int *)data = VUID_FIRM_EVENT; + return(0); + case VUIDSFORMAT: + if (*(int *)data != VUID_FIRM_EVENT) + return(EINVAL); + return(0); + } + return(ENOTTY); +} + +int +msselect(dev, rw, p) +dev_t dev; +int rw; +struct proc *p; +{ + struct ms_softc *ms; + + ms = &ms_softc[minor(dev)]; + return(ev_select(&ms->ms_events, rw, p)); +} +#endif /* NMOUSE > 0 */ diff --git a/sys/arch/atari/dev/ncr5380.c b/sys/arch/atari/dev/ncr5380.c new file mode 100644 index 00000000000..5d88a1f8c68 --- /dev/null +++ b/sys/arch/atari/dev/ncr5380.c @@ -0,0 +1,1906 @@ +/* $NetBSD: ncr5380.c,v 1.11 1995/10/08 13:34:23 leo Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman. + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Leo Weppelman. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + + +#ifdef DBG_NOSTATIC +# define static +#endif +#ifdef DBG_SEL +# define DBG_SELPRINT(a,b) printf(a,b) +#else +# define DBG_SELPRINT(a,b) +#endif +#ifdef DBG_PIO +# define DBG_PIOPRINT(a,b,c) printf(a,b,c) +#else +# define DBG_PIOPRINT(a,b,c) +#endif +#ifdef DBG_INF +# define DBG_INFPRINT(a,b,c) a(b,c) +#else +# define DBG_INFPRINT(a,b,c) +#endif +#ifdef DBG_PID + static char *last_hit = NULL, *olast_hit = NULL; +# define PID(a) olast_hit = last_hit; last_hit = a; +#else +# define PID(a) +#endif + +/* + * Bit mask of targets you want debugging to be shown + */ +u_char dbg_target_mask = 0x7f; + +/* + * Set bit for target when parity checking must be disabled. + * My (LWP) Maxtor 7245S seems to generate parity errors on about 50% + * of all transfers while the data is correct!? + */ +u_char ncr5380_no_parchk = 0xff; + +/* + * This is the default sense-command we send. + */ +static u_char sense_cmd[] = { + REQUEST_SENSE, 0, 0, 0, sizeof(struct scsi_sense_data), 0 +}; + +/* + * True if the main co-routine is running + */ +static volatile int main_running = 0; + +/* + * Mask of targets selected + */ +static u_char busy; + +static void ncr5380_minphys(struct buf *bp); +static int ncr5380_scsi_cmd(struct scsi_xfer *xs); +static int ncr5380_show_scsi_cmd(struct scsi_xfer *xs); + +struct scsi_adapter ncr5380_switch = { + ncr5380_scsi_cmd, /* scsi_cmd() */ + ncr5380_minphys, /* scsi_minphys() */ + 0, /* open_target_lu() */ + 0 /* close_target_lu() */ +}; + +struct scsi_device ncr5380_dev = { + NULL, /* use default error handler */ + NULL, /* do not have a start functio */ + NULL, /* have no async handler */ + NULL /* Use default done routine */ +}; + + +static SC_REQ req_queue[NREQ]; +static SC_REQ *free_head = NULL; /* Free request structures */ + + +/* + * Inline functions: + */ + +/* + * Determine the size of a SCSI command. + */ +extern __inline__ int command_size(opcode) +u_char opcode; +{ + switch ((opcode >> 4) & 0xf) { + case 0: + case 1: + return (6); + case 2: + case 3: + return (10); + } + return (12); +} + + +/* + * Wait for request-line to become active. When it doesn't return 0. + * Otherwise return != 0. + * The timeouts in the 'wait_req_*' functions are arbitrary and rather + * large. In 99% of the invocations nearly no timeout is needed but in + * some cases (especially when using my tapedrive, a Tandberg 3600) the + * device is busy internally and the first SCSI-phase will be delayed. + */ +extern __inline__ int wait_req_true(void) +{ + int timeout = 25000; + + while (!(GET_5380_REG(NCR5380_IDSTAT) & SC_S_REQ) && --timeout) + delay(1); + return (GET_5380_REG(NCR5380_IDSTAT) & SC_S_REQ); +} + +/* + * Wait for request-line to become inactive. When it doesn't return 0. + * Otherwise return != 0. + */ +extern __inline__ int wait_req_false(void) +{ + int timeout = 25000; + + while ((GET_5380_REG(NCR5380_IDSTAT) & SC_S_REQ) && --timeout) + delay(1); + return (!(GET_5380_REG(NCR5380_IDSTAT) & SC_S_REQ)); +} + +extern __inline__ void ack_message() +{ + SET_5380_REG(NCR5380_ICOM, 0); +} + +extern __inline__ void nack_message(SC_REQ *reqp, u_char msg) +{ + SET_5380_REG(NCR5380_ICOM, SC_A_ATN); + reqp->msgout = msg; +} + +extern __inline__ void finish_req(SC_REQ *reqp) +{ + int sps; + struct scsi_xfer *xs = reqp->xs; + +#ifdef REAL_DMA + /* + * If we bounced, free the bounce buffer + */ + if (reqp->dr_flag & DRIVER_BOUNCING) + free_bounceb(reqp->bounceb); +#endif /* REAL_DMA */ +#ifdef DBG_REQ + if (dbg_target_mask & (1 << reqp->targ_id)) + show_request(reqp, "DONE"); +#endif +#ifdef DBG_ERR_RET + if (reqp->xs->error != 0) + show_request(reqp, "ERR_RET"); +#endif + + /* + * Return request to free-q + */ + sps = splbio(); + reqp->next = free_head; + free_head = reqp; + splx(sps); + + xs->flags |= ITSDONE; + scsi_done(xs); +} + +/* + * Auto config stuff.... + */ +int ncr_cprint __P((void *auxp, char *)); +void ncr_attach __P((struct device *, struct device *, void *)); +int ncr_match __P((struct device *, struct cfdata *, void *)); + +/* + * Tricks to make driver-name configurable + */ +#define CFNAME(n) __CONCAT(n,cd) +#define CFSTRING(n) __STRING(n) + +struct cfdriver CFNAME(DRNAME) = { + NULL, CFSTRING(DRNAME), (cfmatch_t)ncr_match, ncr_attach, + DV_DULL, sizeof(struct ncr_softc), NULL, 0 }; + +int +ncr_match(pdp, cdp, auxp) +struct device *pdp; +struct cfdata *cdp; +void *auxp; +{ + return (machine_match(pdp, cdp, auxp, &CFNAME(DRNAME))); +} + +void +ncr_attach(pdp, dp, auxp) +struct device *pdp, *dp; +void *auxp; +{ + struct ncr_softc *sc; + int i; + + sc = (struct ncr_softc *)dp; + + sc->sc_link.adapter_softc = sc; + sc->sc_link.adapter_target = 7; + sc->sc_link.adapter = &ncr5380_switch; + sc->sc_link.device = &ncr5380_dev; + sc->sc_link.openings = NREQ - 1; + + /* + * bitmasks + */ + sc->sc_noselatn = 0; + sc->sc_selected = 0; + + /* + * Initialize machine-type specific things... + */ + scsi_mach_init(sc); + printf("\n"); + + /* + * Initialize request queue freelist. + */ + for (i = 0; i < NREQ; i++) { + req_queue[i].next = free_head; + free_head = &req_queue[i]; + } + + /* + * Initialize the host adapter + */ + scsi_idisable(); + ENABLE_NCR5380(sc); + SET_5380_REG(NCR5380_ICOM, 0); + SET_5380_REG(NCR5380_MODE, IMODE_BASE); + SET_5380_REG(NCR5380_TCOM, 0); + SET_5380_REG(NCR5380_IDSTAT, 0); + scsi_ienable(); + + /* + * attach all scsi units on us + */ + config_found(dp, &sc->sc_link, ncr_cprint); +} + +/* + * print diag if name is NULL else just extra + */ +int +ncr_cprint(auxp, name) +void *auxp; +char *name; +{ + if (name == NULL) + return (UNCONF); + return (QUIET); +} +/* + * End of auto config stuff.... + */ + +/* + * Carry out a request from the high level driver. + */ +static int +ncr5380_scsi_cmd(struct scsi_xfer *xs) +{ + int sps; + SC_REQ *reqp; + int flags = xs->flags; + + /* + * We do not queue RESET commands + */ + if (flags & SCSI_RESET) { + scsi_reset(xs->sc_link->adapter_softc); + return (COMPLETE); + } + + /* + * Get a request block + */ + sps = splbio(); + if ((reqp = free_head) == 0) { + splx(sps); + return (TRY_AGAIN_LATER); + } + free_head = reqp->next; + reqp->next = NULL; + splx(sps); + + /* + * Initialize our private fields + */ + reqp->dr_flag = (flags & SCSI_POLL) ? DRIVER_NOINT : 0; + reqp->phase = NR_PHASE; + reqp->msgout = MSG_NOOP; + reqp->status = SCSGOOD; + reqp->link = NULL; + reqp->xs = xs; + reqp->targ_id = xs->sc_link->target; + reqp->targ_lun = xs->sc_link->lun; + reqp->xdata_ptr = (u_char*)xs->data; + reqp->xdata_len = xs->datalen; + memcpy(&reqp->xcmd, xs->cmd, sizeof(struct scsi_generic)); + reqp->xcmd.bytes[0] |= reqp->targ_lun << 5; + + /* + * Sanity check on flags... + */ + if (flags & ITSDONE) { + ncr_tprint(reqp, "scsi_cmd: command already done.....\n"); + xs->flags &= ~ITSDONE; + } + if (!(flags & INUSE)) { + ncr_tprint(reqp, "scsi_cmd: command not in use.....\n"); + xs->flags |= ~INUSE; + } + +#ifdef REAL_DMA + /* + * Check if DMA can be used on this request + */ + if (scsi_dmaok(reqp)) + reqp->dr_flag |= DRIVER_DMAOK; +#endif /* REAL_DMA */ + + /* + * Insert the command into the issue queue. Note that 'REQUEST SENSE' + * commands are inserted at the head of the queue since any command + * will clear the existing contingent allegience condition and the sense + * data is only valid while the condition exists. + * When possible, link the command to a previous command to the same + * target. This is not very sensible when AUTO_SENSE is not defined! + * Interrupts are disabled while we are fiddling with the issue-queue. + */ + sps = splbio(); + if ((issue_q == NULL) || (reqp->xcmd.opcode == REQUEST_SENSE)) { + reqp->next = issue_q; + issue_q = reqp; + } + else { + SC_REQ *tmp, *link; + + tmp = issue_q; + link = NULL; + do { + if (!link && (tmp->targ_id == reqp->targ_id) && !tmp->link) + link = tmp; + } while (tmp->next && (tmp = tmp->next)); + tmp->next = reqp; +#ifdef AUTO_SENSE + if (link) { + link->link = reqp; + link->xcmd.bytes[link->xs->cmdlen-1] |= 1; + } +#endif + } + splx(sps); + +#ifdef DBG_REQ + if (dbg_target_mask & (1 << reqp->targ_id)) + show_request(reqp, (reqp->xcmd.opcode == REQUEST_SENSE) ? + "HEAD":"TAIL"); +#endif + + run_main(xs->sc_link->adapter_softc); + + if (xs->flags & SCSI_POLL) + return (COMPLETE); /* We're booting */ + return (SUCCESSFULLY_QUEUED); +} + +static void +ncr5380_minphys(struct buf *bp) +{ + if (bp->b_bcount > MIN_PHYS) + bp->b_bcount = MIN_PHYS; + minphys(bp); +} +#undef MIN_PHYS + +static int +ncr5380_show_scsi_cmd(struct scsi_xfer *xs) +{ + u_char *b = (u_char *) xs->cmd; + int i = 0; + + if (!(xs->flags & SCSI_RESET)) { + printf("(%d:%d:%d,0x%x)-", xs->sc_link->scsibus, + xs->sc_link->target, xs->sc_link->lun, xs->sc_link->flags); + while (i < xs->cmdlen) { + if (i) + printf(","); + printf("%x",b[i++]); + } + printf("-\n"); + } + else { + printf("(%d:%d:%d)-RESET-\n", + xs->sc_link->scsibus,xs->sc_link->target, xs->sc_link->lun); + } +} + +/* + * The body of the driver. + */ +static void +scsi_main(sc) +struct ncr_softc *sc; +{ + SC_REQ *req, *prev; + int itype; + int sps; + + /* + * While running in the driver SCSI-interrupts are disabled. + */ + scsi_idisable(); + ENABLE_NCR5380(sc); + + PID("scsi_main1"); + for (;;) { + sps = splbio(); + if (!connected) { + /* + * Check if it is fair keep any exclusive access to DMA + * claimed. If not, stop queueing new jobs so the discon_q + * will be eventually drained and DMA can be given up. + */ + if (!fair_to_keep_dma()) + goto main_exit; + + /* + * Search through the issue-queue for a command + * destined for a target that isn't busy. + */ + prev = NULL; + for (req=issue_q; req != NULL; prev = req, req = req->next) { + if (!(busy & (1 << req->targ_id))) { + /* + * Found one, remove it from the issue queue + */ + if (prev == NULL) + issue_q = req->next; + else prev->next = req->next; + req->next = NULL; + break; + } + } + + /* + * When a request has just ended, we get here before an other + * device detects that the bus is free and that it can + * reconnect. The problem is that when this happens, we always + * baffle the device because our (initiator) id is higher. This + * can cause a sort of starvation on slow devices. So we check + * for a pending reselection here. + * Note that 'connected' will be non-null if the reselection + * succeeds. + */ + if ((GET_5380_REG(NCR5380_IDSTAT) & (SC_S_SEL|SC_S_IO)) + == (SC_S_SEL|SC_S_IO)){ + if (req != NULL) { + req->next = issue_q; + issue_q = req; + } + splx(sps); + + reselect(sc); + scsi_clr_ipend(); + goto connected; + } + + /* + * The host is not connected and there is no request + * pending, exit. + */ + if (req == NULL) { + PID("scsi_main2"); + goto main_exit; + } + + /* + * Re-enable interrupts before handling the request. + */ + splx(sps); + +#ifdef DBG_REQ + if (dbg_target_mask & (1 << req->targ_id)) + show_request(req, "TARGET"); +#endif + /* + * We found a request. Try to connect to the target. If the + * initiator fails arbitration, the command is put back in the + * issue queue. + */ + if (scsi_select(req, 0)) { + sps = splbio(); + req->next = issue_q; + issue_q = req; + splx(sps); +#ifdef DBG_REQ + if (dbg_target_mask & (1 << req->targ_id)) + ncr_tprint(req, "Select failed\n"); +#endif + } + } + else splx(sps); +connected: + if (connected) { + /* + * If the host is currently connected but a 'real-dma' transfer + * is in progress, the 'end-of-dma' interrupt restarts main. + * So quit. + */ + sps = splbio(); + if (connected && (connected->dr_flag & DRIVER_IN_DMA)) { + PID("scsi_main3"); + goto main_exit; + } + splx(sps); + + /* + * Let the target guide us through the bus-phases + */ + while (information_transfer() == -1) + ; + } + } + /* NEVER TO REACH HERE */ + panic("ncr5380-SCSI: not designed to come here"); + +main_exit: + /* + * We enter here with interrupts disabled. We are about to exit main + * so interrupts should be re-enabled. Because interrupts are edge + * triggered, we could already have missed the interrupt. Therefore + * we check the IRQ-line here and re-enter when we really missed a + * valid interrupt. + */ + PID("scsi_main4"); + scsi_ienable(); + SET_5380_REG(NCR5380_IDSTAT, SC_HOST_ID); + if (GET_5380_REG(NCR5380_DMSTAT) & SC_IRQ_SET) { + if ((itype = check_intr(sc)) != INTR_SPURIOUS) { + scsi_idisable(); + splx(sps); + + if (itype == INTR_RESEL) + reselect(sc); +#ifdef REAL_DMA + else dma_ready(); +#else + else { + if (pdma_ready()) + goto connected; + panic("Got DMA interrupt without DMA"); + } +#endif + scsi_clr_ipend(); + goto connected; + } + } + reconsider_dma(); + + main_running = 0; + splx(sps); + PID("scsi_main5"); +} + +#ifdef REAL_DMA +/* + * The SCSI-DMA interrupt. + * This interrupt can only be triggered when running in non-polled DMA + * mode. When DMA is not active, it will be silently ignored, it is usually + * to late because the EOP interrupt of the controller happens just a tiny + * bit earlier. It might become usefull when scatter/gather is implemented, + * because in that case only part of the DATAIN/DATAOUT transfer is taken + * out of a single buffer. + */ +static void +ncr_dma_intr(sc) +struct ncr_softc *sc; +{ + SC_REQ *reqp; + int dma_done; + + PID("ncr_dma_intr"); + if ((reqp = connected) && (reqp->dr_flag & DRIVER_IN_DMA)) { + scsi_idisable(); + if (!(dma_done = dma_ready())) { + transfer_dma(reqp, reqp->phase, 0); + return; + } + run_main(sc); + } +} +#endif /* REAL_DMA */ + +/* + * The SCSI-controller interrupt. This interrupt occurs on reselections and + * at the end of non-polled DMA-interrupts. It is assumed to be called from + * the machine-dependent hardware interrupt. + */ +static void +ncr_ctrl_intr(sc) +struct ncr_softc *sc; +{ + int itype; + int dma_done; + + while (GET_5380_REG(NCR5380_DMSTAT) & SC_IRQ_SET) { + scsi_idisable(); + if ((itype = check_intr(sc)) != INTR_SPURIOUS) { + if (itype == INTR_RESEL) + reselect(sc); + else { +#ifdef REAL_DMA + if (!(dma_done = dma_ready())) { + transfer_dma(connected, connected->phase, 0); + return; + } +#else + if (pdma_ready()) + return; + panic("Got DMA interrupt without DMA\n"); +#endif + } + scsi_clr_ipend(); + } + run_main(sc); + return; + } + PID("ncr_ctrl_intr1"); +} + +/* + * Initiate a connection path between the host and the target. The function + * first goes into arbitration for the SCSI-bus. When this succeeds, the target + * is selected and an 'IDENTIFY' message is send. + * Returns -1 when the arbitration failed. Otherwise 0 is returned. When + * the target does not respond (to either selection or 'MESSAGE OUT') the + * 'done' function is executed. + * The result code given by the driver can be influenced by setting 'code' + * to a non-zero value. This is the case when 'select' is called by abort. + */ +static int +scsi_select(reqp, code) +SC_REQ *reqp; +{ + u_long timeout; + u_char tmp[1]; + u_char phase; + u_long cnt; + int sps; + u_int8_t atn_flag; + u_int8_t targ_bit; + struct ncr_softc *sc; + + sc = reqp->xs->sc_link->adapter_softc; + DBG_SELPRINT ("Starting arbitration\n", 0); + PID("scsi_select1"); + + sps = splbio(); + + /* + * Prevent a race condition here. If a reslection interrupt occurred + * between the decision to pick a new request and the call to select, + * we abort the selection. + * Interrupts are lowered when the 5380 is setup to arbitrate for the + * bus. + */ + if (connected) { + splx(sps); + PID("scsi_select2"); + return (-1); + } + + /* + * Set phase bits to 0, otherwise the 5380 won't drive the bus during + * selection. + */ + SET_5380_REG(NCR5380_TCOM, 0); + SET_5380_REG(NCR5380_ICOM, 0); + + /* + * Arbitrate for the bus. + */ + SET_5380_REG(NCR5380_DATA, SC_HOST_ID); + SET_5380_REG(NCR5380_MODE, SC_ARBIT); + + splx(sps); + + cnt = 10; + while (!(GET_5380_REG(NCR5380_ICOM) & SC_AIP) && --cnt) + delay(1); + + if (!(GET_5380_REG(NCR5380_ICOM) & SC_AIP)) { + SET_5380_REG(NCR5380_MODE, IMODE_BASE); + SET_5380_REG(NCR5380_ICOM, 0); + DBG_SELPRINT ("Arbitration lost, bus not free\n",0); + PID("scsi_select3"); + return (-1); + } + + /* The arbitration delay is 2.2 usecs */ + delay(3); + + /* + * Check the result of the arbitration. If we failed, return -1. + */ + if (GET_5380_REG(NCR5380_ICOM) & SC_LA) { + SET_5380_REG(NCR5380_MODE, IMODE_BASE); + SET_5380_REG(NCR5380_ICOM, 0); + PID("scsi_select4"); + return (-1); + } + + /* + * The spec requires that we should read the data register to + * check for higher id's and check the SC_LA again. + */ + tmp[0] = GET_5380_REG(NCR5380_DATA); + if (tmp[0] & ~((SC_HOST_ID << 1) - 1)) { + SET_5380_REG(NCR5380_MODE, IMODE_BASE); + SET_5380_REG(NCR5380_ICOM, 0); + DBG_SELPRINT ("Arbitration lost, higher id present\n",0); + PID("scsi_select5"); + return (-1); + } + if (GET_5380_REG(NCR5380_ICOM) & SC_LA) { + SET_5380_REG(NCR5380_MODE, IMODE_BASE); + SET_5380_REG(NCR5380_ICOM, 0); + DBG_SELPRINT ("Arbitration lost,deassert SC_ARBIT\n",0); + PID("scsi_select6"); + return (-1); + } + SET_5380_REG(NCR5380_ICOM, SC_A_SEL | SC_A_BSY); + if (GET_5380_REG(NCR5380_ICOM) & SC_LA) { + SET_5380_REG(NCR5380_MODE, IMODE_BASE); + SET_5380_REG(NCR5380_ICOM, 0); + DBG_SELPRINT ("Arbitration lost, deassert SC_A_SEL\n", 0); + PID("scsi_select7"); + return (-1); + } + /* Bus settle delay + Bus clear delay = 1.2 usecs */ + delay(2); + DBG_SELPRINT ("Arbitration complete\n", 0); + + /* + * Now that we won the arbitration, start the selection. + */ + targ_bit = 1 << reqp->targ_id; + SET_5380_REG(NCR5380_DATA, SC_HOST_ID | targ_bit); + + if (sc->sc_noselatn & targ_bit) + atn_flag = 0; + else + atn_flag = SC_A_ATN; + + /* + * Raise ATN while SEL is true before BSY goes false from arbitration, + * since this is the only way to guarantee that we'll get a MESSAGE OUT + * phase immediately after the selection. + */ + SET_5380_REG(NCR5380_ICOM, SC_A_BSY | SC_A_SEL | atn_flag | SC_ADTB); + SET_5380_REG(NCR5380_MODE, IMODE_BASE); + + /* + * Turn off reselection interrupts + */ + SET_5380_REG(NCR5380_IDSTAT, 0); + + /* + * Reset BSY. The delay following it, surpresses a glitch in the + * 5380 which causes us to see our own BSY signal instead of that of + * the target. + */ + SET_5380_REG(NCR5380_ICOM, SC_A_SEL | atn_flag | SC_ADTB); + delay(1); + + /* + * Wait for the target to react, the specs call for a timeout of + * 250 ms. + */ + cnt = 25000; + while (!(GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY) && --cnt) + delay(10); + + if (!(GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY)) { + /* + * There is no reaction from the target, start the selection + * timeout procedure. We release the databus but keep SEL + * asserted. After that we wait a 'selection abort time' (200 + * usecs) and 2 deskew delays (90 ns) and check BSY again. + * When BSY is asserted, we assume the selection succeeded, + * otherwise we release the bus. + */ + SET_5380_REG(NCR5380_ICOM, SC_A_SEL | atn_flag); + delay(201); + if (!(GET_5380_REG(NCR5380_IDSTAT) & SC_S_BSY)) { + SET_5380_REG(NCR5380_ICOM, 0); + reqp->xs->error = code ? code : XS_SELTIMEOUT; + DBG_SELPRINT ("Target %d not responding to sel\n", + reqp->targ_id); + finish_req(reqp); + PID("scsi_select8"); + return (0); + } + } + SET_5380_REG(NCR5380_ICOM, atn_flag); + + DBG_SELPRINT ("Target %d responding to select.\n", reqp->targ_id); + + /* + * The SCSI-interrupts are disabled while a request is being handled. + */ + scsi_idisable(); + + /* + * If we did not request ATN, then don't try to send IDENTIFY. + */ + if (atn_flag == 0) { + reqp->phase = PH_CMD; + goto identify_failed; + } + + /* + * Here we prepare to send an 'IDENTIFY' message. + * Allow disconnect only when interrups are allowed. + */ + tmp[0] = MSG_IDENTIFY(reqp->targ_lun, + (reqp->dr_flag & DRIVER_NOINT) ? 0 : 1); + cnt = 1; + phase = PH_MSGOUT; + + /* + * Since we followed the SCSI-spec and raised ATN while SEL was true + * but before BSY was false during the selection, a 'MESSAGE OUT' + * phase should follow. Unfortunately, this does not happen on + * all targets (Asante ethernet devices, for example), so we must + * check the actual mode if the message transfer fails--if the + * new phase is PH_CMD and has never been successfully selected + * w/ATN in the past, then we assume that it is an old device + * that doesn't support select w/ATN. + */ + if (transfer_pio(&phase, tmp, &cnt, 0) || cnt) { + + if ((phase == PH_CMD) && !(sc->sc_selected & targ_bit)) { + DBG_SELPRINT ("Target %d: not responding to ATN.\n", + reqp->targ_id); + sc->sc_noselatn |= targ_bit; + reqp->phase = PH_CMD; + goto identify_failed; + } + + DBG_SELPRINT ("Target %d: failed to send identify\n", + reqp->targ_id); + /* + * Try to disconnect from the target. We cannot leave + * it just hanging here. + */ + if (!reach_msg_out(sc, sizeof(struct scsi_generic))) { + u_long len = 1; + u_char phase = PH_MSGOUT; + u_char msg = MSG_ABORT; + + transfer_pio(&phase, &msg, &len, 0); + } + else scsi_reset(sc); + + SET_5380_REG(NCR5380_ICOM, 0); + reqp->xs->error = code ? code : XS_DRIVER_STUFFUP; + finish_req(reqp); + PID("scsi_select9"); + return (0); + } + reqp->phase = PH_MSGOUT; + +identify_failed: + sc->sc_selected |= targ_bit; + +#ifdef notyet /* LWP: Do we need timeouts in the driver? */ + /* + * Command is connected, start timer ticking. + */ + ccb_p->xtimeout = ccb_p->timeout + Lbolt; +#endif + + connected = reqp; + busy |= targ_bit; + PID("scsi_select10"); + return (0); +} + +/* + * Return codes: + * -1: quit main, trigger on interrupt + * 0: keep on running main. + */ +static int +information_transfer() +{ + SC_REQ *reqp = connected; + u_char tmp, phase; + u_long len; + + PID("info_transf1"); + /* + * Clear pending interrupts from 5380-chip. + */ + scsi_clr_ipend(); + + /* + * We only have a valid SCSI-phase when REQ is asserted. Something + * is deadly wrong when BSY has dropped. + */ + tmp = GET_5380_REG(NCR5380_IDSTAT); + + if (!(tmp & SC_S_BSY)) { + busy &= ~(1 << reqp->targ_id); + connected = NULL; + reqp->xs->error = XS_BUSY; + finish_req(reqp); + PID("info_transf2"); + return (0); + } + + if (tmp & SC_S_REQ) { + phase = (tmp >> 2) & 7; + if (phase != reqp->phase) { + reqp->phase = phase; + DBG_INFPRINT(show_phase, reqp, phase); + } + } + else return (-1); + + switch (phase) { + case PH_DATAOUT: +#ifdef DBG_NOWRITE + ncr_tprint(reqp, "NOWRITE set -- write attempt aborted."); + reqp->msgout = MSG_ABORT; + SET_5380_REG(NCR5380_ICOM, SC_A_ATN); + return (-1); +#endif /* DBG_NOWRITE */ + /* + * If this is the first write using DMA, fill + * the bounce buffer. + */ + if (reqp->xdata_ptr == reqp->xs->data) { /* XXX */ + if (reqp->dr_flag & DRIVER_BOUNCING) + bcopy(reqp->xdata_ptr, reqp->bounceb, reqp->xdata_len); + } + + case PH_DATAIN: +#ifdef REAL_DMA + if (reqp->dr_flag & DRIVER_DMAOK) { + int poll = REAL_DMA_POLL|(reqp->dr_flag & DRIVER_NOINT); + transfer_dma(reqp, phase, poll); + if (!poll) + return (0); + } + else +#endif + { + PID("info_transf3"); + len = reqp->xdata_len; +#ifdef USE_PDMA + if (transfer_pdma(&phase, reqp->xdata_ptr, &len) == 0) + return (0); +#else + transfer_pio(&phase, reqp->xdata_ptr, &len, 0); +#endif + reqp->xdata_ptr += reqp->xdata_len - len; + reqp->xdata_len = len; + } + return (-1); + case PH_MSGIN: + /* + * We only expect single byte messages here. + */ + len = 1; + transfer_pio(&phase, &tmp, &len, 1); + reqp->message = tmp; + return (handle_message(reqp, tmp)); + case PH_MSGOUT: + len = 1; + transfer_pio(&phase, &reqp->msgout, &len, 0); + if (reqp->msgout == MSG_ABORT) { + busy &= ~(1 << reqp->targ_id); + connected = NULL; + reqp->xs->error = XS_DRIVER_STUFFUP; + finish_req(reqp); + PID("info_transf4"); + return (0); + } + reqp->msgout = MSG_NOOP; + return (-1); + case PH_CMD : + len = command_size(reqp->xcmd.opcode); + transfer_pio(&phase, (u_char *)&reqp->xcmd, &len, 0); + PID("info_transf5"); + return (-1); + case PH_STATUS: + len = 1; + transfer_pio(&phase, &tmp, &len, 0); + reqp->status = tmp; + PID("info_transf6"); + return (-1); + default : + ncr_tprint(reqp, "Unknown phase\n"); + } + PID("info_transf7"); + return (-1); +} + +/* + * Handle the message 'msg' send to us by the target. + * Return values: + * 0 : The current command has completed. + * -1 : Get on to the next phase. + */ +static int +handle_message(reqp, msg) +SC_REQ *reqp; +u_int msg; +{ + int sps; + + PID("hmessage1"); + switch (msg) { + /* + * Linking lets us reduce the time required to get + * the next command to the device, skipping the arbitration + * and selection time. In the current implementation, + * we merely have to start the next command pointed + * to by 'next_link'. + */ + case MSG_LINK_CMD_COMPLETE: + case MSG_LINK_CMD_COMPLETEF: + if (reqp->link == NULL) { + ncr_tprint(reqp, "No link for linked command"); + nack_message(reqp, MSG_ABORT); + PID("hmessage2"); + return (-1); + } + ack_message(); + reqp->xs->error = 0; + +#ifdef AUTO_SENSE + if (check_autosense(reqp, 0) == -1) + return (-1); +#endif /* AUTO_SENSE */ + +#ifdef DBG_REQ + if (dbg_target_mask & (1 << reqp->targ_id)) + show_request(reqp->link, "LINK"); +#endif + connected = reqp->link; + finish_req(reqp); + PID("hmessage3"); + return (-1); + case MSG_ABORT: + case MSG_CMDCOMPLETE: + ack_message(); + connected = NULL; + busy &= ~(1 << reqp->targ_id); + if (!(reqp->dr_flag & DRIVER_AUTOSEN)) { + reqp->xs->resid = reqp->xdata_len; + reqp->xs->error = 0; + } + +#ifdef AUTO_SENSE + if (check_autosense(reqp, 0) == -1) { + PID("hmessage4"); + return (0); + } +#endif /* AUTO_SENSE */ + + finish_req(reqp); + PID("hmessage5"); + return (0); + case MSG_MESSAGE_REJECT: + ack_message(); + PID("hmessage6"); + return (-1); + case MSG_DISCONNECT: + ack_message(); +#ifdef DBG_REQ + if (dbg_target_mask & (1 << reqp->targ_id)) + show_request(reqp, "DISCON"); +#endif + sps = splbio(); + connected = NULL; + reqp->next = discon_q; + discon_q = reqp; + splx(sps); + PID("hmessage7"); + return (0); + case MSG_SAVEDATAPOINTER: + case MSG_RESTOREPOINTERS: + /* + * We save pointers implicitely at disconnect. + * So we can ignore these messages. + */ + ack_message(); + PID("hmessage8"); + return (-1); + case MSG_EXTENDED: + nack_message(reqp, MSG_MESSAGE_REJECT); + PID("hmessage9"); + return (-1); + default: + ncr_tprint(reqp, "Unknown message %x\n", msg); + return (-1); + } + PID("hmessage10"); + return (-1); +} + +/* + * Handle reselection. If a valid reconnection occurs, connected + * points at the reconnected command. The command is removed from the + * disconnected queue. + */ +static void +reselect(sc) +struct ncr_softc *sc; +{ + u_char phase; + u_long len; + u_char msg; + u_char target_mask; + int abort = 0; + SC_REQ *tmp, *prev; + + PID("reselect1"); + target_mask = GET_5380_REG(NCR5380_DATA) & ~SC_HOST_ID; + + /* + * At this point, we have detected that our SCSI-id is on the bus, + * SEL is true and BSY was false for at least one bus settle + * delay (400 ns.). + * We must assert BSY ourselves, until the target drops the SEL signal. + * The SCSI-spec specifies no maximum time for this, so we have to + * choose something long enough to suit all targets. + */ + SET_5380_REG(NCR5380_ICOM, SC_A_BSY); + len = 1000; + while ((GET_5380_REG(NCR5380_IDSTAT) & SC_S_SEL) && (len > 0)) { + if(!GET_5380_REG(NCR5380_DATA)) { + /* + * We stepped into the reselection timeout.... + */ + SET_5380_REG(NCR5380_ICOM, 0); + return; + } + delay(1); + len--; + } + if (GET_5380_REG(NCR5380_IDSTAT) & SC_S_SEL) { + /* Damn SEL isn't dropping */ + scsi_reset(sc); + return; + } + + SET_5380_REG(NCR5380_ICOM, 0); + + /* + * Get the expected identify message. + */ + phase = PH_MSGIN; + len = 1; + transfer_pio(&phase, &msg, &len, 0); + if (len || !MSG_ISIDENTIFY(msg)) { + ncr_aprint(sc, "Expecting IDENTIFY, got 0x%x\n", msg); + abort = 1; + } + else { + /* + * Find the command reconnecting + */ + for (tmp = discon_q, prev = NULL; tmp; prev = tmp, tmp = tmp->next){ + if (target_mask == (1 << tmp->targ_id)) { + if (prev) + prev->next = tmp->next; + else discon_q = tmp->next; + tmp->next = NULL; + break; + } + } + if (tmp == NULL) { + ncr_aprint(sc, "No disconnected job for targetmask %x\n", + target_mask); + abort = 1; + } + } + if (abort) { + msg = MSG_ABORT; + len = 1; + phase = PH_MSGOUT; + + SET_5380_REG(NCR5380_ICOM, SC_A_ATN); + transfer_pio(&phase, &msg, &len, 0); + } + else { + connected = tmp; +#ifdef DBG_REQ + if (dbg_target_mask & (1 << tmp->targ_id)) + show_request(tmp, "RECON"); +#endif + } + PID("reselect2"); +} + +/* + * Transfer data in a given phase using programmed I/O. + * Returns -1 when a different phase is entered without transferring the + * maximum number of bytes, 0 if all bytes transferred or exit is in the same + * phase. + */ +static int +transfer_pio(phase, data, len, dont_drop_ack) +u_char *phase; +u_char *data; +u_long *len; +int dont_drop_ack; +{ + u_int cnt = *len; + u_char ph = *phase; + u_char tmp, new_icom; + + DBG_PIOPRINT ("SCSI: transfer_pio start: phase: %d, len: %d\n", ph,cnt); + PID("tpio1"); + SET_5380_REG(NCR5380_TCOM, ph); + do { + if (!wait_req_true()) { + DBG_PIOPRINT ("SCSI: transfer_pio: missing REQ\n", 0, 0); + break; + } + if (((GET_5380_REG(NCR5380_IDSTAT) >> 2) & 7) != ph) { + DBG_PIOPRINT ("SCSI: transfer_pio: phase mismatch\n", 0, 0); + break; + } + if (PH_IN(ph)) { + *data++ = GET_5380_REG(NCR5380_DATA); + SET_5380_REG(NCR5380_ICOM, SC_A_ACK); + if ((cnt == 1) && dont_drop_ack) + new_icom = SC_A_ACK; + else new_icom = 0; + } + else { + SET_5380_REG(NCR5380_DATA, *data++); + + /* + * The SCSI-standard suggests that in the 'MESSAGE OUT' phase, + * the initiator should drop ATN on the last byte of the + * message phase after REQ has been asserted for the handshake + * but before the initiator raises ACK. + */ + if (!( (ph == PH_MSGOUT) && (cnt > 1) )) { + SET_5380_REG(NCR5380_ICOM, SC_ADTB); + SET_5380_REG(NCR5380_ICOM, SC_ADTB | SC_A_ACK); + new_icom = 0; + } + else { + SET_5380_REG(NCR5380_ICOM, SC_ADTB | SC_A_ATN); + SET_5380_REG(NCR5380_ICOM, SC_ADTB|SC_A_ATN|SC_A_ACK); + new_icom = SC_A_ATN; + } + } + if (!wait_req_false()) { + DBG_PIOPRINT ("SCSI: transfer_pio - REQ not dropping\n", 0, 0); + break; + } + SET_5380_REG(NCR5380_ICOM, new_icom); + + } while (--cnt); + + if ((tmp = GET_5380_REG(NCR5380_IDSTAT)) & SC_S_REQ) + *phase = (tmp >> 2) & 7; + else *phase = NR_PHASE; + *len = cnt; + DBG_PIOPRINT ("SCSI: transfer_pio done: phase: %d, len: %d\n", + *phase, cnt); + PID("tpio2"); + if (!cnt || (*phase == ph)) + return (0); + return (-1); +} + +#ifdef REAL_DMA +/* + * Start a DMA-transfer on the device using the current pointers. + * If 'poll' is true, the function busy-waits until DMA has completed. + */ +static void +transfer_dma(reqp, phase, poll) +SC_REQ *reqp; +u_int phase; +int poll; +{ + int dma_done; + u_char mbase = 0; + int sps; + +again: + PID("tdma1"); + + /* + * We should be in phase, otherwise we are not allowed to + * drive the bus. + */ + SET_5380_REG(NCR5380_TCOM, phase); + + /* + * Defer interrupts until DMA is fully running. + */ + sps = splbio(); + + /* + * Clear pending interrupts and parity errors. + */ + scsi_clr_ipend(); + + if (!poll) { + /* + * Enable SCSI interrupts and set IN_DMA flag, set 'mbase' + * to the interrupts we want enabled. + */ + scsi_ienable(); + reqp->dr_flag |= DRIVER_IN_DMA; + mbase = SC_E_EOPI | SC_MON_BSY; + } + else scsi_idisable(); + mbase |= IMODE_BASE | SC_M_DMA; + scsi_dma_setup(reqp, phase, mbase); + + splx(sps); + + if (poll) { + /* + * On polled-dma transfers, we wait here until the + * 'end-of-dma' condition occurs. + */ + poll_edma(reqp); + if (!(dma_done = dma_ready())) + goto again; + } + PID("tdma2"); +} + +/* + * Check results of a DMA data-transfer. + */ +static int +dma_ready() +{ + SC_REQ *reqp = connected; + int dmstat, is_edma; + long bytes_left, bytes_done; + + is_edma = get_dma_result(reqp, &bytes_left); + dmstat = GET_5380_REG(NCR5380_DMSTAT); + + /* + * Check if the call is sensible and not caused by any spurious + * interrupt. + */ + if (!is_edma && !(dmstat & (SC_END_DMA|SC_BSY_ERR)) + && (dmstat & SC_PHS_MTCH) ) { + ncr_tprint(reqp, "dma_ready: spurious call" + "(dm:%x,last_hit: %s)\n", +#ifdef DBG_PID + dmstat, last_hit); +#else + dmstat, "unknown"); +#endif + return (0); + } + + /* + * Clear all (pending) interrupts. + */ + scsi_clr_ipend(); + + /* + * Update various transfer-pointers/lengths + */ + bytes_done = reqp->dm_cur->dm_count - bytes_left; + + if ((reqp->dr_flag & DRIVER_BOUNCING) && (PH_IN(reqp->phase))) { + /* + * Copy the bytes read until now from the bounce buffer + * to the 'real' destination. Flush the data-cache + * before copying. + */ + PCIA(); + bcopy(reqp->bouncerp, reqp->xdata_ptr, bytes_done); + reqp->bouncerp += bytes_done; + } + + reqp->xdata_ptr = &reqp->xdata_ptr[bytes_done]; /* XXX */ + reqp->xdata_len -= bytes_done; /* XXX */ + if ((reqp->dm_cur->dm_count -= bytes_done) == 0) + reqp->dm_cur++; + else reqp->dm_cur->dm_addr += bytes_done; + + if (PH_IN(reqp->phase) && (dmstat & SC_PAR_ERR)) { + if (!(ncr5380_no_parchk & (1 << reqp->targ_id))) + /* XXX: Should be parity error ???? */ + reqp->xs->error = XS_DRIVER_STUFFUP; + } + + /* + * DMA mode should always be reset even when we will continue with the + * next chain. It is also essential to clear the MON_BUSY because + * when LOST_BUSY is unexpectedly set, we will not be able to drive + * the bus.... + */ + SET_5380_REG(NCR5380_MODE, IMODE_BASE); + + + if ((dmstat & SC_BSY_ERR) || !(dmstat & SC_PHS_MTCH) + || (reqp->dm_cur > reqp->dm_last) || (reqp->xs->error)) { + + /* + * Tell interrupt functions DMA mode has ended. + */ + reqp->dr_flag &= ~DRIVER_IN_DMA; + + /* + * Clear mode and icom + */ + SET_5380_REG(NCR5380_MODE, IMODE_BASE); + SET_5380_REG(NCR5380_ICOM, 0); + + if (dmstat & SC_BSY_ERR) { + if (!reqp->xs->error) + reqp->xs->error = XS_BUSY; + finish_req(reqp); + PID("dma_ready1"); + return (1); + } + + if (reqp->xs->error != 0) { +ncr_tprint(reqp, "dma-ready: code = %d\n", reqp->xs->error); /* LWP */ + reqp->msgout = MSG_ABORT; + SET_5380_REG(NCR5380_ICOM, SC_A_ATN); + } + PID("dma_ready2"); + return (1); + } + return (0); +} +#endif /* REAL_DMA */ + +static int +check_autosense(reqp, linked) +SC_REQ *reqp; +int linked; +{ + int sps; + + /* + * If we not executing an auto-sense and the status code + * is request-sense, we automatically issue a request + * sense command. + */ + PID("cautos1"); + if (!(reqp->dr_flag & DRIVER_AUTOSEN)) { + if (reqp->status == SCSCHKC) { + memcpy(&reqp->xcmd, sense_cmd, sizeof(sense_cmd)); + reqp->xdata_ptr = (u_char *)&reqp->xs->sense; + reqp->xdata_len = sizeof(reqp->xs->sense); + reqp->dr_flag |= DRIVER_AUTOSEN; + reqp->dr_flag &= ~DRIVER_DMAOK; + if (!linked) { + sps = splbio(); + reqp->next = issue_q; + issue_q = reqp; + splx(sps); + } + else reqp->xcmd.bytes[4] |= 1; + +#ifdef DBG_REQ + bzero(reqp->xdata_ptr, reqp->xdata_len); + if (dbg_target_mask & (1 << reqp->targ_id)) + show_request(reqp, "AUTO-SENSE"); +#endif + PID("cautos2"); + return (-1); + } + } + else { + /* + * An auto-sense has finished + */ + if ((reqp->status & SCSMASK) != SCSGOOD) + reqp->xs->error = XS_DRIVER_STUFFUP; /* SC_E_AUTOSEN; */ + else reqp->xs->error = XS_SENSE; + reqp->status = SCSCHKC; + } + PID("cautos3"); + return (0); +} + +static int +reach_msg_out(sc, len) +struct ncr_softc *sc; +u_long len; +{ + u_char phase; + u_char data; + + ncr_aprint(sc, "Trying to reach Message-out phase\n"); + if ((phase = GET_5380_REG(NCR5380_IDSTAT)) & SC_S_REQ) + phase = (phase >> 2) & 7; + else return (-1); + ncr_aprint(sc, "Trying to reach Message-out phase, now: %d\n", phase); + if (phase == PH_MSGOUT) + return (0); + + SET_5380_REG(NCR5380_TCOM, phase); + + do { + if (!wait_req_true()) + break; + if (((GET_5380_REG(NCR5380_IDSTAT) >> 2) & 7) != phase) + break; + if (PH_IN(phase)) { + data = GET_5380_REG(NCR5380_DATA); + SET_5380_REG(NCR5380_ICOM, SC_A_ACK | SC_A_ATN); + } + else { + SET_5380_REG(NCR5380_DATA, 0); + SET_5380_REG(NCR5380_ICOM, SC_ADTB|SC_A_ACK|SC_A_ATN); + } + if (!wait_req_false()) + break; + SET_5380_REG(NCR5380_ICOM, SC_A_ATN); + } while (--len); + + if ((phase = GET_5380_REG(NCR5380_IDSTAT)) & SC_S_REQ) { + phase = (phase >> 2) & 7; + if (phase == PH_MSGOUT) { + ncr_aprint(sc, "Message-out phase reached.\n"); + return (0); + } + } + return (-1); +} + +static void +scsi_reset(sc) +struct ncr_softc *sc; +{ + SC_REQ *tmp, *next; + int sps; + + ncr_aprint(sc, "Resetting SCSI-bus\n"); + + PID("scsi_reset1"); + sps = splbio(); + SET_5380_REG(NCR5380_ICOM, SC_A_RST); + delay(1); + SET_5380_REG(NCR5380_ICOM, 0); + + /* + * None of the jobs in the discon_q will ever be reconnected, + * notify this to the higher level code. + */ + for (tmp = discon_q; tmp ;) { + next = tmp->next; + tmp->next = NULL; + tmp->xs->error = XS_TIMEOUT; + busy &= ~(1 << tmp->targ_id); + finish_req(tmp); + tmp = next; + } + discon_q = NULL; + + /* + * The current job will never finish either. + * The problem is that we can't finish the job because an instance + * of main is running on it. Our best guess is that the job is currently + * doing REAL-DMA. In that case 'dma_ready()' should correctly finish + * the job because it detects BSY-loss. + */ + if (tmp = connected) { + if (tmp->dr_flag & DRIVER_IN_DMA) { + tmp->xs->error = XS_DRIVER_STUFFUP; +#ifdef REAL_DMA + dma_ready(); +#endif + } + } + splx(sps); + PID("scsi_reset2"); +} + +/* + * Check validity of the IRQ set by the 5380. If the interrupt is valid, + * the appropriate action is carried out (reselection or DMA ready) and + * INTR_RESEL or INTR_DMA is returned. Otherwise a console notice is written + * and INTR_SPURIOUS is returned. + */ +static int +check_intr(sc) +struct ncr_softc *sc; +{ + SC_REQ *reqp; + + if ((GET_5380_REG(NCR5380_IDSTAT) & (SC_S_SEL|SC_S_IO)) + ==(SC_S_SEL|SC_S_IO)) + return (INTR_RESEL); + else { + if ((reqp = connected) && (reqp->dr_flag & DRIVER_IN_DMA)){ + reqp->dr_flag &= ~DRIVER_IN_DMA; + return (INTR_DMA); + } + } + scsi_clr_ipend(); + printf("-->"); + scsi_show(); + ncr_aprint(sc, "Spurious interrupt.\n"); + return (INTR_SPURIOUS); +} + +#ifdef REAL_DMA +/* + * Check if DMA can be used for this request. This function also builds + * the dma-chain. + */ +static int +scsi_dmaok(reqp) +SC_REQ *reqp; +{ + u_long phy_buf; + u_long phy_len; + void *req_addr; + u_long req_len; + struct dma_chain *dm; + + /* + * Initialize locals and requests' DMA-chain. + */ + req_len = reqp->xdata_len; + req_addr = (void*)reqp->xdata_ptr; + dm = reqp->dm_cur = reqp->dm_last = reqp->dm_chain; + dm->dm_count = dm->dm_addr = 0; + reqp->dr_flag &= ~DRIVER_BOUNCING; + + /* + * Do not accept zero length DMA. + */ + if (req_len == 0) + return (0); + + /* + * LWP: I think that this restriction is not strictly nessecary. + */ + if ((req_len & 0x1) || ((u_int)req_addr & 0x3)) + return (0); + + /* + * Build the DMA-chain. + */ + dm->dm_addr = phy_buf = kvtop(req_addr); + while (req_len) { + if (req_len < (phy_len = NBPG - ((u_long)req_addr & PGOFSET))) + phy_len = req_len; + + req_addr += phy_len; + req_len -= phy_len; + dm->dm_count += phy_len; + + if (req_len) { + u_long tmp = kvtop(req_addr); + + if ((phy_buf + phy_len) != tmp) { + if (wrong_dma_range(reqp, dm)) { + if (reqp->dr_flag & DRIVER_BOUNCING) + goto bounceit; + return (0); + } + + if (++dm >= &reqp->dm_chain[MAXDMAIO]) { + ncr_tprint(reqp,"dmaok: DMA chain too long!\n"); + return (0); + } + dm->dm_count = 0; + dm->dm_addr = tmp; + } + phy_buf = tmp; + } + } + if (wrong_dma_range(reqp, dm)) { + if (reqp->dr_flag & DRIVER_BOUNCING) + goto bounceit; + return (0); + } + reqp->dm_last = dm; + return (1); + +bounceit: + if ((reqp->bounceb = alloc_bounceb(reqp->xdata_len)) == NULL) { + /* + * If we can't get a bounce buffer, forget DMA + */ + reqp->dr_flag &= ~DRIVER_BOUNCING; + return(0); + } + /* + * Initialize a single DMA-range containing the bounced request + */ + dm = reqp->dm_cur = reqp->dm_last = reqp->dm_chain; + dm->dm_addr = kvtop(reqp->bounceb); + dm->dm_count = reqp->xdata_len; + reqp->bouncerp = reqp->bounceb; + + return (1); +} +#endif /* REAL_DMA */ + +static void +run_main(sc) +struct ncr_softc *sc; +{ + int sps = splbio(); + + if (!main_running) { + /* + * If shared resources are required, claim them + * before entering 'scsi_main'. If we can't get them + * now, assume 'run_main' will be called when the resource + * becomes available. + */ + if (!claimed_dma()) { + splx(sps); + return; + } + main_running = 1; + splx(sps); + scsi_main(sc); + } + else splx(sps); +} + +/* + * Prefix message with full target info. + */ +static void +ncr_tprint(SC_REQ *reqp, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + sc_print_addr(reqp->xs->sc_link); + printf("%r", fmt, ap); + va_end(ap); +} + +/* + * Prefix message with adapter info. + */ +static void +ncr_aprint(struct ncr_softc *sc, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + printf("%s : %r", sc->sc_dev.dv_xname, fmt, ap); + va_end(ap); +} +/**************************************************************************** + * Start Debugging Functions * + ****************************************************************************/ +static void +show_data_sense(xs) +struct scsi_xfer *xs; +{ + u_char *p1, *p2; + int i; + int sz; + + p1 = (u_char *) xs->cmd; + p2 = (u_char *)&xs->sense; + if(*p2 == 0) + return; /* No(n)sense */ + printf("cmd[%d,%d]: ", xs->cmdlen, sz = command_size(*p1)); + for (i = 0; i < sz; i++) + printf("%x ", p1[i]); + printf("\nsense: "); + for (i = 0; i < sizeof(xs->sense); i++) + printf("%x ", p2[i]); + printf("\n"); +} + +static void +show_request(reqp, qtxt) +SC_REQ *reqp; +char *qtxt; +{ + printf("REQ-%s: %d %x[%d] cmd[0]=%x S=%x M=%x R=%x resid=%d %s\n", + qtxt, reqp->targ_id, reqp->xdata_ptr, reqp->xdata_len, + reqp->xcmd.opcode, reqp->status, reqp->message, + reqp->xs->error, reqp->xs->resid, reqp->link ? "L":""); + if (reqp->status == SCSCHKC) + show_data_sense(reqp->xs); +} + +static char *sig_names[] = { + "PAR", "SEL", "I/O", "C/D", "MSG", "REQ", "BSY", "RST", + "ACK", "ATN", "LBSY", "PMATCH", "IRQ", "EPAR", "DREQ", "EDMA" +}; + +static void +show_signals(dmstat, idstat) +u_char dmstat, idstat; +{ + u_short tmp, mask; + int i, j, need_pipe; + + tmp = idstat | ((dmstat & 3) << 8); + printf("Bus signals (%02x/%02x): ", idstat, dmstat & 3); + for (mask = 1, j = need_pipe = 0; mask <= tmp; mask <<= 1, j++) { + if (tmp & mask) + printf("%s%s", need_pipe++ ? "|" : "", sig_names[j]); + } + printf("\nDma status (%02x): ", dmstat); + for (mask = 4, j = 10, need_pipe = 0; mask <= dmstat; mask <<= 1, j++) { + if (dmstat & mask) + printf("%s%s", need_pipe++ ? "|" : "", sig_names[j]); + } + printf("\n"); +} + +scsi_show() +{ + SC_REQ *tmp; + int sps = splhigh(); + u_char idstat, dmstat; + +#ifndef DBG_PID + #define last_hit "" + #define olast_hit "" +#endif + + for (tmp = issue_q; tmp; tmp = tmp->next) + show_request(tmp, "ISSUED"); + for (tmp = discon_q; tmp; tmp = tmp->next) + show_request(tmp, "DISCONNECTED"); + if (connected) + show_request(connected, "CONNECTED"); + idstat = GET_5380_REG(NCR5380_IDSTAT); + dmstat = GET_5380_REG(NCR5380_DMSTAT); + show_signals(dmstat, idstat); + if (connected) + printf("phase = %d, ", connected->phase); + printf("busy:%x, last_hit:%s, olast_hit:%s spl:%04x\n", busy, + last_hit, olast_hit, sps); + + splx(sps); +} diff --git a/sys/arch/atari/dev/ncr5380reg.h b/sys/arch/atari/dev/ncr5380reg.h new file mode 100644 index 00000000000..717434ff81d --- /dev/null +++ b/sys/arch/atari/dev/ncr5380reg.h @@ -0,0 +1,258 @@ +/* $NetBSD: ncr5380reg.h,v 1.5 1995/10/05 08:53:00 leo Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman. + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Leo Weppelman. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#ifndef _NCR5380REG_H +#define _NCR5380REG_H +/* + * NCR5380 common interface definitions. + */ + +/* + * Register numbers: (first argument to GET/SET_5380_REG ) + */ +#define NCR5380_DATA 0 /* Data register */ +#define NCR5380_ICOM 1 /* Initiator command register */ +#define NCR5380_MODE 2 /* Mode register */ +#define NCR5380_TCOM 3 /* Target command register */ +#define NCR5380_IDSTAT 4 /* Bus status register */ +#define NCR5380_DMSTAT 5 /* DMA status register */ +#define NCR5380_TRCV 6 /* Target receive register */ +#define NCR5380_IRCV 7 /* Initiator receive register */ + +/* + * Definitions for Initiator command register. + */ +#define SC_A_RST 0x80 /* RW - Assert RST */ +#define SC_TEST 0x40 /* W - Test mode */ +#define SC_AIP 0x40 /* R - Arbitration in progress */ +#define SC_LA 0x20 /* R - Lost arbitration */ +#define SC_A_ACK 0x10 /* RW - Assert ACK */ +#define SC_A_BSY 0x08 /* RW - Assert BSY */ +#define SC_A_SEL 0x04 /* RW - Assert SEL */ +#define SC_A_ATN 0x02 /* RW - Assert ATN */ +#define SC_ADTB 0x01 /* RW - Assert Data To Bus */ + +/* + * Definitions for mode register + */ +#define SC_B_DMA 0x80 /* RW - Block mode DMA (not on TT!) */ +#define SC_T_MODE 0x40 /* RW - Target mode */ +#define SC_E_PAR 0x20 /* RW - Enable parity check */ +#define SC_E_PARI 0x10 /* RW - Enable parity interrupt */ +#define SC_E_EOPI 0x08 /* RW - Enable End Of Process Interrupt */ +#define SC_MON_BSY 0x04 /* RW - Monitor BSY */ +#define SC_M_DMA 0x02 /* RW - Set DMA mode */ +#define SC_ARBIT 0x01 /* RW - Arbitrate */ + +/* + * Definitions for tcom register + */ +#define SC_LBS 0x80 /* RW - Last Byte Send (not on TT!) */ +#define SC_A_REQ 0x08 /* RW - Assert REQ */ +#define SC_A_MSG 0x04 /* RW - Assert MSG */ +#define SC_A_CD 0x02 /* RW - Assert C/D */ +#define SC_A_IO 0x01 /* RW - Assert I/O */ + +/* + * Definitions for idstat register + */ +#define SC_S_RST 0x80 /* R - RST is set */ +#define SC_S_BSY 0x40 /* R - BSY is set */ +#define SC_S_REQ 0x20 /* R - REQ is set */ +#define SC_S_MSG 0x10 /* R - MSG is set */ +#define SC_S_CD 0x08 /* R - C/D is set */ +#define SC_S_IO 0x04 /* R - I/O is set */ +#define SC_S_SEL 0x02 /* R - SEL is set */ +#define SC_S_PAR 0x01 /* R - Parity bit */ + +/* + * Definitions for dmastat register + */ +#define SC_END_DMA 0x80 /* R - End of DMA */ +#define SC_DMA_REQ 0x40 /* R - DMA request */ +#define SC_PAR_ERR 0x20 /* R - Parity error */ +#define SC_IRQ_SET 0x10 /* R - IRQ is active */ +#define SC_PHS_MTCH 0x08 /* R - Phase Match */ +#define SC_BSY_ERR 0x04 /* R - Busy error */ +#define SC_ATN_STAT 0x02 /* R - State of ATN line */ +#define SC_ACK_STAT 0x01 /* R - State of ACK line */ +#define SC_S_SEND 0x00 /* W - Start DMA output */ + +#define SC_CLINT { /* Clear interrupts */ \ + int i = GET_5380_REG(NCR5380_IRCV); \ + } + + +/* + * Definition of SCSI-bus phases. The values are determined by signals + * on the SCSI-bus. DO NOT CHANGE! + * The values must be used to index the pointers in SCSI-PARMS. + */ +#define NR_PHASE 8 +#define PH_DATAOUT 0 +#define PH_DATAIN 1 +#define PH_CMD 2 +#define PH_STATUS 3 +#define PH_RES1 4 +#define PH_RES2 5 +#define PH_MSGOUT 6 +#define PH_MSGIN 7 + +#define PH_OUT(phase) (!(phase & 1)) /* TRUE if output phase */ +#define PH_IN(phase) (phase & 1) /* TRUE if input phase */ + +/* + * Id of Host-adapter + */ +#define SC_HOST_ID 0x80 + +/* + * Base setting for 5380 mode register + */ +#define IMODE_BASE SC_E_PAR + +/* + * SCSI completion status codes, should move to sys/scsi/???? + */ +#define SCSMASK 0x1e /* status code mask */ +#define SCSGOOD 0x00 /* good status */ +#define SCSCHKC 0x02 /* check condition */ +#define SCSBUSY 0x08 /* busy status */ +#define SCSCMET 0x04 /* condition met / good */ + +/* + * Return values of check_intr() + */ +#define INTR_SPURIOUS 0 +#define INTR_RESEL 2 +#define INTR_DMA 3 + +struct ncr_softc { + struct device sc_dev; + struct scsi_link sc_link; + + /* + * Some (pre-SCSI2) devices don't support select with ATN. + * If the device responds to select with ATN by going into + * command phase (ignoring ATN), then we flag it in the + * following bitmask. + * We also keep track of which devices have been selected + * before. This allows us to not even try raising ATN if + * the target doesn't respond to it the first time. + */ + u_int8_t sc_noselatn; + u_int8_t sc_selected; +}; + +/* + * Max. number of dma-chains per request + */ +#define MAXDMAIO (MAXPHYS/NBPG + 1) + +/* + * Some requests are not contiguous in physical memory. We need to break them + * up into contiguous parts for DMA. + */ +struct dma_chain { + u_int dm_count; + u_long dm_addr; +}; + +/* + * Define our issue, free and disconnect queue's. + */ +typedef struct req_q { + struct req_q *next; /* next in free, issue or discon queue */ + struct req_q *link; /* next linked command to execute */ + struct scsi_xfer *xs; /* request from high-level driver */ + u_short dr_flag; /* driver state */ + u_char phase; /* current SCSI phase */ + u_char msgout; /* message to send when requested */ + u_char targ_id; /* target for command */ + u_char targ_lun; /* lun for command */ + u_char status; /* returned status byte */ + u_char message; /* returned message byte */ + u_char *bounceb; /* allocated bounce buffer */ + u_char *bouncerp; /* bounce read-pointer */ + struct dma_chain dm_chain[MAXDMAIO]; + struct dma_chain *dm_cur; /* current dma-request */ + struct dma_chain *dm_last; /* last dma-request */ + long xdata_len; /* length of transfer */ + u_char *xdata_ptr; /* virtual address of transfer */ + struct scsi_generic xcmd; /* command to execute */ +} SC_REQ; + +/* + * Values for dr_flag: + */ +#define DRIVER_IN_DMA 0x01 /* Non-polled DMA activated */ +#define DRIVER_AUTOSEN 0x02 /* Doing automatic sense */ +#define DRIVER_NOINT 0x04 /* We are booting: no interrupts */ +#define DRIVER_DMAOK 0x08 /* DMA can be used on this request */ +#define DRIVER_BOUNCING 0x10 /* Using the bounce buffer */ + +/* XXX: Should go to ncr5380var.h */ +static SC_REQ *issue_q = NULL; /* Commands waiting to be issued*/ +static SC_REQ *discon_q = NULL; /* Commands disconnected */ +static SC_REQ *connected = NULL; /* Command currently connected */ + +/* + * Function decls: + */ +static int transfer_pio __P((u_char *, u_char *, u_long *, int)); +static int wait_req_true __P((void)); +static int wait_req_false __P((void)); +static int scsi_select __P((SC_REQ *, int)); +static int handle_message __P((SC_REQ *, u_int)); +static void ack_message __P((void)); +static void nack_message __P((SC_REQ *, u_char)); +static int information_transfer __P((void)); +static void reselect __P((struct ncr_softc *)); +static int dma_ready __P((void)); +static void transfer_dma __P((SC_REQ *, u_int, int)); +static int check_autosense __P((SC_REQ *, int)); +static int reach_msg_out __P((struct ncr_softc *, u_long)); +static int check_intr __P((struct ncr_softc *)); +static void scsi_reset __P((struct ncr_softc *)); +static int scsi_dmaok __P((SC_REQ *)); +static void run_main __P((struct ncr_softc *)); +static void scsi_main __P((struct ncr_softc *)); +static void ncr_ctrl_intr __P((struct ncr_softc *)); +static void ncr_dma_intr __P((struct ncr_softc *)); +static void ncr_tprint __P((SC_REQ *, char *, ...)); +static void ncr_aprint __P((struct ncr_softc *, char *, ...)); + +static void show_request __P((SC_REQ *, char *)); +static void show_phase __P((SC_REQ *, int)); +static void show_signals __P((u_char, u_char)); + +#endif /* _NCR5380REG_H */ diff --git a/sys/arch/atari/dev/ramd.c b/sys/arch/atari/dev/ramd.c new file mode 100644 index 00000000000..46f7fab41bf --- /dev/null +++ b/sys/arch/atari/dev/ramd.c @@ -0,0 +1,481 @@ +/* $NetBSD: ramd.c,v 1.5 1995/08/12 20:31:02 mycroft Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman. + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Leo Weppelman. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/buf.h> +#include <sys/proc.h> +#include <sys/device.h> +#include <sys/ioctl.h> +#include <sys/fcntl.h> +#include <sys/conf.h> +#include <sys/disklabel.h> +#include <sys/disk.h> +#include <sys/dkbad.h> + +/* + * Misc. defines: + */ +#define RAMD_CHUNK (9 * 512) /* Chunk-size for auto-load */ +#define RAMD_NDEV 2 /* Number of devices configured */ + +struct ramd_info { + u_long ramd_size; /* Size of disk in bytes */ + u_long ramd_flag; /* see defs below */ + dev_t ramd_dev; /* device to load from */ + u_long ramd_state; /* runtime state see defs below */ + caddr_t ramd_addr; /* Kernel virtual addr */ +}; + +/* + * ramd_flag: + */ +#define RAMD_LOAD 0x01 /* Auto load when first opened */ +#define RAMD_LCOMP 0x02 /* Input is compressed */ + +/* + * ramd_state: + */ +#define RAMD_ALLOC 0x01 /* Memory is allocated */ +#define RAMD_OPEN 0x02 /* Ramdisk is open */ +#define RAMD_INOPEN 0x04 /* Ramdisk is being opened */ +#define RAMD_WANTED 0x08 /* Someone is waiting on struct */ +#define RAMD_LOADED 0x10 /* Ramdisk is properly loaded */ + +struct ramd_info rd_info[RAMD_NDEV] = { + { + 1105920, /* 1Mb in 2160 sectors */ + RAMD_LOAD, /* auto-load this device */ + MAKEDISKDEV(2, 0, 1), /* XXX: This is crap! (720Kb flop) */ + 0, /* Will be set at runtime */ + NULL /* Will be set at runtime */ + }, + { + 1474560, /* 1.44Mb in 2880 sectors */ + RAMD_LOAD, /* auto-load this device */ + MAKEDISKDEV(2, 0, 1), /* XXX: This is crap! (720Kb flop) */ + 0, /* Will be set at runtime */ + NULL /* Will be set at runtime */ + } +}; + +struct read_info { + struct buf *bp; /* buffer for strategy function */ + long nbytes; /* total number of bytes to read */ + long offset; /* offset in input medium */ + caddr_t bufp; /* current output buffer */ + caddr_t ebufp; /* absolute maximum for bufp */ + int chunk; /* chunk size on input medium */ + int media_sz; /* size of input medium */ + void (*strat)(); /* strategy function for read */ +}; + +/* + * Autoconfig stuff.... + */ +static int ramdmatch __P((struct device *, struct cfdata *, void *)); +static int ramdprint __P((void *, char *)); +static void ramdattach __P((struct device *, struct device *, void *)); + +struct cfdriver ramdcd = { + NULL, "rd", (cfmatch_t)ramdmatch, ramdattach, DV_DULL, + sizeof(struct device), NULL, 0 }; + +static int +ramdmatch(pdp, cfp, auxp) +struct device *pdp; +struct cfdata *cfp; +void *auxp; +{ + if(strcmp("rd", auxp) || (cfp->cf_unit >= RAMD_NDEV)) + return(0); + return(1); +} + +static void +ramdattach(pdp, dp, auxp) +struct device *pdp, *dp; +void *auxp; +{ + int i; + + for(i = 0; i < RAMD_NDEV; i++) + config_found(dp, (void*)i, ramdprint); +} + +static int +ramdprint(auxp, pnp) +void *auxp; +char *pnp; +{ + return(UNCONF); +} + +static int loaddisk __P((struct ramd_info *, struct proc *)); +static int ramd_norm_read __P((struct read_info *)); +static int cpy_uncompressed __P((caddr_t, int, struct read_info *)); +static int rd_compressed __P((caddr_t, int, struct read_info *)); + +int +rdopen(dev, flags, devtype, p) +dev_t dev; +int flags, devtype; +struct proc *p; +{ + struct ramd_info *ri; + int s; + int error = 0; + + if(DISKUNIT(dev) >= RAMD_NDEV) + return(ENXIO); + + ri = &rd_info[DISKUNIT(dev)]; + if(ri->ramd_state & RAMD_OPEN) + return(0); + + /* + * If someone is busy opening, wait for it to complete. + */ + s = splbio(); + while(ri->ramd_state & RAMD_INOPEN) { + ri->ramd_state |= RAMD_WANTED; + tsleep((caddr_t)ri, PRIBIO, "rdopen", 0); + } + ri->ramd_state |= RAMD_INOPEN; + splx(s); + + if(!(ri->ramd_state & RAMD_ALLOC)) { + ri->ramd_addr = malloc(ri->ramd_size, M_DEVBUF, M_WAITOK); + if(ri->ramd_addr == NULL) { + error = ENXIO; + goto done; + } + ri->ramd_state |= RAMD_ALLOC; + } + if((ri->ramd_flag & RAMD_LOAD) && !(ri->ramd_state & RAMD_LOADED)) { + error = loaddisk(ri, p); + if(!error) + ri->ramd_state |= RAMD_LOADED; + } +done: + ri->ramd_state &= ~RAMD_INOPEN; + if(ri->ramd_state & RAMD_WANTED) { + ri->ramd_state &= ~RAMD_WANTED; + wakeup((caddr_t)ri); + } + return(error); +} + +int +rdclose(dev, flags, devtype, p) +dev_t dev; +int flags, devtype; +struct proc *p; +{ + return(0); +} + +int +rdioctl(dev, cmd, addr, flag, p) +dev_t dev; +u_long cmd; +int flag; +caddr_t addr; +struct proc *p; +{ + return(ENOTTY); +} + +/* + * no dumps to ram disks thank you. + */ +int +rdsize(dev) +dev_t dev; +{ + return(-1); +} + +void +rdstrategy(bp) +struct buf *bp; +{ + struct ramd_info *ri; + long maxsz, sz; + char *datap; + + ri = &rd_info[DISKUNIT(bp->b_dev)]; + + maxsz = ri->ramd_size / DEV_BSIZE; + sz = (bp->b_bcount + DEV_BSIZE - 1) / DEV_BSIZE; + if (bp->b_blkno < 0 || bp->b_blkno + sz > maxsz) { + if((bp->b_blkno == maxsz) && (bp->b_flags & B_READ)) { + /* Hitting EOF */ + bp->b_resid = bp->b_bcount; + goto done; + } + sz = maxsz - bp->b_blkno; + if((sz <= 0) || (bp->b_blkno < 0)) { + bp->b_error = EINVAL; + bp->b_flags |= B_ERROR; + goto done; + } + bp->b_bcount = sz * DEV_BSIZE; + } + datap = (char*)((u_long)ri->ramd_addr + bp->b_blkno * DEV_BSIZE); + if(bp->b_flags & B_READ) + bcopy(datap, bp->b_data, bp->b_bcount); + else bcopy(bp->b_data, datap, bp->b_bcount); + bp->b_resid = 0; + biodone(bp); + return; + +done: + bp->b_resid = bp->b_bcount; + biodone(bp); +} + +int +rdread(dev, uio) +dev_t dev; +struct uio *uio; +{ + return (physio(rdstrategy, NULL, dev, B_READ, minphys, uio)); +} + +int +rdwrite(dev, uio) +dev_t dev; +struct uio *uio; +{ + return (physio(rdstrategy, NULL, dev, B_WRITE, minphys, uio)); +} + +static int +loaddisk(ri, proc) +struct ramd_info *ri; +struct proc *proc; +{ + struct buf buf; + int error; + struct bdevsw *bdp = &bdevsw[major(ri->ramd_dev)]; + struct disklabel dl; + struct read_info rs; + + /* + * Initialize out buffer header: + */ + buf.b_actf = NULL; + buf.b_rcred = buf.b_wcred = proc->p_ucred; + buf.b_vnbufs.le_next = NOLIST; + buf.b_flags = B_BUSY; + buf.b_dev = ri->ramd_dev; + buf.b_error = 0; + buf.b_proc = proc; + + /* + * Setup read_info: + */ + rs.bp = &buf; + rs.nbytes = ri->ramd_size; + rs.offset = 0; + rs.bufp = ri->ramd_addr; + rs.ebufp = ri->ramd_addr + ri->ramd_size; + rs.chunk = RAMD_CHUNK; + rs.media_sz = ri->ramd_size; + rs.strat = bdp->d_strategy; + + /* + * Open device and try to get some statistics. + */ + if(error = bdp->d_open(ri->ramd_dev,FREAD | FNONBLOCK, 0, proc)) + return(error); + if(bdp->d_ioctl(ri->ramd_dev,DIOCGDINFO,(caddr_t)&dl,FREAD,proc) == 0) { + /* Read on a cylinder basis */ + rs.chunk = dl.d_secsize * dl.d_secpercyl; + rs.media_sz = dl.d_secperunit * dl.d_secsize; + } + +#ifdef notyet + if(ri->ramd_flag & RAMD_LCOMP) + error = decompress(cpy_uncompressed, rd_compressed, &rs); + else +#endif /* notyet */ + error = ramd_norm_read(&rs); + + bdp->d_close(ri->ramd_dev,FREAD | FNONBLOCK, 0, proc); + return(error); +} + +static int +ramd_norm_read(rsp) +struct read_info *rsp; +{ + long bytes_left; + int done, error; + struct buf *bp; + int s; + int dotc = 0; + + bytes_left = rsp->nbytes; + bp = rsp->bp; + error = 0; + + while(bytes_left > 0) { + s = splbio(); + bp->b_flags = B_BUSY | B_PHYS | B_READ; + splx(s); + bp->b_blkno = btodb(rsp->offset); + bp->b_bcount = rsp->chunk; + bp->b_data = rsp->bufp; + + /* Initiate read */ + (*rsp->strat)(bp); + + /* Wait for results */ + s = splbio(); + while ((bp->b_flags & B_DONE) == 0) + tsleep((caddr_t) bp, PRIBIO + 1, "ramd_norm_read", 0); + if (bp->b_flags & B_ERROR) + error = (bp->b_error ? bp->b_error : EIO); + splx(s); + + /* Dot counter */ + printf("."); + if(!(++dotc % 40)) + printf("\n"); + + done = bp->b_bcount - bp->b_resid; + bytes_left -= done; + rsp->offset += done; + rsp->bufp += done; + + if(error || !done) + break; + + if((rsp->offset == rsp->media_sz) && (bytes_left != 0)) { + printf("\nInsert next media and hit any key..."); + cngetc(); + printf("\n"); + rsp->offset = 0; + } + } + printf("\n"); + s = splbio(); + splx(s); + return(error); +} + +/* + * Functions supporting uncompression: + */ +/* + * Copy from the uncompression buffer to the ramdisk + */ +static int +cpy_uncompressed(buf, nbyte, rsp) +caddr_t buf; +struct read_info *rsp; +int nbyte; +{ + if((rsp->bufp + nbyte) >= rsp->ebufp) + return(0); + bcopy(buf, rsp->bufp, nbyte); + rsp->bufp += nbyte; + return(0); +} + +/* + * Read a maximum of 'nbyte' bytes into 'buf'. + */ +static int +rd_compressed(buf, nbyte, rsp) +caddr_t buf; +struct read_info *rsp; +int nbyte; +{ + static int dotc = 0; + struct buf *bp; + int nread = 0; + int s; + int done, error; + + + error = 0; + bp = rsp->bp; + nbyte &= ~(DEV_BSIZE - 1); + + while(nbyte > 0) { + s = splbio(); + bp->b_flags = B_BUSY | B_PHYS | B_READ; + splx(s); + bp->b_blkno = btodb(rsp->offset); + bp->b_bcount = min(rsp->chunk, nbyte); + bp->b_data = buf; + + /* Initiate read */ + (*rsp->strat)(bp); + + /* Wait for results */ + s = splbio(); + while ((bp->b_flags & B_DONE) == 0) + tsleep((caddr_t) bp, PRIBIO + 1, "ramd_norm_read", 0); + if (bp->b_flags & B_ERROR) + error = (bp->b_error ? bp->b_error : EIO); + splx(s); + + /* Dot counter */ + printf("."); + if(!(++dotc % 40)) + printf("\n"); + + done = bp->b_bcount - bp->b_resid; + nbyte -= done; + nread += done; + rsp->offset += done; + + if(error || !done) + break; + + if(rsp->offset == rsp->media_sz) { + printf("\nInsert next media and hit any key..."); + if(cngetc() != '\n') + printf("\n"); + rsp->offset = 0; + } + } + s = splbio(); + splx(s); + return(nread); +} diff --git a/sys/arch/atari/dev/view.c b/sys/arch/atari/dev/view.c new file mode 100644 index 00000000000..09dbaf75244 --- /dev/null +++ b/sys/arch/atari/dev/view.c @@ -0,0 +1,420 @@ +/* $NetBSD: view.c,v 1.6 1995/08/17 20:32:50 leo Exp $ */ + +/* + * Copyright (c) 1994 Christian E. Hopps + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christian E. Hopps. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* The view major device is a placeholder device. It serves + * simply to map the semantics of a graphics dipslay to + * the semantics of a character block device. In other + * words the graphics system as currently built does not like to be + * refered to by open/close/ioctl. This device serves as + * a interface to graphics. */ + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/ioctl.h> +#include <sys/file.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/queue.h> +#include <machine/cpu.h> +#include <atari/dev/grfabs_reg.h> +#include <atari/dev/viewioctl.h> +#include <atari/dev/viewvar.h> +#include "view.h" + +static void view_display __P((struct view_softc *)); +static void view_remove __P((struct view_softc *)); +static int view_setsize __P((struct view_softc *, struct view_size *)); +static int view_get_colormap __P((struct view_softc *, colormap_t *)); +static int view_set_colormap __P((struct view_softc *, colormap_t *)); + +void viewclose __P((dev_t, int)); +int viewioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); +int viewopen __P((dev_t, int)); +int viewmmap __P((dev_t, int, int)); + +int viewprobe (); + +struct view_softc views[NVIEW]; +static int view_inited; + +int view_default_x; +int view_default_y; +int view_default_width = 640; +int view_default_height = 400; +int view_default_depth = 1; + +/* + * functions for probeing. + */ +viewattach(cnt) + int cnt; +{ + viewprobe(); + printf("%d view%s configured\n", NVIEW, NVIEW > 1 ? "s" : ""); +} + +/* this function is called early to set up a display. */ +viewprobe() +{ + int i; + + if(view_inited) + return(1); + + view_inited = 1; + + for(i=0; i<NVIEW; i++) { + views[i].view = NULL; + views[i].flags = 0; + } + return(1); +} + + +/* + * Internal functions. + */ + +static void +view_display (vu) + struct view_softc *vu; +{ + int s, i; + + if (vu == NULL) + return; + + s = spltty (); + + /* + * mark views that share this monitor as not displaying + */ + for (i=0; i<NVIEW; i++) { + if(views[i].flags & VUF_DISPLAY) + views[i].flags &= ~VUF_DISPLAY; + } + + vu->flags |= VUF_ADDED; + if (vu->view) { + vu->view->display.x = vu->size.x; + vu->view->display.y = vu->size.y; + + grf_display_view(vu->view); + + vu->size.x = vu->view->display.x; + vu->size.y = vu->view->display.y; + vu->flags |= VUF_DISPLAY; + } + splx(s); +} + +/* + * remove a view from our added list if it is marked as displaying + * switch to a new display. + */ +static void +view_remove(vu) + struct view_softc *vu; +{ + int i; + + if ((vu->flags & VUF_ADDED) == 0) + return; + + vu->flags &= ~VUF_ADDED; + if (vu->flags & VUF_DISPLAY) { + for (i = 0; i < NVIEW; i++) { + if((views[i].flags & VUF_ADDED) && &views[i] != vu) { + view_display(&views[i]); + break; + } + } + } + vu->flags &= ~VUF_DISPLAY; + grf_remove_view(vu->view); +} + +static int +view_setsize(vu, vs) + struct view_softc *vu; + struct view_size *vs; +{ + view_t *new, *old; + dmode_t *dmode; + dimen_t ns; + int co, cs; + + co = 0; + cs = 0; + if (vs->x != vu->size.x || vs->y != vu->size.y) + co = 1; + + if (vs->width != vu->size.width || vs->height != vu->size.height || + vs->depth != vu->size.depth) + cs = 1; + + if (cs == 0 && co == 0) + return(0); + + ns.width = vs->width; + ns.height = vs->height; + + if((dmode = grf_get_best_mode(&ns, vs->depth)) != NULL) { + /* + * If we can't do better, leave it + */ + if(dmode == vu->view->mode) + return(0); + } + new = grf_alloc_view(dmode, &ns, vs->depth); + if (new == NULL) + return(ENOMEM); + + old = vu->view; + vu->view = new; + vu->size.x = new->display.x; + vu->size.y = new->display.y; + vu->size.width = new->display.width; + vu->size.height = new->display.height; + vu->size.depth = new->bitmap->depth; + + /* + * we need a custom remove here to avoid letting + * another view display mark as not added or displayed + */ + if (vu->flags & VUF_DISPLAY) { + vu->flags &= ~(VUF_ADDED|VUF_DISPLAY); + view_display(vu); + } + grf_free_view(old); + return(0); +} + +static int +view_get_colormap (vu, ucm) +struct view_softc *vu; +colormap_t *ucm; +{ + int error; + long *cme; + long *uep; + + if(ucm->size > MAX_CENTRIES) + return(EINVAL); + + /* add one incase of zero, ick. */ + cme = malloc(sizeof(ucm->entry[0])*(ucm->size+1), M_IOCTLOPS,M_WAITOK); + if (cme == NULL) + return(ENOMEM); + + error = 0; + uep = ucm->entry; + ucm->entry = cme; /* set entry to out alloc. */ + if(vu->view == NULL || grf_get_colormap(vu->view, ucm)) + error = EINVAL; + else error = copyout(cme, uep, sizeof(ucm->entry[0]) * ucm->size); + ucm->entry = uep; /* set entry back to users. */ + free(cme, M_IOCTLOPS); + return(error); +} + +static int +view_set_colormap(vu, ucm) +struct view_softc *vu; +colormap_t *ucm; +{ + colormap_t *cm; + int error = 0; + + if(ucm->size > MAX_CENTRIES) + return(EINVAL); + + cm = malloc(sizeof(ucm->entry[0])*ucm->size + sizeof(*cm), M_IOCTLOPS, + M_WAITOK); + if(cm == NULL) + return(ENOMEM); + + bcopy(ucm, cm, sizeof(colormap_t)); + cm->entry = (long *)&cm[1]; /* table directly after. */ + if (((error = + copyin(ucm->entry,cm->entry,sizeof(ucm->entry[0])*ucm->size)) == 0) + && (vu->view == NULL || grf_use_colormap(vu->view, cm))) + error = EINVAL; + free(cm, M_IOCTLOPS); + return(error); +} + +/* + * functions made available by conf.c + */ + +/*ARGSUSED*/ +int viewopen(dev, flags) +dev_t dev; +int flags; +{ + dimen_t size; + struct view_softc *vu; + + vu = &views[minor(dev)]; + + if(minor(dev) >= NVIEW) + return(EXDEV); + if(vu->flags & VUF_OPEN) + return(EBUSY); + + vu->size.x = view_default_x; + vu->size.y = view_default_y; + size.width = vu->size.width = view_default_width; + size.height = vu->size.height = view_default_height; + vu->size.depth = view_default_depth; + vu->view = grf_alloc_view(NULL, &size, vu->size.depth); + if (vu->view == NULL) + return(ENOMEM); + + vu->size.x = vu->view->display.x; + vu->size.y = vu->view->display.y; + vu->size.width = vu->view->display.width; + vu->size.height = vu->view->display.height; + vu->size.depth = vu->view->bitmap->depth; + vu->flags |= VUF_OPEN; + return(0); +} + +/*ARGSUSED*/ +void +viewclose (dev, flags) + dev_t dev; + int flags; +{ + struct view_softc *vu; + + vu = &views[minor(dev)]; + + if ((vu->flags & VUF_OPEN) == 0) + return; + view_remove (vu); + grf_free_view (vu->view); + vu->flags = 0; + vu->view = NULL; +} + + +/*ARGSUSED*/ +int +viewioctl (dev, cmd, data, flag, p) +dev_t dev; +u_long cmd; +caddr_t data; +int flag; +struct proc *p; +{ + struct view_softc *vu; + bmap_t *bm; + int error; + + vu = &views[minor(dev)]; + error = 0; + + switch (cmd) { + case VIOCDISPLAY: + view_display(vu); + break; + case VIOCREMOVE: + view_remove(vu); + break; + case VIOCGSIZE: + bcopy(&vu->size, data, sizeof (struct view_size)); + break; + case VIOCSSIZE: + error = view_setsize(vu, (struct view_size *)data); + break; + case VIOCGBMAP: + bm = (bmap_t *)data; + bcopy(vu->view->bitmap, bm, sizeof(bmap_t)); + if ((int)p != -1) { + bm->plane = NULL; + bm->hw_address = NULL; + } + break; + case VIOCGCMAP: + error = view_get_colormap(vu, (colormap_t *)data); + break; + case VIOCSCMAP: + error = view_set_colormap(vu, (colormap_t *)data); + break; + default: + error = EINVAL; + break; + } + return(error); +} + +/*ARGSUSED*/ +int +viewmmap(dev, off, prot) +dev_t dev; +int off, prot; +{ + struct view_softc *vu; + bmap_t *bm; + u_char *bmd_start; + u_long bmd_size; + + vu = &views[minor(dev)]; + bm = vu->view->bitmap; + bmd_start = bm->hw_address; + bmd_size = bm->bytes_per_row*bm->rows*bm->depth; + + if (off >= 0 && off < bmd_size) + return(((u_int)bmd_start + off) >> PGSHIFT); + + return(-1); +} + +/*ARGSUSED*/ +int +viewselect(dev, rw) +dev_t dev; +int rw; +{ + if(rw == FREAD) + return(0); + return(1); +} + +view_t * +viewview(dev) +dev_t dev; +{ + return(views[minor(dev)].view); +} diff --git a/sys/arch/atari/dev/viewioctl.h b/sys/arch/atari/dev/viewioctl.h new file mode 100644 index 00000000000..86b3970459e --- /dev/null +++ b/sys/arch/atari/dev/viewioctl.h @@ -0,0 +1,57 @@ +/* $NetBSD: viewioctl.h,v 1.1.1.1 1995/03/26 07:12:14 leo Exp $ */ + +/* + * Copyright (c) 1994 Christian E. Hopps + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christian E. Hopps. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * The view major device is a placeholder device. It serves + * simply to map the semantics of a graphics display to + * the semantics of a character block device. In other + * words the graphics system as currently built does not like to be + * refered to by open/close/ioctl. This device serves as + * a interface to graphics. + */ + +struct view_size { + int x; + int y; + u_int width; + u_int height; + u_int depth; +}; + +#define VIOCREMOVE _IO('V', 0x0) /* if displaying remove. */ +#define VIOCDISPLAY _IO('V', 0x1) /* if not displaying, display */ +#define VIOCSSIZE _IOW('V', 0x2, struct view_size) +#define VIOCGSIZE _IOR('V', 0x3, struct view_size) +#define VIOCGBMAP _IOR('V', 0x4, bmap_t) +#define VIOCSCMAP _IOW('V', 0x5, colormap_t) +#define VIOCGCMAP _IOWR('V', 0x6, colormap_t) + diff --git a/sys/arch/atari/dev/viewvar.h b/sys/arch/atari/dev/viewvar.h new file mode 100644 index 00000000000..3c4b7c59de4 --- /dev/null +++ b/sys/arch/atari/dev/viewvar.h @@ -0,0 +1,63 @@ +/* $NetBSD: viewvar.h,v 1.2 1995/05/28 19:45:43 leo Exp $ */ + +/* + * Copyright (c) 1994 Christian E. Hopps + * All rights reserved. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christian E. Hopps. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* The view major device is a placeholder device. It serves + * simply to map the semantics of a graphics dipslay to + * the semantics of a character block device. In other + * words the graphics system as currently built does not like to be + * refered to by open/close/ioctl. This device serves as + * a interface to graphics. */ + +struct view_softc { + struct view_size size; + view_t *view; + pid_t lock_process; + int flags; +}; + +enum view_unit_flag_bits { + VUB_OPEN, + VUB_ADDED, + VUB_DISPLAY, + VUB_LAST_BIT +}; + +enum view_unit_flags { + VUF_OPEN = 1<<VUB_OPEN, + VUF_ADDED = 1<<VUB_ADDED, + VUF_DISPLAY = 1<<VUB_DISPLAY, + VUF_MASK = ((1<<VUB_LAST_BIT)-1) +}; + +#ifdef _KERNEL +view_t *viewview __P((dev_t)); +#endif /* _KERNEL */ diff --git a/sys/arch/atari/dev/vuid_event.h b/sys/arch/atari/dev/vuid_event.h new file mode 100644 index 00000000000..8342f31f19b --- /dev/null +++ b/sys/arch/atari/dev/vuid_event.h @@ -0,0 +1,87 @@ +/* $NetBSD: vuid_event.h,v 1.1.1.1 1995/03/26 07:12:11 leo Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + * + * @(#)vuid_event.h 8.1 (Berkeley) 6/11/93 + * + * from: Header: vuid_event.h,v 1.4 92/11/26 01:20:27 torek Exp (LBL) + */ + +/* + * The following is a minimal emulation of Sun's `Firm_event' structures + * and related operations necessary to make X11 happy (i.e., make it + * compile, and make old X11 binaries run). + */ +typedef struct firm_event { + u_short id; /* key or MS_* or LOC_[XY]_DELTA */ + u_short pad; /* unused, at least by X11 */ + int value; /* VKEY_{UP,DOWN} or locator delta */ + struct timeval time; +} Firm_event; + +/* + * Special `id' fields. These weird numbers simply match the old binaries. + * Others are in 0..0x7f and are keyboard key numbers (keyboard dependent!). + */ +#define MS_LEFT 0x7f20 /* left mouse button */ +#define MS_MIDDLE 0x7f21 /* middle mouse button */ +#define MS_RIGHT 0x7f22 /* right mouse button */ +#define LOC_X_DELTA 0x7f80 /* mouse delta-X */ +#define LOC_Y_DELTA 0x7f81 /* mouse delta-Y */ + +/* + * Special `value' fields. These apply to keys and mouse buttons. The + * value of a mouse delta is the delta. Note that positive deltas are + * left and up (not left and down as you might expect). + */ +#define VKEY_UP 0 /* key or button went up */ +#define VKEY_DOWN 1 /* key or button went down */ + +/* + * The following ioctls are clearly intended to take things in and out + * of `firm event' mode. Since we always run in this mode (as far as + * /dev/kbd and /dev/mouse are concerned, anyway), we always claim to + * be in this mode and reject anything else. + */ +#define VUIDSFORMAT _IOW('v', 1, int) +#define VUIDGFORMAT _IOR('v', 2, int) +#define VUID_FIRM_EVENT 1 /* the only format we support */ diff --git a/sys/arch/atari/dev/zs.c b/sys/arch/atari/dev/zs.c new file mode 100644 index 00000000000..d4bd7d4014a --- /dev/null +++ b/sys/arch/atari/dev/zs.c @@ -0,0 +1,1214 @@ +/* $NetBSD: zs.c,v 1.9 1995/09/23 20:29:17 leo Exp $ */ + +/* + * Copyright (c) 1995 L. Weppelman (Atari modifications) + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + * + * @(#)zs.c 8.1 (Berkeley) 7/19/93 + */ + +/* + * Zilog Z8530 (ZSCC) driver. + * + * Runs two tty ports (modem2 and serial2) on zs0. + * + * This driver knows far too much about chip to usage mappings. + */ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/device.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/syslog.h> + +#include <machine/cpu.h> +#include <machine/iomap.h> +#include <machine/scu.h> +#include <machine/mfp.h> + +#include <dev/ic/z8530reg.h> +#include <atari/dev/zsvar.h> +#include "zs.h" +#if NZS > 1 +#error "This driver supports only 1 85C30!" +#endif + +#if NZS > 0 + +#define PCLK (8000000) /* PCLK pin input clock rate */ + +#define splzs spl5 + +/* + * Software state per found chip. + */ +struct zs_softc { + struct device zi_dev; /* base device */ + volatile struct zsdevice *zi_zs; /* chip registers */ + struct zs_chanstate zi_cs[2]; /* chan A and B software state */ +}; + +static u_char cb_scheduled = 0; /* Already asked for callback? */ +/* + * Define the registers for a closed port + */ +static u_char zs_init_regs[16] = { +/* 0 */ 0, +/* 1 */ 0, +/* 2 */ 0x60, +/* 3 */ 0, +/* 4 */ 0, +/* 5 */ 0, +/* 6 */ 0, +/* 7 */ 0, +/* 8 */ 0, +/* 9 */ ZSWR9_VECTOR_INCL_STAT, +/* 10 */ ZSWR10_NRZ, +/* 11 */ ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD, +/* 12 */ 0, +/* 13 */ 0, +/* 14 */ ZSWR14_BAUD_FROM_PCLK | ZSWR14_BAUD_ENA, +/* 15 */ 0 +}; + +/* + * Define the machine dependant clock frequencies + * If BRgen feeds sender/receiver we always use a + * divisor 16, therefor the division by 16 can as + * well be done here. + */ +static u_long zs_freqs_tt[] = { + /* + * Atari TT, RTxCB is generated by TT-MFP timer C, + * which is set to 307.2KHz during initialisation + * and never changed afterwards. + */ + PCLK/16, /* BRgen, PCLK, divisor 16 */ + 229500, /* BRgen, RTxCA, divisor 16 */ + 3672000, /* RTxCA, from PCLK4 */ + 0, /* TRxCA, external */ + + PCLK/16, /* BRgen, PCLK, divisor 16 */ + 19200, /* BRgen, RTxCB, divisor 16 */ + 307200, /* RTxCB, from TT-MFP TCO */ + 2457600 /* TRxCB, from BCLK */ +}; +static u_long zs_freqs_falcon[] = { + /* + * Atari Falcon, XXX no specs available, this might be wrong + */ + PCLK/16, /* BRgen, PCLK, divisor 16 */ + 229500, /* BRgen, RTxCA, divisor 16 */ + 3672000, /* RTxCA, ??? */ + 0, /* TRxCA, external */ + + PCLK/16, /* BRgen, PCLK, divisor 16 */ + 229500, /* BRgen, RTxCB, divisor 16 */ + 3672000, /* RTxCB, ??? */ + 2457600 /* TRxCB, ??? */ +}; +static u_long zs_freqs_generic[] = { + /* + * other machines, assume only PCLK is available + */ + PCLK/16, /* BRgen, PCLK, divisor 16 */ + 0, /* BRgen, RTxCA, divisor 16 */ + 0, /* RTxCA, unknown */ + 0, /* TRxCA, unknown */ + + PCLK/16, /* BRgen, PCLK, divisor 16 */ + 0, /* BRgen, RTxCB, divisor 16 */ + 0, /* RTxCB, unknown */ + 0 /* TRxCB, unknown */ +}; +static u_long *zs_frequencies; + +/* Definition of the driver for autoconfig. */ +static int zsmatch __P((struct device *, struct cfdata *, void *)); +static void zsattach __P((struct device *, struct device *, void *)); +struct cfdriver zscd = { + NULL, "zs", (cfmatch_t)zsmatch, zsattach, DV_TTY, + sizeof(struct zs_softc), NULL, 0 }; + +/* Interrupt handlers. */ +int zshard __P((long)); +static int zssoft __P((long)); +static int zsrint __P((struct zs_chanstate *, volatile struct zschan *)); +static int zsxint __P((struct zs_chanstate *, volatile struct zschan *)); +static int zssint __P((struct zs_chanstate *, volatile struct zschan *)); + +static struct zs_chanstate *zslist; + +/* Routines called from other code. */ +static void zsstart __P((struct tty *)); +void zsstop __P((struct tty *, int)); +static int zsparam __P((struct tty *, struct termios *)); +static int zsbaudrate __P((int, int, int *, int *, int *, int *)); + +/* Routines purely local to this driver. */ +static void zs_reset __P((volatile struct zschan *, int, int)); +static int zs_modem __P((struct zs_chanstate *, int, int)); +static void zs_loadchannelregs __P((volatile struct zschan *, u_char *)); + +static int zsshortcuts; /* number of "shortcut" software interrupts */ + +static int +zsmatch(pdp, cfp, auxp) +struct device *pdp; +struct cfdata *cfp; +void *auxp; +{ + if(strcmp("zs", auxp) || cfp->cf_unit != 0) + return(0); + return(1); +} + +/* + * Attach a found zs. + */ +static void +zsattach(parent, dev, aux) +struct device *parent; +struct device *dev; +void *aux; +{ + register struct zs_softc *zi; + register struct zs_chanstate *cs; + register volatile struct zsdevice *addr; + register struct tty *tp; + char tmp; + + addr = (struct zsdevice *)AD_SCC; + zi = (struct zs_softc *)dev; + zi->zi_zs = addr; + cs = zi->zi_cs; + + /* + * Get the command register into a known state. + */ + tmp = addr->zs_chan[ZS_CHAN_A].zc_csr; + tmp = addr->zs_chan[ZS_CHAN_A].zc_csr; + tmp = addr->zs_chan[ZS_CHAN_B].zc_csr; + tmp = addr->zs_chan[ZS_CHAN_B].zc_csr; + + /* + * Do a hardware reset. + */ + ZS_WRITE(&addr->zs_chan[ZS_CHAN_A], 9, ZSWR9_HARD_RESET); + delay(50000); /*enough ? */ + ZS_WRITE(&addr->zs_chan[ZS_CHAN_A], 9, 0); + + /* + * Initialize both channels + */ + zs_loadchannelregs(&addr->zs_chan[ZS_CHAN_A], zs_init_regs); + zs_loadchannelregs(&addr->zs_chan[ZS_CHAN_B], zs_init_regs); + + if(machineid & ATARI_TT) { + /* + * ininitialise TT-MFP timer C: 307200Hz + * timer C and D share one control register: + * bits 0-2 control timer D + * bits 4-6 control timer C + */ + int cr = MFP2->mf_tcdcr & 7; + MFP2->mf_tcdcr = cr; /* stop timer C */ + MFP2->mf_tcdr = 1; /* counter 1 */ + cr |= T_Q004 << 4; /* divisor 4 */ + MFP2->mf_tcdcr = cr; /* start timer C */ + /* + * enable scc related interrupts + */ + SCU->sys_mask |= SCU_SCC; + + zs_frequencies = zs_freqs_tt; + } else if (machineid & ATARI_FALCON) { + zs_frequencies = zs_freqs_falcon; + } else { + zs_frequencies = zs_freqs_generic; + } + + /* link into interrupt list with order (A,B) (B=A+1) */ + cs[0].cs_next = &cs[1]; + cs[1].cs_next = zslist; + zslist = cs; + + cs->cs_unit = 0; + cs->cs_zc = &addr->zs_chan[ZS_CHAN_A]; + cs++; + cs->cs_unit = 1; + cs->cs_zc = &addr->zs_chan[ZS_CHAN_B]; + + printf(": serial2 on channel a and modem2 on channel b\n"); +} + +/* + * Open a zs serial port. + */ +int +zsopen(dev, flags, mode, p) +dev_t dev; +int flags; +int mode; +struct proc *p; +{ + register struct tty *tp; + register struct zs_chanstate *cs; + struct zs_softc *zi; + int unit = ZS_UNIT(dev); + int zs = unit >> 1; + int error, s; + + if(zs >= zscd.cd_ndevs || (zi = zscd.cd_devs[zs]) == NULL) + return (ENXIO); + cs = &zi->zi_cs[unit & 1]; + tp = cs->cs_ttyp; + if(tp == NULL) { + cs->cs_ttyp = tp = ttymalloc(); + tp->t_dev = dev; + tp->t_oproc = zsstart; + tp->t_param = zsparam; + } + + s = spltty(); + if((tp->t_state & TS_ISOPEN) == 0) { + ttychars(tp); + if(tp->t_ispeed == 0) { + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_cflag = TTYDEF_CFLAG; + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; + } + (void)zsparam(tp, &tp->t_termios); + ttsetwater(tp); + } + else if(tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { + splx(s); + return (EBUSY); + } + error = 0; + for(;;) { + /* loop, turning on the device, until carrier present */ + zs_modem(cs, ZSWR5_RTS|ZSWR5_DTR, DMSET); + + /* May never get a status intr. if DCD already on. -gwr */ + if(cs->cs_zc->zc_csr & ZSRR0_DCD) + tp->t_state |= TS_CARR_ON; + if(cs->cs_softcar) + tp->t_state |= TS_CARR_ON; + if(flags & O_NONBLOCK || tp->t_cflag & CLOCAL || + tp->t_state & TS_CARR_ON) + break; + tp->t_state |= TS_WOPEN; + if(error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, + ttopen, 0)) { + if(!(tp->t_state & TS_ISOPEN)) { + zs_modem(cs, 0, DMSET); + tp->t_state &= ~TS_WOPEN; + ttwakeup(tp); + } + splx(s); + return error; + } + } + splx(s); + if(error == 0) + error = linesw[tp->t_line].l_open(dev, tp); + if(error) + zs_modem(cs, 0, DMSET); + return(error); +} + +/* + * Close a zs serial port. + */ +int +zsclose(dev, flags, mode, p) +dev_t dev; +int flags; +int mode; +struct proc *p; +{ + register struct zs_chanstate *cs; + register struct tty *tp; + struct zs_softc *zi; + int unit = ZS_UNIT(dev); + int s; + + zi = zscd.cd_devs[unit >> 1]; + cs = &zi->zi_cs[unit & 1]; + tp = cs->cs_ttyp; + linesw[tp->t_line].l_close(tp, flags); + if(tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN || + (tp->t_state & TS_ISOPEN) == 0) { + zs_modem(cs, 0, DMSET); + /* hold low for 1 second */ + (void)tsleep((caddr_t)cs, TTIPRI, ttclos, hz); + } + if(cs->cs_creg[5] & ZSWR5_BREAK) { + s = splzs(); + cs->cs_preg[5] &= ~ZSWR5_BREAK; + cs->cs_creg[5] &= ~ZSWR5_BREAK; + ZS_WRITE(cs->cs_zc, 5, cs->cs_creg[5]); + splx(s); + } + ttyclose(tp); + + /* + * Drop all lines and cancel interrupts + */ + zs_loadchannelregs(&zi->zi_zs->zs_chan[unit & 1], zs_init_regs); + return (0); +} + +/* + * Read/write zs serial port. + */ +int +zsread(dev, uio, flags) +dev_t dev; +struct uio *uio; +int flags; +{ + register struct zs_chanstate *cs; + register struct zs_softc *zi; + register struct tty *tp; + int unit; + + unit = ZS_UNIT(dev); + zi = zscd.cd_devs[unit >> 1]; + cs = &zi->zi_cs[unit & 1]; + tp = cs->cs_ttyp; + + return(linesw[tp->t_line].l_read(tp, uio, flags)); +} + +int +zswrite(dev, uio, flags) +dev_t dev; +struct uio *uio; +int flags; +{ + register struct zs_chanstate *cs; + register struct zs_softc *zi; + register struct tty *tp; + int unit; + + unit = ZS_UNIT(dev); + zi = zscd.cd_devs[unit >> 1]; + cs = &zi->zi_cs[unit & 1]; + tp = cs->cs_ttyp; + + return(linesw[tp->t_line].l_write(tp, uio, flags)); +} + +struct tty * +zstty(dev) +dev_t dev; +{ + register struct zs_chanstate *cs; + register struct zs_softc *zi; + int unit; + + unit = ZS_UNIT(dev); + zi = zscd.cd_devs[unit >> 1]; + cs = &zi->zi_cs[unit & 1]; + return(cs->cs_ttyp); +} + +/* + * ZS hardware interrupt. Scan all ZS channels. NB: we know here that + * channels are kept in (A,B) pairs. + * + * Do just a little, then get out; set a software interrupt if more + * work is needed. + * + * We deliberately ignore the vectoring Zilog gives us, and match up + * only the number of `reset interrupt under service' operations, not + * the order. + */ + +int +zshard(sr) +long sr; +{ + register struct zs_chanstate *a; +#define b (a + 1) + register volatile struct zschan *zc; + register int rr3, intflags = 0, v, i; + + do { + intflags &= ~4; + for(a = zslist; a != NULL; a = b->cs_next) { + rr3 = ZS_READ(a->cs_zc, 3); + if(rr3 & (ZSRR3_IP_A_RX|ZSRR3_IP_A_TX|ZSRR3_IP_A_STAT)) { + intflags |= 4|2; + zc = a->cs_zc; + i = a->cs_rbput; + if(rr3 & ZSRR3_IP_A_RX && (v = zsrint(a, zc)) != 0) { + a->cs_rbuf[i++ & ZLRB_RING_MASK] = v; + intflags |= 1; + } + if(rr3 & ZSRR3_IP_A_TX && (v = zsxint(a, zc)) != 0) { + a->cs_rbuf[i++ & ZLRB_RING_MASK] = v; + intflags |= 1; + } + if(rr3 & ZSRR3_IP_A_STAT && (v = zssint(a, zc)) != 0) { + a->cs_rbuf[i++ & ZLRB_RING_MASK] = v; + intflags |= 1; + } + a->cs_rbput = i; + } + if(rr3 & (ZSRR3_IP_B_RX|ZSRR3_IP_B_TX|ZSRR3_IP_B_STAT)) { + intflags |= 4|2; + zc = b->cs_zc; + i = b->cs_rbput; + if(rr3 & ZSRR3_IP_B_RX && (v = zsrint(b, zc)) != 0) { + b->cs_rbuf[i++ & ZLRB_RING_MASK] = v; + intflags |= 1; + } + if(rr3 & ZSRR3_IP_B_TX && (v = zsxint(b, zc)) != 0) { + b->cs_rbuf[i++ & ZLRB_RING_MASK] = v; + intflags |= 1; + } + if(rr3 & ZSRR3_IP_B_STAT && (v = zssint(b, zc)) != 0) { + b->cs_rbuf[i++ & ZLRB_RING_MASK] = v; + intflags |= 1; + } + b->cs_rbput = i; + } + } + } while(intflags & 4); +#undef b + + if(intflags & 1) { + if(BASEPRI(sr)) { + spl1(); + zsshortcuts++; + return(zssoft(sr)); + } + else if(!cb_scheduled) { + cb_scheduled++; + add_sicallback(zssoft, 0, 0); + } + } + return(intflags & 2); +} + +static int +zsrint(cs, zc) +register struct zs_chanstate *cs; +register volatile struct zschan *zc; +{ + register int c; + + /* + * First read the status, because read of the received char + * destroy the status of this char. + */ + c = ZS_READ(zc, 1); + c |= (zc->zc_data << 8); + + /* clear receive error & interrupt condition */ + zc->zc_csr = ZSWR0_RESET_ERRORS; + zc->zc_csr = ZSWR0_CLR_INTR; + + return(ZRING_MAKE(ZRING_RINT, c)); +} + +static int +zsxint(cs, zc) +register struct zs_chanstate *cs; +register volatile struct zschan *zc; +{ + register int i = cs->cs_tbc; + + if(i == 0) { + zc->zc_csr = ZSWR0_RESET_TXINT; + zc->zc_csr = ZSWR0_CLR_INTR; + return(ZRING_MAKE(ZRING_XINT, 0)); + } + cs->cs_tbc = i - 1; + zc->zc_data = *cs->cs_tba++; + zc->zc_csr = ZSWR0_CLR_INTR; + return (0); +} + +static int +zssint(cs, zc) +register struct zs_chanstate *cs; +register volatile struct zschan *zc; +{ + register int rr0; + + rr0 = zc->zc_csr; + zc->zc_csr = ZSWR0_RESET_STATUS; + zc->zc_csr = ZSWR0_CLR_INTR; + /* + * The chip's hardware flow control is, as noted in zsreg.h, + * busted---if the DCD line goes low the chip shuts off the + * receiver (!). If we want hardware CTS flow control but do + * not have it, and carrier is now on, turn HFC on; if we have + * HFC now but carrier has gone low, turn it off. + */ + if(rr0 & ZSRR0_DCD) { + if(cs->cs_ttyp->t_cflag & CCTS_OFLOW && + (cs->cs_creg[3] & ZSWR3_HFC) == 0) { + cs->cs_creg[3] |= ZSWR3_HFC; + ZS_WRITE(zc, 3, cs->cs_creg[3]); + } + } + else { + if (cs->cs_creg[3] & ZSWR3_HFC) { + cs->cs_creg[3] &= ~ZSWR3_HFC; + ZS_WRITE(zc, 3, cs->cs_creg[3]); + } + } + return(ZRING_MAKE(ZRING_SINT, rr0)); +} + +/* + * Print out a ring or fifo overrun error message. + */ +static void +zsoverrun(unit, ptime, what) +int unit; +long *ptime; +char *what; +{ + + if(*ptime != time.tv_sec) { + *ptime = time.tv_sec; + log(LOG_WARNING, "zs%d%c: %s overrun\n", unit >> 1, + (unit & 1) + 'a', what); + } +} + +/* + * ZS software interrupt. Scan all channels for deferred interrupts. + */ +int +zssoft(sr) +long sr; +{ + register struct zs_chanstate *cs; + register volatile struct zschan *zc; + register struct linesw *line; + register struct tty *tp; + register int get, n, c, cc, unit, s; + int retval = 0; + + cb_scheduled = 0; + s = spltty(); + for(cs = zslist; cs != NULL; cs = cs->cs_next) { + get = cs->cs_rbget; +again: + n = cs->cs_rbput; /* atomic */ + if(get == n) /* nothing more on this line */ + continue; + retval = 1; + unit = cs->cs_unit; /* set up to handle interrupts */ + zc = cs->cs_zc; + tp = cs->cs_ttyp; + line = &linesw[tp->t_line]; + /* + * Compute the number of interrupts in the receive ring. + * If the count is overlarge, we lost some events, and + * must advance to the first valid one. It may get + * overwritten if more data are arriving, but this is + * too expensive to check and gains nothing (we already + * lost out; all we can do at this point is trade one + * kind of loss for another). + */ + n -= get; + if(n > ZLRB_RING_SIZE) { + zsoverrun(unit, &cs->cs_rotime, "ring"); + get += n - ZLRB_RING_SIZE; + n = ZLRB_RING_SIZE; + } + while(--n >= 0) { + /* race to keep ahead of incoming interrupts */ + c = cs->cs_rbuf[get++ & ZLRB_RING_MASK]; + switch (ZRING_TYPE(c)) { + + case ZRING_RINT: + c = ZRING_VALUE(c); + if(c & ZSRR1_DO) + zsoverrun(unit, &cs->cs_fotime, "fifo"); + cc = c >> 8; + if(c & ZSRR1_FE) + cc |= TTY_FE; + if(c & ZSRR1_PE) + cc |= TTY_PE; + line->l_rint(cc, tp); + break; + + case ZRING_XINT: + /* + * Transmit done: change registers and resume, + * or clear BUSY. + */ + if(cs->cs_heldchange) { + int sps; + + sps = splzs(); + c = zc->zc_csr; + if((c & ZSRR0_DCD) == 0) + cs->cs_preg[3] &= ~ZSWR3_HFC; + bcopy((caddr_t)cs->cs_preg, + (caddr_t)cs->cs_creg, 16); + zs_loadchannelregs(zc, cs->cs_creg); + splx(sps); + cs->cs_heldchange = 0; + if(cs->cs_heldtbc + && (tp->t_state & TS_TTSTOP) == 0) { + cs->cs_tbc = cs->cs_heldtbc - 1; + zc->zc_data = *cs->cs_tba++; + goto again; + } + } + tp->t_state &= ~TS_BUSY; + if(tp->t_state & TS_FLUSH) + tp->t_state &= ~TS_FLUSH; + else ndflush(&tp->t_outq,cs->cs_tba + - (caddr_t)tp->t_outq.c_cf); + line->l_start(tp); + break; + + case ZRING_SINT: + /* + * Status line change. HFC bit is run in + * hardware interrupt, to avoid locking + * at splzs here. + */ + c = ZRING_VALUE(c); + if((c ^ cs->cs_rr0) & ZSRR0_DCD) { + cc = (c & ZSRR0_DCD) != 0; + if(line->l_modem(tp, cc) == 0) + zs_modem(cs, ZSWR5_RTS|ZSWR5_DTR, + cc ? DMBIS : DMBIC); + } + cs->cs_rr0 = c; + break; + + default: + log(LOG_ERR, "zs%d%c: bad ZRING_TYPE (%x)\n", + unit >> 1, (unit & 1) + 'a', c); + break; + } + } + cs->cs_rbget = get; + goto again; + } + splx(s); + return (retval); +} + +int +zsioctl(dev, cmd, data, flag, p) +dev_t dev; +u_long cmd; +caddr_t data; +int flag; +struct proc *p; +{ + int unit = ZS_UNIT(dev); + struct zs_softc *zi = zscd.cd_devs[unit >> 1]; + register struct tty *tp = zi->zi_cs[unit & 1].cs_ttyp; + register int error, s; + register struct zs_chanstate *cs = &zi->zi_cs[unit & 1]; + + error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p); + if(error >= 0) + return(error); + error = ttioctl(tp, cmd, data, flag, p); + if(error >= 0) + return (error); + + switch (cmd) { + case TIOCSBRK: + s = splzs(); + cs->cs_preg[5] |= ZSWR5_BREAK; + cs->cs_creg[5] |= ZSWR5_BREAK; + ZS_WRITE(cs->cs_zc, 5, cs->cs_creg[5]); + splx(s); + break; + case TIOCCBRK: + s = splzs(); + cs->cs_preg[5] &= ~ZSWR5_BREAK; + cs->cs_creg[5] &= ~ZSWR5_BREAK; + ZS_WRITE(cs->cs_zc, 5, cs->cs_creg[5]); + splx(s); + break; + case TIOCGFLAGS: { + int bits = 0; + + if(cs->cs_softcar) + bits |= TIOCFLAG_SOFTCAR; + if(cs->cs_creg[15] & ZSWR15_DCD_IE) + bits |= TIOCFLAG_CLOCAL; + if(cs->cs_creg[3] & ZSWR3_HFC) + bits |= TIOCFLAG_CRTSCTS; + *(int *)data = bits; + break; + } + case TIOCSFLAGS: { + int userbits, driverbits = 0; + + error = suser(p->p_ucred, &p->p_acflag); + if(error != 0) + return (EPERM); + + userbits = *(int *)data; + + /* + * can have `local' or `softcar', and `rtscts' or `mdmbuf' + # defaulting to software flow control. + */ + if(userbits & TIOCFLAG_SOFTCAR && userbits & TIOCFLAG_CLOCAL) + return(EINVAL); + if(userbits & TIOCFLAG_MDMBUF) /* don't support this (yet?) */ + return(ENXIO); + + s = splzs(); + if((userbits & TIOCFLAG_SOFTCAR)) { + cs->cs_softcar = 1; /* turn on softcar */ + cs->cs_preg[15] &= ~ZSWR15_DCD_IE; /* turn off dcd */ + cs->cs_creg[15] &= ~ZSWR15_DCD_IE; + ZS_WRITE(cs->cs_zc, 15, cs->cs_creg[15]); + } + else if(userbits & TIOCFLAG_CLOCAL) { + cs->cs_softcar = 0; /* turn off softcar */ + cs->cs_preg[15] |= ZSWR15_DCD_IE; /* turn on dcd */ + cs->cs_creg[15] |= ZSWR15_DCD_IE; + ZS_WRITE(cs->cs_zc, 15, cs->cs_creg[15]); + tp->t_termios.c_cflag |= CLOCAL; + } + if(userbits & TIOCFLAG_CRTSCTS) { + cs->cs_preg[15] |= ZSWR15_CTS_IE; + cs->cs_creg[15] |= ZSWR15_CTS_IE; + ZS_WRITE(cs->cs_zc, 15, cs->cs_creg[15]); + cs->cs_preg[3] |= ZSWR3_HFC; + cs->cs_creg[3] |= ZSWR3_HFC; + ZS_WRITE(cs->cs_zc, 3, cs->cs_creg[3]); + tp->t_termios.c_cflag |= CRTSCTS; + } + else { + /* no mdmbuf, so we must want software flow control */ + cs->cs_preg[15] &= ~ZSWR15_CTS_IE; + cs->cs_creg[15] &= ~ZSWR15_CTS_IE; + ZS_WRITE(cs->cs_zc, 15, cs->cs_creg[15]); + cs->cs_preg[3] &= ~ZSWR3_HFC; + cs->cs_creg[3] &= ~ZSWR3_HFC; + ZS_WRITE(cs->cs_zc, 3, cs->cs_creg[3]); + tp->t_termios.c_cflag &= ~CRTSCTS; + } + splx(s); + break; + } + case TIOCSDTR: + zs_modem(cs, ZSWR5_DTR, DMBIS); + break; + case TIOCCDTR: + zs_modem(cs, ZSWR5_DTR, DMBIC); + break; + case TIOCMGET: + zs_modem(cs, 0, DMGET); + break; + case TIOCMSET: + case TIOCMBIS: + case TIOCMBIC: + default: + return (ENOTTY); + } + return (0); +} + +/* + * Start or restart transmission. + */ +static void +zsstart(tp) +register struct tty *tp; +{ + register struct zs_chanstate *cs; + register int s, nch; + int unit = ZS_UNIT(tp->t_dev); + struct zs_softc *zi = zscd.cd_devs[unit >> 1]; + + cs = &zi->zi_cs[unit & 1]; + s = spltty(); + + /* + * If currently active or delaying, no need to do anything. + */ + if(tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) + goto out; + + /* + * If there are sleepers, and output has drained below low + * water mark, awaken. + */ + if(tp->t_outq.c_cc <= tp->t_lowat) { + if(tp->t_state & TS_ASLEEP) { + tp->t_state &= ~TS_ASLEEP; + wakeup((caddr_t)&tp->t_outq); + } + selwakeup(&tp->t_wsel); + } + + nch = ndqb(&tp->t_outq, 0); /* XXX */ + if(nch) { + register char *p = tp->t_outq.c_cf; + + /* mark busy, enable tx done interrupts, & send first byte */ + tp->t_state |= TS_BUSY; + (void) splzs(); + cs->cs_preg[1] |= ZSWR1_TIE; + cs->cs_creg[1] |= ZSWR1_TIE; + ZS_WRITE(cs->cs_zc, 1, cs->cs_creg[1]); + cs->cs_zc->zc_data = *p; + cs->cs_tba = p + 1; + cs->cs_tbc = nch - 1; + } else { + /* + * Nothing to send, turn off transmit done interrupts. + * This is useful if something is doing polled output. + */ + (void) splzs(); + cs->cs_preg[1] &= ~ZSWR1_TIE; + cs->cs_creg[1] &= ~ZSWR1_TIE; + ZS_WRITE(cs->cs_zc, 1, cs->cs_creg[1]); + } +out: + splx(s); +} + +/* + * Stop output, e.g., for ^S or output flush. + */ +void +zsstop(tp, flag) +register struct tty *tp; + int flag; +{ + register struct zs_chanstate *cs; + register int s, unit = ZS_UNIT(tp->t_dev); + struct zs_softc *zi = zscd.cd_devs[unit >> 1]; + + cs = &zi->zi_cs[unit & 1]; + s = splzs(); + if(tp->t_state & TS_BUSY) { + /* + * Device is transmitting; must stop it. + */ + cs->cs_tbc = 0; + if ((tp->t_state & TS_TTSTOP) == 0) + tp->t_state |= TS_FLUSH; + } + splx(s); +} + +/* + * Set ZS tty parameters from termios. + * + * This routine makes use of the fact that only registers + * 1, 3, 4, 5, 9, 10, 11, 12, 13, 14, and 15 are written. + */ +static int +zsparam(tp, t) +register struct tty *tp; +register struct termios *t; +{ + int unit = ZS_UNIT(tp->t_dev); + struct zs_softc *zi = zscd.cd_devs[unit >> 1]; + register struct zs_chanstate *cs = &zi->zi_cs[unit & 1]; + int cdiv, clkm, brgm, tcon; + register int tmp, tmp5, cflag, s; + + tmp = t->c_ospeed; + tmp5 = t->c_ispeed; + if(tmp < 0 || (tmp5 && tmp5 != tmp)) + return(EINVAL); + if(tmp == 0) { + /* stty 0 => drop DTR and RTS */ + zs_modem(cs, 0, DMSET); + return(0); + } + tmp = zsbaudrate(unit, tmp, &cdiv, &clkm, &brgm, &tcon); + if (tmp < 0) + return(EINVAL); + tp->t_ispeed = tp->t_ospeed = tmp; + + cflag = tp->t_cflag = t->c_cflag; + if (cflag & CSTOPB) + cdiv |= ZSWR4_TWOSB; + else + cdiv |= ZSWR4_ONESB; + if (!(cflag & PARODD)) + cdiv |= ZSWR4_EVENP; + if (cflag & PARENB) + cdiv |= ZSWR4_PARENB; + + switch(cflag & CSIZE) { + case CS5: + tmp = ZSWR3_RX_5; + tmp5 = ZSWR5_TX_5; + break; + case CS6: + tmp = ZSWR3_RX_6; + tmp5 = ZSWR5_TX_6; + break; + case CS7: + tmp = ZSWR3_RX_7; + tmp5 = ZSWR5_TX_7; + break; + case CS8: + default: + tmp = ZSWR3_RX_8; + tmp5 = ZSWR5_TX_8; + break; + } + tmp |= ZSWR3_RX_ENABLE; + tmp5 |= ZSWR5_TX_ENABLE | ZSWR5_DTR | ZSWR5_RTS; + + /* + * Block interrupts so that state will not + * be altered until we are done setting it up. + */ + s = splzs(); + cs->cs_preg[4] = cdiv; + cs->cs_preg[11] = clkm; + cs->cs_preg[12] = tcon; + cs->cs_preg[13] = tcon >> 8; + cs->cs_preg[14] = brgm; + cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE; + cs->cs_preg[9] = ZSWR9_MASTER_IE | ZSWR9_VECTOR_INCL_STAT; + cs->cs_preg[10] = ZSWR10_NRZ; + cs->cs_preg[15] = ZSWR15_BREAK_IE | ZSWR15_DCD_IE; + + /* + * Output hardware flow control on the chip is horrendous: if + * carrier detect drops, the receiver is disabled. Hence we + * can only do this when the carrier is on. + */ + if(cflag & CCTS_OFLOW && cs->cs_zc->zc_csr & ZSRR0_DCD) + tmp |= ZSWR3_HFC; + cs->cs_preg[3] = tmp; + cs->cs_preg[5] = tmp5; + + /* + * If nothing is being transmitted, set up new current values, + * else mark them as pending. + */ + if(cs->cs_heldchange == 0) { + if (cs->cs_ttyp->t_state & TS_BUSY) { + cs->cs_heldtbc = cs->cs_tbc; + cs->cs_tbc = 0; + cs->cs_heldchange = 1; + } else { + bcopy((caddr_t)cs->cs_preg, (caddr_t)cs->cs_creg, 16); + zs_loadchannelregs(cs->cs_zc, cs->cs_creg); + } + } + splx(s); + return (0); +} + +/* + * search for the best matching baudrate + */ +static int +zsbaudrate(unit, wanted, divisor, clockmode, brgenmode, timeconst) +int unit, wanted, *divisor, *clockmode, *brgenmode, *timeconst; +{ + int bestdiff, bestbps, source; + + unit = (unit & 1) << 2; + for (source = 0; source < 4; ++source) { + long freq = zs_frequencies[unit + source]; + int diff, bps, div, clkm, brgm, tcon; + switch (source) { + case 0: /* BRgen, PCLK */ + brgm = ZSWR14_BAUD_ENA|ZSWR14_BAUD_FROM_PCLK; + break; + case 1: /* BRgen, RTxC */ + brgm = ZSWR14_BAUD_ENA; + break; + case 2: /* RTxC */ + clkm = ZSWR11_RXCLK_RTXC|ZSWR11_TXCLK_RTXC; + break; + case 3: /* TRxC */ + clkm = ZSWR11_RXCLK_TRXC|ZSWR11_TXCLK_TRXC; + break; + } + switch (source) { + case 0: + case 1: + div = ZSWR4_CLK_X16; + clkm = ZSWR11_RXCLK_BAUD|ZSWR11_TXCLK_BAUD; + tcon = BPS_TO_TCONST(freq, wanted); + if (tcon < 0) + tcon = 0; + bps = TCONST_TO_BPS(freq, tcon); + break; + case 2: + case 3: + { int b1 = freq / 16, d1 = abs(b1 - wanted); + int b2 = freq / 32, d2 = abs(b2 - wanted); + int b3 = freq / 64, d3 = abs(b3 - wanted); + + if (d1 < d2 && d1 < d3) { + div = ZSWR4_CLK_X16; + bps = b1; + } else if (d2 < d3 && d2 < d1) { + div = ZSWR4_CLK_X32; + bps = b2; + } else { + div = ZSWR4_CLK_X64; + bps = b3; + } + brgm = tcon = 0; + break; + } + } + diff = abs(bps - wanted); + if (!source || diff < bestdiff) { + *divisor = div; + *clockmode = clkm; + *brgenmode = brgm; + *timeconst = tcon; + bestbps = bps; + bestdiff = diff; + if (diff == 0) + break; + } + } + /* Allow deviations upto 5% */ + if (20 * bestdiff > wanted) + return -1; + return bestbps; +} + +/* + * Raise or lower modem control (DTR/RTS) signals. If a character is + * in transmission, the change is deferred. + */ +static int +zs_modem(cs, bits, how) +struct zs_chanstate *cs; +int bits, how; +{ + int s, mbits; + + bits &= ZSWR5_DTR | ZSWR5_RTS; + + s = splzs(); + mbits = cs->cs_preg[5] & (ZSWR5_DTR | ZSWR5_RTS); + + switch(how) { + case DMSET: + mbits = bits; + break; + case DMBIS: + mbits |= bits; + break; + case DMBIC: + mbits &= ~bits; + break; + case DMGET: + splx(s); + return(mbits); + } + + cs->cs_preg[5] = (cs->cs_preg[5] & ~(ZSWR5_DTR | ZSWR5_RTS)) | mbits; + if(cs->cs_heldchange == 0) { + if(cs->cs_ttyp->t_state & TS_BUSY) { + cs->cs_heldtbc = cs->cs_tbc; + cs->cs_tbc = 0; + cs->cs_heldchange = 1; + } + else { + ZS_WRITE(cs->cs_zc, 5, cs->cs_creg[5]); + } + } + splx(s); + return(0); +} + +/* + * Write the given register set to the given zs channel in the proper order. + * The channel must not be transmitting at the time. The receiver will + * be disabled for the time it takes to write all the registers. + */ +static void +zs_loadchannelregs(zc, reg) +volatile struct zschan *zc; +u_char *reg; +{ + int i; + + zc->zc_csr = ZSM_RESET_ERR; /* reset error condition */ + i = zc->zc_data; /* drain fifo */ + i = zc->zc_data; + i = zc->zc_data; + ZS_WRITE(zc, 4, reg[4]); + ZS_WRITE(zc, 10, reg[10]); + ZS_WRITE(zc, 3, reg[3] & ~ZSWR3_RX_ENABLE); + ZS_WRITE(zc, 5, reg[5] & ~ZSWR5_TX_ENABLE); + ZS_WRITE(zc, 1, reg[1]); + ZS_WRITE(zc, 9, reg[9]); + ZS_WRITE(zc, 11, reg[11]); + ZS_WRITE(zc, 12, reg[12]); + ZS_WRITE(zc, 13, reg[13]); + ZS_WRITE(zc, 14, reg[14]); + ZS_WRITE(zc, 15, reg[15]); + ZS_WRITE(zc, 3, reg[3]); + ZS_WRITE(zc, 5, reg[5]); +} +#endif /* NZS > 1 */ diff --git a/sys/arch/atari/dev/zsvar.h b/sys/arch/atari/dev/zsvar.h new file mode 100644 index 00000000000..7f2b5019339 --- /dev/null +++ b/sys/arch/atari/dev/zsvar.h @@ -0,0 +1,147 @@ +/* $NetBSD: zsvar.h,v 1.2 1995/04/11 02:37:18 mycroft Exp $ */ + +/* + * Copyright (c) 1995 Leo Weppelman (Atari modifications) + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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. + * + * @(#)zsvar.h 8.1 (Berkeley) 6/11/93 + */ + +/* + * Software state, per zs channel. + * + * The zs chip has insufficient buffering, so we provide a software + * buffer using a two-level interrupt scheme. The hardware (high priority) + * interrupt simply grabs the `cause' of the interrupt and stuffs it into + * a ring buffer. It then schedules a software interrupt; the latter + * empties the ring as fast as it can, hoping to avoid overflow. + * + * Interrupts can happen because of: + * - received data; + * - transmit pseudo-DMA done; and + * - status change. + * These are all stored together in the (single) ring. The size of the + * ring is a power of two, to make % operations fast. Since we need two + * bits to distinguish the interrupt type, and up to 16 for the received + * data plus RR1 status, we use 32 bits per ring entry. + * + * When the value is a character + RR1 status, the character is in the + * upper 8 bits of the RR1 status. + */ +#define ZLRB_RING_SIZE 256 /* ZS line ring buffer size */ +#define ZLRB_RING_MASK 255 /* mask for same */ + +/* 0 is reserved (means "no interrupt") */ +#define ZRING_RINT 1 /* receive data interrupt */ +#define ZRING_XINT 2 /* transmit done interrupt */ +#define ZRING_SINT 3 /* status change interrupt */ + +#define ZRING_TYPE(x) ((x) & 3) +#define ZRING_VALUE(x) ((x) >> 8) +#define ZRING_MAKE(t, v) ((t) | (v) << 8) + +struct zs_chanstate { + struct zs_chanstate *cs_next; /* linked list for zshard() */ + volatile struct zschan *cs_zc; /* points to hardware regs */ + int cs_unit; /* unit number */ + struct tty *cs_ttyp; /* ### */ + + /* + * We must keep a copy of the write registers as they are + * mostly write-only and we sometimes need to set and clear + * individual bits (e.g., in WR3). Not all of these are + * needed but 16 bytes is cheap and this makes the addressing + * simpler. Unfortunately, we can only write to some registers + * when the chip is not actually transmitting, so whenever + * we are expecting a `transmit done' interrupt the preg array + * is allowed to `get ahead' of the current values. In a + * few places we must change the current value of a register, + * rather than (or in addition to) the pending value; for these + * cs_creg[] contains the current value. + */ + u_char cs_creg[16]; /* current values */ + u_char cs_preg[16]; /* pending values */ + u_char cs_heldchange; /* change pending (creg != preg) */ + u_char cs_rr0; /* last rr0 processed */ + + /* pure software data, per channel */ + char cs_softcar; /* software carrier */ + char cs_xxx; /* (spare) */ + + /* + * The transmit byte count and address are used for pseudo-DMA + * output in the hardware interrupt code. PDMA can be suspended + * to get pending changes done; heldtbc is used for this. It can + * also be stopped for ^S; this sets TS_TTSTOP in tp->t_state. + */ + int cs_tbc; /* transmit byte count */ + caddr_t cs_tba; /* transmit buffer address */ + int cs_heldtbc; /* held tbc while xmission stopped */ + + /* + * Printing an overrun error message often takes long enough to + * cause another overrun, so we only print one per second. + */ + long cs_rotime; /* time of last ring overrun */ + long cs_fotime; /* time of last fifo overrun */ + + /* + * The ring buffer. + */ + u_int cs_rbget; /* ring buffer `get' index */ + volatile u_int cs_rbput; /* ring buffer `put' index */ + int cs_rbuf[ZLRB_RING_SIZE];/* type, value pairs */ +}; + +#define ZS_CHAN_A 0 +#define ZS_CHAN_B 1 + +/* + * Macros to read and write individual registers (except 0) in a channel. + */ +#define ZS_READ(c, r) ((c)->zc_csr = (r), (c)->zc_csr) +#define ZS_WRITE(c, r, v) ((c)->zc_csr = (r), (c)->zc_csr = (v)) + +/* + * Split minor into unit & flag nibble. + */ +#define ZS_UNIT(dev) ((minor(dev) >> 4) & 0xf) +#define ZS_FLAGS(dev) (minor(dev) & 0xf) |