From f07a4c844da9f0ecae5bbee1ab94be56505f26f7 Mon Sep 17 00:00:00 2001 From: Thomas Bushnell Date: Tue, 25 Feb 1997 21:28:37 +0000 Subject: Initial source --- chips/atm.c | 302 +++++ chips/atmreg.h | 89 ++ chips/audio.c | 733 ++++++++++++ chips/audio_config.h | 130 ++ chips/audio_defs.h | 129 ++ chips/bt431.c | 239 ++++ chips/bt431.h | 78 ++ chips/bt455.c | 222 ++++ chips/bt455.h | 43 + chips/bt459.c | 384 ++++++ chips/bt459.h | 82 ++ chips/bt478.c | 243 ++++ chips/bt478.h | 44 + chips/build_font.c | 132 ++ chips/busses.c | 230 ++++ chips/busses.h | 154 +++ chips/cfb_hdw.c | 188 +++ chips/cfb_misc.c | 249 ++++ chips/dc503.c | 189 +++ chips/dc503.h | 69 ++ chips/dtop.h | 241 ++++ chips/dtop_handlers.c | 441 +++++++ chips/dtop_hdw.c | 644 ++++++++++ chips/dz_7085.h | 153 +++ chips/dz_defs.h | 65 + chips/dz_hdw.c | 649 ++++++++++ chips/eccreg.h | 110 ++ chips/fb_hdw.c | 219 ++++ chips/fb_misc.c | 242 ++++ chips/fdc_82077.h | 525 ++++++++ chips/fdc_82077_hdw.c | 821 +++++++++++++ chips/frc.c | 150 +++ chips/ims332.c | 312 +++++ chips/ims332.h | 137 +++ chips/isdn_79c30.h | 165 +++ chips/isdn_79c30_hdw.c | 602 ++++++++++ chips/kernel_font.c | 3083 +++++++++++++++++++++++++++++++++++++++++++++++ chips/kernel_font.data | 3108 ++++++++++++++++++++++++++++++++++++++++++++++++ chips/lance.c | 1570 ++++++++++++++++++++++++ chips/lance.h | 284 +++++ chips/lance_mapped.c | 417 +++++++ chips/lk201.c | 695 +++++++++++ chips/lk201.h | 241 ++++ chips/mc_clock.c | 516 ++++++++ chips/mc_clock.h | 147 +++ chips/mouse.c | 321 +++++ chips/nc.c | 851 +++++++++++++ chips/nc.h | 232 ++++ chips/nw.h | 494 ++++++++ chips/nw_mk.c | 1323 +++++++++++++++++++++ chips/nw_mk.h | 97 ++ chips/pm_defs.h | 57 + chips/pm_hdw.c | 201 ++++ chips/pm_misc.c | 594 +++++++++ chips/scc_8530.h | 355 ++++++ chips/scc_8530_hdw.c | 1145 ++++++++++++++++++ chips/screen.c | 1103 +++++++++++++++++ chips/screen.h | 289 +++++ chips/screen_defs.h | 97 ++ chips/screen_switch.c | 154 +++ chips/screen_switch.h | 85 ++ chips/serial_console.c | 694 +++++++++++ chips/serial_defs.h | 53 + chips/sfb_hdw.c | 253 ++++ chips/sfb_misc.c | 133 +++ chips/spans.c | 114 ++ chips/spans.h | 58 + chips/tca100.c | 360 ++++++ chips/tca100.h | 200 ++++ chips/tca100_if.c | 1377 +++++++++++++++++++++ chips/tca100_if.h | 89 ++ chips/vs42x_rb.h | 267 +++++ chips/xcfb_hdw.c | 230 ++++ chips/xcfb_misc.c | 246 ++++ chips/xcfb_monitor.h | 56 + 75 files changed, 30994 insertions(+) create mode 100644 chips/atm.c create mode 100644 chips/atmreg.h create mode 100644 chips/audio.c create mode 100644 chips/audio_config.h create mode 100644 chips/audio_defs.h create mode 100644 chips/bt431.c create mode 100644 chips/bt431.h create mode 100644 chips/bt455.c create mode 100644 chips/bt455.h create mode 100644 chips/bt459.c create mode 100644 chips/bt459.h create mode 100644 chips/bt478.c create mode 100644 chips/bt478.h create mode 100644 chips/build_font.c create mode 100644 chips/busses.c create mode 100644 chips/busses.h create mode 100644 chips/cfb_hdw.c create mode 100644 chips/cfb_misc.c create mode 100644 chips/dc503.c create mode 100644 chips/dc503.h create mode 100644 chips/dtop.h create mode 100644 chips/dtop_handlers.c create mode 100644 chips/dtop_hdw.c create mode 100644 chips/dz_7085.h create mode 100644 chips/dz_defs.h create mode 100644 chips/dz_hdw.c create mode 100644 chips/eccreg.h create mode 100644 chips/fb_hdw.c create mode 100644 chips/fb_misc.c create mode 100644 chips/fdc_82077.h create mode 100644 chips/fdc_82077_hdw.c create mode 100644 chips/frc.c create mode 100644 chips/ims332.c create mode 100644 chips/ims332.h create mode 100644 chips/isdn_79c30.h create mode 100644 chips/isdn_79c30_hdw.c create mode 100644 chips/kernel_font.c create mode 100644 chips/kernel_font.data create mode 100644 chips/lance.c create mode 100644 chips/lance.h create mode 100644 chips/lance_mapped.c create mode 100644 chips/lk201.c create mode 100644 chips/lk201.h create mode 100644 chips/mc_clock.c create mode 100644 chips/mc_clock.h create mode 100644 chips/mouse.c create mode 100644 chips/nc.c create mode 100644 chips/nc.h create mode 100644 chips/nw.h create mode 100644 chips/nw_mk.c create mode 100644 chips/nw_mk.h create mode 100644 chips/pm_defs.h create mode 100644 chips/pm_hdw.c create mode 100644 chips/pm_misc.c create mode 100644 chips/scc_8530.h create mode 100644 chips/scc_8530_hdw.c create mode 100644 chips/screen.c create mode 100644 chips/screen.h create mode 100644 chips/screen_defs.h create mode 100644 chips/screen_switch.c create mode 100644 chips/screen_switch.h create mode 100644 chips/serial_console.c create mode 100644 chips/serial_defs.h create mode 100644 chips/sfb_hdw.c create mode 100644 chips/sfb_misc.c create mode 100644 chips/spans.c create mode 100644 chips/spans.h create mode 100644 chips/tca100.c create mode 100644 chips/tca100.h create mode 100644 chips/tca100_if.c create mode 100644 chips/tca100_if.h create mode 100644 chips/vs42x_rb.h create mode 100644 chips/xcfb_hdw.c create mode 100644 chips/xcfb_misc.c create mode 100644 chips/xcfb_monitor.h (limited to 'chips') diff --git a/chips/atm.c b/chips/atm.c new file mode 100644 index 0000000..165cd23 --- /dev/null +++ b/chips/atm.c @@ -0,0 +1,302 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include + +#if NATM > 0 + +#include +#include /* spl definitions */ +#include /* ? maybe */ +#include +#include +#include + +#include +#include + +#include + +#include + + +struct bus_device *atm_info[NATM]; +int atm_probe(); +static void atm_attach(); + +struct bus_driver atm_driver = + { atm_probe, 0, atm_attach, 0, /* csr */ 0, "atm", atm_info, + "", 0, /* flags */ 0 }; /* ENABLED BUS INTR? */ + +/* XX "", 0, BUS_INTR_DISABLED}; */ + +typedef struct atm_softc { + struct atm_device *atm_dev; + struct evc atm_eventcounter; + mapped_atm_info_t atm_mapped_info; +} atm_softc_t; + + +natural_t atm_nintrs = 0; + +atm_softc_t atm_softc[NATM]; + +atm_probe(reg, ui) + vm_offset_t reg; + register struct bus_device *ui; +{ + register atm_softc_t *atm; + mapped_atm_info_t info; /* info struct to hand to users */ + vm_offset_t addr; + int unit = ui->unit; + + if (check_memory(reg, 0)) { + return 0; + } + + atm_info[unit] = ui; + atm = &atm_softc[unit]; + atm->atm_dev = (struct atm_device *) reg; /* k1 address */ + + evc_init(&atm->atm_eventcounter); + +printf("evc_init of atm: event counter id is %d\n", atm->atm_eventcounter.ev_id); + + /* initialize the interface to deliver. No interrupts by default */ + atm->atm_dev->sreg = 0; + atm->atm_dev->creg = (CR_RX_RESET | CR_TX_RESET); + atm->atm_dev->creg = 0; + atm->atm_dev->creg_set = (CR_RX_ENABLE | CR_TX_ENABLE); +#ifdef notdef + atm->atm_dev->rxthresh = 0; + atm->atm_dev->rxtimerv = 0; + atm->atm_dev->creg_s = RX_EOM_INTR; /* enable interrupt on end of message */ +#endif + + /* + * Grab a page to be mapped later to users + */ + (void) kmem_alloc_wired(kernel_map, &addr, PAGE_SIZE); /* kseg2 */ + bzero(addr, PAGE_SIZE); + addr = pmap_extract(pmap_kernel(), addr); /* phys */ + info = (mapped_atm_info_t) PHYS_TO_K0SEG(addr); + atm->atm_mapped_info = info; + + /* + * Set some permanent info + */ + info->hello_world = 0xdeadbeef; + info->interrupt_count = 0; + info->wait_event = atm->atm_eventcounter.ev_id; + info->saved_status_reg = 0; + + return 1; +} + +static void +atm_attach(ui) +register struct bus_device *ui; +{ +} + +int atm_disable_interrupts_after_each = 1; + + +#define ATM_INTERRUPTS (RX_COUNT_INTR | RX_EOM_INTR | RX_TIME_INTR) + +atm_intr(unit, spllevel) +int unit; +int spllevel; +{ + register struct atm_softc *atm = &atm_softc[unit]; + struct atm_device *atm_dev = atm->atm_dev; + unsigned int intr; + + if (atm_dev == 0) { + printf("atm: stray interrupt\n"); + return; + } + + /* Acknowledge interrupt request */ + intr = ATM_READ_REG(atm_dev->sreg); + atm_dev->sreg = ~(intr & ATM_INTERRUPTS); + + /* clear the reason for the interrupt */ + if (atm_disable_interrupts_after_each) + atm_dev->creg &= ~intr; + + splx(spllevel); /* drop priority now */ + + atm_intr_occurred(); + + + /* Pass status info up to user */ + if (atm->atm_mapped_info) { + atm->atm_mapped_info->interrupt_count++; + atm->atm_mapped_info->saved_status_reg = intr; + } + + /* Awake user thread */ + + evc_signal(&atm->atm_eventcounter); + + /* NOTE: INTERRUPTS ARE DISABLED. */ +} + +atm_intr_occurred() +{ + atm_nintrs++; +} + + +atm_output(dev, ior) +int dev; +io_req_t ior; +{ +} + +atm_start(unit) +int unit; +{ +} + +atm_open(dev, flag, ior) + int dev; + int flag; + io_req_t ior; +{ + register int unit = dev; + register atm_softc_t *atm = &atm_softc[unit]; + + if (unit >= NATM) + return EINVAL; + if (!atm->atm_dev) + return ENXIO; + + return KERN_SUCCESS; +} + +atm_close(dev, flag) +int dev; +{ +} + +atm_read(dev, ior) +int dev; +io_req_t ior; +{ +} + +atm_write(dev, ior) +int dev; +io_req_t ior; +{ +} + +atm_get_status(dev, flavor, status, status_count) + int dev; + int flavor; + dev_status_t status; /* pointer to OUT array */ + natural_t *status_count; /* out */ +{ + switch (flavor) { + case NET_STATUS: + { + register struct net_status *ns = (struct net_status *)status; + + ns->min_packet_size = sizeof(struct sar_data); + ns->max_packet_size = sizeof(struct sar_data); + ns->header_format = 999; /* XX */ + ns->header_size = sizeof(int); /* XX */ + ns->address_size = 0; + ns->flags = 0; + ns->mapped_size = sizeof(struct atm_device) + PAGE_SIZE; + *status_count = NET_STATUS_COUNT; + break; + } + case NET_ADDRESS: + /* This would be a good place for it */ + default: + return (D_INVALID_OPERATION); + } + return (D_SUCCESS); +} + +atm_set_status(dev, flavor, status, status_count) + int dev; + int flavor; + dev_status_t status; + natural_t status_count; +{ +} + +atm_mmap(dev, off, prot) + int dev; + vm_offset_t off; + int prot; +{ + int unit = dev; + vm_offset_t addr; + + /* + * Layout of mapped area is: + * 000 -- FA_END: DEVICE + * FA_END -- FA_END + PAGE_SIZE: SHARED STATE + */ + if (off < sizeof(struct atm_device)) { + addr = K1SEG_TO_PHYS((vm_offset_t)(atm_softc[unit].atm_dev)) + off; + } else if (off < sizeof(struct atm_device) + PAGE_SIZE) { + addr = K0SEG_TO_PHYS(atm_softc[unit].atm_mapped_info); + } else return -1; + return mips_btop(addr); +} + +atm_setinput(dev, receive_port, priority, filter, filter_count) + int dev; + ipc_port_t receive_port; + int priority; + /*filter_t *filter;*/ + natural_t filter_count; +{ +} + +atm_restart(ifp) +/* register struct ifnet *ifp; */ +{ +} + +atm_portdeath(dev, port) + int dev; + mach_port_t port; +{ +} + +#endif NATM > 0 + + + + + diff --git a/chips/atmreg.h b/chips/atmreg.h new file mode 100644 index 0000000..a895783 --- /dev/null +++ b/chips/atmreg.h @@ -0,0 +1,89 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +/*** FORE TCA-100 Turbochannel ATM computer interface ***/ + +#define RX_COUNT_INTR 0x0001 +#define RX_EOM_INTR 0x0002 +#define RX_TIME_INTR 0x0004 +#define TX_COUNT_INTR 0x0008 +#define RX_CELL_LOST 0x0010 +#define RX_NO_CARRIER 0x0020 +#define CR_RX_ENABLE 0x0040 +#define CR_TX_ENABLE 0x0080 +#define CR_RX_RESET 0x0100 +#define CR_TX_RESET 0x0200 + +#define ATM_READ_REG(reg) ((reg) & 0x3ff) /* 10 bit register mask */ + + +struct atm_device { + unsigned int prom[64 * 1024 / 4]; + volatile unsigned int sreg; + volatile unsigned int creg_set; + volatile unsigned int creg_clr; + volatile unsigned int creg; + volatile unsigned int rxtimer; + unsigned int pad1; + volatile unsigned int rxtimerv; + unsigned int pad2; + volatile unsigned int rxcount; + unsigned int pad3; + volatile unsigned int rxthresh; + unsigned int pad4; + volatile unsigned int txcount; + unsigned int pad5; + volatile unsigned int txthresh; + unsigned int pad6[64*1024/4 - 15]; + volatile unsigned int rxfifo[14]; + unsigned int pad7[64*1024/4 - 14]; + volatile unsigned int txfifo[14]; + unsigned int pad8[64*1024/4 - 14]; +}; +/* MUST BE PAGE ALIGNED OR YOU WILL GET KILLED BELOW WITH ATM_INFO */ + +struct sar_data { + int header; + int payload[12]; + int trailer; +}; + + +/* + * Information for mapped atm device + */ +typedef struct mapped_atm_info { + volatile unsigned int interrupt_count; /* tot interrupts received */ + volatile unsigned short saved_status_reg; /* copy of status reg from last interrupt */ + unsigned int hello_world; + unsigned wait_event; +} *mapped_atm_info_t; + + + +#define ATM_DEVICE(p) (struct atm_device*)(p) +#define ATM_INFO(p) (mapped_atm_info_t)( (p) + sizeof(struct atm_device) ) + diff --git a/chips/audio.c b/chips/audio.c new file mode 100644 index 0000000..00bf2be --- /dev/null +++ b/chips/audio.c @@ -0,0 +1,733 @@ +/* + * Mach Operating System + * Copyright (c) 1993 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/*- + * Copyright (c) 1991, 1992 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 Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. The name of the Laboratory may not 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 +#if NAUDIO > 0 + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include /* user interface */ +#include /* chip interface */ +#include /* machdep config */ + +#define private static + +/* + * Exported functions and data structures + * [see header file for listing] + */ +int audio_blocksize = DEFBLKSIZE; /* patchable */ +int audio_backlog = 400; /* 50ms in samples */ + +/* + * Software state, per AMD79C30 audio chip. + */ +private +struct audio_softc { + void *hw; /* chip status */ + audio_switch_t *ops; /* chip operations */ + au_io_t *sc_au; /* recv and xmit buffers, etc */ + + + unsigned int sc_wseek; /* timestamp of last frame written */ + unsigned int sc_rseek; /* timestamp of last frame read */ +#if 0 + struct selinfo sc_wsel; /* write selector */ + struct selinfo sc_rsel; /* read selector */ +#endif + +} audio_softc_data[NAUDIO]; + +#define unit_to_softc(u) &audio_softc_data[u] + + +/* forward declarations */ +private int audio_sleep (au_cb_t *cb, int thresh); +private void audio_swintr (struct audio_softc *sc); + +/* + * Audio chip found. + */ +void +audio_attach( + void *hw, /* IN, chip status */ + audio_switch_t *ops, + void **audio_status) /* OUT, audio status */ +{ + register struct audio_softc *sc; + static int next = 0; + + if (next >= NAUDIO) + panic("Please configure more than %d audio devices\n", NAUDIO); + sc = &audio_softc_data[next++]; + + printf(" audio"); + + sc->hw = hw; + sc->ops = ops; + + *audio_status = (void *)sc; +} + + +private int audio_setinfo (struct audio_softc *, audio_info_t *); +private int audio_getinfo (struct audio_softc *, audio_info_t *); + +io_return_t +audio_open( + int unit, + int mode, + io_req_t req) +{ + register struct audio_softc *sc; + register au_io_t *au; + + sc = unit_to_softc(unit); + if (unit > NAUDIO || (!sc->hw)) + return (D_NO_SUCH_DEVICE); + + if (!sc->sc_au) { + sc->sc_au = (au_io_t *) kalloc(sizeof(au_io_t)); + bzero(sc->sc_au, sizeof(au_io_t)); + } + au = sc->sc_au; + + au->au_lowat = audio_blocksize; + au->au_hiwat = AUCB_SIZE - au->au_lowat; + au->au_blksize = audio_blocksize; + au->au_backlog = audio_backlog; + + /* set up read and write blocks and `dead sound' zero value. */ + AUCB_INIT(&au->au_rb); + au->au_rb.cb_thresh = AUCB_SIZE; + AUCB_INIT(&au->au_wb); + au->au_wb.cb_thresh = -1; + + /* nothing read or written yet */ + sc->sc_rseek = 0; + sc->sc_wseek = 0; + + (*sc->ops->init)(sc->hw); + + return (0); +} + +private int +audio_drain( + register au_io_t *au) +{ + register int error; + + while (!AUCB_EMPTY(&au->au_wb)) + if ((error = audio_sleep(&au->au_wb, 0)) != 0) + return (error); + return (0); +} + +/* + * Close an audio chip. + */ +/* ARGSUSED */ +io_return_t +audio_close( + int unit) +{ + register struct audio_softc *sc = unit_to_softc(unit); + register au_cb_t *cb; + register spl_t s; + + /* + * Block until output drains, but allow ^C interrupt. + */ + sc->sc_au->au_lowat = 0; /* avoid excessive wakeups */ + + /* + * If there is pending output, let it drain (unless + * the output is paused). + */ + cb = &sc->sc_au->au_wb; + s = splaudio(); + if (!AUCB_EMPTY(cb) && !cb->cb_pause) + (void)audio_drain(sc->sc_au); + /* + * Disable interrupts, and done. + */ + (*sc->ops->close)(sc->hw); + splx(s); + return (D_SUCCESS); +} + +private int +audio_sleep( + register au_cb_t *cb, + register int thresh) +{ + register spl_t s = splaudio(); + + cb->cb_thresh = thresh; + assert_wait((event_t)cb, TRUE); + splx(s); + thread_block((void (*)()) 0); + return (0); /* XXXX */ +} + +io_return_t +audio_read( + int unit, + io_req_t ior) +{ + register struct audio_softc *sc = unit_to_softc(unit); + register au_cb_t *cb; + register int n, head, taildata; + register int blocksize = sc->sc_au->au_blksize; + io_return_t rc; + unsigned char *data; + + /* + * Allocate read buffer + */ + rc = device_read_alloc(ior, (vm_size_t)ior->io_count); + if (rc != KERN_SUCCESS) + return rc; + data = (unsigned char *) ior->io_data; + ior->io_residual = ior->io_count; + + cb = &sc->sc_au->au_rb; + cb->cb_drops = 0; + sc->sc_rseek = sc->sc_au->au_stamp - AUCB_LEN(cb); + do { + while (AUCB_LEN(cb) < blocksize) { + + if (ior->io_mode & D_NODELAY) + return (D_WOULD_BLOCK); + + if ((rc = audio_sleep(cb, blocksize)) != 0) + return(rc); + } + /* + * The space calculation can only err on the short + * side if an interrupt occurs during processing: + * only cb_tail is altered in the interrupt code. + */ + head = cb->cb_head; + if ((n = AUCB_LEN(cb)) > ior->io_residual) + n = ior->io_residual; + taildata = AUCB_SIZE - head; + + if (n > taildata) { + bcopy(cb->cb_data + head, data, taildata); + bcopy(cb->cb_data, data + taildata, n - taildata); + } else + bcopy(cb->cb_data + head, data, n); + data += n; + ior->io_residual -= n; + + head = AUCB_MOD(head + n); + cb->cb_head = head; + } while (ior->io_residual >= blocksize); + + return (rc); +} + +io_return_t +audio_write( + int unit, + io_req_t ior) +{ + register struct audio_softc *sc = unit_to_softc(unit); + register au_io_t *au = sc->sc_au; + register au_cb_t *cb = &au->au_wb; + register int n, tail, tailspace, first, watermark; + io_return_t rc; + unsigned char *data; + vm_offset_t addr = 0; + + if (!(ior->io_op & IO_INBAND)) { + /* + * Copy out-of-line data into kernel address space. + * Since data is copied as page list, it will be + * accessible. + */ + vm_map_copy_t copy = (vm_map_copy_t) ior->io_data; + kern_return_t kr; + + kr = vm_map_copyout(device_io_map, &addr, copy); + if (kr != KERN_SUCCESS) + return kr; + data = (unsigned char *) addr; + } else + data = (unsigned char *) ior->io_data; + ior->io_residual = ior->io_count; + + rc = D_SUCCESS; + first = 1; + while (ior->io_residual > 0) { + watermark = au->au_hiwat; + while (AUCB_LEN(cb) > watermark) { + + if (ior->io_mode & D_NODELAY) { + rc = D_WOULD_BLOCK; + goto out; + } + + if ((rc = audio_sleep(cb, watermark)) != 0) + goto out; + + watermark = au->au_lowat; + } + /* + * The only value that can change on an interrupt is + * cb->cb_head. We only pull that out once to decide + * how much to write into cb_data; if we lose a race + * and cb_head changes, we will merely be overly + * conservative. For a legitimate time stamp, + * however, we need to synchronize the accesses to + * au_stamp and cb_head at a high ipl below. + */ + tail = cb->cb_tail; + if ((n = (AUCB_SIZE - 1) - AUCB_LEN(cb)) > ior->io_residual) { + n = ior->io_residual; + if (cb->cb_head == tail && + n <= au->au_blksize && + au->au_stamp - sc->sc_wseek > 400) { + /* + * the write is 'small', the buffer is empty + * and we have been silent for at least 50ms + * so we might be dealing with an application + * that writes frames synchronously with + * reading them. If so, we need an output + * backlog to cover scheduling delays or + * there will be gaps in the sound output. + * Also take this opportunity to reset the + * buffer pointers in case we ended up on + * a bad boundary (odd byte, blksize bytes + * from end, etc.). + */ + register unsigned long *ip; + register unsigned long muzero; + spl_t s; + register int i; + + s = splaudio(); + cb->cb_head = cb->cb_tail = 0; + splx(s); + + tail = au->au_backlog; + ip = (unsigned long *)cb->cb_data; + muzero = sample_rpt_long(0x7fL); + for (i = tail / sizeof muzero; --i >= 0; ) + *ip++ = muzero; + } + } + tailspace = AUCB_SIZE - tail; + if (n > tailspace) { + /* write first part at tail and rest at head */ + bcopy(data, cb->cb_data + tail, tailspace); + bcopy(data + tailspace, cb->cb_data, + n - tailspace); + } else + bcopy(data, cb->cb_data + tail, n); + data += n; + ior->io_residual -= n; + + tail = AUCB_MOD(tail + n); + if (first) { + register spl_t s = splaudio(); + sc->sc_wseek = AUCB_LEN(cb) + au->au_stamp + 1; + /* + * To guarantee that a write is contiguous in the + * sample space, we clear the drop count the first + * time through. If we later get drops, we will + * break out of the loop below, before writing + * a new frame. + */ + cb->cb_drops = 0; + cb->cb_tail = tail; + splx(s); + first = 0; + } else { +#if 0 + if (cb->cb_drops != 0) + break; +#endif + cb->cb_tail = tail; + } + } +out: + if (!(ior->io_op & IO_INBAND)) + (void) vm_deallocate(device_io_map, addr, ior->io_count); + return (rc); +} + +#include + +io_return_t +audio_get_status( + int unit, + dev_flavor_t flavor, + dev_status_t status, + natural_t *status_count) +{ + register struct audio_softc *sc = unit_to_softc(unit); + register au_io_t *au = sc->sc_au; + io_return_t rc = D_SUCCESS; + spl_t s; + + switch (flavor) { + + case AUDIO_GETMAP: + case AUDIOGETREG: + rc = (*sc->ops->getstate)(sc->hw, flavor, + (void *)status, status_count); + break; + + /* + * Number of read samples dropped. We don't know where or + * when they were dropped. + */ + case AUDIO_RERROR: + *(int *)status = au->au_rb.cb_drops; + *status_count = 1; + break; + + case AUDIO_WERROR: + *(int *)status = au->au_wb.cb_drops; + *status_count = 1; + break; + + /* + * How many samples will elapse until mike hears the first + * sample of what we last wrote? + */ + case AUDIO_WSEEK: + s = splaudio(); + *(unsigned int *)status = sc->sc_wseek - au->au_stamp + + AUCB_LEN(&au->au_rb); + splx(s); + *status_count = 1; + break; + + case AUDIO_GETINFO: + rc = audio_getinfo(sc, (audio_info_t *)status); + *status_count = sizeof(audio_info_t) / sizeof(int); + break; + + default: + rc = D_INVALID_OPERATION; + break; + } + return (rc); +} + +io_return_t +audio_set_status( + int unit, + dev_flavor_t flavor, + dev_status_t status, + natural_t status_count) +{ + register struct audio_softc *sc = unit_to_softc(unit); + register au_io_t *au = sc->sc_au; + io_return_t rc = D_SUCCESS; + spl_t s; + + switch (flavor) { + + case AUDIO_SETMAP: + case AUDIOSETREG: + rc = (*sc->ops->setstate)(sc->hw, flavor, + (void *)status, status_count); + break; + + case AUDIO_FLUSH: + s = splaudio(); + AUCB_INIT(&au->au_rb); + AUCB_INIT(&au->au_wb); + au->au_stamp = 0; + splx(s); + sc->sc_wseek = 0; + sc->sc_rseek = 0; + break; + + case AUDIO_SETINFO: + rc = audio_setinfo(sc, (audio_info_t *)status); + break; + + case AUDIO_DRAIN: + rc = audio_drain(au); + break; + + default: + rc = D_INVALID_OPERATION; + break; + } + return (rc); +} + + +/* + * Interrupt routine + */ +boolean_t +audio_hwintr( + void *status, + unsigned int s_in, + unsigned int *s_out) +{ + register au_io_t *au = ((struct audio_softc *) status)->sc_au; + register au_cb_t *cb; + register int h, t, k; + register boolean_t wakeit = FALSE; + + ++au->au_stamp; + + /* receive incoming data */ + cb = &au->au_rb; + h = cb->cb_head; + t = cb->cb_tail; + k = AUCB_MOD(t + 1); + if (h == k) + cb->cb_drops++; + else if (cb->cb_pause != 0) + cb->cb_pdrops++; + else { + cb->cb_data[t] = s_in; + cb->cb_tail = t = k; + } + if (AUCB_MOD(t - h) >= cb->cb_thresh) { + cb->cb_thresh = AUCB_SIZE; + cb->cb_waking = 1; + wakeit = TRUE; + } + /* send outgoing data */ + cb = &au->au_wb; + h = cb->cb_head; + t = cb->cb_tail; + k = 0; + if (h == t) + cb->cb_drops++; + else if (cb->cb_pause != 0) + cb->cb_pdrops++; + else { + cb->cb_head = h = AUCB_MOD(h + 1); + *s_out = cb->cb_data[h]; + k = 1; + } + if (AUCB_MOD(t - h) <= cb->cb_thresh) { + cb->cb_thresh = -1; + cb->cb_waking = 1; + wakeit = TRUE; + } + if (wakeit) + audio_swintr((struct audio_softc *) status); + return (k == 1); +} + +private void +audio_swintr( + register struct audio_softc *sc) +{ + register au_io_t *au = sc->sc_au; + + if (au->au_rb.cb_waking != 0) { + au->au_rb.cb_waking = 0; + wakeup(&au->au_rb); + } + if (au->au_wb.cb_waking != 0) { + au->au_wb.cb_waking = 0; + wakeup(&au->au_wb); + } +} + +private int +audio_setinfo( + struct audio_softc *sc, + audio_info_t *ai) +{ + struct audio_prinfo *r = &ai->record, *p = &ai->play; + register int bsize; + register au_io_t *au = sc->sc_au; + spl_t s; + + (*sc->ops->setgains)(sc->hw, p->gain, r->gain, ai->monitor_gain ); + + if (p->pause != (unsigned char)~0) + au->au_wb.cb_pause = p->pause; + if (r->pause != (unsigned char)~0) + au->au_rb.cb_pause = r->pause; + + if (p->port != ~0) + (*sc->ops->setport)(sc->hw, p->port); + + if (ai->blocksize != ~0) { + if (ai->blocksize == 0) + bsize = ai->blocksize = DEFBLKSIZE; + else if (ai->blocksize > MAXBLKSIZE) + bsize = ai->blocksize = MAXBLKSIZE; + else + bsize = ai->blocksize; + + s = splaudio(); + au->au_blksize = bsize; + /* AUDIO_FLUSH */ + AUCB_INIT(&au->au_rb); + AUCB_INIT(&au->au_wb); + splx(s); + + } + if (ai->hiwat != ~0 && (unsigned)ai->hiwat < AUCB_SIZE) + au->au_hiwat = ai->hiwat; + if (ai->lowat != ~0 && ai->lowat < AUCB_SIZE) + au->au_lowat = ai->lowat; + if (ai->backlog != ~0 && ai->backlog < (AUCB_SIZE/2)) + au->au_backlog = ai->backlog; + + return (0); +} + +private int +audio_getinfo( + struct audio_softc *sc, + audio_info_t *ai) +{ + struct audio_prinfo *r = &ai->record, *p = &ai->play; + register au_io_t *au = sc->sc_au; + + p->sample_rate = r->sample_rate = 8000; + p->channels = r->channels = 1; + p->precision = r->precision = 8; + p->encoding = r->encoding = AUDIO_ENCODING_ULAW; + + (*sc->ops->getgains)(sc->hw, &p->gain, &r->gain, &ai->monitor_gain ); + + r->port = AUDIO_MIKE; + p->port = (*sc->ops->getport)(sc->hw); + + p->pause = au->au_wb.cb_pause; + r->pause = au->au_rb.cb_pause; + p->error = au->au_wb.cb_drops != 0; + r->error = au->au_rb.cb_drops != 0; + + /* Now this is funny. If you got here it means you must have + opened the device, so how could it possibly be closed ? + Unless we upgrade the berkeley code to check if the chip + is currently playing and/or recording... Later. */ + p->open = TRUE; + r->open = TRUE; + + p->samples = au->au_stamp - au->au_wb.cb_pdrops; + r->samples = au->au_stamp - au->au_rb.cb_pdrops; + + p->seek = sc->sc_wseek; + r->seek = sc->sc_rseek; + + ai->blocksize = au->au_blksize; + ai->hiwat = au->au_hiwat; + ai->lowat = au->au_lowat; + ai->backlog = au->au_backlog; + + return (0); +} + +#if MACH_KDB +#include + +void audio_queue_status( au_cb_t *cb, char *logo) +{ + db_printf("%s ring status:\n", logo); + db_printf(" h %x t %x sh %x w %d p %d d %x pd %x\n", + cb->cb_head, cb->cb_tail, cb->cb_thresh, + cb->cb_waking, cb->cb_pause, (long)cb->cb_drops, + (long)cb->cb_pdrops); +} + +int audio_status(int unit) +{ + struct audio_softc *sc = unit_to_softc(unit); + au_io_t *au; + + if (!sc) { + db_printf("No such thing\n"); + return 0; + } + db_printf("@%lx: wseek %d rseek %d, au @%lx\n", + sc, sc->sc_wseek, sc->sc_rseek, sc->sc_au); + if (!(au = sc->sc_au)) return 0; + + db_printf("au: stamp %x lo %x hi %x blk %x blg %x\n", + au->au_stamp, au->au_lowat, au->au_hiwat, + au->au_blksize, au->au_backlog); + audio_queue_status(&au->au_rb, "read"); + audio_queue_status(&au->au_wb, "write"); + + return 0; +} +#endif /* MACH_KDB */ + +#endif /* NAUDIO > 0 */ + diff --git a/chips/audio_config.h b/chips/audio_config.h new file mode 100644 index 0000000..bd2c0a0 --- /dev/null +++ b/chips/audio_config.h @@ -0,0 +1,130 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Here platform specific code to define sample_t & co + * [to cope with weird DMA engines], and other customs + */ +#ifdef FLAMINGO +#define splaudio splbio +#define sample_t unsigned char /* later */ +#define samples_to_chars bcopy +#define chars_to_samples bcopy +/* Sparse space ! */ +typedef struct { + volatile unsigned long cr; /* command register (wo) */ +/*#define ir cr /* interrupt register (ro) */ + volatile unsigned long dr; /* data register (rw) */ + volatile unsigned long dsr1; /* D-channel status register 1 (ro) */ + volatile unsigned long der; /* D-channel error register (ro) */ + volatile unsigned long dctb; /* D-channel transmit register (wo) */ +/*#define dcrb dctb /* D-channel receive register (ro) */ + volatile unsigned long bbtb; /* Bb-channel transmit register (wo) */ +/*#define bbrb bbtb /* Bb-channel receive register (ro) */ + volatile unsigned long bctb; /* Bc-channel transmit register (wo)*/ +/*#define bcrb bctb /* Bc-channel receive register (ro) */ + volatile unsigned long dsr2; /* D-channel status register 2 (ro) */ +} amd79c30_padded_regs_t; + +/* give the chip 400ns in between accesses */ +#define read_reg(r,v) \ + { (v) = ((r) >> 8) & 0xff; delay(1); } + +#define write_reg(r,v) \ + { (r) = (((v) & 0xff) << 8) | \ + 0x200000000L; /*bytemask*/ \ + delay(1); wbflush(); \ + } + +/* Write 16 bits of data from variable v to the data port of the audio chip */ +#define WAMD16(regs, v) \ + { write_reg((regs)->dr,v); \ + write_reg((regs)->dr,v>>8); } + +#define mb() wbflush() + +#endif /* FLAMINGO */ + + +#ifdef MAXINE +#define splaudio splhigh +typedef struct { + volatile unsigned char cr; /* command register (wo) */ +/*#define ir cr /* interrupt register (ro) */ + char pad0[63]; + volatile unsigned char dr; /* data register (rw) */ + char pad1[63]; + volatile unsigned char dsr1; /* D-channel status register 1 (ro) */ + char pad2[63]; + volatile unsigned char der; /* D-channel error register (ro) */ + char pad3[63]; + volatile unsigned char dctb; /* D-channel transmit register (wo) */ +/*#define dcrb dctb /* D-channel receive register (ro) */ + char pad4[63]; + volatile unsigned char bbtb; /* Bb-channel transmit register (wo) */ +/*#define bbrb bbtb /* Bb-channel receive register (ro) */ + char pad5[63]; + volatile unsigned char bctb; /* Bc-channel transmit register (wo)*/ +/*#define bcrb bctb /* Bc-channel receive register (ro) */ + char pad6[63]; + volatile unsigned char dsr2; /* D-channel status register 2 (ro) */ + char pad7[63]; +} amd79c30_padded_regs_t; + +/* give the chip 400ns in between accesses */ +#define read_reg(r,v) \ + { (v) = (r); delay(1); } + +#define write_reg(r,v) \ + { (r) = (v); delay(1); wbflush(); } + +/* Write 16 bits of data from variable v to the data port of the audio chip */ +#define WAMD16(regs, v) \ + { write_reg((regs)->dr,v); \ + write_reg((regs)->dr,v>>8); } + +#define mb() + +#endif /* MAXINE */ + + +#ifndef sample_t +#define sample_t unsigned char +#define samples_to_chars bcopy +#define chars_to_samples bcopy +#endif + +/* + * More architecture-specific customizations + */ +#ifdef alpha +#define sample_rpt_int(x) (((x)<<24)|((x)<<16)|((x)<<8)|((x)<<0)) +#define sample_rpt_long(x) ((sample_rpt_int(x)<<32)|sample_rpt_int(x)) +#endif + +#ifndef sample_rpt_long +#define sample_rpt_long(x) (((x)<<24)|((x)<<16)|((x)<<8)|((x)<<0)) +#endif + diff --git a/chips/audio_defs.h b/chips/audio_defs.h new file mode 100644 index 0000000..448153e --- /dev/null +++ b/chips/audio_defs.h @@ -0,0 +1,129 @@ +/* + * Mach Operating System + * Copyright (c) 1993 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/*- + * Copyright (c) 1991, 1992 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 Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. The name of the Laboratory may not 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. + */ + +#define AUCB_SIZE 4096 +#define AUCB_MOD(k) ((k) & (AUCB_SIZE - 1)) + +#define AUCB_INIT(cb) ((cb)->cb_head = (cb)->cb_tail = (cb)->cb_drops = \ + (cb)->cb_pdrops = 0) + +#define AUCB_EMPTY(cb) ((cb)->cb_head == (cb)->cb_tail) +#define AUCB_FULL(cb) (AUCB_MOD((cb)->cb_tail + 1) == (cb)->cb_head) +#define AUCB_LEN(cb) (AUCB_MOD((cb)->cb_tail - (cb)->cb_head)) + +#define MAXBLKSIZE (AUCB_SIZE / 2) +#define DEFBLKSIZE 128 + +#ifndef LOCORE + +/* + * Our own circular buffers, used if not doing DMA. + * [af: with some work we could use the circbuf.c code instead] + */ +typedef struct au_cb { + int cb_head; /* queue head */ + int cb_tail; /* queue tail */ + int cb_thresh; /* threshold for wakeup */ + unsigned int cb_waking; /* needs wakeup at softint level */ + unsigned int cb_pause; /* io paused */ + unsigned int cb_drops; /* missed samples from over/underrun */ + unsigned int cb_pdrops; /* sun compat -- paused samples */ + unsigned char cb_data[AUCB_SIZE]; /* data buffer */ +} au_cb_t; + +/* + * Handle on a bi-directional stream of samples + */ +typedef struct au_io { + unsigned int au_stamp; /* time stamp */ + int au_lowat; /* xmit low water mark (for wakeup) */ + int au_hiwat; /* xmit high water mark (for wakeup) */ + int au_blksize; /* recv block (chunk) size */ + int au_backlog; /* # samples of xmit backlog to gen. */ + struct au_cb au_rb; /* read (recv) buffer */ + struct au_cb au_wb; /* write (xmit) buffer */ +} au_io_t; + +/* + * Interface to specific chips + */ +typedef struct { + void (*init)(); + void (*close)(); + void (*setport)(); + int (*getport)(); + void (*setgains)(); + void (*getgains)(); + io_return_t (*setstate)(); + io_return_t (*getstate)(); +} audio_switch_t; + +/* + * Callbacks into audio module, and interface to kernel + */ +void audio_attach( void *, audio_switch_t *, void **); +boolean_t audio_hwintr( void *, unsigned int, unsigned int *); + +extern io_return_t audio_open( int, int, io_req_t ); +extern io_return_t audio_close( int ); +extern io_return_t audio_read( int, io_req_t ); +extern io_return_t audio_write( int, io_req_t ); +extern io_return_t audio_get_status( int, dev_flavor_t, dev_status_t, natural_t *); +extern io_return_t audio_set_status( int, dev_flavor_t, dev_status_t, natural_t); + +#endif diff --git a/chips/bt431.c b/chips/bt431.c new file mode 100644 index 0000000..0c6368c --- /dev/null +++ b/chips/bt431.c @@ -0,0 +1,239 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: bt431.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 8/91 + * + * Routines for the bt431 Cursor + */ + +#include + +#include +#include + +#ifdef DECSTATION +/* + * This configuration uses two twin 431s + */ +#define set_value(x) (((x)<<8)|((x)&0xff)) +#define get_value(x) ((x)&0xff) + +typedef struct { + volatile unsigned short addr_lo; + short pad0; + volatile unsigned short addr_hi; + short pad1; + volatile unsigned short addr_cmap; + short pad2; + volatile unsigned short addr_reg; + short pad3; +} bt431_padded_regmap_t; + +#else /*DECSTATION*/ + +#define set_value(x) x +#define get_value(x) x +typedef bt431_regmap_t bt431_padded_regmap_t; +#define wbflush() + +#endif /*DECSTATION*/ + +/* + * Generic register access + */ +void +bt431_select_reg( regs, regno) + bt431_padded_regmap_t *regs; +{ + regs->addr_lo = set_value(regno&0xff); + regs->addr_hi = set_value((regno >> 8) & 0xff); + wbflush(); +} + +void +bt431_write_reg( regs, regno, val) + bt431_padded_regmap_t *regs; +{ + bt431_select_reg( regs, regno ); + regs->addr_reg = set_value(val); + wbflush(); +} + +unsigned char +bt431_read_reg( regs, regno) + bt431_padded_regmap_t *regs; +{ + bt431_select_reg( regs, regno ); + return get_value(regs->addr_reg); +} + +/* when using autoincrement */ +#define bt431_write_reg_autoi( regs, regno, val) \ + { \ + (regs)->addr_reg = set_value(val); \ + wbflush(); \ + } +#define bt431_read_reg_autoi( regs, regno) \ + get_value(((regs)->addr_reg)) + +#define bt431_write_cmap_autoi( regs, regno, val) \ + { \ + (regs)->addr_cmap = (val); \ + wbflush(); \ + } +#define bt431_read_cmap_autoi( regs, regno) \ + ((regs)->addr_cmap) + + +/* + * Cursor ops + */ +bt431_cursor_on(regs) + bt431_padded_regmap_t *regs; +{ + bt431_write_reg( regs, BT431_REG_CMD, + BT431_CMD_CURS_ENABLE|BT431_CMD_OR_CURSORS| + BT431_CMD_4_1_MUX|BT431_CMD_THICK_1); +} + +bt431_cursor_off(regs) + bt431_padded_regmap_t *regs; +{ + bt431_write_reg( regs, BT431_REG_CMD, BT431_CMD_4_1_MUX); +} + +bt431_pos_cursor(regs,x,y) + bt431_padded_regmap_t *regs; + register int x,y; +{ +#define lo(v) ((v)&0xff) +#define hi(v) (((v)&0xf00)>>8) + + /* + * Cx = x + D + H - P + * P = 37 if 1:1, 52 if 4:1, 57 if 5:1 + * D = pixel skew between outdata and external data + * H = pixels between HSYNCH falling and active video + * + * Cy = y + V - 32 + * V = scanlines between HSYNCH falling, two or more + * clocks after VSYNCH falling, and active video + */ + + bt431_write_reg( regs, BT431_REG_CXLO, lo(x + 360)); + /* use autoincr feature */ + bt431_write_reg_autoi( regs, BT431_REG_CXHI, hi(x + 360)); + bt431_write_reg_autoi( regs, BT431_REG_CYLO, lo(y + 36)); + bt431_write_reg_autoi( regs, BT431_REG_CYHI, hi(y + 36)); +} + + +bt431_cursor_sprite( regs, cursor) + bt431_padded_regmap_t *regs; + register unsigned short *cursor; +{ + register int i; + + bt431_select_reg( regs, BT431_REG_CRAM_BASE+0); + for (i = 0; i < 512; i++) + bt431_write_cmap_autoi( regs, BT431_REG_CRAM_BASE+i, *cursor++); +} + +#if 1 +bt431_print_cursor(regs) + bt431_padded_regmap_t *regs; +{ + unsigned short curs[512]; + register int i; + + bt431_select_reg( regs, BT431_REG_CRAM_BASE+0); + for (i = 0; i < 512; i++) { + curs[i] = bt431_read_cmap_autoi( regs, BT431_REG_CRAM_BASE+i); + } + for (i = 0; i < 512; i += 16) + printf("%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n", + curs[i], curs[i+1], curs[i+2], curs[i+3], + curs[i+4], curs[i+5], curs[i+6], curs[i+7], + curs[i+8], curs[i+9], curs[i+10], curs[i+11], + curs[i+12], curs[i+13], curs[i+14], curs[i+15]); +} + +#endif + +/* + * Initialization + */ +unsigned /*char*/short bt431_default_cursor[64*8] = { + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0xffff, 0, 0, 0, 0, 0, 0, 0, + 0, +}; + +bt431_init(regs) + bt431_padded_regmap_t *regs; +{ + register int i; + + /* use 4:1 input mux */ + bt431_write_reg( regs, BT431_REG_CMD, + BT431_CMD_CURS_ENABLE|BT431_CMD_OR_CURSORS| + BT431_CMD_4_1_MUX|BT431_CMD_THICK_1); + + /* home cursor */ + bt431_write_reg_autoi( regs, BT431_REG_CXLO, 0x00); + bt431_write_reg_autoi( regs, BT431_REG_CXHI, 0x00); + bt431_write_reg_autoi( regs, BT431_REG_CYLO, 0x00); + bt431_write_reg_autoi( regs, BT431_REG_CYHI, 0x00); + + /* no crosshair window */ + bt431_write_reg_autoi( regs, BT431_REG_WXLO, 0x00); + bt431_write_reg_autoi( regs, BT431_REG_WXHI, 0x00); + bt431_write_reg_autoi( regs, BT431_REG_WYLO, 0x00); + bt431_write_reg_autoi( regs, BT431_REG_WYHI, 0x00); + bt431_write_reg_autoi( regs, BT431_REG_WWLO, 0x00); + bt431_write_reg_autoi( regs, BT431_REG_WWHI, 0x00); + bt431_write_reg_autoi( regs, BT431_REG_WHLO, 0x00); + bt431_write_reg_autoi( regs, BT431_REG_WHHI, 0x00); + + /* load default cursor */ + bt431_cursor_sprite( regs, bt431_default_cursor); +} diff --git a/chips/bt431.h b/chips/bt431.h new file mode 100644 index 0000000..d98b08d --- /dev/null +++ b/chips/bt431.h @@ -0,0 +1,78 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: bt431.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 8/91 + * + * Defines for the bt431 Cursor chip + */ + + +typedef struct { + volatile unsigned char addr_lo; + volatile unsigned char addr_hi; + volatile unsigned char addr_cmap; + volatile unsigned char addr_reg; +} bt431_regmap_t; + +/* + * Additional registers addressed indirectly + */ + +#define BT431_REG_CMD 0x0000 +#define BT431_REG_CXLO 0x0001 +#define BT431_REG_CXHI 0x0002 +#define BT431_REG_CYLO 0x0003 +#define BT431_REG_CYHI 0x0004 +#define BT431_REG_WXLO 0x0005 +#define BT431_REG_WXHI 0x0006 +#define BT431_REG_WYLO 0x0007 +#define BT431_REG_WYHI 0x0008 +#define BT431_REG_WWLO 0x0009 +#define BT431_REG_WWHI 0x000a +#define BT431_REG_WHLO 0x000b +#define BT431_REG_WHHI 0x000c + +#define BT431_REG_CRAM_BASE 0x0000 +#define BT431_REG_CRAM_END 0x01ff + +/* + * Command register + */ + +#define BT431_CMD_CURS_ENABLE 0x40 +#define BT431_CMD_XHAIR_ENABLE 0x20 +#define BT431_CMD_OR_CURSORS 0x10 +#define BT431_CMD_AND_CURSORS 0x00 +#define BT431_CMD_1_1_MUX 0x00 +#define BT431_CMD_4_1_MUX 0x04 +#define BT431_CMD_5_1_MUX 0x08 +#define BT431_CMD_xxx_MUX 0x0c +#define BT431_CMD_THICK_1 0x00 +#define BT431_CMD_THICK_3 0x01 +#define BT431_CMD_THICK_5 0x02 +#define BT431_CMD_THICK_7 0x03 diff --git a/chips/bt455.c b/chips/bt455.c new file mode 100644 index 0000000..12acecb --- /dev/null +++ b/chips/bt455.c @@ -0,0 +1,222 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: bt455.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 7/91 + * + * Routines for the bt454/bt455 RAMDAC + */ + +#include + +#include +#include + +#ifdef DECSTATION + +typedef struct { + volatile unsigned char addr_cmap; + char pad0[3]; + volatile unsigned char addr_cmap_data; + char pad1[3]; + volatile unsigned char addr_clr; + char pad2[3]; + volatile unsigned char addr_ovly; + char pad3[3]; +} bt455_padded_regmap_t; + +#else /*DECSTATION*/ + +typedef bt455_regmap_t bt455_padded_regmap_t; +#define wbflush() + +#endif /*DECSTATION*/ + + +/* + * Generic register access + */ +#define bt455_select_entry(regs, regno) \ + { \ + (regs)->addr_cmap = (regno)&0x0f; \ + wbflush(); \ + } + + +/* + * Color map + */ +bt455_load_colormap( regs, map) + bt455_padded_regmap_t *regs; + color_map_t *map; +{ + register int i; + + bt455_select_entry(regs, 0); + + for (i = 0; i < 16; i++, map++) { + regs->addr_cmap_data = map->red >> 4; + wbflush(); + regs->addr_cmap_data = map->green >> 4; + wbflush(); + regs->addr_cmap_data = map->blue >> 4; + wbflush(); + } +} + +bt455_load_colormap_entry( regs, entry, map) + register bt455_padded_regmap_t *regs; + register color_map_t *map; +{ + bt455_select_entry(regs, entry); + + regs->addr_cmap_data = map->red >> 4; + wbflush(); + regs->addr_cmap_data = map->green >> 4; + wbflush(); + regs->addr_cmap_data = map->blue >> 4; + wbflush(); +} + +bt455_init_colormap( regs) + bt455_padded_regmap_t *regs; +{ + register int i; + color_map_t m[2]; + + m[0].red = m[0].green = m[0].blue = 0; + m[1].red = m[1].green = m[1].blue = 0xff; + + for (i = 0; i < 16; i++) + bt455_load_colormap_entry(regs, i, &m[0]); + + bt455_load_colormap_entry(regs, 1, &m[1]); + + bt455_cursor_color( regs, &m[0]); +} + +#if 1/*debug*/ +bt455_print_colormap( regs) + bt455_padded_regmap_t *regs; +{ + register int i; + + for (i = 0; i < 16; i++) { + register unsigned char red, green, blue; + + bt455_select_entry(regs, i); + red = regs->addr_cmap_data; + green = regs->addr_cmap_data; + blue = regs->addr_cmap_data; + printf("%x->[x%x x%x x%x]\n", i, + red, green, blue); + + } +} +#endif + +/* + * Video on/off + */ +bt455_video_off(regs, up) + bt455_padded_regmap_t *regs; + user_info_t *up; +{ + color_map_t m; + unsigned char *save; + + /* Yes, this is awful */ + save = (unsigned char *)up->dev_dep_2.gx.colormap; + + bt455_select_entry( regs, 0); + + *save++ = regs->addr_cmap_data; /* entry 0 */ + *save++ = regs->addr_cmap_data; + *save++ = regs->addr_cmap_data; + + *save++ = regs->addr_cmap_data; /* entry 1 */ + *save++ = regs->addr_cmap_data; + *save++ = regs->addr_cmap_data; + + m.red = m.green = m.blue = 0; + bt455_load_colormap_entry(regs, 0, &m); + bt455_load_colormap_entry(regs, 1, &m); +} + +bt455_video_on(regs, up) + bt455_padded_regmap_t *regs; + user_info_t *up; +{ + unsigned char *save; + + /* Like I said.. */ + save = (unsigned char *)up->dev_dep_2.gx.colormap; + + bt455_select_entry( regs, 0); + + regs->addr_cmap_data = *save++; wbflush(); + regs->addr_cmap_data = *save++; wbflush(); + regs->addr_cmap_data = *save++; wbflush(); + + regs->addr_cmap_data = *save++; wbflush(); + regs->addr_cmap_data = *save++; wbflush(); + regs->addr_cmap_data = *save; + +} + +/* + * Cursor 'color' [as used on DEC's board] + */ +bt455_cursor_color( regs, color) + bt455_padded_regmap_t *regs; + color_map_t *color; +{ + register int i; + + /* Bg is the first in color */ + bt455_load_colormap_entry( regs, 8, color); + bt455_load_colormap_entry( regs, 9, color); + + /* Fg is overlay */ + color++; + regs->addr_ovly = color->red >> 4; + wbflush(); + regs->addr_ovly = color->green >> 4; + wbflush(); + regs->addr_ovly = color->blue >> 4; + wbflush(); +} + +/* + * Initialization + */ +bt455_init(regs) + bt455_padded_regmap_t *regs; +{ + /* Nothing really needed */ +} + diff --git a/chips/bt455.h b/chips/bt455.h new file mode 100644 index 0000000..10145ef --- /dev/null +++ b/chips/bt455.h @@ -0,0 +1,43 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: bt455.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 7/91 + * + * Defines for the bt455 RAMDAC + */ + +typedef struct { + volatile unsigned char addr_cmap; + volatile unsigned char addr_cmap_data; + volatile unsigned char addr_clr; + volatile unsigned char addr_ovly; +} bt455_regmap_t; + +/* + * Color Map entries 00-0f are accessed indirectly + */ diff --git a/chips/bt459.c b/chips/bt459.c new file mode 100644 index 0000000..0bee2f1 --- /dev/null +++ b/chips/bt459.c @@ -0,0 +1,384 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: bt459.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Routines for the bt459 RAMDAC + */ + +#include + +#include +#include + +#ifdef DECSTATION + +typedef struct { + volatile unsigned char addr_lo; + char pad0[3]; + volatile unsigned char addr_hi; + char pad1[3]; + volatile unsigned char addr_reg; + char pad2[3]; + volatile unsigned char addr_cmap; + char pad3[3]; +} bt459_ds_padded_regmap_t; +#define bt459_padded_regmap_t bt459_ds_padded_regmap_t + +#define mb() /* no write/read reordering problems */ + +#endif /* DECSTATION */ + +#ifdef FLAMINGO + +/* Sparse space ! */ +typedef struct { + volatile unsigned int addr_lo; + int pad0; + volatile unsigned int addr_hi; + int pad1; + volatile unsigned int addr_reg; + int pad2; + volatile unsigned int addr_cmap; + int pad3; +} bt459_fl_padded_regmap_t; +#define bt459_padded_regmap_t bt459_fl_padded_regmap_t + +#define mb() wbflush() + +#endif /* FLAMINGO */ + + +#ifndef bt459_padded_regmap_t +typedef bt459_regmap_t bt459_padded_regmap_t; +#define wbflush() +#endif + +/* + * Generic register access + */ +#define bt459_select_reg_macro(r,n) \ + (r)->addr_lo = (n); mb(); \ + (r)->addr_hi = (n) >> 8; \ + wbflush(); + +void +bt459_select_reg( + bt459_padded_regmap_t *regs, + int regno) +{ + bt459_select_reg_macro( regs, regno); +} + +void +bt459_write_reg( + bt459_padded_regmap_t *regs, + int regno, + unsigned char val) +{ + bt459_select_reg_macro( regs, regno ); + regs->addr_reg = val; + wbflush(); +} + +unsigned char +bt459_read_reg( + bt459_padded_regmap_t *regs, + int regno) +{ + bt459_select_reg_macro( regs, regno ); + return regs->addr_reg; +} + + +/* + * Color map + */ +bt459_load_colormap_entry( + bt459_padded_regmap_t *regs, + int entry, + color_map_t *map) +{ + bt459_select_reg(regs, entry & 0xff); + + regs->addr_cmap = map->red; + wbflush(); + regs->addr_cmap = map->green; + wbflush(); + regs->addr_cmap = map->blue; + wbflush(); +} + +bt459_init_colormap( + bt459_padded_regmap_t *regs) +{ + register int i; + + bt459_select_reg(regs, 0); + regs->addr_cmap = 0; + wbflush(); + regs->addr_cmap = 0; + wbflush(); + regs->addr_cmap = 0; + wbflush(); + + regs->addr_cmap = 0xff; + wbflush(); + regs->addr_cmap = 0xff; + wbflush(); + regs->addr_cmap = 0xff; + wbflush(); + + bt459_select_reg(regs, 255); + regs->addr_cmap = 0xff; + wbflush(); + regs->addr_cmap = 0xff; + wbflush(); + regs->addr_cmap = 0xff; + wbflush(); + +} + +#if 1/*debug*/ +bt459_print_colormap( + bt459_padded_regmap_t *regs) +{ + register int i; + + for (i = 0; i < 256; i++) { + register unsigned char red, green, blue; + + bt459_select_reg(regs, i); + red = regs->addr_cmap; wbflush(); + green = regs->addr_cmap; wbflush(); + blue = regs->addr_cmap; wbflush(); + printf("%x->[x%x x%x x%x]\n", i, + red, green, blue); + + } +} +#endif + +/* + * Video on/off + * + * It is unfortunate that X11 goes backward with white@0 + * and black@1. So we must stash away the zero-th entry + * and fix it while screen is off. Also must remember + * it, sigh. + */ +struct vstate { + bt459_padded_regmap_t *regs; + unsigned short off; +}; + +bt459_video_off( + struct vstate *vstate, + user_info_t *up) +{ + register bt459_padded_regmap_t *regs = vstate->regs; + unsigned char *save; + + if (vstate->off) + return; + + /* Yes, this is awful */ + save = (unsigned char *)up->dev_dep_2.gx.colormap; + + bt459_select_reg(regs, 0); + *save++ = regs->addr_cmap; + *save++ = regs->addr_cmap; + *save++ = regs->addr_cmap; + + bt459_select_reg(regs, 0); + regs->addr_cmap = 0; + wbflush(); + regs->addr_cmap = 0; + wbflush(); + regs->addr_cmap = 0; + wbflush(); + + bt459_write_reg( regs, BT459_REG_PRM, 0); + bt459_write_reg( regs, BT459_REG_CCR, 0); + + vstate->off = 1; +} + +bt459_video_on( + struct vstate *vstate, + user_info_t *up) +{ + register bt459_padded_regmap_t *regs = vstate->regs; + unsigned char *save; + + if (!vstate->off) + return; + + /* Like I said.. */ + save = (unsigned char *)up->dev_dep_2.gx.colormap; + + bt459_select_reg(regs, 0); + regs->addr_cmap = *save++; + wbflush(); + regs->addr_cmap = *save++; + wbflush(); + regs->addr_cmap = *save++; + wbflush(); + + bt459_write_reg( regs, BT459_REG_PRM, 0xff); + bt459_write_reg( regs, BT459_REG_CCR, 0xc0); + + vstate->off = 0; +} + +/* + * Cursor + */ +bt459_pos_cursor( + bt459_padded_regmap_t *regs, + register int x, + register int y) +{ +#define lo(v) ((v)&0xff) +#define hi(v) (((v)&0xf00)>>8) + bt459_write_reg( regs, BT459_REG_CXLO, lo(x + 219)); + bt459_write_reg( regs, BT459_REG_CXHI, hi(x + 219)); + bt459_write_reg( regs, BT459_REG_CYLO, lo(y + 34)); + bt459_write_reg( regs, BT459_REG_CYHI, hi(y + 34)); +} + + +bt459_cursor_color( + bt459_padded_regmap_t *regs, + color_map_t *color) +{ + register int i; + + bt459_select_reg_macro( regs, BT459_REG_CCOLOR_2); + for (i = 0; i < 2; i++) { + regs->addr_reg = color->red; + wbflush(); + regs->addr_reg = color->green; + wbflush(); + regs->addr_reg = color->blue; + wbflush(); + color++; + } +} + +bt459_cursor_sprite( + bt459_padded_regmap_t *regs, + unsigned char *cursor) +{ + register int i, j; + + /* + * As per specs, must run a check to see if we + * had contention. If so, re-write the cursor. + */ + for (i = 0, j = 0; j < 2; j++) { + /* loop once to write */ + for ( ; i < 1024; i++) + bt459_write_reg( regs, BT459_REG_CRAM_BASE+i, cursor[i]); + + /* loop to check, if fail write again */ + for (i = 0; i < 1024; i++) + if (bt459_read_reg( regs, BT459_REG_CRAM_BASE+i) != cursor[i]) + break; + if (i == 1024) + break;/* all is well now */ + } +} + +/* + * Initialization + */ +bt459_init( + bt459_padded_regmap_t *regs, + volatile char *reset, + int mux) +{ + if (bt459_read_reg(regs, BT459_REG_ID) != 0x4a) + panic("bt459"); + + if (mux == 4) { + /* use 4:1 input mux */ + bt459_write_reg( regs, BT459_REG_CMD0, 0x40); + } else if (mux == 5) { + /* use 5:1 input mux */ + bt459_write_reg( regs, BT459_REG_CMD0, 0xc0); + } /* else donno */ + + *reset = 0; /* force chip reset */ + + /* no zooming, no panning */ + bt459_write_reg( regs, BT459_REG_CMD1, 0x00); + + /* signature test, X-windows cursor, no overlays, SYNC* PLL, + normal RAM select, 7.5 IRE pedestal, do sync */ + bt459_write_reg( regs, BT459_REG_CMD2, 0xc2); + + /* get all pixel bits */ + bt459_write_reg( regs, BT459_REG_PRM, 0xff); + + /* no blinking */ + bt459_write_reg( regs, BT459_REG_PBM, 0x00); + + /* no overlay */ + bt459_write_reg( regs, BT459_REG_ORM, 0x00); + + /* no overlay blink */ + bt459_write_reg( regs, BT459_REG_OBM, 0x00); + + /* no interleave, no underlay */ + bt459_write_reg( regs, BT459_REG_ILV, 0x00); + + /* normal operation, no signature analysis */ + bt459_write_reg( regs, BT459_REG_TEST, 0x00); + + /* no blinking, 1bit cross hair, XOR reg&crosshair, + no crosshair on either plane 0 or 1, + regular cursor on both planes */ + bt459_write_reg( regs, BT459_REG_CCR, 0xc0); + + /* home cursor */ + bt459_write_reg( regs, BT459_REG_CXLO, 0x00); + bt459_write_reg( regs, BT459_REG_CXHI, 0x00); + bt459_write_reg( regs, BT459_REG_CYLO, 0x00); + bt459_write_reg( regs, BT459_REG_CYHI, 0x00); + + /* no crosshair window */ + bt459_write_reg( regs, BT459_REG_WXLO, 0x00); + bt459_write_reg( regs, BT459_REG_WXHI, 0x00); + bt459_write_reg( regs, BT459_REG_WYLO, 0x00); + bt459_write_reg( regs, BT459_REG_WYHI, 0x00); + bt459_write_reg( regs, BT459_REG_WWLO, 0x00); + bt459_write_reg( regs, BT459_REG_WWHI, 0x00); + bt459_write_reg( regs, BT459_REG_WHLO, 0x00); + bt459_write_reg( regs, BT459_REG_WHHI, 0x00); +} diff --git a/chips/bt459.h b/chips/bt459.h new file mode 100644 index 0000000..66012d2 --- /dev/null +++ b/chips/bt459.h @@ -0,0 +1,82 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: bt459.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Defines for the bt459 Cursor/RAMDAC chip + */ + +typedef struct { + volatile unsigned char addr_lo; + volatile unsigned char addr_hi; + volatile unsigned char addr_reg; + volatile unsigned char addr_cmap; +} bt459_regmap_t; + +/* + * Additional registers addressed indirectly + */ + + /* 0000-00ff Color Map entries */ + /* 0100-010f Overlay color regs, unsupp */ +#define BT459_REG_CCOLOR_1 0x0181 /* Cursor color regs */ +#define BT459_REG_CCOLOR_2 0x0182 +#define BT459_REG_CCOLOR_3 0x0183 +#define BT459_REG_ID 0x0200 /* read-only, gives "4a" */ +#define BT459_REG_CMD0 0x0201 +#define BT459_REG_CMD1 0x0202 +#define BT459_REG_CMD2 0x0203 +#define BT459_REG_PRM 0x0204 + /* 0205 reserved */ +#define BT459_REG_PBM 0x0206 + /* 0207 reserved */ +#define BT459_REG_ORM 0x0208 +#define BT459_REG_OBM 0x0209 +#define BT459_REG_ILV 0x020a +#define BT459_REG_TEST 0x020b +#define BT459_REG_RSIG 0x020c +#define BT459_REG_GSIG 0x020d +#define BT459_REG_BSIG 0x020e + /* 020f-02ff reserved */ +#define BT459_REG_CCR 0x0300 +#define BT459_REG_CXLO 0x0301 +#define BT459_REG_CXHI 0x0302 +#define BT459_REG_CYLO 0x0303 +#define BT459_REG_CYHI 0x0304 +#define BT459_REG_WXLO 0x0305 +#define BT459_REG_WXHI 0x0306 +#define BT459_REG_WYLO 0x0307 +#define BT459_REG_WYHI 0x0308 +#define BT459_REG_WWLO 0x0309 +#define BT459_REG_WWHI 0x030a +#define BT459_REG_WHLO 0x030b +#define BT459_REG_WHHI 0x030c + /* 030d-03ff reserved */ +#define BT459_REG_CRAM_BASE 0x0400 +#define BT459_REG_CRAM_END 0x07ff + diff --git a/chips/bt478.c b/chips/bt478.c new file mode 100644 index 0000000..841728f --- /dev/null +++ b/chips/bt478.c @@ -0,0 +1,243 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: bt478.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Routines for the bt478 Cursor/RAMDAC chip + */ + +#include + +#include +#include + +#ifdef DECSTATION + +typedef struct { + volatile unsigned char addr_mapwa; + char pad0[3]; + volatile unsigned char addr_map; + char pad1[3]; + volatile unsigned char addr_mask; + char pad2[3]; + volatile unsigned char addr_mapra; + char pad3[3]; + volatile unsigned char addr_overwa; + char pad4[3]; + volatile unsigned char addr_over; + char pad5[3]; + volatile unsigned char addr_xxxx; + char pad6[3]; + volatile unsigned char addr_overra; + char pad7[3]; +} bt478_padded_regmap_t; + +#else /*DECSTATION*/ + +typedef bt478_regmap_t bt478_padded_regmap_t; +#define wbflush() + +#endif /*DECSTATION*/ + + +/* + * Cursor color + */ +static +bt478_load_cc(bt478, bg, fg) + register bt478_padded_regmap_t *bt478; + unsigned int *bg, *fg; +{ + register int i; + + /* See init function for gotchas */ + + bt478->addr_overwa = 4; + wbflush(); + for (i = 0; i < 3; i++) { + bt478->addr_over = (*bg++) >> 8; + wbflush(); + } + + bt478->addr_overwa = 8; + wbflush(); + bt478->addr_over = 0x00; + wbflush(); + bt478->addr_over = 0x00; + wbflush(); + bt478->addr_over = 0x7f; + wbflush(); + + bt478->addr_overwa = 12; + wbflush(); + for (i = 0; i < 3; i++) { + bt478->addr_over = (*fg++) >> 8; + wbflush(); + } + +} + + +bt478_cursor_color(bt478, color) + bt478_padded_regmap_t *bt478; + cursor_color_t *color; +{ + register int i; + register unsigned int *p; + + /* Do it twice, in case of collisions */ + + bt478_load_cc(bt478, color->Bg_rgb, color->Fg_rgb); + + p = color->Bg_rgb; + for (i = 0; i < 3; i++) { + bt478->addr_over = (*p++) >> 8; + wbflush(); + } + + p = color->Fg_rgb; + for (i = 0; i < 3; i++) { + bt478->addr_over = (*p++) >> 8; + wbflush(); + } + + bt478_load_cc(bt478, color->Bg_rgb, color->Fg_rgb); +} + +/* + * Color map + */ +bt478_load_colormap( regs, map) + bt478_padded_regmap_t *regs; + color_map_t *map; +{ + register int i; + + regs->addr_mapwa = 0; + wbflush(); + for (i = 0; i < 256; i++, map++) { + regs->addr_map = map->red; + wbflush(); + regs->addr_map = map->green; + wbflush(); + regs->addr_map = map->blue; + wbflush(); + } +} + +bt478_load_colormap_entry( regs, entry, map) + bt478_padded_regmap_t *regs; + color_map_t *map; +{ + regs->addr_mapwa = entry & 0xff; + wbflush(); + regs->addr_map = map->red; + wbflush(); + regs->addr_map = map->green; + wbflush(); + regs->addr_map = map->blue; + wbflush(); +} + +/* + * Video on/off (unused) + */ +bt478_video_on(pregs, up) + bt478_padded_regmap_t **pregs; +{ + (*pregs)->addr_mask = 0xff; +} + +bt478_video_off(pregs, up) + bt478_padded_regmap_t **pregs; +{ + (*pregs)->addr_mask = 0; +} + +/* + * Initialization + */ +static +bt478_overlay(regs, plane) + bt478_padded_regmap_t *regs; + unsigned char *plane; +{ + *plane = 0xff; + + /* Overlay planes 0 and 1 are wired zero, overlay plane 2 + is plane "B" of the cursor (second half of it), plane 3 + is plane "A" of the cursor. Soo, we get three colors + for the cursor, at map entries 4, 8 and 12 */ +# define ovv(i,r,g,b) \ + regs->addr_overwa = i; wbflush(); \ + regs->addr_over = r; wbflush(); \ + regs->addr_over = b; wbflush(); \ + regs->addr_over = g; wbflush(); + + ovv(4,0,0,0); ovv(8,0,0,0x7f); ovv(12,0xff,0xff,0xff); + +# undef ovv + + /* enable data input */ + regs->addr_mask = 0xff; +} + +bt478_init_bw_map(regs, plane) + bt478_padded_regmap_t *regs; +{ + register int i; + + /* Set overlay color registers */ + bt478_overlay(regs, plane); + + /* loadup vdac map */ +# define mvv(i,v) { \ + regs->addr_mapwa = i; wbflush(); \ + regs->addr_map = v; wbflush(); \ + regs->addr_map = v; wbflush(); \ + regs->addr_map = v; wbflush();} + + for (i = 0; i < 128; i++) mvv(i,0x00); + for (i = i; i < 256; i++) mvv(i,0xff); + +} + +bt478_init_color_map( regs, plane) + bt478_padded_regmap_t *regs; +{ + register int i; + + bt478_overlay(regs, plane); + + mvv(0,0); + mvv(1,0xff); + mvv(255,0xff); + +# undef mvv +} + diff --git a/chips/bt478.h b/chips/bt478.h new file mode 100644 index 0000000..a60108f --- /dev/null +++ b/chips/bt478.h @@ -0,0 +1,44 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: bt478.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 10/90 + * + * Defines for the bt478 Cursor/RAMDAC chip + */ + +typedef struct { + volatile unsigned char addr_mapwa; + volatile unsigned char addr_map; + volatile unsigned char addr_mask; + volatile unsigned char addr_mapra; + volatile unsigned char addr_overwa; + volatile unsigned char addr_over; + volatile unsigned char addr_xxxx; + volatile unsigned char addr_overra; +} bt478_regmap_t; + diff --git a/chips/build_font.c b/chips/build_font.c new file mode 100644 index 0000000..2542351 --- /dev/null +++ b/chips/build_font.c @@ -0,0 +1,132 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: build_font.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 10/90 + * + * + * Takes a font description file and generates a C source + * appropriate for use as kernel font on mips/vax boxes. + * This basically means encoding and mirroring the bitmaps. + */ + +#include + +main(argc,argv) + char **argv; +{ + int fd; + FILE *fout; + int i, j, k, n, l; + int first, last; + char *fname = "kernel_font.data"; + char buf[16*9]; + int verbose = 0; + + if (argc > 1 && argv[1][0] == '+') + verbose++, argc--, argv++; + + first = 0; + last = 190; /* 8-bit ASCII, offset by 'space' */ + if (argc > 1) { + first = atoi(argv[1]); + last = first + 1; + } + if (argc > 2) + last = atoi(argv[2]) + 1; + if (argc > 3) + fname = argv[3]; + + fd = open(fname, 0, 0); + fout = fopen("kernel_font.c", "w"); + + fprintf(fout, "/* \n\ + * Mach Operating System\n\ + * Copyright (c) 1989 Carnegie-Mellon University\n\ + * All rights reserved. The CMU software License Agreement specifies\n\ + * the terms and conditions for use and redistribution.\n\ + */\n\ +/*\n\ + * THIS FILE WAS GENERATED BY %s FROM %s\n\ + * IF YOU NEED TO, BE SURE YOU EDIT THE REAL THING!\n\ + */\n\ +/*\n\ + * Object:\n\ + * kfont_7x14 EXPORTED array\n\ + *\n\ + * Kernel font for printable ASCII chars\n\ + *\n\ + * The smallest index in this array corresponds to a\n\ + * space. So, we start at 0x20 in the ascii table.\n\ + * Note that glyphs are mirrored (byteorder, I think)\n\ + * the commented bitmap shows how they really look like\n\ + */\n\ +\n\ +unsigned char kfont_7x14[] = {\n", argv[0], fname); + +skip_comments: + read(fd, buf, 1); + if (buf[0] == '#') { + do + read(fd, buf, 1); + while (buf[0] != '\n'); + goto skip_comments; + } + lseek(fd, -1, 1); /* put char back */ + + /* if must skip some */ + for (l = 0; l < first; l++) + read(fd, buf, 2+(9*15)); + + /* scan for real now */ + for (i = first; i < last; i++) { + /* read one full glyph */ + if (read(fd, buf, 2+(9*15)) < 0) + break; + if (verbose) + printf("Character '%c':\n\t", buf[0]); + /* index and char itself in comments */ + fprintf(fout, "/* %3x '%c' */\n", i, 0x20+i); + + /* encode and mirror each one of the 15 scanlines */ + for (n = 0; n < 15; n++) { + unsigned char cc[8], swap = 0; + /* 8 bits per scanline */ + for (k = 2+(n*9), j = 0; j < 8; k++, j++) { + if (verbose) + printf("%c", (buf[k] == '1') ? '@' : ' '); + swap = ((buf[k] - '0') << 7) | (swap >> 1); + cc[j] = buf[k]; + } + fprintf(fout,"\t/* %8s */\t%#2x,\n", cc, (unsigned char)swap); + if (verbose) + printf("\n\t"); + } + } + fprintf(fout, "};\n"); + fclose(fout); +} diff --git a/chips/busses.c b/chips/busses.c new file mode 100644 index 0000000..dd64f48 --- /dev/null +++ b/chips/busses.c @@ -0,0 +1,230 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: busses.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 4/90 + * + * Generic autoconfiguration functions, + * usable to probe and attach devices + * on any bus that suits the generic bus + * structure, such as VME, TURBOChannel, + * and all the VAX busses. + * + */ + +#include +#include +#include + + + + +/* + * configure_bus_master + * + * Given the name of a bus_ctlr, look it up in the + * init table. If found, probe it. If there can be + * slaves attached, walk the device's init table + * for those that might be attached to this controller. + * Call the 'slave' function on each one to see if + * ok, then the 'attach' one. + * + * Returns 0 if the controller is not there. + * + */ +boolean_t configure_bus_master( + char *name, + vm_offset_t virt, + vm_offset_t phys, + int adpt_no, + char *bus_name) +{ + register struct bus_device *device; + register struct bus_ctlr *master; + register struct bus_driver *driver; + + int found = 0; + + /* + * Match the name in the table, then pick the entry that has the + * right adaptor number, or one that has it wildcarded. Entries + * already allocated are marked alive, skip them. + */ + for (master = bus_master_init; master->driver; master++) { + if (master->alive) + continue; + if (((master->adaptor == adpt_no) || (master->adaptor == '?')) && + (strcmp(master->name, name) == 0)) { + found = 1; + break; + } + } + + if (!found) + return FALSE; + + /* + * Found a match, probe it + */ + driver = master->driver; + if ((*driver->probe) (virt, master) == 0) + return FALSE; + + master->alive = 1; + master->adaptor = adpt_no; + + /* + * Remember which controller this device is attached to + */ + driver->minfo[master->unit] = master; + + printf("%s%d: at %s%d\n", master->name, master->unit, bus_name, adpt_no); + + /* + * Now walk all devices to check those that might be attached to this + * controller. We match the unallocated ones that have the right + * controller number, or that have a widcarded controller number. + */ + for (device = bus_device_init; device->driver; device++) { + int ctlr; + if (device->alive || device->driver != driver || + (device->adaptor != '?' && device->adaptor != adpt_no)) + continue; + ctlr = device->ctlr; + if (ctlr == '?') device->ctlr = master->unit; + /* + * A matching entry. See if the slave-probing routine is + * happy. + */ + if ((device->ctlr != master->unit) || + ((*driver->slave) (device, virt) == 0)) { + device->ctlr = ctlr; + continue; + } + + device->alive = 1; + device->adaptor = adpt_no; + device->ctlr = master->unit; + + /* + * Save a backpointer to the controller + */ + device->mi = master; + + /* + * ..and to the device + */ + driver->dinfo[device->unit] = device; + + if (device->slave >= 0) + printf(" %s%d: at %s%d slave %d", + device->name, device->unit, + driver->mname, master->unit, device->slave); + else + printf(" %s%d: at %s%d", + device->name, device->unit, + driver->mname, master->unit); + + /* + * Now attach this slave + */ + (*driver->attach) (device); + printf("\n"); + } + return TRUE; +} + +/* + * configure_bus_device + * + * Given the name of a bus_device, look it up in the + * init table. If found, probe it. If it is present, + * call the driver's 'attach' function. + * + * Returns 0 if the device is not there. + * + */ +boolean_t configure_bus_device( + char *name, + vm_offset_t virt, + vm_offset_t phys, + int adpt_no, + char *bus_name) +{ + register struct bus_device *device; + register struct bus_driver *driver; + + int found = 0; + + /* + * Walk all devices to find one with the right name + * and adaptor number (or wildcard). The entry should + * be unallocated, and also the slave number should + * be wildcarded. + */ + for (device = bus_device_init; device->driver; device++) { + if (device->alive) + continue; + if (((device->adaptor == adpt_no) || (device->adaptor == '?')) && + (device->slave == -1) && + ((!device->phys_address) || + ((device->phys_address == phys) && (device->address == virt))) && + (strcmp(device->name, name) == 0)) { + found = 1; + break; + } + } + + if (!found) + return FALSE; + + /* + * Found an entry, probe the device + */ + driver = device->driver; + if ((*driver->probe) (virt, (struct bus_ctlr *)device) == 0) + return FALSE; + + device->alive = 1; + device->adaptor = adpt_no; + + printf("%s%d: at %s%d", device->name, device->unit, bus_name, adpt_no); + + /* + * Remember which driver this device is attached to + */ + driver->dinfo[device->unit] = device; + + /* + * Attach the device + */ + (*driver->attach) (device); + printf("\n"); + + return TRUE; +} + diff --git a/chips/busses.h b/chips/busses.h new file mode 100644 index 0000000..56a9ed3 --- /dev/null +++ b/chips/busses.h @@ -0,0 +1,154 @@ +/* + * Mach Operating System + * Copyright (c) 1994-1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: busses.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 4/90 + * + * Structures used by configuration routines to + * explore a given bus structure. + */ + +#ifndef _CHIPS_BUSSES_H_ +#define _CHIPS_BUSSES_H_ + +#include +#include + +/* + * + * This is mildly modeled after the Unibus on Vaxen, + * one of the most complicated bus structures. + * Therefore, let's hope this can be done once and for all. + * + * At the bottom level there is a "bus_device", which + * might exist in isolation (e.g. a clock on the CPU + * board) or be a standard component of an architecture + * (e.g. the bitmap display on some workstations). + * + * Disk devices and communication lines support multiple + * units, hence the "bus_driver" structure which is more + * flexible and allows probing and dynamic configuration + * of the number and type of attached devices. + * + * At the top level there is a "bus_ctlr" structure, used + * in systems where the I/O bus(ses) are separate from + * the memory bus(ses), and/or when memory boards can be + * added to the main bus (and they must be config-ed + * and/or can interrupt the processor for ECC errors). + * + * The autoconfiguration process typically starts at + * the top level and walks down tables that are + * defined either in a generic file or are specially + * created by config. + */ + +/* + * Per-controller structure. + */ +struct bus_ctlr { + struct bus_driver *driver; /* myself, as a device */ + char *name; /* readability */ + int unit; /* index in driver */ + int (*intr)(); /* interrupt handler(s) */ + vm_offset_t address; /* device virtual address */ + int am; /* address modifier */ + vm_offset_t phys_address;/* device phys address */ + char adaptor; /* slot where found */ + char alive; /* probed successfully */ + char flags; /* any special conditions */ + vm_offset_t sysdep; /* On some systems, queue of + * operations in-progress */ + natural_t sysdep1; /* System dependent */ +}; + + +/* + * Per-``device'' structure + */ +struct bus_device { + struct bus_driver *driver; /* autoconf info */ + char *name; /* my name */ + int unit; + int (*intr)(); + vm_offset_t address; /* device address */ + int am; /* address modifier */ + vm_offset_t phys_address;/* device phys address */ + char adaptor; + char alive; + char ctlr; + char slave; + int flags; + struct bus_ctlr *mi; /* backpointer to controller */ + struct bus_device *next; /* optional chaining */ + vm_offset_t sysdep; /* System dependent */ + natural_t sysdep1; /* System dependent */ +}; + +/* + * General flag definitions + */ +#define BUS_INTR_B4_PROBE 0x01 /* enable interrupts before probe */ +#define BUS_INTR_DISABLED 0x02 /* ignore all interrupts */ +#define BUS_CTLR 0x04 /* descriptor for a bus adaptor */ +#define BUS_XCLU 0x80 /* want exclusive use of bdp's */ + +/* + * Per-driver structure. + * + * Each bus driver defines entries for a set of routines + * that are used at boot time by the configuration program. + */ +struct bus_driver { + int (*probe)( /* see if the driver is there */ + /* vm_offset_t address, + struct bus_ctlr * */ ); + int (*slave)( /* see if any slave is there */ + /* struct bus_device *, + vm_offset_t */ ); + void (*attach)( /* setup driver after probe */ + /* struct bus_device * */); + int (*dgo)(); /* start transfer */ + vm_offset_t *addr; /* device csr addresses */ + char *dname; /* name of a device */ + struct bus_device **dinfo; /* backpointers to init structs */ + char *mname; /* name of a controller */ + struct bus_ctlr **minfo; /* backpointers to init structs */ + int flags; +}; + +#ifdef KERNEL +extern struct bus_ctlr bus_master_init[]; +extern struct bus_device bus_device_init[]; + +extern boolean_t configure_bus_master(char *, vm_offset_t, vm_offset_t, + int, char * ); +extern boolean_t configure_bus_device(char *, vm_offset_t, vm_offset_t, + int, char * ); +#endif /* KERNEL */ + + +#endif /* _CHIPS_BUSSES_H_ */ diff --git a/chips/cfb_hdw.c b/chips/cfb_hdw.c new file mode 100644 index 0000000..78764aa --- /dev/null +++ b/chips/cfb_hdw.c @@ -0,0 +1,188 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: cfb_hdw.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Driver for the 3max Color Frame Buffer Display, + * hardware-level operations. + */ + +#include +#if (NCFB > 0) + +#include + +#include +#include +#include +#include +#include + +typedef pm_softc_t cfb_softc_t; + +#ifdef DECSTATION +#include +#include +#endif + +#ifdef FLAMINGO +#include /* XXX fixme */ +#include +#endif + +/* + * Definition of the driver for the auto-configuration program. + */ + +int cfb_probe(), cfb_intr(); +static void cfb_attach(); + +vm_offset_t cfb_std[NCFB] = { 0 }; +struct bus_device *cfb_info[NCFB]; +struct bus_driver cfb_driver = + { cfb_probe, 0, cfb_attach, 0, cfb_std, "cfb", cfb_info, + 0, 0, BUS_INTR_DISABLED}; + +/* + * Probe/Attach functions + */ + +cfb_probe( /* reg, ui */) +{ + static probed_once = 0; + + /* + * Probing was really done sweeping the TC long ago + */ + if (tc_probe("cfb") == 0) + return 0; + if (probed_once++ > 1) + printf("[mappable] "); + return 1; +} + +static void +cfb_attach(ui) + struct bus_device *ui; +{ + /* ... */ + printf(": color display"); +} + + +/* + * Interrupt routine + */ + +cfb_intr(unit,spllevel) + spl_t spllevel; +{ + register volatile char *ack; + + /* acknowledge interrupt */ + ack = (volatile char *) cfb_info[unit]->address + CFB_OFFSET_IREQ; + *ack = 0; + +#ifdef mips + splx(spllevel); +#endif + lk201_led(unit); +} + +cfb_vretrace(cfb, on) + cfb_softc_t *cfb; +{ + int i; + + for (i = 0; i < NCFB; i++) + if (cfb_info[i]->address == (vm_offset_t)cfb->framebuffer) + break; + if (i == NCFB) return; + + (*tc_enable_interrupt)(cfb_info[i]->adaptor, on, 0); +} + +/* + * Boot time initialization: must make device + * usable as console asap. + */ +extern int + cfb_soft_reset(), cfb_set_status(), + bt459_pos_cursor(), bt459_video_on(), + bt459_video_off(), cfb_vretrace(), + pm_get_status(), pm_char_paint(), + pm_insert_line(), pm_remove_line(), + pm_clear_bitmap(), pm_map_page(); + +static struct screen_switch cfb_sw = { + screen_noop, /* graphic_open */ + cfb_soft_reset, /* graphic_close */ + cfb_set_status, /* set_status */ + pm_get_status, /* get_status */ + pm_char_paint, /* char_paint */ + bt459_pos_cursor, /* pos_cursor */ + pm_insert_line, /* insert_line */ + pm_remove_line, /* remove_line */ + pm_clear_bitmap, /* clear_bitmap */ + bt459_video_on, /* video_on */ + bt459_video_off, /* video_off */ + cfb_vretrace, /* intr_enable */ + pm_map_page /* map_page */ +}; + +cfb_cold_init(unit, up) + user_info_t *up; +{ + cfb_softc_t *cfb; + screen_softc_t sc = screen(unit); + int base = tc_probe("cfb"); + + bcopy(&cfb_sw, &sc->sw, sizeof(sc->sw)); + sc->flags |= COLOR_SCREEN; + sc->frame_scanline_width = 1024; + sc->frame_height = 1024; + sc->frame_visible_width = 1024; + sc->frame_visible_height = 864; + + pm_init_screen_params(sc,up); + (void) screen_up(unit, up); + + cfb = pm_alloc(unit, base + CFB_OFFSET_BT459, base + CFB_OFFSET_VRAM, -1); + + screen_default_colors(up); + + cfb_soft_reset(sc); + + /* + * Clearing the screen at boot saves from scrolling + * much, and speeds up booting quite a bit. + */ + screen_blitc( unit, 'C'-'@');/* clear screen */ +} + +#endif (NCFB > 0) diff --git a/chips/cfb_misc.c b/chips/cfb_misc.c new file mode 100644 index 0000000..2bda86b --- /dev/null +++ b/chips/cfb_misc.c @@ -0,0 +1,249 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: cfb_misc.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Driver for the PMAG-BA simple color framebuffer + * + */ + +#include +#include /* shares code */ +#if ((NCFB > 0) || (NSFB > 0)) +#include + +/* + * NOTE: This driver relies heavily on the pm one. + */ + +#include +#include +#include +typedef pm_softc_t cfb_softc_t; + +#include +#define bt459 cursor_registers + +#ifdef DECSTATION +#include +#endif + +#ifdef FLAMINGO +#include /* XXX fixme */ +#endif + +/* + * Initialize color map, for kernel use + */ +cfb_init_colormap( + screen_softc_t sc) +{ + cfb_softc_t *cfb = (cfb_softc_t*)sc->hw_state; + user_info_t *up = sc->up; + color_map_t Bg_Fg[2]; + register int i; + + bt459_init_colormap( cfb->bt459 ); + + /* init bg/fg colors */ + for (i = 0; i < 3; i++) { + up->dev_dep_2.pm.Bg_color[i] = 0x00; + up->dev_dep_2.pm.Fg_color[i] = 0xff; + } + + Bg_Fg[0].red = Bg_Fg[0].green = Bg_Fg[0].blue = 0x00; + Bg_Fg[1].red = Bg_Fg[1].green = Bg_Fg[1].blue = 0xff; + bt459_cursor_color( cfb->bt459, Bg_Fg); +} + +/* + * Large viz small cursor + */ +cfb_small_cursor_to_large( + user_info_t *up, + cursor_sprite_t cursor) +{ + unsigned short new_cursor[32]; + unsigned char *curbytes, fg, fbg; + int i, j, k; + char *sprite; + + /* Clear out old cursor */ + bzero( up->dev_dep_2.pm.cursor_sprite, + sizeof(up->dev_dep_2.pm.cursor_sprite)); + + /* small cursor is 32x2 bytes, fg first */ + curbytes = (unsigned char *) cursor; + + /* use the upper left corner of the large cursor + * as a 64x1 cursor, fg&bg alternated */ + for (i = 0; i < 32; i++) { + fg = curbytes[i]; + fbg = fg | curbytes[i + 32]; + new_cursor[i] = 0; + for (j = 0, k = 15; j < 8; j++, k -= 2) { + new_cursor[i] |= ((fbg >> j) & 0x1) << (k); + new_cursor[i] |= ((fg >> j) & 0x1) << (k - 1); + } + } + + /* Now stick it in the proper place */ + + curbytes = (unsigned char *) new_cursor; + sprite = up->dev_dep_2.pm.cursor_sprite; + for (i = 0; i < 64; i += 4) { + /* butterfly as we go */ + *sprite++ = curbytes[i + 1]; + *sprite++ = curbytes[i + 0]; + *sprite++ = curbytes[i + 3]; + *sprite++ = curbytes[i + 2]; + sprite += 12; /* skip rest of the line */ + } +} + + +/* + * Device-specific set status + */ +cfb_set_status( + screen_softc_t sc, + dev_flavor_t flavor, + dev_status_t status, + natural_t status_count) +{ + cfb_softc_t *cfb = (cfb_softc_t*) sc->hw_state; + + switch (flavor) { + + case SCREEN_ADJ_MAPPED_INFO: + return pm_set_status(sc, flavor, status, status_count); + + case SCREEN_LOAD_CURSOR: + + if (status_count < sizeof(cursor_sprite_t)/sizeof(int)) + return D_INVALID_SIZE; +/* cfb_small_cursor_to_large(sc->up, (cursor_sprite_t) status);*/ + cfb_small_cursor_to_large(sc->up, (unsigned short *) status); + + /* Fall through */ + + case SCREEN_LOAD_CURSOR_LONG: /* 3max only */ + + sc->flags |= SCREEN_BEING_UPDATED; + bt459_cursor_sprite(cfb->bt459, sc->up->dev_dep_2.pm.cursor_sprite); + sc->flags &= ~SCREEN_BEING_UPDATED; + + break; + + case SCREEN_SET_CURSOR_COLOR: { + color_map_t c[2]; + register cursor_color_t *cc = (cursor_color_t*) status; + + c[0].red = cc->Bg_rgb[0]; + c[0].green = cc->Bg_rgb[1]; + c[0].blue = cc->Bg_rgb[2]; + c[1].red = cc->Fg_rgb[0]; + c[1].green = cc->Fg_rgb[1]; + c[1].blue = cc->Fg_rgb[2]; + + sc->flags |= SCREEN_BEING_UPDATED; + bt459_cursor_color (cfb->bt459, c ); + sc->flags &= ~SCREEN_BEING_UPDATED; + + break; + } + + case SCREEN_SET_CMAP_ENTRY: { + color_map_entry_t *e = (color_map_entry_t*) status; + + if (e->index < 256) { + sc->flags |= SCREEN_BEING_UPDATED; + bt459_load_colormap_entry( cfb->bt459, e->index, &e->value); + sc->flags &= ~SCREEN_BEING_UPDATED; + } + break; + } + + default: + return D_INVALID_OPERATION; + } + return D_SUCCESS; +} + +#if (NCFB > 0) +/* + * Hardware initialization + */ +cfb_init_screen( + cfb_softc_t *cfb) +{ + bt459_init( cfb->bt459, + cfb->bt459 + (CFB_OFFSET_RESET - CFB_OFFSET_BT459), + 4 /* 4:1 MUX */); +} + +/* + * Do what's needed when X exits + */ +cfb_soft_reset( + screen_softc_t sc) +{ + cfb_softc_t *cfb = (cfb_softc_t*) sc->hw_state; + user_info_t *up = sc->up; + extern cursor_sprite_t dc503_default_cursor; + + /* + * Restore params in mapped structure + */ + pm_init_screen_params(sc,up); + up->row = up->max_row - 1; + + up->dev_dep_2.pm.x26 = 2; /* you do not want to know */ + up->dev_dep_1.pm.x18 = (short*)2; + + /* + * Restore RAMDAC chip to default state + */ + cfb_init_screen(cfb); + + /* + * Load kernel's cursor sprite: just use the same pmax one + */ + cfb_small_cursor_to_large(up, dc503_default_cursor); + bt459_cursor_sprite(cfb->bt459, up->dev_dep_2.pm.cursor_sprite); + + /* + * Color map and cursor color + */ + cfb_init_colormap(sc); +} +#endif /* NCFB > 0 */ + + + +#endif /* (NCFB > 0) || (NSFB > 0) */ diff --git a/chips/dc503.c b/chips/dc503.c new file mode 100644 index 0000000..8bfab50 --- /dev/null +++ b/chips/dc503.c @@ -0,0 +1,189 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: dc503.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Routines for the DEC DC503 Programmable Cursor Chip + */ +#include + +#include +#include + + +#if defined(DECSTATION) || defined(VAXSTATION) + +typedef struct { + volatile unsigned short pcc_cmdr; /* all regs are wo */ + short pad0; + volatile unsigned short pcc_xpos; + short pad1; + volatile unsigned short pcc_ypos; + short pad2; + volatile unsigned short pcc_xmin1; + short pad3; + volatile unsigned short pcc_xmax1; + short pad4; + volatile unsigned short pcc_ymin1; + short pad5; + volatile unsigned short pcc_ymax1; + short pad6[9]; + volatile unsigned short pcc_xmin2; + short pad7; + volatile unsigned short pcc_xmax2; + short pad8; + volatile unsigned short pcc_ymin2; + short pad9; + volatile unsigned short pcc_ymax2; + short pad10; + volatile unsigned short pcc_memory; + short pad11; +} dc503_padded_regmap_t; + +#else + +typedef dc503_regmap_t dc503_padded_regmap_t; + +#endif + +#ifdef VAXSTATION +#define X_CSHIFT 216 +#define Y_CSHIFT 34 +#define wbflush() +#define PCC_STATE (DC503_CMD_ENPA | DC503_CMD_ENPB | DC503_CMD_HSHI) +#endif /*VAXSTATION*/ + +/* defaults, for the innocents */ + +#ifndef X_CSHIFT +#define X_CSHIFT 212 +#define Y_CSHIFT 34 +#define PCC_STATE (DC503_CMD_ENPA | DC503_CMD_ENPB) +#endif + +/* + * Cursor + */ +dc503_pos_cursor( regs, x, y) + dc503_padded_regmap_t *regs; +{ + regs->pcc_xpos = x + X_CSHIFT; + regs->pcc_ypos = y + Y_CSHIFT; + wbflush(); +} + +dc503_load_cursor( pm, cursor) + pm_softc_t *pm; + unsigned short *cursor; +{ + dc503_padded_regmap_t *regs; + register int i; + + regs = (dc503_padded_regmap_t*)pm->cursor_registers; + + pm->cursor_state |= DC503_CMD_LODSA; + regs->pcc_cmdr = pm->cursor_state; + wbflush(); + for (i = 0; i < 32; i++) { + regs->pcc_memory = *cursor++; + wbflush(); + } + pm->cursor_state &= ~DC503_CMD_LODSA; + regs->pcc_cmdr = pm->cursor_state; +} + + +unsigned short dc503_default_cursor[16+16] = { +/* Plane A */ + 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, + 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, +/* Plane B */ + 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, + 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff, 0x00ff +}; + +/* + * Vert retrace interrupt + */ +dc503_vretrace( pm, on) + pm_softc_t *pm; +{ + if (on) + pm->cursor_state |= DC503_CMD_ENRG2; + else + pm->cursor_state &= ~DC503_CMD_ENRG2; + ((dc503_padded_regmap_t*)pm->cursor_registers)->pcc_cmdr = pm->cursor_state; +} + +/* + * Video on/off + */ +dc503_video_on( pm, up) + pm_softc_t *pm; +{ + pm->cursor_state = DC503_CMD_ENPA | (pm->cursor_state & ~DC503_CMD_FOPB); + ((dc503_padded_regmap_t*)pm->cursor_registers)->pcc_cmdr = pm->cursor_state; +} + +dc503_video_off( pm, up) + pm_softc_t *pm; +{ + pm->cursor_state = DC503_CMD_FOPB | (pm->cursor_state & ~DC503_CMD_ENPA); + ((dc503_padded_regmap_t*)pm->cursor_registers)->pcc_cmdr = pm->cursor_state; +} + + +/* + * Initialization + */ +dc503_init( pm ) + pm_softc_t *pm; +{ + dc503_padded_regmap_t *regs; + + regs = (dc503_padded_regmap_t*)pm->cursor_registers; + + dc503_load_cursor( pm, dc503_default_cursor); + dc503_pos_cursor( regs, 0, 0); /* XXX off screen */ + + regs->pcc_xmin1 = 0; /* test only */ + regs->pcc_xmax1 = 0; + regs->pcc_ymin1 = 0; + regs->pcc_ymax1 = 0; + + regs->pcc_xmin2 = 212; /* vert retrace detector */ + regs->pcc_xmax2 = 212+1023; + regs->pcc_ymin2 = 34+863; + regs->pcc_ymax2 = 34+863; + +#if 0 + regs->pcc_cmdr = DC503_CMD_FOPB | DC503_CMD_VBHI;/* reset */ +#endif + pm->cursor_state = PCC_STATE; + regs->pcc_cmdr = pm->cursor_state; +} diff --git a/chips/dc503.h b/chips/dc503.h new file mode 100644 index 0000000..e3c330c --- /dev/null +++ b/chips/dc503.h @@ -0,0 +1,69 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: dc503.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Defines for the DEC DC503 Programmable Cursor + */ + +typedef struct { + volatile unsigned short pcc_cmdr; /* all regs are wo */ + volatile unsigned short pcc_xpos; + volatile unsigned short pcc_ypos; + volatile unsigned short pcc_xmin1; + volatile unsigned short pcc_xmax1; + volatile unsigned short pcc_ymin1; + volatile unsigned short pcc_ymax1; + volatile unsigned short pcc_xmin2; + volatile unsigned short pcc_xmax2; + volatile unsigned short pcc_ymin2; + volatile unsigned short pcc_ymax2; + volatile unsigned short pcc_memory; +} dc503_regmap_t; + +/* + * Command register bits + */ + +#define DC503_CMD_TEST 0x8000 /* cursor test flip-flop */ +#define DC503_CMD_HSHI 0x4000 /* Hor sync polarity */ +#define DC503_CMD_VBHI 0x2000 /* Ver blank polarity */ +#define DC503_CMD_LODSA 0x1000 /* load sprite array */ +#define DC503_CMD_FORG2 0x0800 /* force detector2 to one */ +#define DC503_CMD_ENRG2 0x0400 /* enable detector2 */ +#define DC503_CMD_FORG1 0x0200 /* force detector1 to one */ +#define DC503_CMD_ENRG1 0x0100 /* enable detector1 */ +#define DC503_CMD_XHWID 0x0080 /* hair cursor (double) width */ +#define DC503_CMD_XHCL1 0x0040 /* hair clip region */ +#define DC503_CMD_XHCLP 0x0020 /* clip hair inside region */ +#define DC503_CMD_XHAIR 0x0010 /* enable hair cursor */ +#define DC503_CMD_FOPB 0x0008 /* force curs plane B to one */ +#define DC503_CMD_ENPB 0x0004 /* enable curs plane B */ +#define DC503_CMD_FOPA 0x0002 /* force curs plane A to one */ +#define DC503_CMD_ENPA 0x0001 /* enable curs plane A */ + diff --git a/chips/dtop.h b/chips/dtop.h new file mode 100644 index 0000000..e37ba04 --- /dev/null +++ b/chips/dtop.h @@ -0,0 +1,241 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: dtop.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 1/92 + * + * Definitions for the Desktop serial bus (i2c aka ACCESS). + */ + +#ifndef _DTOP_H_ +#define _DTOP_H_ + +#define DTOP_MAX_DEVICES 14 +#define DTOP_MAX_MSG_SIZE 36 /* 3 hdr + 32 data + 1 checksum */ + +typedef struct { + + unsigned char dest_address; /* low bit is zero */ + unsigned char src_address; /* ditto */ + union { + struct { + unsigned char len : 5, /* message byte len */ + sub : 2, /* sub-address */ + P : 1; /* Control(1)/Data(0) marker */ + } val; + unsigned char bits; /* quick check */ + } code; + + /* varzise, checksum byte at end */ + unsigned char body[DTOP_MAX_MSG_SIZE-3]; + +} dtop_message, *dtop_message_t; + +/* + * Standard addresses + */ + +#define DTOP_ADDR_HOST 0x50 /* address for the (only) host */ +#define DTOP_ADDR_DEFAULT 0x6e /* power-up default address */ +#define DTOP_ADDR_FIRST 0x52 /* first assignable address */ +#define DTOP_ADDR_LAST 0x6c /* last, inclusive */ + +#define DTOP_ADDR_KBD 0x6c /* as used by DEC */ +#define DTOP_ADDR_MOUSE 0x6a + +/* + * Standard messages + */ + +/* from host to devices */ + +#define DTOP_MSG_RESET 0xf0 /* preceeded by 0x81: P,len 1 */ + +#define DTOP_MSG_ID_REQUEST 0xf1 /* preceeded by 0x81: P,len 1 */ + +#define DTOP_MSG_ASSIGN_ADDRESS 0xf2 /* preceeded by 0x9e: P,len 30 */ + /* followed by a dtop_id_reply_t */ + /* and by the new_IC_address */ + +#define DTOP_MSG_CAP_REQUEST 0xf3 /* preceeded by 0x83: P,len 3 */ + /* followed by a 16 bit u_offset */ + +#define DTOP_MSG_APPL_TEST 0xb1 /* preceed by P, sub, len 1 */ + +/* from devices to host */ + +#define DTOP_MSG_ATTENTION 0xe0 /* preceeded by P, len */ +# define DTOP_ATN_OK_STATUS 0x00 /* anything else bad */ + /* followed by 0-30 bytes */ + +#define DTOP_MSG_ID_REPLY 0xe1 /* preceeded by P,len (29..32) */ + +typedef struct { + unsigned char module_revision[8]; /* ascii, blank padded */ + unsigned char vendor_name[8]; + unsigned char module_name[8]; + int device_number; /* 32 bits cpl-2 */ + /* 0-3 optional bytes follow, ignore */ +} dtop_id_reply_t; + +#define DTOP_MSG_CAP_REPLY 0xe3 /* preceeded by P,len (3..32) */ + /* followed by 16 bit u_offset */ + /* followed by data */ + +#define DTOP_MSG_APPL_SIGNAL 0xa0 /* application level signal */ +# define DTOP_SIG_ATTENTION 0x00 +# define DTOP_SIG_RESET 0x01 +# define DTOP_SIG_HALT 0x02 + +#define DTOP_MSG_APPL_TREPLY 0xa1 /* followed by status (0-->ok) */ + /* and 0..30 bytes of result data */ + +/* reserved message codes (testing, manifacturing) */ + +#define DTOP_MSG_RES0 0xc0 +#define DTOP_MSG_RES1 0xc1 +#define DTOP_MSG_RES2 0xc2 +#define DTOP_MSG_RES3 0xc3 + + +/* + * Device specific definitions: Keyboard + */ + +/* from host to keyboard */ + +#define DTOP_KMSG_CLICK 0x01 /* preceeded by P, sub len 2 */ +# define DTOP_CLICK_VOLUME_MAX 0x7 /* followed by one byte */ + +#define DTOP_KMSG_BELL 0x02 /* preceeded by P, sub len 2 */ + /* same as above */ + +#define DTOP_KMSG_LED 0x03 /* preceeded by P, sub len 2 */ + /* four lower bits turn leds on */ + +#define DTOP_KMSG_POLL 0x04 /* preceeded by P, sub len 1 */ + +/* keyboard sends up to 11 codes in a data message, distinguished values: */ +#define DTOP_KBD_EMPTY 0x00 +#define DTOP_KBD_OUT_ERR 0x01 +#define DTOP_KBD_IN_ERR 0x02 + +#define DTOP_KBD_KEY_MIN 0x08 +#define DTOP_KBD_KEY_MAX 0xff + +/* powerup status values: 0 ok, else.. */ +#define DTOP_KBD_ROM_FAIL 0x01 +#define DTOP_KBD_RAM_FAIL 0x02 +#define DTOP_KBD_KEY_DOWN 0x03 + + +/* + * Device specific definitions: Locators (mouse) + */ + +/* locator sends this type of report data */ + +typedef struct { + unsigned short buttons; /* 1->pressed */ + short x; + short y; + short z; + /* possibly 3 more dimensions for gloves */ +} dtop_locator_msg_t; + +#define DTOP_LMSG_SET_RATE 0x01 /* preceeded by P,sub, len 2 */ + /* followed by sampling interval, + from 8 to 25 msecs (0->polled */ + +#define DTOP_LMSG_POLL 0x02 /* preceeded by P,sub, len 1 */ + +/* Powerup codes same as keyboard */ + + +/* + * Implementation specific definitions + */ + +typedef union { + + dtop_message unknown_report; + + struct { + char last_codes_count; + unsigned char last_codes[11]; /* max as per specs */ + unsigned int last_msec; /* autorepeat state */ + unsigned short poll_frequency; + unsigned char k_ar_state; +# define K_AR_IDLE 0 /* quiescent, no polling */ +# define K_AR_OFF 4 /* turn off polling pls */ +# define K_AR_ACTIVE 2 /* polling, no autos yet */ +# define K_AR_TRIGGER 1 /* sent one autorepeat */ + unsigned char bell_volume; + unsigned char led_status; + } keyboard; + + struct { + unsigned char type : 7, /* DEV_MOUSE, DEV_TABLET, .. */ + relative : 1; + unsigned char n_coords; + unsigned short prev_buttons; +# define L_BUTTON_MAX 16 + unsigned char button_code[L_BUTTON_MAX]; +# define L_COORD_MAX 6 + unsigned int coordinate[L_COORD_MAX]; /* max 6D */ + } locator; + + /* add more as they come along */ + +} dtop_device, *dtop_device_t; + +/* All handler functions should have this interface */ +extern int + dtop_null_device_handler( + dtop_device_t dev, + dtop_message_t msg, + int event, + unsigned char outc), + dtop_locator_handler( + dtop_device_t dev, + dtop_message_t msg, + int event, + unsigned char outc), + dtop_keyboard_handler( + dtop_device_t dev, + dtop_message_t msg, + int event, + unsigned char outc); + + +#define DTOP_EVENT_RECEIVE_PACKET 1 +#define DTOP_EVENT_BAD_PACKET 2 +#define DTOP_EVENT_PUTC 4 +#define DTOP_EVENT_POLL 8 + + +#endif /* _DTOP_H_ */ diff --git a/chips/dtop_handlers.c b/chips/dtop_handlers.c new file mode 100644 index 0000000..7a83ea2 --- /dev/null +++ b/chips/dtop_handlers.c @@ -0,0 +1,441 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: dtop_handlers.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 1/92 + * + * Handler functions for devices attached to the DESKTOP bus. + */ + +#include +#if NDTOP > 0 + +#include + +#include /* spl definitions */ +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +/* + * Default handler function + */ +int +dtop_null_device_handler( + dtop_device_t dev, + dtop_message_t msg, + int event, + unsigned char outc) +{ + /* See if the message was to the default address (powerup) */ + + /* Uhmm, donno how to handle this. Drop it */ + if (event == DTOP_EVENT_RECEIVE_PACKET) + dev->unknown_report = *msg; + return 0; +} + +/* + * Handler for locator devices (mice) + */ +int +dtop_locator_handler( + dtop_device_t dev, + dtop_message_t msg, + int event, + unsigned char outc) +{ + register unsigned short buttons; + register short coord; +#if BYTE_MSF +# define get_short(b0,b1) (((b1)<<8)|(b0)) +#else +# define get_short(b0,b1) (((b0)<<8)|(b1)) +#endif + + /* + * Do the position first + */ + { + register int i; + register boolean_t moved; + int delta_coords[L_COORD_MAX]; + + /* + * Get all coords, see if it moved at all (buttons!) + */ + moved = FALSE; + for (i = 0; i < dev->locator.n_coords; i++) { + + coord = get_short(msg->body[2+(i<<1)], + msg->body[3+(i<<1)]); + + if (dev->locator.relative) { + /* + * Flame on + * I am getting tired of this, why do they have to + * keep this bug around ? Religion ? Damn, they + * design a keyboard for X11 use and forget the mouse ? + * Flame off + */ +#define BOGUS_DEC_X_AXIS +#ifdef BOGUS_DEC_X_AXIS + if (i == 1) coord = - coord; +#endif /* BOGUS_DEC_X_AXIS */ + /* dev->locator.coordinate[i] += coord; */ + } else { + register unsigned int old_coord; + + old_coord = dev->locator.coordinate[i]; + dev->locator.coordinate[i] = coord; + coord = old_coord - coord; + } + delta_coords[i] = coord; + if (coord != 0) + moved = TRUE; + } + if (moved) { + /* scale and threshold done higher up */ + screen_motion_event( 0, + dev->locator.type, + delta_coords[0], + delta_coords[1]); + } + } + + /* + * Time for the buttons now + */ +#define new_buttons coord + new_buttons = get_short(msg->body[0],msg->body[1]); + buttons = new_buttons ^ dev->locator.prev_buttons; + if (buttons) { + register int i, type; + + dev->locator.prev_buttons = new_buttons; + for (i = 0; buttons; i++, buttons >>= 1) { + + if ((buttons & 1) == 0) continue; + + type = (new_buttons & (1<locator.type, + dev->locator.button_code[i], + type); + } + } +#undef new_buttons +} + +/* + * Handler for keyboard devices + * Special case: outc set for recv packet means + * we are inside the kernel debugger + */ +int +dtop_keyboard_handler( + dtop_device_t dev, + dtop_message_t msg, + int event, + unsigned char outc) +{ + char save[11]; + register int msg_len, c; + + /* + * Well, really this code handles just an lk401 and in + * a very primitive way at that. Should at least emulate + * an lk201 decently, and make that a pluggable module. + * Sigh. + */ + + if (event != DTOP_EVENT_RECEIVE_PACKET) { + switch (event) { + case DTOP_EVENT_POLL: + { + register unsigned int t, t0; + + /* + * Note we will always have at least the + * end-of-list marker present (a zero) + * Here stop and trigger of autorepeat. + * Do not repeat shift keys, either. + */ + { + register unsigned char uc, i = 0; + +rpt_char: + uc = dev->keyboard.last_codes[i]; + + if (uc == DTOP_KBD_EMPTY) { + dev->keyboard.k_ar_state = K_AR_OFF; + return 0; + } + if ((uc >= LK_R_SHIFT) && (uc <= LK_R_ALT)) { + /* sometimes swapped. Grrr. */ + if (++i < dev->keyboard.last_codes_count) + goto rpt_char; + dev->keyboard.k_ar_state = K_AR_OFF; + return 0; + } + c = uc; + } + + /* + * Got a char. See if enough time from stroke, + * or from last repeat. + */ + t0 = (dev->keyboard.k_ar_state == K_AR_TRIGGER) ? 30 : 500; + t = approx_time_in_msec(); + if ((t - dev->keyboard.last_msec) < t0) + return 0; + + dev->keyboard.k_ar_state = K_AR_TRIGGER; + + /* + * Simplest thing to do is to mimic lk201 + */ + outc = lk201_input(0, LK_REPEAT); + if ( ! screen_keypress_event( 0, + DEV_KEYBD, + c, + EVT_BUTTON_UP)) { + if (outc > 0) cons_input(0, outc, 0); + } else + screen_keypress_event( 0, + DEV_KEYBD, + c, + EVT_BUTTON_DOWN); + return 0; + } + default: gimmeabreak();/*fornow*/ + } + return -1; + } + + msg_len = msg->code.val.len; + + /* Check for errors */ + c = msg->body[0]; + if ((c < DTOP_KBD_KEY_MIN) && (c != DTOP_KBD_EMPTY)) { + printf("Keyboard error: %x %x %x..\n", msg_len, c, msg->body[1]); + if (c != DTOP_KBD_OUT_ERR) return -1; + /* spec sez if scan list overflow still there is data */ + msg->body[0] = 0; + } + + dev->keyboard.last_msec = approx_time_in_msec(); + + switch (dev->keyboard.k_ar_state) { + case K_AR_IDLE: + /* if from debugger, timeouts might not be working yet */ + if (outc == 0xff) + break; + dtop_keyboard_autorepeat( dev ); + /* fall through */ + case K_AR_TRIGGER: + dev->keyboard.k_ar_state = K_AR_ACTIVE; + break; + case K_AR_ACTIVE: + break; + case K_AR_OFF: gimmeabreak(); /* ??? */ + dev->keyboard.k_ar_state = K_AR_IDLE; + } + + /* + * We can only assume that pressed keys are reported in the + * same order (a minimum of sanity, please) across scans. + * To make things readable, do a first pass cancelling out + * all keys that are still pressed, and a second one generating + * events. While generating events, do the upstrokes first + * from oldest to youngest, then the downstrokes from oldest + * to youngest. This copes with lost packets and provides + * a reasonable model even if scans are too slow. + */ + + /* make a copy of new state first */ + { + register char *p, *q, *e; + + p = save; + q = (char*)msg->body; + e = (char*)&msg->body[msg_len]; + + while (q < e) + *p++ = *q++; + } + + /* + * Do the cancelling pass + */ + { + register char *ls, *le, *ns, *ne, *sync; + + ls = (char*)dev->keyboard.last_codes; + le = (char*)&dev->keyboard.last_codes[dev->keyboard.last_codes_count]; + ns = (char*)msg->body; + ne = (char*)&msg->body[msg_len]; + + /* sync marks where to restart scanning, saving + time thanks to ordering constraints */ + for (sync = ns; ls < le; ls++) { + register char c = *ls; + for (ns = sync; ns < ne; ns++) + if (c == *ns) { + *ls = *ns = 0; + sync = ns + 1; + break; + } + /* we could already tell if c is an upstroke, + but see the above discussion about errors */ + } + } + /* + * Now generate all upstrokes + */ + { + register char *ls, *le; + register unsigned char c; + + le = (char*)dev->keyboard.last_codes; + ls = (char*)&dev->keyboard.last_codes[dev->keyboard.last_codes_count - 1]; + + for ( ; ls >= le; ls--) + if (c = *ls) { + /* keep kernel notion of lk201 state consistent */ + (void) lk201_input(0,c); + + if (outc == 0) + screen_keypress_event(0, + DEV_KEYBD, + c, + EVT_BUTTON_UP); + } + } + /* + * And finally the downstrokes + */ + { + register char *ns, *ne, c, retc; + + ne = (char*)msg->body; + ns = (char*)&msg->body[msg_len - 1]; + retc = 0; + + for ( ; ns >= ne; ns--) + if (c = *ns) { + register unsigned char data; + + data = c; + c = lk201_input(0, data); + + if (c == -2) { /* just returned from kdb */ + /* NOTE: many things have happened while + we were sitting on the stack, now it + is last_codes that holds the truth */ +#if 1 + /* But the truth might not be welcome. + If we get out because we hit RETURN + on the rconsole line all is well, + but if we did it from the keyboard + we get here on the downstroke. Then + we will get the upstroke which we + would give to X11. People complained + about this extra keypress.. so they + lose everything. */ + + dev->keyboard.last_codes_count = 1; + dev->keyboard.last_codes[0] = 0; +#endif + return -1; + } + + /* + * If X11 had better code for the keyboard this + * would be an EVT_BUTTON_DOWN. But that would + * screwup the REPEAT function. Grrr. + */ + /* outc non zero sez we are in the debugger */ + if (outc == 0) { + if (screen_keypress_event(0, + DEV_KEYBD, + data, + EVT_BUTTON_DOWN)) + c = -1; /* consumed by X */ + else + if (c > 0) cons_input(0, c, 0); + } + /* return the xlated keycode anyways */ + if ((c > 0) && (retc == 0)) + retc = c; + } + outc = retc; + } + /* install new scan state */ + { + register char *p, *q, *e; + + p = (char*)dev->keyboard.last_codes; + q = (char*)save; + e = (char*)&save[msg_len]; + + while (q < e) + *p++ = *q++; + dev->keyboard.last_codes_count = msg_len; + } + return outc; +} + +/* + * Polled operations: we must do autorepeat by hand. Sigh. + */ +dtop_keyboard_autorepeat( + dtop_device_t dev) +{ + spl_t s = spltty(); + + if (dev->keyboard.k_ar_state != K_AR_IDLE) + dtop_keyboard_handler( dev, 0, DTOP_EVENT_POLL, 0); + + if (dev->keyboard.k_ar_state == K_AR_OFF) + dev->keyboard.k_ar_state = K_AR_IDLE; + else + timeout( dtop_keyboard_autorepeat, dev, dev->keyboard.poll_frequency); + + splx(s); +} + +#endif /*NDTOP>0*/ diff --git a/chips/dtop_hdw.c b/chips/dtop_hdw.c new file mode 100644 index 0000000..6962d70 --- /dev/null +++ b/chips/dtop_hdw.c @@ -0,0 +1,644 @@ +/* + * Mach Operating System + * Copyright (c) 1993,1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: dtop_hdw.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 1/92 + * + * Hardware-level operations for the Desktop serial line + * bus (i2c aka ACCESS). + */ + +#include +#if NDTOP > 0 +#include +#include + +#include /* spl definitions */ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define DTOP_MAX_POLL 0x7fff /* about half a sec */ + +#ifdef MAXINE + +typedef volatile unsigned int *data_reg_t; /* uC */ +#define DTOP_GET_BYTE(data) (((*(data)) >> 8) & 0xff) +#define DTOP_PUT_BYTE(data,c) { *(data) = (c) << 8; } + +typedef volatile unsigned int *poll_reg_t; /* SIR */ +#define DTOP_RX_AVAIL(poll) (*(poll) & 1) +#define DTOP_TX_AVAIL(poll) (*(poll) & 2) + +#else + +define how to get/put DTOP packets on this box + +#endif + +/* + * Driver status + */ + +struct dtop_softc { + data_reg_t data; + poll_reg_t poll; + char polling_mode; + char probed_once; + short bad_pkts; + + struct dtop_ds { + int (*handler)(dtop_device_t, + dtop_message_t, + int, + unsigned char); + dtop_device status; + } device[(DTOP_ADDR_DEFAULT - DTOP_ADDR_FIRST) >> 1]; + +# define DTOP_DEVICE_NO(address) (((address)-DTOP_ADDR_FIRST)>>1) + +} dtop_softc_data[NDTOP]; + +typedef struct dtop_softc *dtop_softc_t; + +dtop_softc_t dtop_softc[NDTOP]; + +/* + * Definition of the driver for the auto-configuration program. + */ + +int dtop_probe(), dtop_intr(); +static void dtop_attach(); + +vm_offset_t dtop_std[NDTOP] = { 0 }; +struct bus_device *dtop_info[NDTOP]; +struct bus_driver dtop_driver = + { dtop_probe, 0, dtop_attach, 0, dtop_std, "dtop", dtop_info,}; + + +int dtop_print_debug = 0; + +/* + * Adapt/Probe/Attach functions + */ + +set_dtop_address( dtopunit, poll_reg) + data_reg_t poll_reg; +{ + int i; + + extern int dtop_probe(), dtop_param(), dtop_start(), + dtop_putc(), dtop_getc(), + dtop_pollc(), dtop_mctl(), dtop_softCAR(); + + dtop_std[dtopunit] = (vm_offset_t)poll_reg; + + /* Do this here */ + console_probe = dtop_probe; + console_param = dtop_param; + console_start = dtop_start; + console_putc = dtop_putc; + console_getc = dtop_getc; + console_pollc = dtop_pollc; + console_mctl = dtop_mctl; + console_softCAR = dtop_softCAR; + +} + +dtop_probe( data_reg, ui) + data_reg_t data_reg; + struct bus_device *ui; +{ + int dtopunit = ui->unit, i; + dtop_softc_t dtop; + + dtop = &dtop_softc_data[dtopunit]; + dtop_softc[dtopunit] = dtop; + + dtop->poll = (poll_reg_t)dtop_std[dtopunit]; + dtop->data = data_reg; + + for (i = 0; i < DTOP_MAX_DEVICES; i++) + dtop->device[i].handler = dtop_null_device_handler; + + /* a lot more needed here, fornow: */ + dtop->device[DTOP_DEVICE_NO(0x6a)].handler = dtop_locator_handler; + dtop->device[DTOP_DEVICE_NO(0x6a)].status.locator.type = + DEV_MOUSE; + dtop->device[DTOP_DEVICE_NO(0x6a)].status.locator.relative = + 1; + dtop->device[DTOP_DEVICE_NO(0x6a)].status.locator.button_code[0] = + KEY_LEFT_BUTTON; + dtop->device[DTOP_DEVICE_NO(0x6a)].status.locator.button_code[1] = + KEY_RIGHT_BUTTON; + dtop->device[DTOP_DEVICE_NO(0x6a)].status.locator.button_code[2] = + KEY_MIDDLE_BUTTON; + dtop->device[DTOP_DEVICE_NO(0x6a)].status.locator.n_coords = + 2; + + dtop->device[DTOP_DEVICE_NO(0x6c)].handler = dtop_keyboard_handler; + dtop->device[DTOP_DEVICE_NO(0x6c)].status.keyboard.poll_frequency = + (hz * 5) / 100; /* x0.01 secs */ + dtop->device[DTOP_DEVICE_NO(0x6c)].status.keyboard.bell_volume = + DTOP_CLICK_VOLUME_MAX; + + return 1; +} + +static void +dtop_attach(ui) + struct bus_device *ui; +{ + int i; + + /* Initialize all the console ttys */ + for (i = 0; i < 4; i++) + ttychars(console_tty[i]); + /* Mark keyboard and mouse present */ + for (i = 0; i < 2; i++) + console_tty[i]->t_addr = (char*)1; +} + +/* + * Polled I/O (debugger) + */ +dtop_pollc(unit, on) + boolean_t on; +{ + dtop_softc_t dtop; + + dtop = dtop_softc[unit]; + if (on) { + dtop->polling_mode++; +#if NBM > 0 + screen_on_off(unit, TRUE); +#endif NBM > 0 + } else + dtop->polling_mode--; +} + +/* + * Interrupt routine + */ +dtop_intr (unit, spllevel, recvd) + spl_t spllevel; + boolean_t recvd; +{ + + if (recvd) { + dtop_message msg; + int devno; + dtop_softc_t dtop; + + ssaver_bump(unit); + +#ifdef mips + splx(spllevel); +#endif + + dtop = dtop_softc[unit]; + if (dtop_get_packet(dtop, &msg) < 0) { + if (dtop_print_debug) + printf("%s", "dtop: overrun (or stray)\n"); + return; + } + + devno = DTOP_DEVICE_NO(msg.src_address); + if (devno < 0 || devno > 15) return; /* sanity */ + + (void) (*dtop->device[devno].handler) + (&dtop->device[devno].status, &msg, + DTOP_EVENT_RECEIVE_PACKET, 0); + + } else { + /* fornow xmit is not intr based */ + (*tc_enable_interrupt)( dtop_info[unit]->adaptor, FALSE, TRUE); + } +} + +boolean_t +dtop_start(tp) + struct tty *tp; +{ + register int line, temp; + + /* no, we do not need a char out first */ + return FALSE; +} + +dtop_w_test(n, a,b,c,d,e,f,g,h) +{ + int *p = (int*)0xbc2a0000; + + if (n <= 0) return; + + a <<= 8; *p = a; + if (--n == 0) goto out; + delay(20); + b <<= 8; *p = b; + if (--n == 0) goto out; + delay(20); + c <<= 8; *p = c; + if (--n == 0) goto out; + delay(20); + d <<= 8; *p = d; + if (--n == 0) goto out; + delay(20); + e <<= 8; *p = e; + if (--n == 0) goto out; + delay(20); + f <<= 8; *p = f; + if (--n == 0) goto out; + delay(20); + g <<= 8; *p = g; + if (--n == 0) goto out; + delay(20); + h <<= 8; *p = h; +out: + delay(10000); + { + int buf[100]; + + delay(20); + a = *p; + buf[0] = a; + c = 1; + for (n = 0; n < 100; n++) { + delay(20); + b = *p; + if (b != a) { + buf[c++] = b; + b = a; + } + } + for (n = 0; n < c; n++) + db_printf("%x ", ((buf[n])>>8)&0xff); + } + return c; +} + +/* + * Take a packet off dtop interface + * A packet MUST be there, this is not checked for. + */ +#define DTOP_ESC_CHAR 0xf8 +dtop_escape(c) +{ + /* I donno much about this stuff.. */ + switch (c) { + case 0xe8: return 0xf8; + case 0xe9: return 0xf9; + case 0xea: return 0xfa; + case 0xeb: return 0xfb; + default: /* printf("{esc %x}", c); */ + return c; + } +} + +dtop_get_packet(dtop, pkt) + dtop_softc_t dtop; + dtop_message_t pkt; +{ + register poll_reg_t poll; + register data_reg_t data; + register int max, i, len; + register unsigned char c; + + poll = dtop->poll; + data = dtop->data; + + /* + * The interface does not handle us the first byte, + * which is our address and cannot ever be anything + * else but 0x50. This is a good thing, it makes + * the average packet exactly one word long, too. + */ + pkt->src_address = DTOP_GET_BYTE(data); + + for (max = 0; (max < DTOP_MAX_POLL) && !DTOP_RX_AVAIL(poll); max++) + delay(16); + if (max == DTOP_MAX_POLL) goto bad; + pkt->code.bits = DTOP_GET_BYTE(data); + + /* + * Now get data and checksum + */ + len = pkt->code.val.len + 1; + c = 0; + for (i = 0; i < len; i++) { + +again: for (max = 0; (max < DTOP_MAX_POLL) && !DTOP_RX_AVAIL(poll); max++) + delay(16); + if (max == DTOP_MAX_POLL) goto bad; + if (c == DTOP_ESC_CHAR) { + c = dtop_escape(DTOP_GET_BYTE(data) & 0xff); + } else { + c = DTOP_GET_BYTE(data); + if (c == DTOP_ESC_CHAR) + goto again; + } + + pkt->body[i] = c; + } + return len; +bad: + dtop->bad_pkts++; + return -1; +} + +/* Conversely... */ +dtop_put_packet(dtop, pkt) + dtop_softc_t dtop; + dtop_message_t pkt; +{ + register int i, max; + register unsigned char *cp; + register unsigned int spl; + register unsigned char c; + + spl = spltty(); + pkt->src_address = pkt->dest_address; + i = 0; + cp = (unsigned char *)&pkt->src_address; + while (i < pkt->code.val.len + 2) { + for (max = 0; max < DTOP_MAX_POLL && !DTOP_TX_AVAIL(dtop->poll); + max++); + if (max == DTOP_MAX_POLL) + goto bad; + DTOP_PUT_BYTE(dtop->data, *cp); + cp++; + i++; + } + for (max = 0; (max < DTOP_MAX_POLL) && !DTOP_RX_AVAIL(dtop->poll); max++) + delay(16); + if (max == DTOP_MAX_POLL) + goto bad; + c = DTOP_GET_BYTE(dtop->data); + if (c == DTOP_ESC_CHAR) { + for (max = 0; (max < DTOP_MAX_POLL) + && !DTOP_RX_AVAIL(dtop->poll); max++) + delay(16); + if (max == DTOP_MAX_POLL) + goto bad; + c = DTOP_GET_BYTE(dtop->data); + } + splx(spl); + switch (c) { + case 0xfb: /* XMT, ok */ + break; + default: + return 0; + } + return 1; + bad: + splx(spl); + return 0; +} + + +/* + * Get a char from a specific DTOP line + * [this is only used for console&screen purposes] + */ +dtop_getc( unit, line, wait, raw ) + boolean_t wait; + boolean_t raw; +{ + register int c; + dtop_softc_t dtop; + + dtop = dtop_softc[unit]; +again: + c = -1; + + /* + * Try rconsole first + */ + if (rcline && line == SCREEN_LINE_KEYBOARD) { + c = scc_getc( 0, rcline, FALSE, raw); + if (c != -1) return c; + } + + /* + * Now check keyboard + */ + if (DTOP_RX_AVAIL(dtop->poll)) { + + dtop_message msg; + struct dtop_ds *ds; + + if (dtop_get_packet(dtop, &msg) >= 0) { + + ds = &dtop->device[DTOP_DEVICE_NO(msg.src_address)]; + if (ds->handler == dtop_keyboard_handler) { + + c = dtop_keyboard_handler( + &ds->status, &msg, + DTOP_EVENT_RECEIVE_PACKET, -1); + + if (c > 0) return c; + + c = -1; + } + } + } + + if (wait && (c == -1)) { + delay(100); + goto again; + } + + return c; +} + +/* + * Put a char on a specific DTOP line + */ +dtop_putc( unit, line, c ) +{ + if (rcline && line == rcline) { + scc_putc(0, rcline, c); + } +/* dprintf("%c", c); */ +} + +dtop_param(tp, line) + struct tty *tp; +{ + if (tp->t_ispeed == 0) + ttymodem(tp, 0); + else + /* called too early to invoke ttymodem, sigh */ + tp->t_state |= TS_CARR_ON; +} + +/* + * Modem control functions, we don't need 'em + */ +dtop_mctl(dev, bits, how) + int dev; + int bits, how; +{ + return 0; +} + +dtop_softCAR(unit, line, on) +{ +} + +/* Some keyboard specific stuff, probably belongs elsewhere */ + +dtop_kbd_probe(unit) +{ + if (dtop_std[unit]) { + lk201_probe(unit); + return 1; + } + return 0; +} + +io_return_t +dtop_set_status(unit, flavor, status, status_count) + int unit; + int flavor; + dev_status_t status; + unsigned int status_count; +{ + dtop_device_t dev; + + dev = &dtop_softc[unit]->device[DTOP_DEVICE_NO(0x6c)].status; + + switch (flavor) { + case LK201_SEND_CMD: { + register lk201_cmd_t *cmd = (lk201_cmd_t *)status; + unsigned int cnt; + + if ((status_count < (sizeof(*cmd)/sizeof(int))) || + ((cnt = cmd->len) > 2)) + return D_INVALID_SIZE; + switch (cmd->command) { + case LK_CMD_ENB_BELL: + cmd->params[0] ^= 0x7; + if (dtop_print_debug) + printf("LK_CMD_ENB_BELL %d\n", cmd->params[0]); + dev->keyboard.bell_volume = cmd->params[0] & 0x7; + break; + case LK_CMD_DIS_BELL: + dev->keyboard.bell_volume = 0; + break; + case LK_CMD_BELL: + dtop_ring_bell(unit); + break; + case LK_CMD_LEDS_ON: + cmd->params[0] &= ~0x80; + if (dtop_print_debug) + printf("LK_CMD_LEDS_ON %d %x\n", + cmd->params[0], cmd->params[0]); + dev->keyboard.led_status |= cmd->params[0]; + dtop_leds(unit, dev->keyboard.led_status); + break; + case LK_CMD_LEDS_OFF: + cmd->params[0] &= ~0x80; + dev->keyboard.led_status &= ~cmd->params[0]; + dtop_leds(unit, dev->keyboard.led_status); + break; + case LK_CMD_ENB_KEYCLK: + case LK_CMD_DIS_KEYCLK: + case LK_CMD_SOUND_CLK: + case LK_CMD_DIS_CTLCLK: + case LK_CMD_ENB_CTLCLK: + break; + default: + break; + } + break; + } + default: + break; + } + return lk201_set_status(unit, flavor, status, status_count); +} + +dtop_kbd_reset(unit) +{ + return lk201_reset(unit); +} + +#define DTOP_BITS(p, len) (((p) << 7) | (len)) + +dtop_ring_bell(unit) +{ + dtop_message msg; + dtop_device_t dev; + int vol; + + dev = &dtop_softc[unit]->device[DTOP_DEVICE_NO(0x6c)].status; + vol = dev->keyboard.bell_volume; + + if (dtop_print_debug) + printf("dtop_ring_bell: %d\n", vol); + msg.dest_address = DTOP_ADDR_KBD; + msg.code.bits = DTOP_BITS(1, 2); + msg.body[0] = DTOP_KMSG_BELL; + msg.body[1] = vol; + if (!dtop_put_packet(dtop_softc[unit], &msg)) { + if (dtop_print_debug) + printf("dtop_ring_bell: dtop_put_packet failed\n"); + return -1; + } + return 0; +} + +dtop_leds(unit, mask) +{ + dtop_message msg; + + if (dtop_print_debug) + printf("dtop_leds %x\n", mask); + msg.dest_address = DTOP_ADDR_KBD; + msg.code.bits = DTOP_BITS(1, 2); + msg.body[0] = DTOP_KMSG_LED; + msg.body[1] = mask; + if (!dtop_put_packet(dtop_softc[unit], &msg)) { + if (dtop_print_debug) + printf("dtop_leds: dtop_put_packet failed\n"); + return -1; + } + return 0; +} + + + +#endif NDTOP > 0 diff --git a/chips/dz_7085.h b/chips/dz_7085.h new file mode 100644 index 0000000..66c8916 --- /dev/null +++ b/chips/dz_7085.h @@ -0,0 +1,153 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: dz_7085.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Defines for the DEC 7085 Serial Line Controller Chip + */ + +#define NDZ_LINE 4 + +/* + * What's hanging off those 4 lines + */ + +#define DZ_LINE_KEYBOARD 0 +#define DZ_LINE_MOUSE 1 +#define DZ_LINE_MODEM 2 +#define DZ_LINE_PRINTER 3 + +/* + * Register layout, ignoring padding + */ +typedef struct { + volatile unsigned short dz_csr; /* Control and Status */ + volatile unsigned short dz_rbuf; /* Rcv buffer (RONLY) */ + volatile unsigned short dz_tcr; /* Xmt control (R/W)*/ + volatile unsigned short dz_tbuf; /* Xmt buffer (WONLY)*/ +# define dz_lpr dz_rbuf /* Line parameters (WONLY)*/ +# define dz_msr dz_tbuf /* Modem status (RONLY)*/ +} dz_regmap_t; + +/* + * CSR bits + */ + +#define DZ_CSR_MBZ 0x3c07 /* Must be zero */ +#define DZ_CSR_MAINT 0x0008 /* rw: Maintenance mode */ +#define DZ_CSR_CLR 0x0010 /* rw: Master clear (init) */ +#define DZ_CSR_MSE 0x0020 /* rw: Master scan enable */ +#define DZ_CSR_RIE 0x0040 /* rw: Rcv Interrupt Enable */ +#define DZ_CSR_RDONE 0x0080 /* ro: Rcv done (silo avail) */ +#define DZ_CSR_TLINE 0x0300 /* ro: Lineno ready for xmt */ +#define DZ_CSR_TIE 0x4000 /* rw: Xmt Interrupt Enable */ +#define DZ_CSR_TRDY 0x8000 /* ro: Xmt ready */ + +/* + * Receiver buffer (top of silo). Read-only. + */ + +#define DZ_SILO_DEEP 64 + +#define DZ_RBUF_CHAR 0x00ff /* Received character */ +#define DZ_RBUF_RLINE 0x0300 /* Line it came from */ +#define DZ_RBUF_XXXX 0x0c00 /* Reads as zero */ +#define DZ_RBUF_PERR 0x1000 /* Parity error */ +#define DZ_RBUF_FERR 0x2000 /* Framing error (break) */ +#define DZ_RBUF_OERR 0x4000 /* Silo overrun */ +#define DZ_RBUF_VALID 0x8000 /* Info is valid */ + +/* + * Line parameters register. Write-only. + */ + +#define DZ_LPAR_LINE 0x0003 /* Bin encoded line no */ +#define DZ_LPAR_MBZ 0xe004 /* Must be zero */ +#define DZ_LPAR_CLEN 0x0018 /* Character length: */ +# define DZ_LPAR_5BITS 0x0000 /* 5 bits per char */ +# define DZ_LPAR_6BITS 0x0008 /* 6 bits per char */ +# define DZ_LPAR_7BITS 0x0010 /* 7 bits per char */ +# define DZ_LPAR_8BITS 0x0018 /* 8 bits per char */ +#define DZ_LPAR_STOP 0x0020 /* stop bits: off->1, on->2 */ +#define DZ_LPAR_PAR_ENB 0x0040 /* generate/detect parity */ +#define DZ_LPAR_ODD_PAR 0x0080 /* generate/detect ODD parity */ +#define DZ_LPAR_SPEED 0x0f00 /* Speed code: */ +# define DZ_LPAR_50 0x0000 /* 50 baud */ +# define DZ_LPAR_75 0x0100 /* 75 baud */ +# define DZ_LPAR_110 0x0200 /* 110 baud */ +# define DZ_LPAR_134_5 0x0300 /* 134.5 baud */ +# define DZ_LPAR_150 0x0400 /* 150 baud */ +# define DZ_LPAR_300 0x0500 /* 300 baud */ +# define DZ_LPAR_600 0x0600 /* 600 baud */ +# define DZ_LPAR_1200 0x0700 /* 1200 baud */ +# define DZ_LPAR_1800 0x0800 /* 1800 baud */ +# define DZ_LPAR_2000 0x0900 /* 2000 baud */ +# define DZ_LPAR_2400 0x0a00 /* 2400 baud */ +# define DZ_LPAR_3600 0x0b00 /* 3600 baud */ +# define DZ_LPAR_4800 0x0c00 /* 4800 baud */ +# define DZ_LPAR_7200 0x0d00 /* 7200 baud */ +# define DZ_LPAR_9600 0x0e00 /* 9600 baud */ +# define DZ_LPAR_MAX_SPEED 0x0f00 /* 19200/38400 baud */ +#define DZ_LPAR_ENABLE 0x1000 /* Enable receiver */ + +/* + * Xmt control register + */ + +#define DZ_TCR_LNENB 0x000f /* rw: Xmt line enable */ +#define DZ_TCR_MBZ 0xf0f0 /* Must be zero */ +#define DZ_TCR_DTR3 0x0100 /* rw: DTR on printer line */ +#define DZ_TCR_RTS3 0x0200 /* rw: RTS on printer line */ +#define DZ_TCR_DTR2 0x0400 /* rw: DTR on modem line */ +#define DZ_TCR_RTS2 0x0800 /* rw: RTS on modem line */ + +/* + * Modem status register. Read-only. + */ + +#define DZ_MSR_CTS3 0x0001 /* Clear To Send, printer line */ +#define DZ_MSR_DSR3 0x0002 /* Data Set Ready, printer line */ +#define DZ_MSR_CD3 0x0004 /* Carrier Detect, printer line */ +#define DZ_MSR_RI3 0x0008 /* Ring Indicator, printer line */ +#define DZ_MSR_XXXX 0xf0f0 /* Reads as zero */ +#define DZ_MSR_CTS2 0x0100 /* Clear To Send, modem line */ +#define DZ_MSR_DSR2 0x0200 /* Data Set Ready, modem line */ +#define DZ_MSR_CD2 0x0400 /* Carrier Detect, modem line */ +#define DZ_MSR_RI2 0x0800 /* Ring Indicator, modem line */ + + +/* + * Xmt buffer + */ + +#define DZ_TBUF_CHAR 0x00ff /* Xmt character */ +#define DZ_TBUF_BREAK_0 0x0100 /* set line 0 to space */ +#define DZ_TBUF_BREAK_1 0x0200 /* set line 1 to space */ +#define DZ_TBUF_BREAK_2 0x0400 /* set line 2 to space */ +#define DZ_TBUF_BREAK_3 0x0800 /* set line 3 to space */ +#define DZ_TBUF_MBZ 0xf000 /* Must be zero */ diff --git a/chips/dz_defs.h b/chips/dz_defs.h new file mode 100644 index 0000000..7c792bb --- /dev/null +++ b/chips/dz_defs.h @@ -0,0 +1,65 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: dz_defs.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Internal definitions for the DZ Serial Line Driver + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +extern struct tty *dz_tty[]; + +extern struct pseudo_dma { + dz_regmap_t *p_addr; + char *p_mem; + char *p_end; + int p_arg; + int (*p_fcn)(); +} dz_pdma[]; + +extern int rcline, cnline; +extern int console; + +/* + * Modem control operations on DZ lines + */ + +extern unsigned dz_mctl(/* int, int, int */); + diff --git a/chips/dz_hdw.c b/chips/dz_hdw.c new file mode 100644 index 0000000..fa47282 --- /dev/null +++ b/chips/dz_hdw.c @@ -0,0 +1,649 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: dz_hdw.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Hardware-level operations for the DZ Serial Line Driver + */ + +#include +#if NDZ_ > 0 +#include +#include + +#include + +#include /* spl definitions */ +#include +#include + +#include +#include +#include + +#include + + +#ifdef DECSTATION +#include +#include +#define DZ_REGS_DEFAULT (vm_offset_t)PHYS_TO_K1SEG(KN01_SYS_DZ) +#define PAD(n) char n[6]; +#endif /*DECSTATION*/ + +#ifdef VAXSTATION +#define DZ_REGS_DEFAULT 0 +#define wbflush() +#define check_memory(addr,dow) ((dow) ? wbadaddr(addr,4) : badaddr(addr,4)) +#define PAD(n) char n[2]; +#endif /*VAXSTATION*/ + +#ifndef PAD +#define PAD(n) +#endif + +typedef struct { + volatile unsigned short dz_csr; /* Control and Status */ + PAD(pad0) + volatile unsigned short dz_rbuf; /* Rcv buffer (RONLY) */ + PAD(pad1) + volatile unsigned short dz_tcr; /* Xmt control (R/W)*/ + PAD(pad2) + volatile unsigned short dz_tbuf; /* Xmt buffer (WONLY)*/ +# define dz_lpr dz_rbuf /* Line parameters (WONLY)*/ +# define dz_msr dz_tbuf /* Modem status (RONLY)*/ + PAD(pad3) +} dz_padded_regmap_t; + + +/* this is ok both for rcv (char) and xmt (csr) */ +#define LINEOF(x) (((x) >> 8) & 0x3) + +/* + * Driver status + */ +struct dz7085_softc { + dz_padded_regmap_t *regs; + unsigned short breaks; + unsigned short fake; /* missing rs232 bits */ + int polling_mode; + unsigned short prev_msr; + char softCAR; +} dz7085_softc_data[NDZ_]; + +typedef struct dz7085_softc *dz7085_softc_t; + +dz7085_softc_t dz7085_softc[NDZ_]; + +static void check_car(); +static void check_ring(); + +dz7085_softCAR(unit, line, on) +{ + if (on) + dz7085_softc[unit]->softCAR |= 1<softCAR &= ~(1 << line); +} + +static +short dz7085_speeds[] = + { 0, DZ_LPAR_50, DZ_LPAR_75, DZ_LPAR_110, DZ_LPAR_134_5, DZ_LPAR_150, + 0, DZ_LPAR_300, DZ_LPAR_600, DZ_LPAR_1200, DZ_LPAR_1800, DZ_LPAR_2400, + DZ_LPAR_4800, DZ_LPAR_9600, DZ_LPAR_MAX_SPEED, 0 }; + + +/* + * Definition of the driver for the auto-configuration program. + */ + +int dz7085_probe(), dz7085_intr(); +static void dz7085_attach(); + +vm_offset_t dz7085_std[NDZ_] = { DZ_REGS_DEFAULT, }; +struct bus_device *dz7085_info[NDZ_]; +struct bus_driver dz_driver = + { dz7085_probe, 0, dz7085_attach, 0, dz7085_std, "dz", dz7085_info,}; + +/* + * Adapt/Probe/Attach functions + */ + +static boolean_t dz7085_full_modem = FALSE; +boolean_t dz7085_uses_modem_control = FALSE;/* patch this with adb */ + +set_dz_address( unit, regs, has_modem) + vm_offset_t regs; + boolean_t has_modem; +{ + extern int dz7085_probe(), dz7085_param(), dz7085_start(), + dz7085_putc(), dz7085_getc(), + dz7085_pollc(), dz7085_mctl(), dz7085_softCAR(); + + dz7085_std[unit] = regs; + dz7085_full_modem = has_modem & dz7085_uses_modem_control; + + /* Do this here */ + console_probe = dz7085_probe; + console_param = dz7085_param; + console_start = dz7085_start; + console_putc = dz7085_putc; + console_getc = dz7085_getc; + console_pollc = dz7085_pollc; + console_mctl = dz7085_mctl; + console_softCAR = dz7085_softCAR; + +} + +dz7085_probe( xxx, ui) + struct bus_device *ui; +{ + int unit = ui->unit; + dz7085_softc_t sc; + register int cntr; + register dz_padded_regmap_t *regs; + + static int probed_once = 0; + + regs = (dz_padded_regmap_t *)dz7085_std[unit]; /* like the old days! */ + if (regs == 0) + return 0; + /* + * If this is not there we are toast + */ + if (check_memory(regs, 0)) + return 0; + + if (probed_once++) + return 1; + + sc = &dz7085_softc_data[unit]; + dz7085_softc[unit] = sc; + sc->regs = regs; + + for (cntr = unit*NDZ_LINE; cntr < NDZ_LINE*(unit+1); cntr++) { + console_tty[cntr]->t_addr = (char*)regs; + console_tty[cntr]->t_state |= TS_MIN; + } + + /* pmaxen et al. lack many modem bits */ + dz7085_set_modem_control(sc, dz7085_full_modem); + + regs->dz_tcr = 0;/* disable all lines, drop RTS,DTR */ + return 1; +} + +boolean_t dz7085_timer_started = FALSE; + +static void +dz7085_attach(ui) + register struct bus_device *ui; +{ + int unit = ui->unit; + extern dz7085_scan(); + extern int tty_inq_size; + int i; + + /* We only have 4 ttys, but always at 9600 + * Give em a lot of room + */ + tty_inq_size = 2048; + for (i = 0; i < (NDZ_*NDZ_LINE); i++) + ttychars(console_tty[i]); + + if (!dz7085_timer_started) { + dz7085_timer_started = TRUE; + dz7085_scan(); + } + +#if NBM > 0 + if (SCREEN_ISA_CONSOLE()) { + printf("\n sl0: "); lk201_attach(0, unit); + printf("\n sl1: "); mouse_attach(0, unit); + printf("\n sl2: \n sl3: "); + if (rcline == 3) printf("( rconsole )"); + } else { +#endif /*NBM > 0*/ + printf("\n sl0:\n sl1:\n sl2:\n sl3: ( alternate console )"); +#if NBM > 0 + } +#endif +} + +/* + * Would you like to make a phone call ? + */ +dz7085_set_modem_control(sc, on) + dz7085_softc_t sc; + boolean_t on; +{ + if (on) + /* your problem if the hardware then is broke */ + sc->fake = 0; + else + sc->fake = DZ_MSR_CTS3|DZ_MSR_DSR3|DZ_MSR_CD3| + DZ_MSR_CTS2|DZ_MSR_CD2; +} + +/* + * Polled I/O (debugger) + */ +dz7085_pollc(unit, on) + boolean_t on; +{ + dz7085_softc_t sc = dz7085_softc[unit]; + + if (on) { + sc->polling_mode++; +#if NBM > 0 + screen_on_off(unit, TRUE); +#endif NBM > 0 + } else + sc->polling_mode--; +} + +/* + * Interrupt routine + */ +dz_intr(unit,spllevel) + spl_t spllevel; +{ + dz7085_softc_t sc = dz7085_softc[unit]; + register dz_padded_regmap_t *regs = sc->regs; + register short csr; + + csr = regs->dz_csr; + + if (csr & DZ_CSR_TRDY) { + register int c; + + c = cons_simple_tint(unit*NDZ_LINE + LINEOF(csr), FALSE); + if (c == -1) { + /* no more data for this line */ + regs->dz_tcr &= ~(1 << LINEOF(csr)); + c = cons_simple_tint(unit*NDZ_LINE + LINEOF(csr), TRUE); + /* because funny race possible ifnot */ + } + if (c != -1) { + regs->dz_tbuf = (c & 0xff) | sc->breaks; + /* and leave it enabled */ + } + } + if (sc->polling_mode) + return; + + while (regs->dz_csr & DZ_CSR_RDONE) { + short c = regs->dz_rbuf; + spl_t oldspl; + +#ifdef DECSTATION + oldspl = splhigh(); + splx(spllevel); +#endif /*DECSTATION*/ + cons_simple_rint(unit*NDZ_LINE+LINEOF(c), LINEOF(c), + c&0xff, c&0xff00); +#ifdef DECSTATION + splx(oldspl); +#endif /*DECSTATION*/ + } +} + +/* + * Start transmission on a line + */ +dz7085_start(tp) + struct tty *tp; +{ + register dz_padded_regmap_t *regs; + register int line; + + line = tp->t_dev; + + regs = (dz_padded_regmap_t*)tp->t_addr; + regs->dz_tcr |= (1<<(line&3)); + + /* no, we do not need a char out to interrupt */ +} + +/* + * Get a char from a specific DZ line + */ +dz7085_getc( unit, line, wait, raw ) + boolean_t wait; + boolean_t raw; +{ + dz7085_softc_t sc = dz7085_softc[unit]; + spl_t s = spltty(); + register dz_padded_regmap_t *regs = sc->regs; + unsigned short c; + int rl; + +again: + /* + * wait till something in silo + */ + while ((regs->dz_csr & DZ_CSR_RDONE) == 0 && wait) + delay(10); + c = regs->dz_rbuf; + + /* + * check if right line. For keyboard, rconsole is ok too + */ + rl = LINEOF(c); + if (wait && (line != rl) && + !((line == DZ_LINE_KEYBOARD) && rcline == rl)) + goto again; + /* + * bad chars not ok + */ + if ((c & (DZ_RBUF_PERR | DZ_RBUF_OERR | DZ_RBUF_FERR)) && wait) + goto again; + + splx(s); + + /* + * if nothing found return -1 + */ + if ( ! (c & DZ_RBUF_VALID)) + return -1; + +#if NBM > 0 + if ((rl == DZ_LINE_KEYBOARD) && !raw && SCREEN_ISA_CONSOLE()) + return lk201_rint(SCREEN_CONS_UNIT(), c, wait, sc->polling_mode); + else +#endif NBM > 0 + return c & DZ_RBUF_CHAR; +} + +/* + * Put a char on a specific DZ line + */ +dz7085_putc( unit, line, c ) +{ + dz7085_softc_t sc = dz7085_softc[unit]; + register dz_padded_regmap_t *regs = sc->regs; + spl_t s = spltty(); + + /* + * do not change the break status of other lines + */ + c = (c & 0xff) | sc->breaks; + + /* + * Xmit line info only valid if TRDY, + * but never TRDY if no xmit enabled + */ + if ((regs->dz_tcr & DZ_TCR_LNENB) == 0) + goto select_it; + + while ((regs->dz_csr & DZ_CSR_TRDY) == 0) + delay(100); + + /* + * see if by any chance we are already on the right line + */ + if (LINEOF(regs->dz_csr) == line) + regs->dz_tbuf = c; + else { + unsigned short tcr; +select_it: + tcr = regs->dz_tcr; + regs->dz_tcr = (1 << line) | (tcr & 0xff00); + wbflush(); + + do + delay(2); + while ((regs->dz_csr & DZ_CSR_TRDY) == 0 || + (LINEOF(regs->dz_csr) != line)); + + regs->dz_tbuf = c; + wbflush(); + + /* restore previous settings */ + regs->dz_tcr = tcr; + } + + splx(s); +} + + +dz7085_param(tp, line) + register struct tty *tp; + register int line; +{ + register dz_padded_regmap_t *regs; + register int lpr; + + line = tp->t_dev; + regs = dz7085_softc[line/NDZ_LINE]->regs; + + /* + * Do not let user fool around with kbd&mouse + */ +#if NBM > 0 + if (screen_captures(line)) { + tp->t_ispeed = tp->t_ospeed = B4800; + tp->t_flags |= TF_LITOUT; + } +#endif NBM > 0 + regs->dz_csr = DZ_CSR_MSE|DZ_CSR_RIE|DZ_CSR_TIE; + if (tp->t_ispeed == 0) { + (void) (*console_mctl)(tp->t_dev, TM_HUP, DMSET); /* hang up line */ + return; + } +/* 19200/38400 here */ + lpr = dz7085_speeds[tp->t_ispeed] | (line&DZ_LPAR_LINE) | DZ_LPAR_ENABLE; + lpr |= DZ_LPAR_8BITS; + + if ((tp->t_flags & (TF_ODDP|TF_EVENP)) == TF_ODDP) + lpr |= DZ_LPAR_ODD_PAR; + + if (tp->t_ispeed == B110) + lpr |= DZ_LPAR_STOP; + regs->dz_lpr = lpr; +} + +/* + * This is a total mess: not only are bits spread out in + * various registers, but we have to fake some for pmaxen. + */ +dz7085_mctl(dev, bits, how) + int dev; + int bits, how; +{ + register dz_padded_regmap_t *regs; + register int unit; + register int tcr, msr, brk, n_tcr, n_brk; + int b; + spl_t s; + dz7085_softc_t sc; + + unit = dev; + + /* no modem support on lines 0 & 1 */ +/* XXX break on 0&1 */ + if ((unit & 2) == 0) + return TM_LE|TM_DTR|TM_CTS|TM_CAR|TM_DSR; + + b = 1 ^ (unit & 1); /* line 2 ? */ + + sc = dz7085_softc[unit>>2]; + regs = sc->regs; + s = spltty(); + + tcr = ((regs->dz_tcr | (sc->fake>>4)) & 0xf00) >> (8 + b*2); + brk = (sc->breaks >> (8 + (unit&3))) & 1; /* THE break bit */ + + n_tcr = (bits & (TM_RTS|TM_DTR)) >> 1; + n_brk = (bits & TM_BRK) >> 9; + + /* break transitions, must 'send' a char out */ + bits = (brk ^ n_brk) & 1; + + switch (how) { + case DMSET: + tcr = n_tcr; + brk = n_brk; + break; + + case DMBIS: + tcr |= n_tcr; + brk |= n_brk; + break; + + case DMBIC: + tcr &= ~n_tcr; + brk = 0; + break; + + case DMGET: + msr = ((regs->dz_msr|sc->fake) & 0xf0f) >> (b*8); + (void) splx(s); + return (tcr<<1)|/* DTR, RTS */ + ((msr&1)<<5)|/* CTS */ + ((msr&2)<<7)|/* DSR */ + ((msr&0xc)<<4)|/* CD, RNG */ + (brk << 9)|/* BRK */ + TM_LE; + } + n_tcr = (regs->dz_tcr & ~(3 << (8 + b*2))) | + (tcr << (8 + b*2)); + + regs->dz_tcr = n_tcr; + sc->fake = (sc->fake & 0xf0f) | (n_tcr<<4&0xf000); + + sc->breaks = (sc->breaks & ~(1 << (8 + (unit&3)))) | + (brk << (8 + (unit&3))); + if(bits) (*console_putc)( unit>>2, unit&3, 0);/* force break, now */ + (void) splx(s); + return 0;/* useless to compute it */ +} + +/* + * Periodically look at the CD signals: + * they do not generate interrupts. + */ +dz7085_scan() +{ + register i; + register dz_padded_regmap_t *regs; + register msr; + register struct tty *tp; + + for (i = 0; i < NDZ_; i++) { + dz7085_softc_t sc = dz7085_softc[i]; + register int temp; + + if (sc == 0) + continue; + regs = sc->regs; + + tp = console_tty[i * NDZ_LINE]; + + msr = regs->dz_msr | (sc->fake & 0xf0f); + if (temp = sc->softCAR) { + if (temp & 0x4) + msr |= DZ_MSR_CD2 | DZ_MSR_CTS2; + if (temp & 0x8) + msr |= DZ_MSR_CD3 | DZ_MSR_CTS3; + } + + /* Lines 0 and 1 have carrier on by definition */ + /* [horrid casts cuz compiler stupid] */ + check_car((char*)tp + 0*sizeof(struct tty), 1); + check_car((char*)tp + 1*sizeof(struct tty), 1); + check_car((char*)tp + 2*sizeof(struct tty), msr & DZ_MSR_CD2); + check_car((char*)tp + 3*sizeof(struct tty), msr & DZ_MSR_CD3); + + /* nothing else to do if no msr transitions */ + if ((temp = sc->prev_msr) == msr) + continue; + else + sc->prev_msr = msr; + + /* see if we have an incoming call */ +#define RING (DZ_MSR_RI2|DZ_MSR_RI3) + if ((msr & RING) != (temp & RING)) { +/*printf("%s %x->%x\n", "ET Phone RI", temp & RING, msr & RING);*/ + check_ring((char*)tp + 2*sizeof(struct tty), + msr & DZ_MSR_RI2, temp & DZ_MSR_RI2); + check_ring((char*)tp + 3*sizeof(struct tty), + msr & DZ_MSR_RI3, temp & DZ_MSR_RI3); + } +#undef RING + /* see if we must do flow-control */ + if ((msr ^ temp) & DZ_MSR_CTS2) { + tty_cts((char*)tp + 2*sizeof(struct tty), + msr & DZ_MSR_CTS2); + } + if ((msr ^ temp) & DZ_MSR_CTS3) { + tty_cts((char*)tp + 3*sizeof(struct tty), + msr & DZ_MSR_CTS3); + } + } + timeout(dz7085_scan, (vm_offset_t)0, 2*hz); +} + +static dz7085_hup(tp) + register struct tty *tp; +{ + (*console_mctl)(tp->t_dev, TM_DTR, DMBIC); +} + +static void check_car(tp, car) + register struct tty *tp; +{ + if (car) { + /* cancel modem timeout if need to */ + if (car & (DZ_MSR_CD2|DZ_MSR_CD3)) + untimeout(dz7085_hup, (vm_offset_t)tp); + + /* I think this belongs in the MI code */ + if (tp->t_state & TS_WOPEN) + tp->t_state |= TS_ISOPEN; + /* carrier present */ + if ((tp->t_state & TS_CARR_ON) == 0) + (void)ttymodem(tp, 1); + } else if ((tp->t_state&TS_CARR_ON) && ttymodem(tp, 0) == 0) + (*console_mctl)( tp->t_dev, TM_DTR, DMBIC); +} + +int dz7085_ring_timeout = 60; /* seconds, patchable */ + +static void check_ring(tp, ring, oring) + register struct tty *tp; +{ + if (ring == oring) + return; + if (ring) { + (*console_mctl)( tp->t_dev, TM_DTR, DMBIS); + /* give it ample time to find the right carrier */ + timeout(dz7085_hup, (vm_offset_t)tp, dz7085_ring_timeout*hz); + } +} +#endif NDZ_ > 0 diff --git a/chips/eccreg.h b/chips/eccreg.h new file mode 100644 index 0000000..21c8fb0 --- /dev/null +++ b/chips/eccreg.h @@ -0,0 +1,110 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#define FA_BLCK 0x10000 + +#define FA_ROM 0x00000 + +#define FA_CTL 0x10000 +#define FA_STAT 0x10000 +#define I_RCV_CNT 0x00001 +#define I_RCV_EOM 0x00002 +#define I_RCV_TIM 0x00004 +#define I_XMT_CNT 0x00008 +#define I_RCV_LOS 0x00010 +#define I_RCV_CARRIER 0x00020 +#define FA_CR_S 0x10004 +#define FA_CR_C 0x10008 +#define FA_CR 0x1000C +#define ENI_RCV_CNT 0x00001 +#define ENI_RCV_END 0x00002 +#define ENI_RCV_TIM 0x00004 +#define ENI_XMT_CNT 0x00008 +#define EN_TEST 0x00010 +#define EN_UNUSED 0x00020 +#define EN_RCV 0x00040 +#define EN_XMT 0x00080 +#define RESET_RCV 0x00100 +#define RESET_XMT 0x00200 +#define FA_TIM 0x10010 +#define FA_TIM_SET 0x10018 +#define FA_RCV_CNT 0x10020 +#define FA_RCV_CMP 0x10028 +#define FA_XMT_CNT 0x10030 +#define FA_XMT_CMP 0x10038 + + +#define FA_DISCARD 0x20000 +#define FA_RCV 0x20000 +#define FA_RCV_HD 0x20000 +#define FA_RCV_PAYLD 0x20004 +#define FA_RCV_TR 0x20034 + +#define FA_XMT 0x30000 +#define FA_XMT_HD 0x30000 +#define FA_XMT_PAYLD 0x30004 +#define FA_XMT_TR 0x30034 + +#define FA_END 0x40000 + + +struct ecc { +/* 00000 */ char rom[FA_BLCK]; +/* 10000 */ int stat; +/* 10004 */ int cr_s; +/* 10008 */ int cr_c; +/* 1000C */ int cr; +/* 10010 */ int tim; + int fill1; +/* 10018 */ int tim_set; + int fill2; +/* 10020 */ int rcv_cnt; + int fill3; +/* 10028 */ int rcv_cmp; + int fill4; +/* 10030 */ int xmt_cnt; + int fill5; +/* 10038 */ int xmt_cmp; + int fill6; + char pad[FA_BLCK-0x40]; + +/* 20000 */ +/* 20000 */ char rcv[FA_BLCK]; +/* 30000 */ char xmt[FA_BLCK]; +}; + +struct sar { + int header; + int payload[12]; + int trailer; +}; + +typedef struct ecc ecc_t; +typedef struct sar sar_t; + + + + diff --git a/chips/fb_hdw.c b/chips/fb_hdw.c new file mode 100644 index 0000000..7139a86 --- /dev/null +++ b/chips/fb_hdw.c @@ -0,0 +1,219 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: fb_hdw.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 7/91 + * + * Driver for the 3max Monochrome Frame Buffer Display, + * hardware-level operations. + */ + +#include +#if (NMFB > 0) +#include + +#include +#include +#include + +#include + +#include +typedef pm_softc_t fb_softc_t; + + +#ifdef DECSTATION +#include +#include +#endif + +#ifdef FLAMINGO +#include /* XXX fixme */ +#include +#endif + +/* + * Definition of the driver for the auto-configuration program. + */ + +int fb_probe(), fb_intr(); +static void fb_attach(); + +vm_offset_t fb_std[NMFB] = { 0 }; +struct bus_device *fb_info[NMFB]; +struct bus_driver fb_driver = + { fb_probe, 0, fb_attach, 0, fb_std, "fb", fb_info, + 0, 0, BUS_INTR_DISABLED}; + +/* + * Probe/Attach functions + */ + +fb_probe( /* reg, ui */) +{ + static probed_once = 0; + + /* + * Probing was really done sweeping the TC long ago + */ + if (tc_probe("fb") == 0) + return 0; + if (probed_once++ > 1) + printf("[mappable] "); + return 1; +} + +static void +fb_attach(ui) + struct bus_device *ui; +{ + /* ... */ + printf(": monochrome display"); +} + + +/* + * Interrupt routine + */ + +fb_intr(unit,spllevel) + spl_t spllevel; +{ + register volatile char *ack; + + /* acknowledge interrupt */ + ack = (volatile char *) fb_info[unit]->address + FB_OFFSET_IREQ; + *ack = 0; + +#if mips + splx(spllevel); +#endif + lk201_led(unit); +} + +fb_vretrace(fb, on) + fb_softc_t *fb; +{ + int i; + + for (i = 0; i < NMFB; i++) + if (fb_info[i]->address == (vm_offset_t)fb->framebuffer) + break; + if (i == NMFB) return; + + (*tc_enable_interrupt)(fb_info[i]->adaptor, on, 0); +} + +/* + * Video on/off + */ +fb_video_on(fb, up) + fb_softc_t *fb; + user_info_t *up; +{ + if (!fb->cursor_state) /* video is "on" at boot */ + return; + bt455_video_on(fb->vdac_registers, up); + bt431_cursor_on(fb->cursor_registers); + fb->cursor_state = 0; +} + +fb_video_off(fb, up) + fb_softc_t *fb; + user_info_t *up; +{ + if (fb->cursor_state) + return; + bt455_video_off(fb->vdac_registers, up); + bt431_cursor_off(fb->cursor_registers); + fb->cursor_state = 1; +} + +/* + * Boot time initialization: must make device + * usable as console asap. + */ +extern int + fb_soft_reset(), fb_set_status(), + bt431_pos_cursor(), fb_video_on(), + fb_video_off(), fb_vretrace(), + pm_get_status(), pm_char_paint(), + pm_insert_line(), pm_remove_line(), + pm_clear_bitmap(), pm_map_page(); + +static struct screen_switch fb_sw = { + screen_noop, /* graphic_open */ + fb_soft_reset, /* graphic_close */ + fb_set_status, /* set_status */ + pm_get_status, /* get_status */ + pm_char_paint, /* char_paint */ + bt431_pos_cursor, /* pos_cursor */ + pm_insert_line, /* insert_line */ + pm_remove_line, /* remove_line */ + pm_clear_bitmap, /* clear_bitmap */ + fb_video_on, /* video_on */ + fb_video_off, /* video_off */ + fb_vretrace, /* intr_enable */ + pm_map_page /* map_page */ +}; + +fb_cold_init(unit, up) + user_info_t *up; +{ + fb_softc_t *fb; + screen_softc_t sc = screen(unit); + vm_offset_t base = tc_probe("fb"); + + bcopy(&fb_sw, &sc->sw, sizeof(sc->sw)); +#if 0 + sc->flags |= MONO_SCREEN; +#else + sc->flags |= COLOR_SCREEN; +#endif + sc->frame_scanline_width = 2048; + sc->frame_height = 1024; + sc->frame_visible_width = 1280; + sc->frame_visible_height = 1024; + + pm_init_screen_params(sc, up); + (void) screen_up(unit, up); + + fb = pm_alloc(unit, base+FB_OFFSET_BT431, base+FB_OFFSET_VRAM, -1); + fb->vdac_registers = (char*) base + FB_OFFSET_BT455; + + screen_default_colors(up); + + fb_soft_reset(sc); + + /* + * Clearing the screen at boot saves from scrolling + * much, and speeds up booting quite a bit. + */ + screen_blitc( unit, 'C'-'@');/* clear screen */ +} + +#endif (NMFB > 0) diff --git a/chips/fb_misc.c b/chips/fb_misc.c new file mode 100644 index 0000000..3a99dcd --- /dev/null +++ b/chips/fb_misc.c @@ -0,0 +1,242 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: fb_misc.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 7/91 + * + * Driver for the PMAG-AA simple mono framebuffer + * + */ + +#include +#if (NMFB > 0) + +/* + * NOTE: This driver relies heavily on the pm one. + */ + +#include +#include +#include +typedef pm_softc_t fb_softc_t; + +#include + +/* + * Initialize color map, for kernel use + */ +fb_init_colormap(sc) + screen_softc_t sc; +{ + fb_softc_t *fb = (fb_softc_t*)sc->hw_state; + user_info_t *up = sc->up; + color_map_t Bg_Fg[2]; + register int i; + + bt455_init_colormap( fb->vdac_registers ); + + /* init bg/fg colors */ + for (i = 0; i < 3; i++) { + up->dev_dep_2.pm.Bg_color[i] = 0x00; + up->dev_dep_2.pm.Fg_color[i] = 0xff; + } + + Bg_Fg[0].red = Bg_Fg[0].green = Bg_Fg[0].blue = 0x00; + Bg_Fg[1].red = Bg_Fg[1].green = Bg_Fg[1].blue = 0xff; + bt455_cursor_color( fb->vdac_registers, Bg_Fg); +} + +/* + * Large viz small cursor + */ +fb_small_cursor_to_large(up, cursor) + user_info_t *up; + cursor_sprite_t cursor; +{ + unsigned char *curbytes, *sprite; + int i; + /* Our cursor turns out mirrored, donno why */ + static unsigned char mirror[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff + }; + + /* Clear out old cursor */ + bzero( up->dev_dep_2.pm.cursor_sprite, + sizeof(up->dev_dep_2.pm.cursor_sprite)); + + /* small cursor is 32x2 bytes, image(fg) first then mask(bg) */ + curbytes = (unsigned char *) cursor; + + /* we have even byte --> image, odd byte --> mask; + line size is 8 bytes instead of 2 */ + sprite = (unsigned char *) up->dev_dep_2.pm.cursor_sprite; + + for (i = 0; i < 32; i += 2) { + *sprite++ = mirror[curbytes[i]]; /* fg */ + *sprite++ = mirror[curbytes[i + 32]]; /* bg */ + *sprite++ = mirror[curbytes[i + 1]]; /* fg */ + *sprite++ = mirror[curbytes[i + 33]]; /* bg */ + sprite += 12; /* skip rest of the line */ + } +} + +/* + * Device-specific set status + */ +fb_set_status(sc, flavor, status, status_count) + screen_softc_t sc; + int flavor; + dev_status_t status; + unsigned int status_count; +{ + fb_softc_t *fb = (fb_softc_t*) sc->hw_state; + + switch (flavor) { + + case SCREEN_ADJ_MAPPED_INFO: + return pm_set_status(sc, flavor, status, status_count); + + case SCREEN_LOAD_CURSOR: + + if (status_count < sizeof(cursor_sprite_t)/sizeof(int)) + return D_INVALID_SIZE; + fb_small_cursor_to_large(sc->up, (cursor_sprite_t*) status); + + /* Fall through */ + + case SCREEN_LOAD_CURSOR_LONG: { /* 3max/3min only */ + + sc->flags |= SCREEN_BEING_UPDATED; + bt431_cursor_sprite(fb->cursor_registers, sc->up->dev_dep_2.pm.cursor_sprite); + sc->flags &= ~SCREEN_BEING_UPDATED; + + break; + } + + case SCREEN_SET_CURSOR_COLOR: { + color_map_t c[2]; + register cursor_color_t *cc = (cursor_color_t*) status; + + c[0].red = cc->Bg_rgb[0]; + c[0].green = cc->Bg_rgb[1]; + c[0].blue = cc->Bg_rgb[2]; + c[1].red = cc->Fg_rgb[0]; + c[1].green = cc->Fg_rgb[1]; + c[1].blue = cc->Fg_rgb[2]; + + sc->flags |= SCREEN_BEING_UPDATED; + bt455_cursor_color (fb->vdac_registers, c ); + sc->flags &= ~SCREEN_BEING_UPDATED; + + break; + } + + case SCREEN_SET_CMAP_ENTRY: { + color_map_entry_t *e = (color_map_entry_t*) status; + + if (e->index < 8) { /* 8&9 are fg&bg, do not touch */ + sc->flags |= SCREEN_BEING_UPDATED; + bt455_load_colormap_entry( fb->vdac_registers, e->index, &e->value); + sc->flags &= ~SCREEN_BEING_UPDATED; + } + break; + } + + default: + return D_INVALID_OPERATION; + } + return D_SUCCESS; +} + +/* + * Do what's needed when X exits + */ +fb_soft_reset(sc) + screen_softc_t sc; +{ + fb_softc_t *fb = (fb_softc_t*) sc->hw_state; + user_info_t *up = sc->up; + extern cursor_sprite_t bt431_default_cursor; + + /* + * Restore params in mapped structure + */ + pm_init_screen_params(sc,up); + up->row = up->max_row - 1; + + up->dev_dep_2.pm.x26 = 2; /* you do not want to know */ + up->dev_dep_1.pm.x18 = (short*)2; + + /* + * Restore RAMDAC chip to default state, and init cursor + */ + bt455_init(fb->vdac_registers); + bt431_init(fb->cursor_registers); + + /* + * Load kernel's cursor sprite + */ + bt431_cursor_sprite(fb->cursor_registers, bt431_default_cursor); + + /* + * Color map and cursor color + */ + fb_init_colormap(sc); +} + +#endif (NMFB > 0) diff --git a/chips/fdc_82077.h b/chips/fdc_82077.h new file mode 100644 index 0000000..9519218 --- /dev/null +++ b/chips/fdc_82077.h @@ -0,0 +1,525 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: fdi_82077_hdw.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 1/92 + * + * Defines for the Intel 82077 Floppy Disk Controller chip. + * Includes defines for 8272A and 82072. + */ + +#ifndef _FDC_82077_H_ +#define _FDC_82077_H_ + +/* + * Chips we claim to understand, and their modes + */ +#define fdc_8272a 0 +#define fdc_82072 1 +#define fdc_82077aa 2 + +#define at_mode 0 +#define ps2_mode 1 +#define mod30_mode 2 + +#define DRIVES_PER_FDC 4 + +/* + * Register maps + */ +typedef struct { + volatile unsigned char fd_sra; /* r: status register A */ + volatile unsigned char fd_srb; /* r: status register B */ + volatile unsigned char fd_dor; /* rw: digital output reg */ + volatile unsigned char fd_tdr; /* rw: tape drive register */ + volatile unsigned char fd_msr; /* r: main status register */ +#define fd_dsr fd_msr /* w: data rate select reg */ + volatile unsigned char fd_data; /* rw: fifo */ + volatile unsigned char fd_xxx; /* --reserved-- */ + volatile unsigned char fd_dir; /* r: digital input reg */ +#define fd_ccr fd_dir /* w: config control reg */ +} fd_regmap_t; + +typedef struct { + volatile unsigned char fd_msr; /* r: main status register */ + volatile unsigned char fd_data; /* rw: data register */ +} fd_8272a_regmap_t; + +typedef fd_8272a_regmap_t fd_82072_regmap_t; +/*#define fd_dsr fd_msr /* w: data rate select reg */ + +/* + * Status register A (82077AA only) + * + * Only available in PS/2 (ps2) and Model 30 (m30) modes, + * not available in PC/AT (at) mode. + * Some signals have inverted polarity (~) on mod30 + */ + +#define FD_SRA_INT 0x80 /* interrupt */ +#define FD_SRA_DRV2 0x40 /* 2nd drive installed (ps2) */ +#define FD_SRA_DRQ 0x40 /* dma request (mod30) */ +#define FD_SRA_STEP 0x20 /* step pulse (~mod30) */ +#define FD_SRA_TRK0 0x10 /* Track 0 (~mod30) */ +#define FD_SRA_HDSEL 0x08 /* select head 1 (~mod30) */ +#define FD_SRA_INDX 0x04 /* Index hole (~mod30) */ +#define FD_SRA_WP 0x02 /* write protect (~mod30) */ +#define FD_SRA_DIR 0x01 /* step dir, 1->center (~mod30) */ + +/* + * Status register B (82077AA only) + * Not available in at mode. + */ + +#define FD_SRB_DRV2 0x80 /* 2nd drive installed (mod30) */ + /* wired 1 on ps2 */ + +#define FD_SRB_DS1 0x40 /* drive select 1 (mod30) */ + /* wired 1 on ps2 */ + +#define FD_SRB_DS0 0x20 /* drive select 0 */ +#define FD_SRB_WRDATA 0x10 /* out data (toggle or ~trigger) */ +#define FD_SRB_RDDATA 0x08 /* in data (toggle or ~trigger) */ +#define FD_SRB_WE 0x04 /* write enable (~mod30) */ +#define FD_SRB_MOT_1 0x02 /* motor enable drive 1 (ps2) */ +#define FD_SRB_DS3 0x02 /* drive select 3 (mod30) */ +#define FD_SRB_MOT_0 0x01 /* motor enable drive 0 (ps2) */ +#define FD_SRB_DS2 0x01 /* drive select 2 (mod30) */ + +/* + * Digital output register (82077AA only) + */ + +#define FD_DOR_MOT_3 0x80 /* motor enable drive 3 */ +#define FD_DOR_MOT_2 0x40 +#define FD_DOR_MOT_1 0x20 +#define FD_DOR_MOT_0 0x10 +#define FD_DOR_DMA_GATE 0x08 /* enable dma (mod30,at) */ +#define FD_DOR_ENABLE 0x04 /* chip reset (inverted) */ +#define FD_DOR_DRIVE_0 0x00 /* select drive no 0 */ +#define FD_DOR_DRIVE_1 0x01 +#define FD_DOR_DRIVE_2 0x02 +#define FD_DOR_DRIVE_3 0x03 + +/* + * Tape drive register (82077AA only) + */ + +#define FD_TDR_TAPE_1 0x01 /* unit 1 is a tape */ +#define FD_TDR_TAPE_2 0x02 +#define FD_TDR_TAPE_3 0x03 +#define FD_TDR_xxx 0xfc + +/* + * Data-rate select register (82077AA and 82072) + */ + +#define FD_DSR_RESET 0x80 /* self-clearing reset */ +#define FD_DSR_POWER_DOWN 0x40 /* stop clocks and oscill */ +#define FD_DSR_zero 0x20 /* wired zero on 82077AA */ +#define FD_DSR_EPLL 0x20 /* enable PLL on 82072 */ + +#define FD_DSR_PRECOMP_MASK 0x1c /* precompensation value */ +# define FD_DSR_PRECOMP_SHIFT 2 + +# define FD_DSR_PRECOMP_DEFAULT 0 /* 41.67@1Mbps else 125ns */ +# define FD_DSR_PRECOMP_41_67 1 +# define FD_DSR_PRECOMP_83_34 2 +# define FD_DSR_PRECOMP_125_00 3 +# define FD_DSR_PRECOMP_166_67 4 +# define FD_DSR_PRECOMP_208_33 5 +# define FD_DSR_PRECOMP_250_00 6 +# define FD_DSR_PRECOMP_DISABLE 7 /* 0.00ns */ + +#define FD_DSR_DATA_RATE_MASK 0x03 +#define FD_DSR_SD_250 0x00 /* fm modulation, 250Kbps bit clock */ +#define FD_DSR_SD_150 0x01 +#define FD_DSR_SD_125 0x02 + +#define FD_DSR_DD_500 0x00 /* mfm modulation, 500Kbps */ +#define FD_DSR_DD_300 0x01 +#define FD_DSR_DD_250 0x02 +#define FD_DSR_DD_1000 0x03 /* illegal for 82077 */ + +/* + * Main status register (all chips) + */ + +#define FD_MSR_RQM 0x80 /* request from master (allowed) */ +#define FD_MSR_DIO 0x40 /* data in/out, 1->master read */ +#define FD_MSR_NON_DMA 0x20 /* dma disabled */ +#define FD_MSR_CMD_BSY 0x10 /* command in progress */ +#define FD_MSR_DRV_3_BSY 0x08 /* drive busy seeking */ +#define FD_MSR_DRV_2_BSY 0x04 +#define FD_MSR_DRV_1_BSY 0x02 +#define FD_MSR_DRV_0_BSY 0x01 + +/* + * FIFO (82077AA and 82072) + * + * Service delay is + * Threshold * 8 + * delay = ------------- - 1.5 usecs + * Data-rate + */ + +#define FD_FIFO_DEEP 16 + +/* + * Digital input register (82077AA only) + */ + +#define FD_DIR_DSK_CHG 0x80 /* disk was changed (~mod30) */ + +#define FD_DIR_ones 0x78 /* wired ones for ps2 */ +#define FD_DIR_zeroes 0x70 /* wired zeroes for mod30 */ +#define FD_DIR_undef 0x7f /* undefined for at */ + +#define FD_DIR_DR_MASK_PS2 0x06 /* current data rate (ps2) */ +# define FD_DIR_DR_SHIFT_PS2 1 +#define FD_DIR_LOW_DENS 0x01 /* zero for 500/1M dr (ps2) */ + +#define FD_DIR_DMA_GATE 0x08 /* same as DOR (mod30) */ +#define FD_DIR_NOPREC 0x04 /* same as CCR (mod30) */ +#define FD_DIR_DR_MASK_M30 0x03 /* current data rate (mod30) */ +# define FD_DIR_DR_SHIFT_M30 0 + +/* + * Configuration control register (82077AA only) + */ + +#define FD_CCR_DATA_RATE_MASK 0x03 /* see DSR for values */ +#define FD_CCR_NOPREC 0x04 /* "has no function" (mod30) */ + + +/* + * Programming + * + * Legend for command bytes, when applicable + * + * hds bit 2 of byte 1, head select (1 -> head 1) + * ds bits 0-1 of byte 1, drive select + * c cylinder number (max 76 for 8272A, else 255) + * h head number + * r sector number + * n number of bytes in sector + * eot end-of-track, e.g. final sector number + * gpl gap length + * dtl data length (for partial sectors) + * st0-3 status byte + * srt step rate time + * hut head unload time + * hlt head load time + * nd disable DMA + * mot do not turn motor on before checking drive status + * pcn present cylinder number + * ncn new cylinder number + * rcn relative cylinder number (new=present+rcn) + * sc sectors/cylinder + * d filler byte + * ? undefined + * hsda high-speed disk adjust (doubles motor on/off delays) + * moff motor off timer, one disk revolution increments + * mon motor on timer, ditto + * eis enable implied seeks + * dfifo disable fifo + * poll disable poll + * fifthr fifo threshold (1 to 16 bytes) + * pretrk precomp starts on this trackno (0-255) + * wgate change timings of WE signal, in perpendicular mode + * gap change gap2 length, in perpendicular mode + * ec in verify, qualify terminating conditions (sc viz eot) + */ + +/* First byte of command, qualifiers */ +#define FD_CMD_MT 0x80 /* Multi-track */ +#define FD_CMD_MFM 0x40 /* Double density */ +#define FD_CMD_SK 0x20 /* skip deleted data address mark */ +#define FD_CMD_DIR 0x40 /* relative seek direction (up) */ + +/* command codes and description */ + +/* + * Read an entire track. + * Qualifiers: MFM, SK (8272A only) + * Bytes total: 9 code,hds+ds,c,h,r,n,eot,gpl,dtl + * Result total: 7 st0,st1,st2,c,h,r,n + */ +#define FD_CMD_READ_TRACK 0x02 + +/* + * Specify timers + * Qualifiers: + * Bytes total: 3 code,srt+hut,hlt+nd + * Result total: + */ +#define FD_CMD_SPECIFY 0x03 + +/* + * Sense status of drive + * Qualifiers: + * Bytes total: 2 code,hds+ds +mot(82072 only) + * Result total: 1 st3 + */ +#define FD_CMD_SENSE_DRIVE_STATUS 0x04 +# define FD_CMD_SDS_NO_MOT 0x80 + +/* + * Write + * Qualifiers: MT, MFM + * Bytes total: 9 code,hds+ds,c,h,r,n,eot,gpl,dtl + * Result total: 7 st0,st1,st2,c,h,r,n + */ +#define FD_CMD_WRITE_DATA 0x05 + +/* + * Read + * Qualifiers: MT, MFM, SK + * Bytes total: 9 code,hds+ds,c,h,r,n,eot,gpl,dtl + * Result total: 7 st0,st1,st2,c,h,r,n + */ +#define FD_CMD_READ_DATA 0x06 + +/* + * Seek to track 0 + * Qualifiers: + * Bytes total: 2 code,ds + * Result total: + */ +#define FD_CMD_RECALIBRATE 0x07 + +/* + * Sense interrupt status + * Qualifiers: + * Bytes total: 1 code + * Result total: 2 st0,pcn + */ +#define FD_CMD_SENSE_INT_STATUS 0x08 + +/* + * Write data and mark deleted + * Qualifiers: MT, MFM + * Bytes total: 9 code,hds+ds,c,h,r,n,eot,gpl,dtl + * Result total: 7 st0,st1,st2,c,h,r,n + */ +#define FD_CMD_WRITE_DELETED_DATA 0x09 + +/* + * Read current head position + * Qualifiers: MFM + * Bytes total: 2 code,hds+ds + * Result total: 7 st0,st1,st2,c,h,r,n + */ +#define FD_CMD_READ_ID 0x0a + +/* + * Set value of MOT pin, unconditionally + * Qualifiers: see + * Bytes total: 1 code+.. + * Result total: none returns to command phase + */ +#define FD_CMD_MOTOR_ON_OFF 0x0b /* 82072 only */ + +# define FD_CMD_MOT_ON 0x80 +# define FD_CMD_MOT_DS 0x60 +# define FD_CMD_MOT_DS_SHIFT 5 + +/* + * Read data despite deleted address mark + * Qualifiers: MT, MFM, SK + * Bytes total: 9 code,hds+ds,c,h,r,n,eot,gpl,dtl + * Result total: 7 st0,st1,st2,c,h,r,n + */ +#define FD_CMD_READ_DELETED_DATA 0x0c + +/* + * Media initialization + * Qualifiers: MFM + * Bytes total: 6 code,hds+ds,n,sc,gpl,d + * Data: 4*sc/2 c,h,r,n + * Result total: 7 st0,st1,st2,?,?,?,? + */ +#define FD_CMD_FORMAT_TRACK 0x0d + +/* + * Dump internal register status + * Qualifiers: + * Bytes total: 1 code + * Result total: 10 pcn0,pcn1,pcn2,pcn3,srt+hut,hlt+nd, + * sc/eot,hsda+moff+mon, + * eis+dfifo+poll+fifothr, pretrk + * Notes: 82077AA does not provide for hsda+moff+mon + */ +#define FD_CMD_DUMPREG 0x0e /* not 8272a */ + +/* + * Move head + * Qualifiers: + * Bytes total: 3 code,hds+ds,ncn + * Result total: + */ +#define FD_CMD_SEEK 0x0f + +/* + * + * Qualifiers: + * Bytes total: 1 code + * Result total: 1 version + */ +#define FD_CMD_VERSION 0x10 /* 82077AA only */ +# define FD_VERSION_82077AA 0x90 + +/* + * Scan disk data + * Qualifiers: MT, MFM, SK + * Bytes total: 9 code,hds+ds,c,h,r,n,eot,gpl,dtl + * Result total: 7 st0,st1,st2,c,h,r,n + */ +#define FD_CMD_SCAN_EQUAL 0x11 /* 8272A only */ + +/* + * Specify timers + * Qualifiers: + * Bytes total: 2 code,wgate+gap + * Result total: + */ +#define FD_CMD_PERPENDICULAR_MODE 0x12 /* 82077AA only */ + +/* + * Set configuration parameters + * Qualifiers: + * Bytes total: 4 code,hsda+moff+mon,eis+dfifo+poll+fifothr, + * pretrk + * Result total: + * Notes: 82077AA does not provide for hsda+moff+mon + */ +#define FD_CMD_CONFIGURE 0x13 /* not 8272a */ + +/* + * Verify CRC of disk data + * Qualifiers: MT, MFM, SK + * Bytes total: 9 code,ec+hds+ds,c,h,r,n,eot,gpl,dtl/sc + * Result total: 7 st0,st1,st2,c,h,r,n + */ +#define FD_CMD_VERIFY 0x16 /* 82077AA only */ + +/* + * Scan disk data (disk less-or-equal memory) + * Qualifiers: MT, MFM, SK + * Bytes total: 9 code,hds+ds,c,h,r,n,eot,gpl,dtl + * Result total: 7 st0,st1,st2,c,h,r,n + */ +#define FD_CMD_SCAN_LOW_OR_EQUAL 0x19 /* 8272A only */ + +/* + * Scan disk data (disk greater-or-equal memory) + * Qualifiers: MT, MFM, SK + * Bytes total: 9 code,hds+ds,c,h,r,n,eot,gpl,dtl + * Result total: 7 st0,st1,st2,c,h,r,n + */ +#define FD_CMD_SCAN_HIGH_OR_EQUAL 0x1d /* 8272A only */ + +/* + * Specify timers + * Qualifiers: DIR + * Bytes total: 3 code,hds+ds,rcn + * Result total: + */ +#define FD_CMD_RELATIVE_SEEK 0x8f /* not 8272a */ + +/* + * Any invalid command code + * Qualifiers: + * Bytes total: 1 code + * Result total: 1 st0 (st0 == 0x80) + */ +#define FD_CMD_INVALID 0xff + + +/* + * Results and statii + * + * The typical command returns three status bytes, + * followed by four drive status bytes. + */ + +/* + * Status register 0 + */ +#define FD_ST0_IC_MASK 0xc0 /* interrupt completion code */ + +# define FD_ST0_IC_OK 0x00 /* terminated ok */ +# define FD_ST0_IC_AT 0x40 /* exec phase ended sour */ +# define FD_ST0_IC_BAD_CMD 0x80 /* didnt grok */ +# define FD_ST0_IC_AT_POLL 0xc0 /* polling got in the way */ + +#define FD_ST0_SE 0x20 /* (implied) seek ended */ +#define FD_ST0_EC 0x10 /* equipment check */ +#define FD_ST0_NR 0x08 /* not ready (raz for 82077aa) */ +#define FD_ST0_H 0x04 /* currently selected head */ +#define FD_ST0_DS 0x03 /* currently selected drive */ + +/* + * Status register 1 + */ + +#define FD_ST1_EN 0x80 /* end of cylinder (TC not set?) */ +#define FD_ST1_zero 0x48 +#define FD_ST1_DE 0x20 /* data error, bad CRC */ +#define FD_ST1_OR 0x10 /* overrun/underrun +#define FD_ST1_ND 0x04 /* no data, sector not found */ +#define FD_ST1_NW 0x02 /* write protect signal */ +#define FD_ST1_MA 0x01 /* missing address mark */ + +/* + * Status register 2 + */ + +#define FD_ST2_zero 0x80 +#define FD_ST2_CM 0x40 /* control mark, improper read */ +#define FD_ST2_DD 0x20 /* the CRC error was for data */ +#define FD_ST2_WC 0x10 /* wrong cylinder */ +#define FD_ST2_SH 0x08 /* scan hit (8272a only) */ +#define FD_ST2_SN 0x04 /* scan not met (8272a only) */ +#define FD_ST2_BC 0x02 /* bad cylinder, has 0xff mark */ +#define FD_ST2_MD 0x01 /* missing data mark */ + +/* + * Status register 3 + * (sense drive status) + */ + +#define FD_ST3_FT 0x80 /* fault pin (0 if not 8272a) */ +#define FD_ST3_WP 0x40 /* write protect pin */ +#define FD_ST3_RDY 0x20 /* ready pin (1 on 82077aa) */ +#define FD_ST3_T0 0x10 /* track0 pin */ +#define FD_ST3_TS 0x08 /* two-sided pin (1 if not 8272a) */ +#define FD_ST3_HD 0x04 /* hdsel pin */ +#define FD_ST3_DS 0x03 /* drive select pins (1&0) */ + + +#endif /* _FDC_82077_H_ */ diff --git a/chips/fdc_82077_hdw.c b/chips/fdc_82077_hdw.c new file mode 100644 index 0000000..f52da83 --- /dev/null +++ b/chips/fdc_82077_hdw.c @@ -0,0 +1,821 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: fdi_82077_hdw.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 1/92 + * + * Driver for the Intel 82077 Floppy Disk Controller. + */ + +#include +#if NFD > 0 + +#include +#include +#include + +#include +#include + +/* ---- */ +#include +#include +#include +#include +#define UNITNO(d) ((d)>>5) +#define SLAVENO(d) (((d)>>3)&0x3) +#define PARAMNO(d) ((d)&0x7) +/* ---- */ + +#ifdef MAXINE + +/* we can only take one */ +#define MAX_DRIVES 1 + +#define my_fdc_type fdc_82077aa +#define the_fdc_type fd->fdc_type +/* later: #define the_fdc_type my_fdc_type */ + +/* Registers are read/written as words, byte 0 */ +/* padding is to x40 boundaries */ +typedef struct { + volatile unsigned int fd_sra; /* r: status register A */ + int pad0[15]; + volatile unsigned int fd_srb; /* r: status register B */ + int pad1[15]; + volatile unsigned int fd_dor; /* rw: digital output reg */ + int pad2[15]; + volatile unsigned int fd_tdr; /* rw: tape drive register */ + int pad3[15]; + volatile unsigned int fd_msr; /* r: main status register */ +/*#define fd_dsr fd_msr; /* w: data rate select reg */ + int pad4[15]; + volatile unsigned int fd_data; /* rw: fifo */ + int pad5[15]; + volatile unsigned int fd_xxx; /* --reserved-- */ + int pad6[15]; + volatile unsigned int fd_dir; /* r: digital input reg */ +/*#define fd_ccr fd_dir; /* w: config control reg */ +} fd_padded_regmap_t; + +#define machdep_reset_8272a(f,r) + +#else /* MAXINE */ + +/* Pick your chip and padding */ +#define my_fdc_type fdc_8272a +#define the_fdc_type my_fdc_type + +#define fd_padded_regmap_t fd_8272a_regmap_t + +#define machdep_reset_8272a(f,r) 1 + +#endif /* MAXINE */ + + +#ifndef MAX_DRIVES +#define MAX_DRIVES DRIVES_PER_FDC +#endif + +/* + * Autoconf info + */ + +static vm_offset_t fd_std[NFD] = { 0 }; +static struct bus_device *fd_info[NFD]; +static struct bus_ctlr *fd_minfo[NFD]; +static int fd_probe(), fd_slave(), fd_go(); +static void fd_attach(); + +struct bus_driver fd_driver = + { fd_probe, fd_slave, fd_attach, fd_go, fd_std, "fd", fd_info, + "fdc", fd_minfo, /*BUS_INTR_B4_PROBE*/}; + +/* + * Externally visible functions + */ +int fd_intr(); /* kernel */ + +/* + * Media table + * + * Cyls,Sec,spc,part,Mtype,RWFpl,FGpl + */ +typedef struct { + unsigned char d_cylperunit; + unsigned char d_secpercyl; + unsigned short d_secperunit; + unsigned char d_secpertrk; + unsigned char d_gpl; + unsigned char d_fgpl; + unsigned char d_xfer_rate; +} fd_params_t; + +fd_params_t fd_params[8] = { + {80, 18, 1440, 9, 0x2a, 0x50, FD_DSR_DD_250}, /* [0] 3.50" 720 Kb */ + {80, 36, 2880, 18, 0x1b, 0x6c, FD_DSR_DD_500}, /* [1] 3.50" 1.44 Meg */ + {40, 18, 720, 9, 0x2a, 0x50, FD_DSR_DD_250}, /* [2] 5.25" 360 Kb */ + {80, 30, 2400, 15, 0x1b, 0x54, FD_DSR_DD_500}, /* [3] 5.25" 1.20 Meg */ +}; + +/* + * Software status of chip + */ +struct fd_softc { + fd_padded_regmap_t *regs; + char fdc_type; + char fdc_mode; + char messed_up; + char slave_active; + struct slave_t { + io_req_t ior; + decl_simple_lock_data(,slave_lock) + + /* status at end of last command */ + unsigned char st0; + unsigned char st1; + unsigned char st2; + unsigned char c; + unsigned char h; + unsigned char r; + unsigned char n; + unsigned char st3; + /* ... */ + unsigned char medium_status; +# define ST_MEDIUM_PRESENT 1 +# define ST_MEDIUM_KNOWN 2 + char last_command; + char bytes_expected; + fd_params_t *params; + + } slave_status[DRIVES_PER_FDC]; +} fd_softc_data[NFD]; + +typedef struct fd_softc *fd_softc_t; + +fd_softc_t fd_softc[NFD]; + +static char *chip_names[4] = { "8272-A", "82072", "82077-AA", 0 }; +static char *mode_names[4] = { "PC AT", "PS/2", "Model 30", 0 }; + +/* + * Probe chip to see if it is there + */ +static fd_probe (reg, ctlr) + vm_offset_t reg; + struct bus_ctlr *ctlr; +{ + int unit = ctlr->unit; + fd_softc_t fd; + fd_padded_regmap_t *regs; + + /* + * See if we are here + */ + if (check_memory(reg, 0)) { + /* no rides today */ + return 0; + } + + fd = &fd_softc_data[unit]; + fd_softc[unit] = fd; + + regs = (fd_padded_regmap_t *)reg; + fd->regs = regs; + fd->fdc_type = my_fdc_type; + + fd_reset(fd); + + if (the_fdc_type == fdc_82077aa) { + /* See if properly functioning */ + unsigned char temp = FD_CMD_VERSION; + if (!fd_go(fd, 0, &temp, 1, 1)) + return 0; /* total brxage */ + if (!fd_get_result(fd, &temp, 1, FALSE)) + return 0; /* partial brxage */ + if (temp != FD_VERSION_82077AA) + printf( "{ %s x%x } ", + "Accepting non-82077aa version id", + temp); + } + + printf("%s%d: %s chip controller", + ctlr->name, ctlr->unit, chip_names[fd->fdc_type]); + if (the_fdc_type == fdc_82077aa) + printf(" in %s mode", mode_names[fd->fdc_mode]); + printf(".\n"); + + return 1; +} + +/* See if we like this slave */ +static fd_slave(ui, reg) + struct bus_device *ui; + vm_offset_t reg; +{ + int slave = ui->slave; + fd_softc_t fd; + unsigned char sns[2]; + + if (slave >= MAX_DRIVES) return 0; + + fd = fd_softc[ui->ctlr]; + + sns[0] = FD_CMD_SENSE_DRIVE_STATUS; + sns[1] = slave & 0x3; + if (the_fdc_type == fdc_82072) + sns[1] |= FD_CMD_SDS_NO_MOT; + if (!fd_go(fd, slave, sns, 2, 1)) return 0; + if (!fd_get_result(fd, sns, 1, FALSE)) return 0; + + fd->slave_status[slave].st3 = sns[0]; + + return 1; +} + +static void +fd_attach (ui) + struct bus_device *ui; +{ + /* Attach a slave */ +} + +static boolean_t +fd_go(fd, slave, cmd, cmdlen, reply_count) + fd_softc_t fd; + unsigned char cmd[]; +{ + + /* XXX check who active, enque ifnot */ + + fd->slave_active = slave; + fd->slave_status[slave].bytes_expected = reply_count; + fd->slave_status[slave].last_command = *cmd; + return fd_command(fd, cmd, cmdlen); +} + +fd_intr (unit, spllevel) +{ + fd_softc_t fd; + fd_padded_regmap_t *regs; + unsigned char msr; + register struct slave_t *slv; + + + splx(spllevel); + + fd = fd_softc[unit]; + regs = fd->regs; + + /* did polling see a media change */ + /* busy bit in msr sez ifasync or not */ + + msr = regs->fd_msr; + if ((msr & (FD_MSR_RQM|FD_MSR_DIO)) == (FD_MSR_RQM|FD_MSR_DIO)) { + + /* result phase */ +*(unsigned int *)0xbc040100 &= ~0x00600000; + + slv = &fd->slave_status[fd->slave_active]; + fd_get_result(fd, &slv->st0, slv->bytes_expected, FALSE); + fd_start(fd, fd->slave_active, TRUE); + return; + } + /* async interrupt, either seek complete or media change */ + while (1) { + unsigned char st[2]; + register int slave, m; + + *st = FD_CMD_SENSE_INT_STATUS; + fd_command(fd, st, 1); + + fd_get_result(fd, st, 2, FALSE); + + slave = *st & FD_ST0_DS; + slv = &fd->slave_status[slave]; + slv->c = st[1]; + + switch (*st & FD_ST0_IC_MASK) { + + case FD_ST0_IC_OK: +/* we get an FD_ST0_SE for RECALIBRATE. Wait for it or discard ? */ + + case FD_ST0_IC_AT: + + case FD_ST0_IC_BAD_CMD: + return; + + case FD_ST0_IC_AT_POLL: + m = slv->medium_status; + if (m & ST_MEDIUM_PRESENT) + m &= ~ST_MEDIUM_PRESENT; + else + m |= ST_MEDIUM_PRESENT; + slv->medium_status = m; + } + } +} + +/* + * Non-interface functions and utilities + */ + +fd_reset(fd) + fd_softc_t fd; +{ + register fd_padded_regmap_t *regs; + + regs = fd->regs; + + /* + * Reset the chip + */ + if (the_fdc_type == fdc_82072) + /* Fix if your box uses an external PLL */ + regs->fd_dsr = FD_DSR_RESET | FD_DSR_EPLL; + else if (the_fdc_type == fdc_82077aa) + regs->fd_dor = 0; + else + machdep_reset_8272a(fd, regs); + + delay(5); /* 4usecs in specs */ + + /* + * Be smart with the smart ones + */ + if (the_fdc_type == fdc_82077aa) { + + /* + * See in which mood we are (it cannot be changed) + */ + int temp; + + /* Take chip out of hw reset */ + regs->fd_dor = FD_DOR_ENABLE | FD_DOR_DMA_GATE; + delay(10); + + /* what do we readback from the DIR register as datarate ? */ + regs->fd_ccr = FD_DSR_SD_125; + delay(10); + + temp = regs->fd_dir; + if ((temp & 0x7) == FD_DSR_SD_125) + fd->fdc_mode = mod30_mode; + else if ((temp & (FD_DIR_ones | FD_DIR_DR_MASK_PS2)) == + ((FD_DSR_SD_125 << FD_DIR_DR_SHIFT_PS2) | FD_DIR_ones)) + fd->fdc_mode = ps2_mode; + else + /* this assumes tri-stated bits 1&2 read the same */ + fd->fdc_mode = at_mode; + + } + + /* + * Send at least 4 sense interrupt cmds, one per slave + */ + { + + unsigned char sns, st[2]; + int i, nloops; + + sns = FD_CMD_SENSE_INT_STATUS; + i = nloops = 0; + + do { + nloops++; + + (void) fd_command(fd, &sns, 1); + + st[0] = 0; /* in case bad status */ + (void) fd_get_result(fd, st, 2, TRUE); + + if ((st[0] & FD_ST0_IC_MASK) == FD_ST0_IC_AT_POLL) { + register int slave; + + slave = st[0] & FD_ST0_DS; + fd->slave_status[slave].st0 = st[0]; + fd->slave_status[slave].c = st[1]; + i++; + } + } while ( (nloops < 30) && + ((i < 4) || (st[0] != FD_ST0_IC_BAD_CMD)) ); + + /* sanity check */ + if (nloops == 30) { + (void) fd_messed_up(fd); + return; + } + } + + /* + * Install current parameters + */ + if (the_fdc_type != fdc_8272a) { + + unsigned char cnf[4]; + + /* send configure command to turn polling off */ + cnf[0] = FD_CMD_CONFIGURE; + cnf[1] = 0x60; /* moff 110 */ + cnf[2] = 0x48; /* eis, poll, thr=8 */ + cnf[3] = 0; + if (!fd_command(fd, cnf, 4)) + return; + /* no status */ + } + + /* + * Send specify to select defaults + */ + { + unsigned char sfy[3]; + + sfy[0] = FD_CMD_SPECIFY; +#if 0 + sfy[1] = (12 << 4) | 7; /* step 4, hut 112us @500 */ + sfy[2] = 2 << 1; /* hlt 29us @500 */ +#else + sfy[1] = (13 << 4) | 15; + sfy[2] = 1 << 1; +#endif + (void) fd_command(fd, sfy, 3); + /* no status */ + } +} + +#define FD_MAX_WAIT 1000 + +boolean_t +fd_command(fd, cmd, cmd_len) + fd_softc_t fd; + char *cmd; +{ + register fd_padded_regmap_t *regs; + + regs = fd->regs; + + while (cmd_len > 0) { + register int i, s; + + /* there might be long delays, so we pay this price */ + s = splhigh(); + for (i = 0; i < FD_MAX_WAIT; i++) + if ((regs->fd_msr & (FD_MSR_RQM|FD_MSR_DIO)) == + FD_MSR_RQM) + break; + else + delay(10); + if (i == FD_MAX_WAIT) { + splx(s); + return fd_messed_up(fd); + } + regs->fd_data = *cmd++; + splx(s); + if (--cmd_len) delay(12); + } + + return TRUE; +} + +boolean_t +fd_get_result(fd, st, st_len, ignore_errors) + fd_softc_t fd; + char *st; +{ + register fd_padded_regmap_t *regs; + + regs = fd->regs; + + while (st_len > 0) { + register int i, s; + + /* there might be long delays, so we pay this price */ + s = splhigh(); + for (i = 0; i < FD_MAX_WAIT; i++) + if ((regs->fd_msr & (FD_MSR_RQM|FD_MSR_DIO)) == + (FD_MSR_RQM|FD_MSR_DIO)) + break; + else + delay(10); + if (i == FD_MAX_WAIT) { + splx(s); + return (ignore_errors) ? FALSE : fd_messed_up(fd); + } + *st++ = regs->fd_data; + splx(s); + st_len--; + } + + return TRUE; +} + + +boolean_t +fd_messed_up(fd) + fd_softc_t fd; +{ + fd->messed_up++; + printf("fd%d: messed up, disabling.\n", fd - fd_softc_data); + /* here code to + ior->error = ..; + restart + */ + return FALSE; +} + +/* + * Debugging aids + */ + +fd_state(unit) +{ + fd_softc_t fd = fd_softc[unit]; + fd_padded_regmap_t *regs; + + if (!fd || !fd->regs) return 0; + regs = fd->regs; + if (the_fdc_type == fdc_8272a) + printf("msr %x\n", regs->fd_msr); + else + printf("sra %x srb %x dor %x tdr %x msr %x dir %x\n", + regs->fd_sra, regs->fd_srb, regs->fd_dor, + regs->fd_tdr, regs->fd_msr, regs->fd_dir); +} + +#endif + +/* to be moved in separate file, or the above modified to live with scsi */ + +fd_open(dev, mode, ior) + int dev; + dev_mode_t mode; + io_req_t ior; +{ + unsigned char cmd[2]; + fd_softc_t fd; + int slave; + + fd = fd_softc[UNITNO(dev)]; + slave = SLAVENO(dev); + + /* XXX find out what medium we have, automagically XXX */ + /* fornow, set params depending on minor */ + fd->slave_status[slave].params = &fd_params[PARAMNO(dev)]; + + /* XXXYYYXXXYYY SEND CONFIGURE if params changed */ + + /* Turn motor on */ + if (the_fdc_type == fdc_82072) { + + cmd[0] = FD_CMD_MOTOR_ON_OFF | FD_CMD_MOT_ON | + ((slave << FD_CMD_MOT_DS_SHIFT) & FD_CMD_MOT_DS); + (void) fd_go(fd, slave, cmd, 1, 0); + /* no status */ + + } else if (the_fdc_type == fdc_82077aa) { + + fd->regs->fd_dor |= ((1<regs->fd_dor &= ~((1<io_op & IO_READ) + bzero(ior->io_data, ior->io_count); + iodone(ior); +#else + struct slave_t *slv; + fd_softc_t fd; + unsigned int i, rec, max, dev; + fd_params_t *params; + + /* readonly */ + + dev = ior->io_unit; + + /* only one partition */ + fd = fd_softc[UNITNO(dev)]; + slv = &fd->slave_status[SLAVENO(dev)]; + params = slv->params; + max = params->d_secperunit; + rec = ior->io_recnum; + i = btodb(ior->io_count + DEV_BSIZE - 1); + if (((rec + i) > max) || (ior->io_count < 0)) { + ior->io_error = D_INVALID_SIZE; + ior->io_op |= IO_ERROR; + ior->io_residual = ior->io_count; + iodone(ior); + return; + } + + ior->io_residual = rec / params->d_secpercyl; + + /* + * Enqueue operation + */ + i = splbio(); + simple_lock(&slv->slave_lock); + if (slv->ior) { + disksort(slv->ior, ior); + simple_unlock(&slv->slave_lock); + } else { + ior->io_next = 0; + slv->ior = ior; + simple_unlock(&slv->slave_lock); + fd_start(fd, SLAVENO(dev), FALSE); + } + splx(i); +#endif +} + +fd_start(fd, slave, done) + boolean_t done; + fd_softc_t fd; +{ + register io_req_t ior; + struct slave_t *slv; + + slv = &fd->slave_status[slave]; + if ((ior = slv->ior) == 0) + return; + + if (done) { + /* .. errors .. */ + /* .. partial xfers .. */ + + /* dequeue next one */ + { + io_req_t next; + + simple_lock(&slv->target_lock); + next = ior->io_next; + slv->ior = next; + simple_unlock(&slv->target_lock); + + iodone(ior); + if (next == 0) + return; + + ior = next; + } + } + +#ifdef no_eis + if (slv->c != ior->io_residual) SEEK_it; +#endif + +/* setup dma */ +#if 1 + if (ior->io_op & IO_READ) /* like SCSI */ +#else + if ((ior->io_op & IO_READ) == 0) +#endif + { + *(unsigned int *)0xbc040100 |= 0x00200000 | 0x00400000; + } else { + *(unsigned int *)0xbc040100 &= ~0x00400000; + *(unsigned int *)0xbc040100 |= 0x00200000; + } + *(unsigned int *)0xbc040070 = (((unsigned int)kvtophys(ior->io_data))>>2)<<5; + *(unsigned int *)0xbc0401a0 = 13; + +#ifdef no_eis + if (slv->c == ior->io_residual) { +#else + { +#endif + unsigned char cmd[9]; + unsigned char head, sec; + fd_params_t *params; + + params = slv->params; + + fd->regs->fd_dsr = params->d_xfer_rate; + + sec = ior->io_recnum % params->d_secpercyl; + head = sec / params->d_secpertrk; + sec = (sec % params->d_secpertrk); + + cmd[0] = (ior->io_op & IO_READ) ? + FD_CMD_MT | FD_CMD_MFM | FD_CMD_READ_DATA : + FD_CMD_MT | FD_CMD_MFM | FD_CMD_WRITE_DATA; + cmd[1] = (head << 2) | slave; + cmd[2] = ior->io_residual; + cmd[3] = head; + cmd[4] = sec + 1; /* 0 starts at 1 :-) */ + cmd[5] = 0x2; /* 512 byte sectors */ + cmd[6] = params->d_secpertrk; + cmd[7] = params->d_gpl; + cmd[8] = 0xff; + + fd_go( fd, slave, cmd, 9, 7); + + } +} + +extern minphys(); + +fd_read(dev, ior) + int dev; + io_req_t ior; +{ + return block_io(fd_strategy, minphys, ior); +} + +int fdc_write_enable = 1; + +fd_write(dev, ior) + int dev; + io_req_t ior; +{ +/* check if writeable */ + +if (fdc_write_enable) + return block_io(fd_strategy, minphys, ior); +else return D_SUCCESS; +} + +fd_set_status(dev, flavor, status, status_count) + int dev; + int flavor; + dev_status_t status; + unsigned int *status_count; +{ + printf("fdc_set_status(%x, %x, %x, %x)", dev, flavor, status, status_count); + return D_SUCCESS; +} + +fd_get_status(dev, flavor, status, status_count) + int dev; + int flavor; + dev_status_t status; + unsigned int status_count; +{ + printf("fdc_get_status(%x, %x, %x, %x)", dev, flavor, status, status_count); + return D_SUCCESS; +} + diff --git a/chips/frc.c b/chips/frc.c new file mode 100644 index 0000000..7f033c3 --- /dev/null +++ b/chips/frc.c @@ -0,0 +1,150 @@ +/* + * Mach Operating System + * Copyright (c) 1993,1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: frc.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 3/92 + * + * Generic, mappable free running counter driver. + */ + +#include +#if NFRC > 0 + +#include +#include +#include + +/* + * Machine defines + * All you need to do to get this working on a + * random box is to define one macro and provide + * the correct virtual address. + */ +#include +#ifdef DECSTATION +#define btop(x) mips_btop(x) +#endif /* DECSTATION */ + +/* + * Autoconf info + */ + +static vm_offset_t frc_std[NFRC] = { 0 }; +static vm_size_t frc_offset[NFRC] = { 0 }; +static struct bus_device *frc_info[NFRC]; +static int frc_probe(vm_offset_t,struct bus_ctlr *); +static void frc_attach(struct bus_device *); + +struct bus_driver frc_driver = + { frc_probe, 0, frc_attach, 0, frc_std, "frc", frc_info, }; + +/* + * Externally visible functions + */ +io_return_t frc_openclose(int,int); /* user */ +vm_offset_t frc_mmap(int,vm_offset_t,vm_prot_t); +void frc_set_address(int,vm_size_t); + +/* + * FRC's in kernel virtual memory. For in-kernel timestamps. + */ +vm_offset_t frc_address[NFRC]; + +/* machine-specific setups */ +void +frc_set_address( + int unit, + vm_size_t offset) +{ + if (unit < NFRC) { + frc_offset[unit] = offset; + } +} + + +/* + * Probe chip to see if it is there + */ +static frc_probe ( + vm_offset_t reg, + struct bus_ctlr *ui) +{ + /* see if something present at the given address */ + if (check_memory(reg, 0)) { + frc_address[ui->unit] = 0; + return 0; + } + frc_std[ui->unit] = (vm_offset_t) reg; + printf("[mappable] "); + return 1; +} + +static void +frc_attach ( + struct bus_device *ui) +{ + if (ui->unit < NFRC) { + frc_address[ui->unit] = + (vm_offset_t) frc_std[ui->unit] + frc_offset[ui->unit]; + printf(": free running counter %d at kernel vaddr 0x%x", + ui->unit, frc_address[ui->unit]); + } + else + panic("frc: unknown unit number"); /* shouldn't happen */ +} + +int frc_intr() +{ + /* we do not expect interrupts */ + panic("frc_intr"); +} + +io_return_t +frc_openclose( + int dev, + int flag) +{ + if (frc_std[dev]) + return D_SUCCESS; + else + return D_NO_SUCH_DEVICE; +} + +vm_offset_t +frc_mmap( + int dev, + vm_offset_t off, + vm_prot_t prot) +{ + vm_offset_t addr; + if ((prot & VM_PROT_WRITE) || (off >= PAGE_SIZE) ) + return (-1); + addr = (vm_offset_t) frc_std[dev] + frc_offset[dev]; + return btop(pmap_extract(pmap_kernel(), addr)); +} + +#endif diff --git a/chips/ims332.c b/chips/ims332.c new file mode 100644 index 0000000..ebe6a6c --- /dev/null +++ b/chips/ims332.c @@ -0,0 +1,312 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: ims332.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 1/92 + * + * Routines for the Inmos IMS-G332 Colour video controller + */ + +#include + +#include +#include + +#include + +/* + * Generic register access + */ +typedef volatile unsigned char *ims332_padded_regmap_t; + +#ifdef MAXINE + +unsigned int +ims332_read_register(regs, regno) + unsigned char *regs; +{ + unsigned char *rptr; + register unsigned int val, v1; + + /* spec sez: */ + rptr = regs + 0x80000 + (regno << 4); + val = * ((volatile unsigned short *) rptr ); + v1 = * ((volatile unsigned short *) regs ); + + return (val & 0xffff) | ((v1 & 0xff00) << 8); +} + +ims332_write_register(regs, regno, val) + unsigned char *regs; + register unsigned int val; +{ + unsigned char *wptr; + + /* spec sez: */ + wptr = regs + 0xa0000 + (regno << 4); + * ((volatile unsigned int *)(regs)) = (val >> 8) & 0xff00; + * ((volatile unsigned short *)(wptr)) = val; +} + +#define assert_ims332_reset_bit(r) *r &= ~0x40 +#define deassert_ims332_reset_bit(r) *r |= 0x40 + +#else /*MAXINE*/ + +#define ims332_read_register(p,r) \ + ((unsigned int *)(p)) [ (r) ] +#define ims332_write_register(p,r,v) \ + ((unsigned int *)(p)) [ (r) ] = (v) + +#endif /*MAXINE*/ + + +/* + * Color map + */ +ims332_load_colormap( regs, map) + ims332_padded_regmap_t *regs; + color_map_t *map; +{ + register int i; + + for (i = 0; i < 256; i++, map++) + ims332_load_colormap_entry(regs, i, map); +} + +ims332_load_colormap_entry( regs, entry, map) + ims332_padded_regmap_t *regs; + color_map_t *map; +{ + /* ?? stop VTG */ + ims332_write_register(regs, IMS332_REG_LUT_BASE + (entry & 0xff), + (map->blue << 16) | + (map->green << 8) | + (map->red)); +} + +ims332_init_colormap( regs) + ims332_padded_regmap_t *regs; +{ + color_map_t m; + + m.red = m.green = m.blue = 0; + ims332_load_colormap_entry( regs, 0, &m); + + m.red = m.green = m.blue = 0xff; + ims332_load_colormap_entry( regs, 1, &m); + ims332_load_colormap_entry( regs, 255, &m); + + /* since we are at it, also fix cursor LUT */ + ims332_load_colormap_entry( regs, IMS332_REG_CURSOR_LUT_0, &m); + ims332_load_colormap_entry( regs, IMS332_REG_CURSOR_LUT_1, &m); + /* *we* do not use this, but the prom does */ + ims332_load_colormap_entry( regs, IMS332_REG_CURSOR_LUT_2, &m); +} + +#if 1/*debug*/ +ims332_print_colormap( regs) + ims332_padded_regmap_t *regs; +{ + register int i; + + for (i = 0; i < 256; i++) { + register unsigned int color; + + color = ims332_read_register( regs, IMS332_REG_LUT_BASE + i); + printf("%x->[x%x x%x x%x]\n", i, + (color >> 16) & 0xff, + (color >> 8) & 0xff, + color & 0xff); + } +} +#endif + +/* + * Video on/off + * + * It is unfortunate that X11 goes backward with white@0 + * and black@1. So we must stash away the zero-th entry + * and fix it while screen is off. Also must remember + * it, sigh. + */ +struct vstate { + ims332_padded_regmap_t *regs; + unsigned short off; +}; + +ims332_video_off(vstate, up) + struct vstate *vstate; + user_info_t *up; +{ + register ims332_padded_regmap_t *regs = vstate->regs; + register unsigned *save, csr; + + if (vstate->off) + return; + + /* Yes, this is awful */ + save = (unsigned *)up->dev_dep_2.gx.colormap; + + *save = ims332_read_register(regs, IMS332_REG_LUT_BASE); + + ims332_write_register(regs, IMS332_REG_LUT_BASE, 0); + + ims332_write_register( regs, IMS332_REG_COLOR_MASK, 0); + + /* cursor now */ + csr = ims332_read_register(regs, IMS332_REG_CSR_A); + csr |= IMS332_CSR_A_DISABLE_CURSOR; + ims332_write_register(regs, IMS332_REG_CSR_A, csr); + + vstate->off = 1; +} + +ims332_video_on(vstate, up) + struct vstate *vstate; + user_info_t *up; +{ + register ims332_padded_regmap_t *regs = vstate->regs; + register unsigned *save, csr; + + if (!vstate->off) + return; + + /* Like I said.. */ + save = (unsigned *)up->dev_dep_2.gx.colormap; + + ims332_write_register(regs, IMS332_REG_LUT_BASE, *save); + + ims332_write_register( regs, IMS332_REG_COLOR_MASK, 0xffffffff); + + /* cursor now */ + csr = ims332_read_register(regs, IMS332_REG_CSR_A); + csr &= ~IMS332_CSR_A_DISABLE_CURSOR; + ims332_write_register(regs, IMS332_REG_CSR_A, csr); + + vstate->off = 0; +} + +/* + * Cursor + */ +ims332_pos_cursor(regs,x,y) + ims332_padded_regmap_t *regs; + register int x,y; +{ + ims332_write_register( regs, IMS332_REG_CURSOR_LOC, + ((x & 0xfff) << 12) | (y & 0xfff) ); +} + + +ims332_cursor_color( regs, color) + ims332_padded_regmap_t *regs; + color_map_t *color; +{ + /* Bg is color[0], Fg is color[1] */ + ims332_write_register(regs, IMS332_REG_CURSOR_LUT_0, + (color->blue << 16) | + (color->green << 8) | + (color->red)); + color++; + ims332_write_register(regs, IMS332_REG_CURSOR_LUT_1, + (color->blue << 16) | + (color->green << 8) | + (color->red)); +} + +ims332_cursor_sprite( regs, cursor) + ims332_padded_regmap_t *regs; + unsigned short *cursor; +{ + register int i; + + /* We *could* cut this down a lot... */ + for (i = 0; i < 512; i++, cursor++) + ims332_write_register( regs, + IMS332_REG_CURSOR_RAM+i, *cursor); +} + +/* + * Initialization + */ +ims332_init(regs, reset, mon) + ims332_padded_regmap_t *regs; + unsigned int *reset; + xcfb_monitor_type_t mon; +{ + int shortdisplay, broadpulse, frontporch; + + assert_ims332_reset_bit(reset); + delay(1); /* specs sez 50ns.. */ + deassert_ims332_reset_bit(reset); + + /* CLOCKIN appears to receive a 6.25 Mhz clock --> PLL 12 for 75Mhz monitor */ + ims332_write_register(regs, IMS332_REG_BOOT, 12 | IMS332_BOOT_CLOCK_PLL); + + /* initialize VTG */ + ims332_write_register(regs, IMS332_REG_CSR_A, + IMS332_BPP_8 | IMS332_CSR_A_DISABLE_CURSOR); + delay(50); /* spec does not say */ + + /* datapath registers (values taken from prom's settings) */ + + frontporch = mon->line_time - (mon->half_sync * 2 + + mon->back_porch + + mon->frame_visible_width / 4); + + shortdisplay = mon->line_time / 2 - (mon->half_sync * 2 + + mon->back_porch + frontporch); + broadpulse = mon->line_time / 2 - frontporch; + + ims332_write_register( regs, IMS332_REG_HALF_SYNCH, mon->half_sync); + ims332_write_register( regs, IMS332_REG_BACK_PORCH, mon->back_porch); + ims332_write_register( regs, IMS332_REG_DISPLAY, + mon->frame_visible_width / 4); + ims332_write_register( regs, IMS332_REG_SHORT_DIS, shortdisplay); + ims332_write_register( regs, IMS332_REG_BROAD_PULSE, broadpulse); + ims332_write_register( regs, IMS332_REG_V_SYNC, mon->v_sync * 2); + ims332_write_register( regs, IMS332_REG_V_PRE_EQUALIZE, + mon->v_pre_equalize); + ims332_write_register( regs, IMS332_REG_V_POST_EQUALIZE, + mon->v_post_equalize); + ims332_write_register( regs, IMS332_REG_V_BLANK, mon->v_blank * 2); + ims332_write_register( regs, IMS332_REG_V_DISPLAY, + mon->frame_visible_height * 2); + ims332_write_register( regs, IMS332_REG_LINE_TIME, mon->line_time); + ims332_write_register( regs, IMS332_REG_LINE_START, mon->line_start); + ims332_write_register( regs, IMS332_REG_MEM_INIT, mon->mem_init); + ims332_write_register( regs, IMS332_REG_XFER_DELAY, mon->xfer_delay); + + ims332_write_register( regs, IMS332_REG_COLOR_MASK, 0xffffff); + + ims332_init_colormap( regs ); + + ims332_write_register(regs, IMS332_REG_CSR_A, + IMS332_BPP_8 | IMS332_CSR_A_DMA_DISABLE | IMS332_CSR_A_VTG_ENABLE); + +} diff --git a/chips/ims332.h b/chips/ims332.h new file mode 100644 index 0000000..edb2302 --- /dev/null +++ b/chips/ims332.h @@ -0,0 +1,137 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: ims332.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 1/92 + * + * Defines for the Inmos IMS-G332 Colour video controller + */ + + +#ifndef _CHIPS_IMS332_H_ +#define _CHIPS_IMS332_H_ 1 + +/* + * Although the chip is built to be memory-mapped + * it can be programmed for 32 or 64 bit addressing. + * Moreover, the hardware bits have been twisted + * even more on the machine I am writing this for. + * So I'll just define the chip's offsets and leave + * it to the implementation to define the rest. + */ + +#define IMS332_REG_BOOT 0x000 /* boot time config */ + +#define IMS332_REG_HALF_SYNCH 0x021 /* datapath registers */ +#define IMS332_REG_BACK_PORCH 0x022 +#define IMS332_REG_DISPLAY 0x023 +#define IMS332_REG_SHORT_DIS 0x024 +#define IMS332_REG_BROAD_PULSE 0x025 +#define IMS332_REG_V_SYNC 0x026 +#define IMS332_REG_V_PRE_EQUALIZE 0x027 +#define IMS332_REG_V_POST_EQUALIZE 0x028 +#define IMS332_REG_V_BLANK 0x029 +#define IMS332_REG_V_DISPLAY 0x02a +#define IMS332_REG_LINE_TIME 0x02b +#define IMS332_REG_LINE_START 0x02c +#define IMS332_REG_MEM_INIT 0x02d +#define IMS332_REG_XFER_DELAY 0x02e + +#define IMS332_REG_COLOR_MASK 0x040 /* color mask register */ + +#define IMS332_REG_CSR_A 0x060 + +#define IMS332_REG_CSR_B 0x070 + +#define IMS332_REG_TOP_SCREEN 0x080 /* top-of-screen offset */ + +#define IMS332_REG_CURSOR_LUT_0 0x0a1 /* cursor palette */ +#define IMS332_REG_CURSOR_LUT_1 0x0a2 +#define IMS332_REG_CURSOR_LUT_2 0x0a3 + +#define IMS332_REG_RGB_CKSUM_0 0x0c0 /* test registers */ +#define IMS332_REG_RGB_CKSUM_1 0x0c1 +#define IMS332_REG_RGB_CKSUM_2 0x0c2 + +#define IMS332_REG_CURSOR_LOC 0x0c7 /* cursor location */ + +#define IMS332_REG_LUT_BASE 0x100 /* color palette */ +#define IMS332_REG_LUT_END 0x1ff + +#define IMS332_REG_CURSOR_RAM 0x200 /* cursor bitmap */ +#define IMS332_REG_CURSOR_RAM_END 0x3ff + +/* + * Control register A + */ + +#define IMS332_CSR_A_VTG_ENABLE 0x000001 /* vertical timing generator */ +#define IMS332_CSR_A_INTERLACED 0x000002 /* screen format */ +#define IMS332_CSR_A_CCIR 0x000004 /* default is EIA */ +#define IMS332_CSR_A_SLAVE_SYNC 0x000008 /* else from our pll */ +#define IMS332_CSR_A_PLAIN_SYNC 0x000010 /* else tesselated */ +#define IMS332_CSR_A_SEPARATE_SYNC 0x000020 /* else composite */ +#define IMS332_CSR_A_VIDEO_ONLY 0x000040 /* else video+sync */ +#define IMS332_CSR_A_BLANK_PEDESTAL 0x000080 /* blank level */ +#define IMS332_CSR_A_CBLANK_IS_OUT 0x000100 +#define IMS332_CSR_A_CBLANK_NO_DELAY 0x000200 +#define IMS332_CSR_A_FORCE_BLANK 0x000400 +#define IMS332_CSR_A_BLANK_DISABLE 0x000800 +#define IMS332_CSR_A_VRAM_INCREMENT 0x003000 +# define IMS332_VRAM_INC_1 0x000000 +# define IMS332_VRAM_INC_256 0x001000 /* except interlaced->2 */ +# define IMS332_VRAM_INC_512 0x002000 +# define IMS332_VRAM_INC_1024 0x003000 +#define IMS332_CSR_A_DMA_DISABLE 0x004000 +#define IMS332_CSR_A_SYNC_DELAY_MASK 0x038000 /* 0-7 VTG clk delays */ +#define IMS332_CSR_A_PIXEL_INTERLEAVE 0x040000 +#define IMS332_CSR_A_DELAYED_SAMPLING 0x080000 +#define IMS332_CSR_A_BITS_PER_PIXEL 0x700000 +# define IMS332_BPP_1 0x000000 +# define IMS332_BPP_2 0x100000 +# define IMS332_BPP_4 0x200000 +# define IMS332_BPP_8 0x300000 +# define IMS332_BPP_15 0x400000 +# define IMS332_BPP_16 0x500000 +#define IMS332_CSR_A_DISABLE_CURSOR 0x800000 + + +/* + * Control register B is mbz + */ + +/* + * Boot register + */ + +#define IMS332_BOOT_PLL 0x00001f /* xPLL, binary */ +#define IMS332_BOOT_CLOCK_PLL 0x000020 /* else xternal */ +#define IMS332_BOOT_64_BIT_MODE 0x000040 /* else 32 */ +#define IMS332_BOOT_xxx 0xffff80 /* reserved, mbz */ + + +#endif _CHIPS_IMS332_H_ diff --git a/chips/isdn_79c30.h b/chips/isdn_79c30.h new file mode 100644 index 0000000..2e7b5d7 --- /dev/null +++ b/chips/isdn_79c30.h @@ -0,0 +1,165 @@ +/* + * Mach Operating System + * Copyright (c) 1993 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/*- + * Copyright (c) 1991, 1992 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 Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. The name of the Laboratory may not 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. + */ + +/* + * Bit encodings for chip commands from "Microprocessor Access Guide for + * Indirect Registers", p.19 Am79C30A/32A Advanced Micro Devices spec + * sheet (preliminary). + * + * Indirect register numbers (the value written into cr to select a given + * chip registers) have the form AMDR_*. Register fields look like AMD_*. + */ + +typedef struct { + volatile unsigned char cr; /* command register (wo) */ +#define ir cr /* interrupt register (ro) */ + volatile unsigned char dr; /* data register (rw) */ + volatile unsigned char dsr1; /* D-channel status register 1 (ro) */ + volatile unsigned char der; /* D-channel error register (ro) */ + volatile unsigned char dctb; /* D-channel transmit register (wo) */ +#define dcrb dctb /* D-channel receive register (ro) */ + volatile unsigned char bbtb; /* Bb-channel transmit register (wo) */ +#define bbrb bbtb /* Bb-channel receive register (ro) */ + volatile unsigned char bctb; /* Bc-channel transmit register (wo)*/ +#define bcrb bctb /* Bc-channel receive register (ro) */ + volatile unsigned char dsr2; /* D-channel status register 2 (ro) */ +} amd79c30_regmap_t; + +#define AMDR_INIT 0x21 +#define AMD_INIT_PMS_IDLE 0x00 +#define AMD_INIT_PMS_ACTIVE 0x01 +#define AMD_INIT_PMS_ACTIVE_DATA 0x02 +#define AMD_INIT_INT_DISABLE (0x01 << 2) +#define AMD_INIT_CDS_DIV2 (0x00 << 3) +#define AMD_INIT_CDS_DIV1 (0x01 << 3) +#define AMD_INIT_CDS_DIV4 (0x02 << 3) +#define AMD_INIT_AS_RX (0x01 << 6) +#define AMD_INIT_AS_TX (0x01 << 7) + +#define AMDR_LIU_LSR 0xa1 +#define AMDR_LIU_LPR 0xa2 +#define AMDR_LIU_LMR1 0xa3 +#define AMDR_LIU_LMR2 0xa4 +#define AMDR_LIU_2_4 0xa5 +#define AMDR_LIU_MF 0xa6 +#define AMDR_LIU_MFSB 0xa7 +#define AMDR_LIU_MFQB 0xa8 + +#define AMDR_MUX_MCR1 0x41 +#define AMDR_MUX_MCR2 0x42 +#define AMDR_MUX_MCR3 0x43 +#define AMD_MCRCHAN_NC 0x00 +#define AMD_MCRCHAN_B1 0x01 +#define AMD_MCRCHAN_B2 0x02 +#define AMD_MCRCHAN_BA 0x03 +#define AMD_MCRCHAN_BB 0x04 +#define AMD_MCRCHAN_BC 0x05 +#define AMD_MCRCHAN_BD 0x06 +#define AMD_MCRCHAN_BE 0x07 +#define AMD_MCRCHAN_BF 0x08 +#define AMDR_MUX_MCR4 0x44 +#define AMD_MCR4_INT_ENABLE (1 << 3) +#define AMD_MCR4_SWAPBB (1 << 4) +#define AMD_MCR4_SWAPBC (1 << 5) + +#define AMDR_MUX_1_4 0x45 + +#define AMDR_MAP_X 0x61 +#define AMDR_MAP_R 0x62 +#define AMDR_MAP_GX 0x63 +#define AMDR_MAP_GR 0x64 +#define AMDR_MAP_GER 0x65 +#define AMDR_MAP_STG 0x66 +#define AMDR_MAP_FTGR 0x67 +#define AMDR_MAP_ATGR 0x68 +#define AMDR_MAP_MMR1 0x69 +#define AMD_MMR1_ALAW 0x01 +#define AMD_MMR1_GX 0x02 +#define AMD_MMR1_GR 0x04 +#define AMD_MMR1_GER 0x08 +#define AMD_MMR1_X 0x10 +#define AMD_MMR1_R 0x20 +#define AMD_MMR1_STG 0x40 +#define AMD_MMR1_LOOP 0x80 +#define AMDR_MAP_MMR2 0x6a +#define AMD_MMR2_AINB 0x01 +#define AMD_MMR2_LS 0x02 +#define AMD_MMR2_DTMF 0x04 +#define AMD_MMR2_GEN 0x08 +#define AMD_MMR2_RNG 0x10 +#define AMD_MMR2_DIS_HPF 0x20 +#define AMD_MMR2_DIS_AZ 0x40 +#define AMDR_MAP_1_10 0x6b + +#define AMDR_DLC_FRAR123 0x81 +#define AMDR_DLC_SRAR123 0x82 +#define AMDR_DLC_TAR 0x83 +#define AMDR_DLC_DRLR 0x84 +#define AMDR_DLC_DTCR 0x85 +#define AMDR_DLC_DMR1 0x86 +#define AMDR_DLC_DMR2 0x87 +#define AMDR_DLC_1_7 0x88 +#define AMDR_DLC_DRCR 0x89 +#define AMDR_DLC_RNGR1 0x8a +#define AMDR_DLC_RNGR2 0x8b +#define AMDR_DLC_FRAR4 0x8c +#define AMDR_DLC_SRAR4 0x8d +#define AMDR_DLC_DMR3 0x8e +#define AMDR_DLC_DMR4 0x8f +#define AMDR_DLC_12_15 0x90 +#define AMDR_DLC_ASR 0x91 diff --git a/chips/isdn_79c30_hdw.c b/chips/isdn_79c30_hdw.c new file mode 100644 index 0000000..769d1cb --- /dev/null +++ b/chips/isdn_79c30_hdw.c @@ -0,0 +1,602 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: isdn_79c30_hdw.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 1/92 + * + * Driver for the AMD 79c30 ISDN (Integrated Speech and + * Data Network) controller chip. + */ + +/*- + * Copyright (c) 1991, 1992 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 Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. The name of the Laboratory may not 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 +#if NISDN > 0 + +#include + +#include +#include +#include /* for Sun compat */ +#include + +#include +#include +#include +#include + +#include + +#include /* machdep config */ + +#define private static + +/* + * Autoconf info + */ +private int isdn_probe (vm_offset_t reg, struct bus_ctlr *ui); +private void isdn_attach ( struct bus_device *ui); + +private vm_offset_t isdn_std[NISDN] = { 0 }; +private struct bus_device *isdn_info[NISDN]; + +struct bus_driver isdn_driver = + { isdn_probe, 0, isdn_attach, 0, isdn_std, "isdn", isdn_info, }; + + +/* + * Externally visible functions and data + */ +int isdn_intr(); + + +/* + * Status bookeeping and globals + */ +typedef struct { + amd79c30_padded_regs_t *regs; + void *audio_status; /* for upcalls */ + struct mapreg sc_map; /* MAP status */ + /* + * keep track of levels so we don't have to convert back from + * MAP gain constants + */ + int sc_rlevel; /* record level */ + int sc_plevel; /* play level */ + int sc_mlevel; /* monitor level */ +} isdn_softc_t; + +isdn_softc_t isdn_softc_data[NISDN]; +isdn_softc_t *isdn_softc[NISDN]; + +private int audio_default_level = 150; + + +/* + * Forward decls + */ +audio_switch_t isdn_ops; + +private void isdn_init( isdn_softc_t *sc ); + +private void isdn_set_mmr2( + register amd79c30_padded_regs_t *regs, + register int mmr2); + +private void isdn_setgains( + isdn_softc_t *sc, + int pgain, + int rgain, + int mgain); + +/* + * Probe chip to see if it is there + */ +private isdn_probe( + vm_offset_t reg, + struct bus_ctlr *ui) +{ + isdn_softc_t *sc = &isdn_softc_data[ui->unit]; + + isdn_softc[ui->unit] = sc; + sc->regs = (amd79c30_padded_regs_t *)reg; + + return 1; +} + +/* + * Attach device to chip-indep driver(s) + */ +private void +isdn_attach( + struct bus_device *ui) +{ + register isdn_softc_t *sc = isdn_softc[ui->unit]; + register amd79c30_padded_regs_t *regs = sc->regs; + + /* disable interrupts */ + write_reg(regs->cr, AMDR_INIT); + write_reg(regs->dr, AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE); + + /* + * Initialize the mux unit. We use MCR3 to route audio (MAP) + * through channel Bb. MCR1 and MCR2 are unused. + * Setting the INT enable bit in MCR4 will generate an interrupt + * on each converted audio sample. + */ + write_reg(regs->cr, AMDR_MUX_1_4); + write_reg(regs->dr, 0); + write_reg(regs->dr, 0); + write_reg(regs->dr, (AMD_MCRCHAN_BB << 4) | AMD_MCRCHAN_BA); + write_reg(regs->dr, AMD_MCR4_INT_ENABLE); + + printf(" AMD 79C30A/79C32A"); + + audio_attach( sc, &isdn_ops, &sc->audio_status ); +} + +/* + * Chip re-initialization + */ +private void +isdn_init( + isdn_softc_t *sc) +{ + register amd79c30_padded_regs_t *regs; + + bzero((char *)&sc->sc_map, sizeof sc->sc_map); + /* default to speaker */ + sc->sc_map.mr_mmr2 = AMD_MMR2_AINB | AMD_MMR2_LS; + + /* enable interrupts and set parameters established above */ + regs = sc->regs; + isdn_set_mmr2 (regs, sc->sc_map.mr_mmr2); + isdn_setgains (sc, audio_default_level, audio_default_level, 0); + write_reg(regs->cr, AMDR_INIT); + write_reg(regs->dr, AMD_INIT_PMS_ACTIVE); +} + +/* + * Chip shutdown + */ +private void +isdn_close( + isdn_softc_t *sc) +{ + register amd79c30_padded_regs_t *regs; + + regs = sc->regs; + write_reg(regs->cr, AMDR_INIT); + write_reg(regs->dr, AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE); +} + +/* + * Audio port selection + */ +private void +isdn_setport( + isdn_softc_t *sc, + int port) +{ + if (port == AUDIO_SPEAKER) { + sc->sc_map.mr_mmr2 |= AMD_MMR2_LS; + isdn_set_mmr2(sc->regs, sc->sc_map.mr_mmr2); + } else if (port == AUDIO_HEADPHONE) { + sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS; + isdn_set_mmr2(sc->regs, sc->sc_map.mr_mmr2); + } +} + +private int +isdn_getport( + isdn_softc_t *sc) +{ + return (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ? + AUDIO_SPEAKER : AUDIO_HEADPHONE; +} + +/* + * Volume control + */ +private void +isdn_setgains( + isdn_softc_t *sc, + int pgain, + int rgain, + int mgain) +{ + private void isdn_set_pgain(), isdn_set_rgain(), isdn_set_mgain(); + + if (pgain != ~0) + isdn_set_pgain(sc, pgain); + if (rgain != ~0) + isdn_set_rgain(sc, rgain); + if (mgain != ~0) + isdn_set_mgain(sc, mgain); + +} + +private void +isdn_getgains( + isdn_softc_t *sc, + int *pgain, + int *rgain, + int *mgain) +{ + *mgain = sc->sc_mlevel; + *rgain = sc->sc_rlevel; + *pgain = sc->sc_plevel; +} + + +/* + * User control over MAP processor + */ +private io_return_t +isdn_setstate( + isdn_softc_t *sc, + dev_flavor_t flavor, + register struct mapreg *map, + natural_t n_ints) +{ + register amd79c30_padded_regs_t *regs = sc->regs; + register int i, v; + spl_t s; + + /* Sun compat */ + if (flavor == AUDIOSETREG) { + register struct audio_ioctl *a = (struct audio_ioctl *)map; + s = splaudio(); + write_reg(regs->cr, (a->control >> 8) & 0xff); + for (i = 0; i < (a->control & 0xff); i++) { + write_reg(regs->dr, a->data[i]); + } + splx(s); + return D_SUCCESS; + } + + if (flavor != AUDIO_SETMAP) + return D_INVALID_OPERATION; + + if ((n_ints * sizeof(int)) < sizeof(*map)) + return D_INVALID_SIZE; + + bcopy(map, &sc->sc_map, sizeof(sc->sc_map)); + sc->sc_map.mr_mmr2 &= 0x7f; + + s = splaudio(); + write_reg(regs->cr, AMDR_MAP_1_10); + for (i = 0; i < 8; i++) { + v = map->mr_x[i]; + WAMD16(regs, v); + } + for (i = 0; i < 8; ++i) { + v = map->mr_r[i]; + WAMD16(regs, v); + } + v = map->mr_gx; WAMD16(regs, v); + v = map->mr_gr; WAMD16(regs, v); + v = map->mr_ger; WAMD16(regs, v); + v = map->mr_stgr; WAMD16(regs, v); + v = map->mr_ftgr; WAMD16(regs, v); + v = map->mr_atgr; WAMD16(regs, v); + write_reg(regs->dr, map->mr_mmr1); + write_reg(regs->dr, map->mr_mmr2); + splx(s); + return D_SUCCESS; +} + +private io_return_t +isdn_getstate( + isdn_softc_t *sc, + dev_flavor_t flavor, + register struct mapreg *map, + natural_t *count) +{ + register amd79c30_padded_regs_t *regs = sc->regs; + spl_t s; + int i; + + /* Sun compat */ + if (flavor == AUDIOGETREG) { + register struct audio_ioctl *a = (struct audio_ioctl *)map; + s = splaudio(); + write_reg(regs->cr, (a->control >> 8) & 0xff); + for (i = 0; i < (a->control & 0xff); i++) { + read_reg(regs->dr,a->data[i]); + } + splx(s); + *count = sizeof(*a) / sizeof(int); + return D_SUCCESS; + } + + if ( (*count * sizeof(int)) < sizeof(*map)) + return D_INVALID_SIZE; + bcopy(&sc->sc_map, map, sizeof(sc->sc_map)); + *count = sizeof(*map) / sizeof(int); + return D_SUCCESS; +} + + + +/* + * Set the mmr1 register and one other 16 bit register in the audio chip. + * The other register is indicated by op and val. + */ +private void +isdn_set_mmr1( + register amd79c30_padded_regs_t *regs, + register int mmr1, + register int op, + register int val) +{ + register int s = splaudio(); + + write_reg(regs->cr, AMDR_MAP_MMR1); + write_reg(regs->dr, mmr1); + write_reg(regs->cr, op); + WAMD16(regs, val); + splx(s); +} + +/* + * Set the mmr2 register. + */ +private void +isdn_set_mmr2( + register amd79c30_padded_regs_t *regs, + register int mmr2) +{ + register int s = splaudio(); + + write_reg(regs->cr, AMDR_MAP_MMR2); + write_reg(regs->dr, mmr2); + splx(s); +} + +/* + * gx, gr & stg gains. this table must contain 256 elements with + * the 0th being "infinity" (the magic value 9008). The remaining + * elements match sun's gain curve (but with higher resolution): + * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps. + */ +private const unsigned short gx_coeff[256] = { + 0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33, + 0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22, + 0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b, + 0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb, + 0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a, + 0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213, + 0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231, + 0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4, + 0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2, + 0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa, + 0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b, + 0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b, + 0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd, + 0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808, + 0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243, + 0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224, + 0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb, + 0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33, + 0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32, + 0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323, + 0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a, + 0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23, + 0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1, + 0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333, + 0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227, + 0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6, + 0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2, + 0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba, + 0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033, + 0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021, + 0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012, + 0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e, +}; + +/* + * second stage play gain. + */ +private const unsigned short ger_coeff[] = { + 0x431f, /* 5. dB */ + 0x331f, /* 5.5 dB */ + 0x40dd, /* 6. dB */ + 0x11dd, /* 6.5 dB */ + 0x440f, /* 7. dB */ + 0x411f, /* 7.5 dB */ + 0x311f, /* 8. dB */ + 0x5520, /* 8.5 dB */ + 0x10dd, /* 9. dB */ + 0x4211, /* 9.5 dB */ + 0x410f, /* 10. dB */ + 0x111f, /* 10.5 dB */ + 0x600b, /* 11. dB */ + 0x00dd, /* 11.5 dB */ + 0x4210, /* 12. dB */ + 0x110f, /* 13. dB */ + 0x7200, /* 14. dB */ + 0x2110, /* 15. dB */ + 0x2200, /* 15.9 dB */ + 0x000b, /* 16.9 dB */ + 0x000f /* 18. dB */ +#define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0])) +}; + +private void +isdn_set_rgain( + register isdn_softc_t *sc, + register int level) +{ + level &= 0xff; + sc->sc_rlevel = level; + sc->sc_map.mr_mmr1 |= AMD_MMR1_GX; + sc->sc_map.mr_gx = gx_coeff[level]; + isdn_set_mmr1(sc->regs, sc->sc_map.mr_mmr1, + AMDR_MAP_GX, sc->sc_map.mr_gx); +} + +private void +isdn_set_pgain( + register isdn_softc_t *sc, + register int level) +{ + register int gi, s; + register amd79c30_padded_regs_t *regs; + + level &= 0xff; + sc->sc_plevel = level; + sc->sc_map.mr_mmr1 |= AMD_MMR1_GER|AMD_MMR1_GR; + level *= 256 + NGER; + level >>= 8; + if (level >= 256) { + gi = level - 256; + level = 255; + } else + gi = 0; + sc->sc_map.mr_ger = ger_coeff[gi]; + sc->sc_map.mr_gr = gx_coeff[level]; + + regs = sc->regs; + s = splaudio(); + write_reg(regs->cr, AMDR_MAP_MMR1); + write_reg(regs->dr, sc->sc_map.mr_mmr1); + write_reg(regs->cr, AMDR_MAP_GR); + gi = sc->sc_map.mr_gr; + WAMD16(regs, gi); + write_reg(regs->cr, AMDR_MAP_GER); + gi = sc->sc_map.mr_ger; + WAMD16(regs, gi); + splx(s); +} + +private void +isdn_set_mgain( + register isdn_softc_t *sc, + register int level) +{ + level &= 0xff; + sc->sc_mlevel = level; + sc->sc_map.mr_mmr1 |= AMD_MMR1_STG; + sc->sc_map.mr_stgr = gx_coeff[level]; + isdn_set_mmr1(sc->regs, sc->sc_map.mr_mmr1, + AMDR_MAP_STG, sc->sc_map.mr_stgr); +} + +/* + * Interrupt routine + */ +#if old +isdn_intr (unit, spllevel) + spl_t spllevel; +{ +#ifdef MAXINE + xine_enable_interrupt(7, 0, 0); +#endif +#ifdef FLAMINGO + kn15aa_enable_interrupt(12, 0, 0); +#endif + printf("ISDN interrupt"); +} +#else +isdn_intr (unit, spllevel) + spl_t spllevel; +{ + isdn_softc_t *sc = isdn_softc[unit]; + amd79c30_padded_regs_t *regs = sc->regs; + register int i; + unsigned int c; + + read_reg(regs->ir, i); mb(); /* clear interrupt, now */ +#if mips + splx(spllevel); /* drop priority */ +#endif + +#if 0 + if (..this is an audio interrupt..) +#endif + { + read_reg(regs->bbrb, c); + if (audio_hwintr(sc->audio_status, c, &c)) + write_reg(regs->bbtb, c); + } +} +#endif + + + +/* + * Standard operations vector + */ +audio_switch_t isdn_ops = { + isdn_init, + isdn_close, + isdn_setport, + isdn_getport, + isdn_setgains, + isdn_getgains, + isdn_setstate, + isdn_getstate +}; + +#if 1 +write_an_int(int *where, int what) { *where = what;} +read_an_int(int *where) { return *where;} +#endif + +#endif diff --git a/chips/kernel_font.c b/chips/kernel_font.c new file mode 100644 index 0000000..71c52c4 --- /dev/null +++ b/chips/kernel_font.c @@ -0,0 +1,3083 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * THIS FILE WAS GENERATED BY build_font FROM kernel_font.data + * IF YOU NEED TO, BE SURE YOU EDIT THE REAL THING! + */ +/* + * Object: + * kfont_7x14 EXPORTED array + * + * Kernel font for printable ASCII chars + * + * The smallest index in this array corresponds to a + * space. So, we start at 0x20 in the ascii table. + * Note that glyphs are mirrored (byteorder, I think) + * the commented bitmap shows how they really look like + */ + +unsigned char kfont_7x14[] = { +/* 0 ' ' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 1 '!' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 2 '"' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 3 '#' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01001000 */ 0x12, + /* 01001000 */ 0x12, + /* 11111100 */ 0x3f, + /* 01001000 */ 0x12, + /* 01001000 */ 0x12, + /* 01001000 */ 0x12, + /* 01001000 */ 0x12, + /* 11111100 */ 0x3f, + /* 01001000 */ 0x12, + /* 01001000 */ 0x12, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 4 '$' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 01111110 */ 0x7e, + /* 10010000 */ 0x9, + /* 10010000 */ 0x9, + /* 01111100 */ 0x3e, + /* 00010010 */ 0x48, + /* 00010010 */ 0x48, + /* 11111100 */ 0x3f, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 5 '%' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01000010 */ 0x42, + /* 10100100 */ 0x25, + /* 01000100 */ 0x22, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00100000 */ 0x4, + /* 01000100 */ 0x22, + /* 01001010 */ 0x52, + /* 10000100 */ 0x21, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 6 '&' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01110000 */ 0xe, + /* 10001000 */ 0x11, + /* 10001000 */ 0x11, + /* 10001000 */ 0x11, + /* 01110000 */ 0xe, + /* 10001000 */ 0x11, + /* 10001010 */ 0x51, + /* 10000100 */ 0x21, + /* 10001100 */ 0x31, + /* 01110010 */ 0x4e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 7 ''' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00011000 */ 0x18, + /* 00011000 */ 0x18, + /* 00100000 */ 0x4, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 8 '(' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00100000 */ 0x4, + /* 00100000 */ 0x4, + /* 00100000 */ 0x4, + /* 00100000 */ 0x4, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00001000 */ 0x10, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 9 ')' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00001000 */ 0x10, + /* 00001000 */ 0x10, + /* 00001000 */ 0x10, + /* 00001000 */ 0x10, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00100000 */ 0x4, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* a '*' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 10010010 */ 0x49, + /* 01010100 */ 0x2a, + /* 00111000 */ 0x1c, + /* 00111000 */ 0x1c, + /* 01010100 */ 0x2a, + /* 10010010 */ 0x49, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* b '+' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 11111110 */ 0x7f, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* c ',' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00110000 */ 0xc, + /* 00110000 */ 0xc, + /* 01000000 */ 0x2, + /* 00000000 */ 0, +/* d '-' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 11111110 */ 0x7f, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* e '.' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00110000 */ 0xc, + /* 00110000 */ 0xc, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* f '/' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000010 */ 0x40, + /* 00000100 */ 0x20, + /* 00000100 */ 0x20, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00100000 */ 0x4, + /* 01000000 */ 0x2, + /* 01000000 */ 0x2, + /* 10000000 */ 0x1, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 10 '0' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00111000 */ 0x1c, + /* 01000100 */ 0x22, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01000100 */ 0x22, + /* 00111000 */ 0x1c, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 11 '1' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00110000 */ 0xc, + /* 01010000 */ 0xa, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 12 '2' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 00000100 */ 0x20, + /* 00011000 */ 0x18, + /* 00100000 */ 0x4, + /* 01000000 */ 0x2, + /* 10000000 */ 0x1, + /* 11111110 */ 0x7f, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 13 '3' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 00011100 */ 0x38, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 14 '4' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000100 */ 0x20, + /* 00001100 */ 0x30, + /* 00010100 */ 0x28, + /* 00100100 */ 0x24, + /* 01000100 */ 0x22, + /* 10000100 */ 0x21, + /* 11111110 */ 0x7f, + /* 00000100 */ 0x20, + /* 00000100 */ 0x20, + /* 00000100 */ 0x20, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 15 '5' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 11111110 */ 0x7f, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 11111100 */ 0x3f, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 16 '6' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 11111100 */ 0x3f, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 17 '7' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 11111110 */ 0x7f, + /* 10000010 */ 0x41, + /* 00000010 */ 0x40, + /* 00000100 */ 0x20, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00100000 */ 0x4, + /* 01000000 */ 0x2, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 18 '8' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 19 '9' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111110 */ 0x7e, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 1a ':' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00110000 */ 0xc, + /* 00110000 */ 0xc, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00110000 */ 0xc, + /* 00110000 */ 0xc, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 1b ';' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00110000 */ 0xc, + /* 00110000 */ 0xc, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00110000 */ 0xc, + /* 00110000 */ 0xc, + /* 01000000 */ 0x2, + /* 00000000 */ 0, +/* 1c '<' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00100000 */ 0x4, + /* 01000000 */ 0x2, + /* 10000000 */ 0x1, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00001000 */ 0x10, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 1d '=' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 11111110 */ 0x7f, + /* 00000000 */ 0, + /* 11111110 */ 0x7f, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 1e '>' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00001000 */ 0x10, + /* 00000100 */ 0x20, + /* 00000010 */ 0x40, + /* 00000100 */ 0x20, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00100000 */ 0x4, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 1f '?' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 00000100 */ 0x20, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 20 '@' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00111100 */ 0x3c, + /* 01000010 */ 0x42, + /* 10011010 */ 0x59, + /* 10101010 */ 0x55, + /* 10101010 */ 0x55, + /* 10011100 */ 0x39, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 01000010 */ 0x42, + /* 00111100 */ 0x3c, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 21 'A' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00111000 */ 0x1c, + /* 01000100 */ 0x22, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11111110 */ 0x7f, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 22 'B' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 11111100 */ 0x3f, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11111100 */ 0x3f, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11111100 */ 0x3f, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 23 'C' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 24 'D' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 11111000 */ 0x1f, + /* 10000100 */ 0x21, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000100 */ 0x21, + /* 11111000 */ 0x1f, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 25 'E' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 11111110 */ 0x7f, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 11111000 */ 0x1f, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 11111110 */ 0x7f, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 26 'F' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 11111110 */ 0x7f, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 11111000 */ 0x1f, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 27 'G' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10011110 */ 0x79, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 28 'H' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11111110 */ 0x7f, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 29 'I' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 2a 'J' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 2b 'K' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000100 */ 0x21, + /* 10001000 */ 0x11, + /* 10010000 */ 0x9, + /* 10100000 */ 0x5, + /* 11000000 */ 0x3, + /* 10100000 */ 0x5, + /* 10010000 */ 0x9, + /* 10001000 */ 0x11, + /* 10000100 */ 0x21, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 2c 'L' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 11111110 */ 0x7f, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 2d 'M' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11000110 */ 0x63, + /* 10101010 */ 0x55, + /* 10010010 */ 0x49, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 2e 'N' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11000010 */ 0x43, + /* 10100010 */ 0x45, + /* 10010010 */ 0x49, + /* 10010010 */ 0x49, + /* 10001010 */ 0x51, + /* 10000110 */ 0x61, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 2f 'O' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 30 'P' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 11111100 */ 0x3f, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11111100 */ 0x3f, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 31 'Q' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00111000 */ 0x1c, + /* 01000100 */ 0x22, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10001010 */ 0x51, + /* 01000100 */ 0x22, + /* 00111010 */ 0x5c, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 32 'R' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 11111100 */ 0x3f, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11111100 */ 0x3f, + /* 10100000 */ 0x5, + /* 10010000 */ 0x9, + /* 10001000 */ 0x11, + /* 10000100 */ 0x21, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 33 'S' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 01111100 */ 0x3e, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 34 'T' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 11111110 */ 0x7f, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 35 'U' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 36 'V' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01000100 */ 0x22, + /* 01000100 */ 0x22, + /* 01000100 */ 0x22, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 37 'W' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10010010 */ 0x49, + /* 10010010 */ 0x49, + /* 10010010 */ 0x49, + /* 01101100 */ 0x36, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 38 'X' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 01000100 */ 0x22, + /* 01000100 */ 0x22, + /* 00101000 */ 0x14, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00101000 */ 0x14, + /* 01000100 */ 0x22, + /* 01000100 */ 0x22, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 39 'Y' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01000100 */ 0x22, + /* 00101000 */ 0x14, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 3a 'Z' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 11111110 */ 0x7f, + /* 00000010 */ 0x40, + /* 00000100 */ 0x20, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00100000 */ 0x4, + /* 01000000 */ 0x2, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 11111110 */ 0x7f, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 3b '[' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00011110 */ 0x78, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00011110 */ 0x78, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 3c '\' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000000 */ 0x1, + /* 01000000 */ 0x2, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00001000 */ 0x10, + /* 00000100 */ 0x20, + /* 00000100 */ 0x20, + /* 00000010 */ 0x40, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 3d ']' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 11110000 */ 0xf, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 11110000 */ 0xf, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 3e '^' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00101000 */ 0x14, + /* 01000100 */ 0x22, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 3f '_' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 11111110 */ 0x7f, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 40 '`' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01100000 */ 0x6, + /* 01100000 */ 0x6, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 41 'a' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111000 */ 0x1e, + /* 00000100 */ 0x20, + /* 01111100 */ 0x3e, + /* 10000100 */ 0x21, + /* 10000100 */ 0x21, + /* 01111010 */ 0x5e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 42 'b' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10111100 */ 0x3d, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10111100 */ 0x3d, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 43 'c' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 44 'd' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 01111010 */ 0x5e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111010 */ 0x5e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 45 'e' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11111110 */ 0x7f, + /* 10000000 */ 0x1, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 46 'f' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00001000 */ 0x10, + /* 00010100 */ 0x28, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00111100 */ 0x3c, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 47 'g' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111010 */ 0x5e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111010 */ 0x5e, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 01111100 */ 0x3e, +/* 48 'h' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10111100 */ 0x3d, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 49 'i' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00110000 */ 0xc, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 4a 'j' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 01010000 */ 0xa, + /* 00100000 */ 0x4, +/* 4b 'k' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000100 */ 0x21, + /* 10001000 */ 0x11, + /* 10010000 */ 0x9, + /* 10110000 */ 0xd, + /* 11001000 */ 0x13, + /* 10000100 */ 0x21, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 4c 'l' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00110000 */ 0xc, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 4d 'm' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10101100 */ 0x35, + /* 10010010 */ 0x49, + /* 10010010 */ 0x49, + /* 10010010 */ 0x49, + /* 10010010 */ 0x49, + /* 10010010 */ 0x49, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 4e 'n' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10111100 */ 0x3d, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 4f 'o' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 50 'p' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10111100 */ 0x3d, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10111100 */ 0x3d, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, +/* 51 'q' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111010 */ 0x5e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111010 */ 0x5e, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, +/* 52 'r' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10111100 */ 0x3d, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 53 's' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111110 */ 0x7e, + /* 10000000 */ 0x1, + /* 01111100 */ 0x3e, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 11111100 */ 0x3f, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 54 't' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00111000 */ 0x1c, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010100 */ 0x28, + /* 00001000 */ 0x10, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 55 'u' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111010 */ 0x5e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 56 'v' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01000100 */ 0x22, + /* 01000100 */ 0x22, + /* 00101000 */ 0x14, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 57 'w' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10010010 */ 0x49, + /* 10101010 */ 0x55, + /* 01000100 */ 0x22, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 58 'x' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000100 */ 0x21, + /* 01001000 */ 0x12, + /* 00110000 */ 0xc, + /* 00110000 */ 0xc, + /* 01001000 */ 0x12, + /* 10000100 */ 0x21, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 59 'y' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 01111100 */ 0x3e, +/* 5a 'z' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 11111110 */ 0x7f, + /* 00000100 */ 0x20, + /* 00001000 */ 0x10, + /* 00110000 */ 0xc, + /* 01000000 */ 0x2, + /* 11111110 */ 0x7f, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 5b '{' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00001000 */ 0x10, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 5c '|' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 5d '}' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00100000 */ 0x4, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 5e '~' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01100000 */ 0x6, + /* 10010010 */ 0x49, + /* 00001100 */ 0x30, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 5f '' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 60 '€' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, +/* 61 '' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 62 '‚' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00001000 */ 0x10, + /* 00010100 */ 0x28, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00111100 */ 0x3c, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00110000 */ 0xc, + /* 01010010 */ 0x4a, + /* 00101100 */ 0x34, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 63 'ƒ' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 64 '„' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01000100 */ 0x22, + /* 01111100 */ 0x3e, + /* 00010000 */ 0x8, + /* 01111100 */ 0x3e, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 65 '…' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 66 '†' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000010 */ 0x40, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 67 '‡' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 68 'ˆ' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10011010 */ 0x59, + /* 10100010 */ 0x45, + /* 10100010 */ 0x45, + /* 10100010 */ 0x45, + /* 10011010 */ 0x59, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 69 '‰' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00111000 */ 0x1c, + /* 00000100 */ 0x20, + /* 00111100 */ 0x3c, + /* 01000100 */ 0x22, + /* 00111010 */ 0x5c, + /* 00000000 */ 0, + /* 01111110 */ 0x7e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 6a 'Š' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00001010 */ 0x50, + /* 00010100 */ 0x28, + /* 00101000 */ 0x14, + /* 01010000 */ 0xa, + /* 10100000 */ 0x5, + /* 01010000 */ 0xa, + /* 00101000 */ 0x14, + /* 00010100 */ 0x28, + /* 00001010 */ 0x50, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 6b '‹' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 6c 'Œ' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 6d '' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 6e 'Ž' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 6f '' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00110000 */ 0xc, + /* 01001000 */ 0x12, + /* 00110000 */ 0xc, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 70 '' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 11111110 */ 0x7f, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 11111110 */ 0x7f, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 71 '‘' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00111000 */ 0x1c, + /* 01000100 */ 0x22, + /* 01000100 */ 0x22, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00100000 */ 0x4, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 72 '’' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00111000 */ 0x1c, + /* 01000100 */ 0x22, + /* 00000100 */ 0x20, + /* 00011000 */ 0x18, + /* 00000100 */ 0x20, + /* 01000100 */ 0x22, + /* 00111000 */ 0x1c, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 73 '“' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 74 '”' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01000010 */ 0x42, + /* 01000010 */ 0x42, + /* 01000010 */ 0x42, + /* 01000010 */ 0x42, + /* 01100110 */ 0x66, + /* 01011010 */ 0x5a, + /* 01000000 */ 0x2, + /* 10000000 */ 0x1, + /* 00000000 */ 0, +/* 75 '•' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00101000 */ 0x14, + /* 01101000 */ 0x16, + /* 11101000 */ 0x17, + /* 11101000 */ 0x17, + /* 11101000 */ 0x17, + /* 01101000 */ 0x16, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 76 '–' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00011000 */ 0x18, + /* 00011000 */ 0x18, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 77 '—' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 78 '˜' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00110000 */ 0xc, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00111000 */ 0x1c, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 79 '™' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00111100 */ 0x3c, + /* 01000010 */ 0x42, + /* 01000010 */ 0x42, + /* 01000010 */ 0x42, + /* 00111100 */ 0x3c, + /* 00000000 */ 0, + /* 01111110 */ 0x7e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 7a 'š' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 10100000 */ 0x5, + /* 01010000 */ 0xa, + /* 00101000 */ 0x14, + /* 00010100 */ 0x28, + /* 00001010 */ 0x50, + /* 00010100 */ 0x28, + /* 00101000 */ 0x14, + /* 01010000 */ 0xa, + /* 10100000 */ 0x5, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 7b '›' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01000000 */ 0x2, + /* 11000000 */ 0x3, + /* 01000010 */ 0x42, + /* 01000100 */ 0x22, + /* 11101000 */ 0x17, + /* 00010100 */ 0x28, + /* 00101100 */ 0x34, + /* 01010100 */ 0x2a, + /* 10011110 */ 0x79, + /* 00000100 */ 0x20, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 7c 'œ' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01000000 */ 0x2, + /* 11000000 */ 0x3, + /* 01000010 */ 0x42, + /* 01000100 */ 0x22, + /* 11101000 */ 0x17, + /* 00011100 */ 0x38, + /* 00110010 */ 0x4c, + /* 01000100 */ 0x22, + /* 10001000 */ 0x11, + /* 00011110 */ 0x78, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 7d '' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 7e 'ž' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00100000 */ 0x4, + /* 01000000 */ 0x2, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 7f 'Ÿ' */ + /* 00000000 */ 0, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00000000 */ 0, + /* 00111000 */ 0x1c, + /* 01000100 */ 0x22, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11111110 */ 0x7f, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 80 ' ' */ + /* 00000000 */ 0, + /* 00000100 */ 0x20, + /* 00001000 */ 0x10, + /* 00000000 */ 0, + /* 00111000 */ 0x1c, + /* 01000100 */ 0x22, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11111110 */ 0x7f, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 81 '¡' */ + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 00111000 */ 0x1c, + /* 01000100 */ 0x22, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11111110 */ 0x7f, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 82 '¢' */ + /* 00000000 */ 0, + /* 00110100 */ 0x2c, + /* 01001000 */ 0x12, + /* 00000000 */ 0, + /* 00111000 */ 0x1c, + /* 01000100 */ 0x22, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11111110 */ 0x7f, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 83 '£' */ + /* 00000000 */ 0, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 00111000 */ 0x1c, + /* 01000100 */ 0x22, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11111110 */ 0x7f, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 84 '¤' */ + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00101000 */ 0x14, + /* 00010000 */ 0x8, + /* 00111000 */ 0x1c, + /* 01000100 */ 0x22, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11111110 */ 0x7f, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 85 '¥' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00111110 */ 0x7c, + /* 01010000 */ 0xa, + /* 01010000 */ 0xa, + /* 10010000 */ 0x9, + /* 10011100 */ 0x39, + /* 11110000 */ 0xf, + /* 10010000 */ 0x9, + /* 10011110 */ 0x79, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 86 '¦' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00000000 */ 0, +/* 87 '§' */ + /* 00000000 */ 0, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00000000 */ 0, + /* 11111110 */ 0x7f, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 11111000 */ 0x1f, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 11111110 */ 0x7f, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 88 '¨' */ + /* 00000000 */ 0, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 11111110 */ 0x7f, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 11111000 */ 0x1f, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 11111110 */ 0x7f, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 89 '©' */ + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 11111110 */ 0x7f, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 11111000 */ 0x1f, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 11111110 */ 0x7f, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 8a 'ª' */ + /* 00000000 */ 0, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 11111110 */ 0x7f, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 11111000 */ 0x1f, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 11111110 */ 0x7f, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 8b '«' */ + /* 00000000 */ 0, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 8c '¬' */ + /* 00000000 */ 0, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 8d '­' */ + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 8e '®' */ + /* 00000000 */ 0, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 8f '¯' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 90 '°' */ + /* 00000000 */ 0, + /* 00110100 */ 0x2c, + /* 01001000 */ 0x12, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 11000010 */ 0x43, + /* 10100010 */ 0x45, + /* 10010010 */ 0x49, + /* 10010010 */ 0x49, + /* 10001010 */ 0x51, + /* 10000110 */ 0x61, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 91 '±' */ + /* 00000000 */ 0, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 92 '²' */ + /* 00000000 */ 0, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 93 '³' */ + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 94 '´' */ + /* 00000000 */ 0, + /* 00110100 */ 0x2c, + /* 01001000 */ 0x12, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 95 'µ' */ + /* 00000000 */ 0, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 96 '¶' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111110 */ 0x7e, + /* 10010000 */ 0x9, + /* 10010000 */ 0x9, + /* 10010000 */ 0x9, + /* 10011100 */ 0x39, + /* 10010000 */ 0x9, + /* 10010000 */ 0x9, + /* 01111110 */ 0x7e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 97 '·' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000010 */ 0x40, + /* 01111100 */ 0x3e, + /* 10000110 */ 0x61, + /* 10001010 */ 0x51, + /* 10010010 */ 0x49, + /* 10010010 */ 0x49, + /* 10100010 */ 0x45, + /* 11000010 */ 0x43, + /* 01111100 */ 0x3e, + /* 10000000 */ 0x1, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 98 '¸' */ + /* 00000000 */ 0, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 99 '¹' */ + /* 00000000 */ 0, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 9a 'º' */ + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 9b '»' */ + /* 00000000 */ 0, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 9c '¼' */ + /* 00000000 */ 0, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01000100 */ 0x22, + /* 00101000 */ 0x14, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 9d '½' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* 9e '¾' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10111100 */ 0x3d, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10111100 */ 0x3d, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 00000000 */ 0, +/* 9f '¿' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00000000 */ 0, + /* 01111000 */ 0x1e, + /* 00000100 */ 0x20, + /* 01111100 */ 0x3e, + /* 10000100 */ 0x21, + /* 10000100 */ 0x21, + /* 01111010 */ 0x5e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* a0 'À' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 01111000 */ 0x1e, + /* 00000100 */ 0x20, + /* 01111100 */ 0x3e, + /* 10000100 */ 0x21, + /* 10000100 */ 0x21, + /* 01111010 */ 0x5e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* a1 'Á' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 01111000 */ 0x1e, + /* 00000100 */ 0x20, + /* 01111100 */ 0x3e, + /* 10000100 */ 0x21, + /* 10000100 */ 0x21, + /* 01111010 */ 0x5e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* a2 'Â' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00110100 */ 0x2c, + /* 01001000 */ 0x12, + /* 00000000 */ 0, + /* 01111000 */ 0x1e, + /* 00000100 */ 0x20, + /* 01111100 */ 0x3e, + /* 10000100 */ 0x21, + /* 10000100 */ 0x21, + /* 01111010 */ 0x5e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* a3 'Ã' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 01111000 */ 0x1e, + /* 00000100 */ 0x20, + /* 01111100 */ 0x3e, + /* 10000100 */ 0x21, + /* 10000100 */ 0x21, + /* 01111010 */ 0x5e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* a4 'Ä' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00101000 */ 0x14, + /* 00010000 */ 0x8, + /* 01111000 */ 0x1e, + /* 00000100 */ 0x20, + /* 01111100 */ 0x3e, + /* 10000100 */ 0x21, + /* 10000100 */ 0x21, + /* 01111010 */ 0x5e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* a5 'Å' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01101100 */ 0x36, + /* 00010010 */ 0x48, + /* 01111110 */ 0x7e, + /* 10010000 */ 0x9, + /* 10010010 */ 0x49, + /* 01101100 */ 0x36, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* a6 'Æ' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00000000 */ 0, +/* a7 'Ç' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11111110 */ 0x7f, + /* 10000000 */ 0x1, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* a8 'È' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11111110 */ 0x7f, + /* 10000000 */ 0x1, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* a9 'É' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11111110 */ 0x7f, + /* 10000000 */ 0x1, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* aa 'Ê' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 11111110 */ 0x7f, + /* 10000000 */ 0x1, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* ab 'Ë' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00110000 */ 0xc, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* ac 'Ì' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00110000 */ 0xc, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* ad 'Í' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 00110000 */ 0xc, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* ae 'Î' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 00110000 */ 0xc, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* af 'Ï' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* b0 'Ð' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00110100 */ 0x2c, + /* 01001000 */ 0x12, + /* 00000000 */ 0, + /* 10111100 */ 0x3d, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* b1 'Ñ' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* b2 'Ò' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* b3 'Ó' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* b4 'Ô' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00110100 */ 0x2c, + /* 01001000 */ 0x12, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* b5 'Õ' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* b6 'Ö' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01101100 */ 0x36, + /* 10010010 */ 0x49, + /* 10011110 */ 0x79, + /* 10010000 */ 0x9, + /* 10010010 */ 0x49, + /* 01101100 */ 0x36, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* b7 '×' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000010 */ 0x40, + /* 01111100 */ 0x3e, + /* 10001010 */ 0x51, + /* 10010010 */ 0x49, + /* 10010010 */ 0x49, + /* 10100010 */ 0x45, + /* 01111100 */ 0x3e, + /* 10000000 */ 0x1, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* b8 'Ø' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111010 */ 0x5e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* b9 'Ù' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00001000 */ 0x10, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111010 */ 0x5e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* ba 'Ú' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111010 */ 0x5e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* bb 'Û' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111010 */ 0x5e, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +/* bc 'Ü' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00101000 */ 0x14, + /* 00101000 */ 0x14, + /* 00000000 */ 0, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 10000010 */ 0x41, + /* 01111100 */ 0x3e, + /* 00000010 */ 0x40, + /* 00000010 */ 0x40, + /* 01111100 */ 0x3e, +/* bd 'Ý' */ + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 01111100 */ 0x3e, + /* 10000010 */ 0x41, + /* 10000000 */ 0x1, + /* 10000000 */ 0x1, + /* 01000000 */ 0x2, + /* 00100000 */ 0x4, + /* 00010000 */ 0x8, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00010000 */ 0x8, + /* 00000000 */ 0, + /* 00000000 */ 0, + /* 00000000 */ 0, +}; diff --git a/chips/kernel_font.data b/chips/kernel_font.data new file mode 100644 index 0000000..200cf84 --- /dev/null +++ b/chips/kernel_font.data @@ -0,0 +1,3108 @@ +# +# Mach Operating System +# Copyright (c) 1991,1990,1989 Carnegie Mellon University +# All Rights Reserved. +# +# Permission to use, copy, modify and distribute this software and its +# documentation is hereby granted, provided that both the copyright +# notice and this permission notice appear in all copies of the +# software, derivative works or modified versions, and any portions +# thereof, and that both notices appear in supporting documentation. +# +# CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" +# CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR +# ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. +# +# Carnegie Mellon requests users of this software to return to +# +# Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU +# School of Computer Science +# Carnegie Mellon University +# Pittsburgh PA 15213-3890 +# +# any improvements or extensions that they make and grant Carnegie Mellon +# the rights to redistribute these changes. +# +# +# File : kernel_font.data +# Content: Bitmaps for a 7x15 ASCII font +# Authors: Alessandro and Giovanna Forin +# +# Copyright (c) 1990 Alessandro and Giovanna Forin +# +# All Rights Reserved +# +# Permission to use, copy, modify, and distribute this software and +# its documentation for any purpose and without fee is hereby +# granted, provided that the above copyright notice appears in all +# copies and that both the copyright notice and this permission notice +# appear in supporting documentation, and that the name of the authors +# not be used in advertising or publicity pertaining to distribution +# of the software without specific, written prior permission. +# +# THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE +# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT, OR +# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, +# NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# NOTE: comment lines must start with a "#" character, and are +# only permitted at the beginning of the file. + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +! +00000000 +00000000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00000000 +00010000 +00000000 +00000000 +00000000 +" +00000000 +00000000 +00101000 +00101000 +00101000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +# +00000000 +00000000 +01001000 +01001000 +11111100 +01001000 +01001000 +01001000 +01001000 +11111100 +01001000 +01001000 +00000000 +00000000 +00000000 +$ +00000000 +00000000 +00000000 +00010000 +01111110 +10010000 +10010000 +01111100 +00010010 +00010010 +11111100 +00010000 +00000000 +00000000 +00000000 +% +00000000 +00000000 +01000010 +10100100 +01000100 +00001000 +00010000 +00010000 +00100000 +01000100 +01001010 +10000100 +00000000 +00000000 +00000000 +& +00000000 +00000000 +01110000 +10001000 +10001000 +10001000 +01110000 +10001000 +10001010 +10000100 +10001100 +01110010 +00000000 +00000000 +00000000 +' +00000000 +00000000 +00011000 +00011000 +00100000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +( +00000000 +00000000 +00001000 +00010000 +00010000 +00100000 +00100000 +00100000 +00100000 +00100000 +00010000 +00010000 +00001000 +00000000 +00000000 +) +00000000 +00000000 +00100000 +00010000 +00010000 +00001000 +00001000 +00001000 +00001000 +00001000 +00010000 +00010000 +00100000 +00000000 +00000000 +* +00000000 +00000000 +00000000 +00010000 +10010010 +01010100 +00111000 +00111000 +01010100 +10010010 +00010000 +00000000 +00000000 +00000000 +00000000 ++ +00000000 +00000000 +00000000 +00000000 +00010000 +00010000 +00010000 +11111110 +00010000 +00010000 +00010000 +00000000 +00000000 +00000000 +00000000 +, +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00110000 +00110000 +01000000 +00000000 +- +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +11111110 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +. +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00110000 +00110000 +00000000 +00000000 +00000000 +/ +00000000 +00000000 +00000010 +00000100 +00000100 +00001000 +00010000 +00010000 +00100000 +01000000 +01000000 +10000000 +00000000 +00000000 +00000000 +0 +00000000 +00000000 +00111000 +01000100 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +01000100 +00111000 +00000000 +00000000 +00000000 +1 +00000000 +00000000 +00010000 +00110000 +01010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +01111100 +00000000 +00000000 +00000000 +2 +00000000 +00000000 +01111100 +10000010 +00000010 +00000010 +00000100 +00011000 +00100000 +01000000 +10000000 +11111110 +00000000 +00000000 +00000000 +3 +00000000 +00000000 +01111100 +10000010 +00000010 +00000010 +00011100 +00000010 +00000010 +00000010 +10000010 +01111100 +00000000 +00000000 +00000000 +4 +00000000 +00000000 +00000100 +00001100 +00010100 +00100100 +01000100 +10000100 +11111110 +00000100 +00000100 +00000100 +00000000 +00000000 +00000000 +5 +00000000 +00000000 +11111110 +10000000 +10000000 +10000000 +11111100 +00000010 +00000010 +00000010 +10000010 +01111100 +00000000 +00000000 +00000000 +6 +00000000 +00000000 +01111100 +10000000 +10000000 +10000000 +11111100 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 +7 +00000000 +00000000 +11111110 +10000010 +00000010 +00000100 +00001000 +00010000 +00100000 +01000000 +10000000 +10000000 +00000000 +00000000 +00000000 +8 +00000000 +00000000 +01111100 +10000010 +10000010 +10000010 +01111100 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 +9 +00000000 +00000000 +01111100 +10000010 +10000010 +10000010 +01111110 +00000010 +00000010 +00000010 +00000010 +01111100 +00000000 +00000000 +00000000 +: +00000000 +00000000 +00000000 +00000000 +00000000 +00110000 +00110000 +00000000 +00000000 +00000000 +00110000 +00110000 +00000000 +00000000 +00000000 +; +00000000 +00000000 +00000000 +00000000 +00000000 +00110000 +00110000 +00000000 +00000000 +00000000 +00000000 +00110000 +00110000 +01000000 +00000000 +< +00000000 +00000000 +00000000 +00001000 +00010000 +00100000 +01000000 +10000000 +01000000 +00100000 +00010000 +00001000 +00000000 +00000000 +00000000 += +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +11111110 +00000000 +11111110 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +> +00000000 +00000000 +00000000 +00100000 +00010000 +00001000 +00000100 +00000010 +00000100 +00001000 +00010000 +00100000 +00000000 +00000000 +00000000 +? +00000000 +00000000 +01111100 +10000010 +00000010 +00000010 +00000100 +00001000 +00010000 +00010000 +00000000 +00010000 +00000000 +00000000 +00000000 +@ +00000000 +00000000 +00111100 +01000010 +10011010 +10101010 +10101010 +10011100 +10000000 +10000000 +01000010 +00111100 +00000000 +00000000 +00000000 +A +00000000 +00000000 +00111000 +01000100 +10000010 +10000010 +10000010 +11111110 +10000010 +10000010 +10000010 +10000010 +00000000 +00000000 +00000000 +B +00000000 +00000000 +11111100 +10000010 +10000010 +10000010 +11111100 +10000010 +10000010 +10000010 +10000010 +11111100 +00000000 +00000000 +00000000 +C +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +10000000 +10000000 +10000000 +10000000 +10000010 +01111100 +00000000 +00000000 +00000000 +D +00000000 +00000000 +11111000 +10000100 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +10000100 +11111000 +00000000 +00000000 +00000000 +E +00000000 +00000000 +11111110 +10000000 +10000000 +10000000 +11111000 +10000000 +10000000 +10000000 +10000000 +11111110 +00000000 +00000000 +00000000 +F +00000000 +00000000 +11111110 +10000000 +10000000 +10000000 +11111000 +10000000 +10000000 +10000000 +10000000 +10000000 +00000000 +00000000 +00000000 +G +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +10011110 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 +H +00000000 +00000000 +10000010 +10000010 +10000010 +10000010 +11111110 +10000010 +10000010 +10000010 +10000010 +10000010 +00000000 +00000000 +00000000 +I +00000000 +00000000 +01111100 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +01111100 +00000000 +00000000 +00000000 +J +00000000 +00000000 +00000010 +00000010 +00000010 +00000010 +00000010 +00000010 +00000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 +K +00000000 +00000000 +10000100 +10001000 +10010000 +10100000 +11000000 +10100000 +10010000 +10001000 +10000100 +10000010 +00000000 +00000000 +00000000 +L +00000000 +00000000 +10000000 +10000000 +10000000 +10000000 +10000000 +10000000 +10000000 +10000000 +10000000 +11111110 +00000000 +00000000 +00000000 +M +00000000 +00000000 +10000010 +10000010 +11000110 +10101010 +10010010 +10000010 +10000010 +10000010 +10000010 +10000010 +00000000 +00000000 +00000000 +N +00000000 +00000000 +10000010 +10000010 +11000010 +10100010 +10010010 +10010010 +10001010 +10000110 +10000010 +10000010 +00000000 +00000000 +00000000 +O +00000000 +00000000 +01111100 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 +P +00000000 +00000000 +11111100 +10000010 +10000010 +10000010 +11111100 +10000000 +10000000 +10000000 +10000000 +10000000 +00000000 +00000000 +00000000 +Q +00000000 +00000000 +00111000 +01000100 +10000010 +10000010 +10000010 +10000010 +10000010 +10001010 +01000100 +00111010 +00000000 +00000000 +00000000 +R +00000000 +00000000 +11111100 +10000010 +10000010 +10000010 +11111100 +10100000 +10010000 +10001000 +10000100 +10000010 +00000000 +00000000 +00000000 +S +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +01111100 +00000010 +00000010 +00000010 +10000010 +01111100 +00000000 +00000000 +00000000 +T +00000000 +00000000 +11111110 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00000000 +00000000 +00000000 +U +00000000 +00000000 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 +V +00000000 +00000000 +10000010 +10000010 +10000010 +01000100 +01000100 +01000100 +00101000 +00101000 +00010000 +00010000 +00000000 +00000000 +00000000 +W +00000000 +00000000 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +10010010 +10010010 +10010010 +01101100 +00000000 +00000000 +00000000 +X +00000000 +00000000 +10000010 +01000100 +01000100 +00101000 +00010000 +00010000 +00101000 +01000100 +01000100 +10000010 +00000000 +00000000 +00000000 +Y +00000000 +00000000 +10000010 +10000010 +01000100 +00101000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00000000 +00000000 +00000000 +Z +00000000 +00000000 +11111110 +00000010 +00000100 +00001000 +00010000 +00100000 +01000000 +10000000 +10000000 +11111110 +00000000 +00000000 +00000000 +[ +00000000 +00000000 +00011110 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00011110 +00000000 +00000000 +00000000 +\ +00000000 +00000000 +10000000 +01000000 +01000000 +00100000 +00010000 +00010000 +00001000 +00000100 +00000100 +00000010 +00000000 +00000000 +00000000 +] +00000000 +00000000 +11110000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +11110000 +00000000 +00000000 +00000000 +^ +00000000 +00000000 +00010000 +00101000 +01000100 +10000010 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +_ +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +11111110 +00000000 +00000000 +00000000 +` +00000000 +00000000 +01100000 +01100000 +00010000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +a +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +01111000 +00000100 +01111100 +10000100 +10000100 +01111010 +00000000 +00000000 +00000000 +b +00000000 +00000000 +10000000 +10000000 +10000000 +10000000 +10111100 +10000010 +10000010 +10000010 +10000010 +10111100 +00000000 +00000000 +00000000 +c +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +10000010 +01111100 +00000000 +00000000 +00000000 +d +00000000 +00000000 +00000010 +00000010 +00000010 +00000010 +01111010 +10000010 +10000010 +10000010 +10000010 +01111010 +00000000 +00000000 +00000000 +e +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +01111100 +10000010 +10000010 +11111110 +10000000 +01111100 +00000000 +00000000 +00000000 +f +00000000 +00000000 +00001000 +00010100 +00010000 +00010000 +00111100 +00010000 +00010000 +00010000 +00010000 +00010000 +00000000 +00000000 +00000000 +g +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +01111010 +10000010 +10000010 +10000010 +10000010 +01111010 +00000010 +00000010 +01111100 +h +00000000 +00000000 +10000000 +10000000 +10000000 +10000000 +10111100 +10000010 +10000010 +10000010 +10000010 +10000010 +00000000 +00000000 +00000000 +i +00000000 +00000000 +00000000 +00010000 +00000000 +00110000 +00010000 +00010000 +00010000 +00010000 +00010000 +01111100 +00000000 +00000000 +00000000 +j +00000000 +00000000 +00000000 +00010000 +00000000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +01010000 +00100000 +k +00000000 +00000000 +10000000 +10000000 +10000000 +10000100 +10001000 +10010000 +10110000 +11001000 +10000100 +10000010 +00000000 +00000000 +00000000 +l +00000000 +00000000 +00110000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +01111100 +00000000 +00000000 +00000000 +m +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +10101100 +10010010 +10010010 +10010010 +10010010 +10010010 +00000000 +00000000 +00000000 +n +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +10111100 +10000010 +10000010 +10000010 +10000010 +10000010 +00000000 +00000000 +00000000 +o +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +01111100 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 +p +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +10111100 +10000010 +10000010 +10000010 +10000010 +10111100 +10000000 +10000000 +10000000 +q +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +01111010 +10000010 +10000010 +10000010 +10000010 +01111010 +00000010 +00000010 +00000010 +r +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +10111100 +10000010 +10000000 +10000000 +10000000 +10000000 +00000000 +00000000 +00000000 +s +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +01111110 +10000000 +01111100 +00000010 +00000010 +11111100 +00000000 +00000000 +00000000 +t +00000000 +00000000 +00000000 +00010000 +00010000 +00111000 +00010000 +00010000 +00010000 +00010000 +00010100 +00001000 +00000000 +00000000 +00000000 +u +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +10000010 +10000010 +10000010 +10000010 +10000010 +01111010 +00000000 +00000000 +00000000 +v +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +10000010 +10000010 +01000100 +01000100 +00101000 +00010000 +00000000 +00000000 +00000000 +w +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +10000010 +10000010 +10000010 +10010010 +10101010 +01000100 +00000000 +00000000 +00000000 +x +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +10000100 +01001000 +00110000 +00110000 +01001000 +10000100 +00000000 +00000000 +00000000 +y +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +10000010 +10000010 +10000010 +10000010 +10000010 +01111100 +00000010 +00000010 +01111100 +z +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +11111110 +00000100 +00001000 +00110000 +01000000 +11111110 +00000000 +00000000 +00000000 +{ +00000000 +00000000 +00001000 +00010000 +00010000 +00010000 +00010000 +00100000 +00010000 +00010000 +00010000 +00010000 +00001000 +00000000 +00000000 +| +00000000 +00000000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00000000 +00000000 +00000000 +} +00000000 +00000000 +00100000 +00010000 +00010000 +00010000 +00010000 +00001000 +00010000 +00010000 +00010000 +00010000 +00100000 +00000000 +00000000 +~ +00000000 +00000000 +00000000 +01100000 +10010010 +00001100 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00000000 +00010000 +00000000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00000000 + +00000000 +00000000 +00000000 +00000000 +00000000 +00010000 +01111100 +10000010 +10000000 +10000000 +10000010 +01111100 +00010000 +00000000 +00000000 + +00000000 +00000000 +00001000 +00010100 +00010000 +00010000 +00111100 +00010000 +00010000 +00110000 +01010010 +00101100 +00000000 +00000000 +00000000 + +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +01000000 +00100000 +00010000 +00010000 +00000000 +00010000 +00000000 +00000000 +00000000 + +00000000 +00000000 +10000010 +10000010 +01000100 +01111100 +00010000 +01111100 +00010000 +00010000 +00010000 +00010000 +00000000 +00000000 +00000000 + +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +01000000 +00100000 +00010000 +00010000 +00000000 +00010000 +00000000 +00000000 +00000000 + +00000000 +00000000 +01111100 +10000010 +10000000 +01111100 +10000010 +10000010 +01111100 +00000010 +10000010 +01111100 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +10000010 +01111100 +10000010 +10000010 +10000010 +10000010 +01111100 +10000010 +00000000 +00000000 +00000000 +00000000 + +00000000 +00000000 +01111100 +10000010 +10011010 +10100010 +10100010 +10100010 +10011010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00111000 +00000100 +00111100 +01000100 +00111010 +00000000 +01111110 +00000000 +00000000 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00001010 +00010100 +00101000 +01010000 +10100000 +01010000 +00101000 +00010100 +00001010 +00000000 +00000000 +00000000 + +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +01000000 +00100000 +00010000 +00010000 +00000000 +00010000 +00000000 +00000000 +00000000 + +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +01000000 +00100000 +00010000 +00010000 +00000000 +00010000 +00000000 +00000000 +00000000 + +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +01000000 +00100000 +00010000 +00010000 +00000000 +00010000 +00000000 +00000000 +00000000 + +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +01000000 +00100000 +00010000 +00010000 +00000000 +00010000 +00000000 +00000000 +00000000 + +00000000 +00000000 +00110000 +01001000 +00110000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00000000 +00010000 +00010000 +11111110 +00010000 +00010000 +00000000 +11111110 +00000000 +00000000 +00000000 +00000000 + +00000000 +00000000 +00111000 +01000100 +01000100 +00001000 +00010000 +00100000 +01111100 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + +00000000 +00000000 +00111000 +01000100 +00000100 +00011000 +00000100 +01000100 +00111000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +01000000 +00100000 +00010000 +00010000 +00000000 +00010000 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +01000010 +01000010 +01000010 +01000010 +01100110 +01011010 +01000000 +10000000 +00000000 + +00000000 +00000000 +00101000 +01101000 +11101000 +11101000 +11101000 +01101000 +00101000 +00101000 +00101000 +00101000 +00101000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00011000 +00011000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +01000000 +00100000 +00010000 +00010000 +00000000 +00010000 +00000000 +00000000 +00000000 + +00000000 +00000000 +00010000 +00110000 +00010000 +00010000 +00010000 +00010000 +00111000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00111100 +01000010 +01000010 +01000010 +00111100 +00000000 +01111110 +00000000 +00000000 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +10100000 +01010000 +00101000 +00010100 +00001010 +00010100 +00101000 +01010000 +10100000 +00000000 +00000000 +00000000 + +00000000 +00000000 +01000000 +11000000 +01000010 +01000100 +11101000 +00010100 +00101100 +01010100 +10011110 +00000100 +00000000 +00000000 +00000000 + +00000000 +00000000 +01000000 +11000000 +01000010 +01000100 +11101000 +00011100 +00110010 +01000100 +10001000 +00011110 +00000000 +00000000 +00000000 + +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +01000000 +00100000 +00010000 +00010000 +00000000 +00010000 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00010000 +00000000 +00010000 +00010000 +00100000 +01000000 +10000000 +10000000 +10000010 +01111100 +00000000 +00000000 + +00000000 +01000000 +00100000 +00000000 +00111000 +01000100 +10000010 +10000010 +11111110 +10000010 +10000010 +10000010 +00000000 +00000000 +00000000 + +00000000 +00000100 +00001000 +00000000 +00111000 +01000100 +10000010 +10000010 +11111110 +10000010 +10000010 +10000010 +00000000 +00000000 +00000000 + +00000000 +00010000 +00101000 +00000000 +00111000 +01000100 +10000010 +10000010 +11111110 +10000010 +10000010 +10000010 +00000000 +00000000 +00000000 + +00000000 +00110100 +01001000 +00000000 +00111000 +01000100 +10000010 +10000010 +11111110 +10000010 +10000010 +10000010 +00000000 +00000000 +00000000 + +00000000 +00101000 +00101000 +00000000 +00111000 +01000100 +10000010 +10000010 +11111110 +10000010 +10000010 +10000010 +00000000 +00000000 +00000000 + +00000000 +00010000 +00101000 +00010000 +00111000 +01000100 +10000010 +10000010 +11111110 +10000010 +10000010 +10000010 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00000000 +00111110 +01010000 +01010000 +10010000 +10011100 +11110000 +10010000 +10011110 +00000000 +00000000 +00000000 + +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +10000000 +10000000 +10000000 +10000000 +10000010 +01111100 +00001000 +00010000 +00000000 + +00000000 +01000000 +00100000 +00000000 +11111110 +10000000 +10000000 +11111000 +10000000 +10000000 +10000000 +11111110 +00000000 +00000000 +00000000 + +00000000 +00001000 +00010000 +00000000 +11111110 +10000000 +10000000 +11111000 +10000000 +10000000 +10000000 +11111110 +00000000 +00000000 +00000000 + +00000000 +00010000 +00101000 +00000000 +11111110 +10000000 +10000000 +11111000 +10000000 +10000000 +10000000 +11111110 +00000000 +00000000 +00000000 + +00000000 +00101000 +00101000 +00000000 +11111110 +10000000 +10000000 +11111000 +10000000 +10000000 +10000000 +11111110 +00000000 +00000000 +00000000 + +00000000 +01000000 +00100000 +00000000 +01111100 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +01111100 +00000000 +00000000 +00000000 + +00000000 +00001000 +00010000 +00000000 +01111100 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +01111100 +00000000 +00000000 +00000000 + +00000000 +00010000 +00101000 +00000000 +01111100 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +01111100 +00000000 +00000000 +00000000 + +00000000 +00101000 +00101000 +00000000 +01111100 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +01111100 +00000000 +00000000 +00000000 + +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +01000000 +00100000 +00010000 +00010000 +00000000 +00010000 +00000000 +00000000 +00000000 + +00000000 +00110100 +01001000 +00000000 +10000010 +11000010 +10100010 +10010010 +10010010 +10001010 +10000110 +10000010 +00000000 +00000000 +00000000 + +00000000 +01000000 +00100000 +00000000 +01111100 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 + +00000000 +00001000 +00010000 +00000000 +01111100 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 + +00000000 +00010000 +00101000 +00000000 +01111100 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 + +00000000 +00110100 +01001000 +00000000 +01111100 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 + +00000000 +00101000 +00101000 +00000000 +01111100 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00000000 +01111110 +10010000 +10010000 +10010000 +10011100 +10010000 +10010000 +01111110 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00000010 +01111100 +10000110 +10001010 +10010010 +10010010 +10100010 +11000010 +01111100 +10000000 +00000000 +00000000 + +00000000 +01000000 +00100000 +00000000 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 + +00000000 +00001000 +00010000 +00000000 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 + +00000000 +00010000 +00101000 +00000000 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 + +00000000 +00101000 +00101000 +00000000 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 + +00000000 +00101000 +00101000 +00000000 +10000010 +10000010 +01000100 +00101000 +00010000 +00010000 +00010000 +00010000 +00000000 +00000000 +00000000 + +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +01000000 +00100000 +00010000 +00010000 +00000000 +00010000 +00000000 +00000000 +00000000 + +00000000 +00000000 +01111100 +10000010 +10000010 +10000010 +10111100 +10000010 +10000010 +10000010 +10000010 +10111100 +10000000 +10000000 +00000000 + +00000000 +00000000 +00000000 +01000000 +00100000 +00000000 +01111000 +00000100 +01111100 +10000100 +10000100 +01111010 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00001000 +00010000 +00000000 +01111000 +00000100 +01111100 +10000100 +10000100 +01111010 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00010000 +00101000 +00000000 +01111000 +00000100 +01111100 +10000100 +10000100 +01111010 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00110100 +01001000 +00000000 +01111000 +00000100 +01111100 +10000100 +10000100 +01111010 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00101000 +00101000 +00000000 +01111000 +00000100 +01111100 +10000100 +10000100 +01111010 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00010000 +00101000 +00010000 +01111000 +00000100 +01111100 +10000100 +10000100 +01111010 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +01101100 +00010010 +01111110 +10010000 +10010010 +01101100 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +10000010 +01111100 +00001000 +00010000 +00000000 + +00000000 +00000000 +00000000 +01000000 +00100000 +00000000 +01111100 +10000010 +10000010 +11111110 +10000000 +01111100 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00001000 +00010000 +00000000 +01111100 +10000010 +10000010 +11111110 +10000000 +01111100 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00010000 +00101000 +00000000 +01111100 +10000010 +10000010 +11111110 +10000000 +01111100 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00101000 +00101000 +00000000 +01111100 +10000010 +10000010 +11111110 +10000000 +01111100 +00000000 +00000000 +00000000 + +00000000 +00000000 +00100000 +00010000 +00000000 +00110000 +00010000 +00010000 +00010000 +00010000 +00010000 +01111100 +00000000 +00000000 +00000000 + +00000000 +00000000 +00001000 +00010000 +00000000 +00110000 +00010000 +00010000 +00010000 +00010000 +00010000 +01111100 +00000000 +00000000 +00000000 + +00000000 +00000000 +00010000 +00101000 +00000000 +00110000 +00010000 +00010000 +00010000 +00010000 +00010000 +01111100 +00000000 +00000000 +00000000 + +00000000 +00000000 +00101000 +00101000 +00000000 +00110000 +00010000 +00010000 +00010000 +00010000 +00010000 +01111100 +00000000 +00000000 +00000000 + +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +01000000 +00100000 +00010000 +00010000 +00000000 +00010000 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00110100 +01001000 +00000000 +10111100 +10000010 +10000010 +10000010 +10000010 +10000010 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +01000000 +00100000 +00000000 +01111100 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00001000 +00010000 +00000000 +01111100 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00010000 +00101000 +00000000 +01111100 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00110100 +01001000 +00000000 +01111100 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00101000 +00101000 +00000000 +01111100 +10000010 +10000010 +10000010 +10000010 +01111100 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +01101100 +10010010 +10011110 +10010000 +10010010 +01101100 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000010 +01111100 +10001010 +10010010 +10010010 +10100010 +01111100 +10000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +01000000 +00100000 +00000000 +10000010 +10000010 +10000010 +10000010 +10000010 +01111010 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00001000 +00010000 +00000000 +10000010 +10000010 +10000010 +10000010 +10000010 +01111010 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00010000 +00101000 +00000000 +10000010 +10000010 +10000010 +10000010 +10000010 +01111010 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00101000 +00101000 +00000000 +10000010 +10000010 +10000010 +10000010 +10000010 +01111010 +00000000 +00000000 +00000000 + +00000000 +00000000 +00000000 +00101000 +00101000 +00000000 +10000010 +10000010 +10000010 +10000010 +10000010 +01111100 +00000010 +00000010 +01111100 + +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +01000000 +00100000 +00010000 +00010000 +00000000 +00010000 +00000000 +00000000 +00000000 + +00000000 +00000000 +01111100 +10000010 +10000000 +10000000 +01000000 +00100000 +00010000 +00010000 +00000000 +00010000 +00000000 +00000000 +00000000 diff --git a/chips/lance.c b/chips/lance.c new file mode 100644 index 0000000..750d4c5 --- /dev/null +++ b/chips/lance.c @@ -0,0 +1,1570 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: lance.c + * Author: Robert V. Baron & Alessandro Forin + * Date: 5/90 + * + * Driver for the DEC LANCE Ethernet Controller. + */ + +/* + + Byte ordering issues. + + The lance sees data naturally as half word (16 bit) quantitites. + Bit 2 (BSWP) in control register 3 (CSR3) controls byte swapping. + To quote the spec: + + 02 BSWP BYTE SWAP allows the chip to + operate in systems that consdier bits (15:08) of data pointers + by an even addressa and bits (7:0) to be pointed by an + odd address. + + When BSWP=1, the chip will swap the high and low bytes on DMA + data transfers between the silo and bus memory. Only data from + silo transfers is swapped; the Initialization Block data and + the Descriptor Ring entries are NOT swapped. (emphasis theirs) + + + So on systems with BYTE_MSF=1, the BSWP bit should be set. Note, + however, that all shorts in the descriptor ring and initialization + block need to be swapped. The BITFIELD macros in lance.h handle this + magic. + +*/ + +#include +#if NLN > 0 +#include + +/* + * AMD Am7990 LANCE (Ethernet Interface) + */ +#include +#include + +#include /* spl definitions */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef FLAMINGO +#define se_reg_type unsigned int +#endif + +#include +#include + +#define private static +#define public + +typedef struct se_softc *se_softc_t; /* move above prototypes */ + +void se_write_reg(); /* forwards */ +void se_read(); +void se_rint(); +void se_tint(); + +private vm_offset_t se_Hmem_nogap(), se_Hmem_gap16(); +private vm_offset_t se_malloc(); + + +/* This config section should go into a separate file */ + +#ifdef LUNA88K +# include +# define MAPPED 1 + #undef bcopy + extern void bcopy(), bzero(); + +#define wbflush() +#define Hmem(lna) (vm_offset_t)((lna) + sc->lnbuf) +#define Lmem(lna) (vm_offset_t)((lna) + sc->lnoffset) + +#define SPACE (TRI_PORT_RAM_SPACE>>1) +private struct se_switch se_switch[] = { + { LANCE_ADDR - TRI_PORT_RAM, /* pointer */ + SPACE /* host side */, + SPACE /* lance side */, + - TRI_PORT_RAM, + 0, /* romstride */ + 0, /* ramstride */ + SPACE, + /* desc_copyin */ bcopy, + /* desc_copyout */ bcopy, + /* data_copyin */ bcopy, + /* data_copyout */ bcopy, + /* bzero */ bzero, + /* mapaddr */ se_Hmem_nogap, + /* mapoffs */ se_Hmem_nogap + }, +}; + +#endif + +#ifdef DECSTATION +#include +#include + +#define MAPPED 1 + +/* + * The LANCE buffer memory as seen from the Pmax cpu is funny. + * It is viewed as short words (16bits), spaced at word (32bits) + * intervals. The same applies to the registers. From the LANCE + * point of view memory is instead contiguous. + * The ROM that contains the station address is in the space belonging + * to the clock/battery backup memory. This space is again 16 bits + * in a 32bit envelope. And the ether address is stored in the "high" + * byte of 6 consecutive quantities. + * + * But Pmaxen and 3maxen (and..) map lance space differently. + * This requires dynamic adaptation of the driver, which + * is done via the following switches. + * For convenience, the switch holds information about + * the location of the lance control registers as well. + * This could be either absolute (pmax) or relative to + * some register base (3max, turbochannel) + */ +void copyin_gap16(), copyout_gap16(), bzero_gap16(); +extern void bcopy(), bzero(); +void copyin_gap32(), copyout_gap32(); + +private struct se_switch se_switch[] = { +/* pmax */ + { 0x00000000, 0x01000000, 0x0, 0x05000000, 8, 16, 64*1024, + copyin_gap16, copyout_gap16, copyin_gap16, copyout_gap16, + bzero_gap16, se_Hmem_gap16, se_Hmem_gap16}, +/* 3max */ + { PMAD_OFFSET_LANCE, PMAD_OFFSET_RAM, PMAD_OFFSET_RAM, PMAD_OFFSET_ROM, + 16, 0, PMAD_RAM_SIZE, + bcopy, bcopy, bcopy, bcopy, bzero, se_Hmem_nogap, se_Hmem_nogap}, +/* 3min */ +/* XXX re-use other 64k */ + { 0/*later*/, 0/*later*/, 0x0, 0/*later*/, 0, 128, 64*1024, + copyin_gap16, copyout_gap16, copyin_gap32, copyout_gap32, + bzero_gap16, se_Hmem_gap16, se_Hmem_nogap}, +}; + +/* + * "lna" is what se_malloc hands back. They are offsets using + * the sizing that the Lance would use. The Lance space is + * mapped somewhere in the I/O space, as indicated by the softc. + * Hence we have these two macros: + */ +/* H & L are not hi and lo but + H = HOST == addresses for host to reference board memory + L = LOCAL == addresses on board + */ +#define Hmem(lna) (vm_offset_t)((se_sw->mapaddr)(lna) + sc->lnbuf) +#define Lmem(lna) (vm_offset_t)((vm_offset_t)lna + sc->lnoffset) +#endif /*DECSTATION*/ + + +#ifdef VAXSTATION +#include + +#define wbflush() + +void xzero(x, l) vm_offset_t x; int l; { blkclr(x, l); } +void xcopy(f, t, l) vm_offset_t f, t; int l; { bcopy(f, t, l); } + +private struct se_switch se_switch[] = { + /* pvax sees contiguous bits in lower 16Meg of memory */ + { 0, 0, 0, 0, 0, 0, 64*1024, + xcopy, xcopy, xcopy, xcopy, xzero, se_Hmem_nogap, se_Hmem_nogap}, +}; + +/* + * "lna" is what se_malloc hands back. They are offsets using + * the sizing that the Lance would use. The Lance space is + * mapped somewhere in the I/O space, as indicated by the softc. + * Hence we have these two macros: + */ +/* H & L are not hi and lo but + H = HOST == addresses for host to reference board memory + L = LOCAL == addresses on board + */ + /* + * This does not deal with > 16 Meg physical memory, where + * Hmem != Lmem + */ +#define Hmem(lna) (vm_offset_t)((lna) + sc->lnbuf) +#define Lmem(lna) (vm_offset_t)((lna) + sc->lnoffset) + +#endif /*VAXSTATION*/ + + +#ifdef FLAMINGO +#include + +/* XXX might be wrong, mostly stolen from kmin */ +extern void copyin_gap16(), copyout_gap16(), bzero_gap16(); +extern void copyin_gap32(), copyout_gap32(); +extern void bcopy(), bzero(); + +private struct se_switch se_switch[] = { +/* XXX re-use other 64k */ + { 0/*later*/, 0/*later*/, 0x0, 0/*later*/, 0, 128, 64*1024, + copyin_gap16, copyout_gap16, copyin_gap32, copyout_gap32, + bzero_gap16, se_Hmem_gap16, se_Hmem_nogap}, +}; + +/* + * "lna" is what se_malloc hands back. They are offsets using + * the sizing that the Lance would use. The Lance space is + * mapped somewhere in the I/O space, as indicated by the softc. + * Hence we have these two macros: + */ +/* H & L are not hi and lo but + H = HOST == addresses for host to reference board memory + L = LOCAL == addresses on board + */ +#define Hmem(lna) (vm_offset_t)((se_sw->mapaddr)(lna) + sc->lnbuf) +#define Lmem(lna) (vm_offset_t)((vm_offset_t)lna + sc->lnoffset) +#endif /*FLAMINGO*/ + + +/* + * Map a lance-space offset into an host-space one + */ +private vm_offset_t se_Hmem_nogap( vm_offset_t lna) { return lna;} +private vm_offset_t se_Hmem_gap16( vm_offset_t lna) { return lna << 1;} + +/* + * Memory addresses for LANCE are 24 bits wide. + */ +#define Addr_lo(y) ((unsigned short)((vm_offset_t)(y) & 0xffff)) +#define Addr_hi(y) ((unsigned short)(((vm_offset_t)(y)>>16) & 0xff)) + +#define LN_MEMORY_SIZE (se_sw->ramsize) + +/* XXX to accomodate heterogeneity this should be made per-drive */ +/* XXX and then some more */ + +struct se_switch *se_sw = se_switch; + +void set_se_switch(n) +int n; +{ + se_sw = &se_switch[n]; +} + +#ifndef LUNA88K +void setse_switch(n, r, b, l, o) + vm_offset_t r, b, l, o; + int n; +{ + se_switch[n].regspace = r; + se_switch[n].bufspace = b; + se_switch[n].ln_bufspace = l; + se_switch[n].romspace = o; + + /* make sure longword aligned */ + if (se_switch[n].bufspace & 0x7) { + se_switch[n].bufspace = (se_switch[n].bufspace+0x7) & ~0x7; + } + + set_se_switch(n); +} +#endif + +/* + * Autoconf info + */ + +private vm_offset_t se_std[NLN] = { 0 }; +private struct bus_device *se_info[NLN]; +private int se_probe(); +private void se_attach(); + +struct bus_driver se_driver = + { se_probe, 0, se_attach, 0, se_std, "se", se_info, }; + +/* + * Externally visible functions + */ +char *se_unprobed_addr = 0; +void se_intr(); /* kernel */ + +int se_open(), se_output(), se_get_status(), /* user */ + se_set_status(), se_setinput(), se_restart(); + +/* + * + * Internal functions & definitions + * + */ + +private int se_probe(); +private void se_init(); +private void init_lance_space(); +private void se_desc_set_status(); +private volatile long *se_desc_alloc(); /* must be aligned! */ +void se_start(); +private void copy_from_lance(); +private int copy_to_lance(); + +int se_verbose = 0; /* debug flag */ + +#define RLOG 4 /* 2**4 = 16 receive descriptors */ +#define TLOG 4 /* 2**4 = 16 transmit descriptors */ +#define NRCV (1<unit; + + /* + * See if the interface is there by reading the lance CSR. On pmaxen + * and 3maxen this is superfluous, but.. + */ + rdp = (se_reg_t) (reg + se_sw->regspace); +#ifdef DECSTATION + if (check_memory(rdp, 0)) + return 0; +#endif /*DECSTATION*/ +#ifdef MAPPED + SE_probe(reg,ui); +#endif /*MAPPED*/ + rap = rdp + 2; /* XXX might not be true in the future XXX */ + /* rdp and rap are "shorts" on consecutive + "long" word boundaries */ + + /* + * Bind this interface to the softc. + */ + sc = &se_softc_data[unit]; + se_softc[unit] = sc; + sc->lnregs = (se_reg_t) (reg + se_sw->regspace); + sc->lnbuf = (vm_offset_t) (reg + se_sw->bufspace); + sc->lnoffset = (vm_offset_t) (se_sw->ln_bufspace); + sc->lnrom = (vm_offset_t) (reg + se_sw->romspace); + + /* + * Reset the interface, and make sure we really do it! (the 3max + * seems quite stubborn about these registers) + */ + se_write_reg(rap, CSR0_SELECT, CSR0_SELECT, "RAP"); + se_write_reg(rdp, LN_CSR0_STOP, LN_CSR0_STOP, "csr0"); + + /* + * Allocate lance RAM buffer memory + */ + init_lance_space(sc); + + /* + * Initialize the chip + * + * NOTE: From now on we will only touch csr0 + */ + if (se_ship_init_block(sc, unit)) + return 0; + + /* + * Tell the world we are alive and well + */ + se_open_state++; + return 1; +} + +int se_ship_init_block( + register se_softc_t sc, + int unit) +{ + se_reg_t rdp = sc->lnregs; + se_reg_t rap; + register int i = 0; + + rap = rdp + 2; /* XXX might not be true in the future XXX */ + + /* + * Load LANCE control block. + */ + +#ifdef LUNA88K + /* turn on byte swap bit in csr3, set bcon bit - as in 2.5 */ + se_write_reg(rap, CSR3_SELECT, CSR3_SELECT, "RAP"); + se_write_reg(rdp, LN_CSR3_BSWP|LN_CSR3_BCON, + LN_CSR3_BSWP|LN_CSR3_BCON, "csr3"); +#endif + + se_write_reg(rap, CSR1_SELECT, CSR1_SELECT, "RAP"); + se_write_reg(rdp, Addr_lo(Lmem(sc->lninit_block)), + Addr_lo(Lmem(sc->lninit_block)), "csr1"); + + se_write_reg(rap, CSR2_SELECT, CSR2_SELECT, "RAP"); + se_write_reg(rdp, Addr_hi(Lmem(sc->lninit_block)), + Addr_hi(Lmem(sc->lninit_block)), "csr2"); + + /* + * Start the INIT sequence now + */ + se_write_reg(rap, CSR0_SELECT, CSR0_SELECT, "RAP"); + *rdp = (LN_CSR0_IDON | LN_CSR0_INIT); + wbflush(); + + /* give it plenty of time to settle */ + while (i++ < 10000) { + delay(100); + if ((*rdp & LN_CSR0_IDON) != 0) + break; + } + /* make sure got out okay */ + if ((*rdp & LN_CSR0_IDON) == 0) { + printf("se%d: cannot initialize\n", unit); + if (*rdp & LN_CSR0_ERR) + printf("se%d: initialization error, csr = %04x\n", + unit, (*rdp & 0xffff)); + return 1; + } + /* + * Do not enable interrupts just yet. + */ + /* se_write_reg(rdp, LN_CSR0_STOP, LN_CSR0_STOP, "csr0"); */ + + return 0; +} + +void +se_write_reg( + register se_reg_t regptr, + register int val, + register int result, + char *regname) +{ + register int i = 0; + + while ((unsigned short)(*regptr) != (unsigned short)result) { + *regptr = (se_reg_type)val; + wbflush(); + if (++i > 10000) { + printf("se: %s did not settle (to x%x): x%x\n", + regname, result, (unsigned short)(*regptr)); + return; + } + delay(100); + } +} + +unsigned short +se_read_reg( + register se_reg_t regptr) +{ + return (unsigned short) (*regptr); +} + +private void +init_lance_space( + register se_softc_t sc) +{ + register int lptr; /* Generic lance pointer */ + se_desc_t ringaddr; + long *rom_eaddress = (long *) sc->lnrom; + int i; + struct se_init_block init_block; + + /* + * Allocate local RAM buffer memory for the init block, + * fill in our local copy then copyout. + */ + + sc->lninit_block = se_malloc(sc, sizeof (struct se_init_block)); + + /* + * Set values on stack, then copyout en-masse + */ + bzero(&init_block, sizeof(init_block)); + init_block.mode = 0; + + /* byte swapping between host and lance */ + + init_block.phys_addr_low = ((rom_eaddress[0]>>se_sw->romstride)&0xff) | + (((rom_eaddress[1]>>se_sw->romstride)&0xff) << 8); + init_block.phys_addr_med = ((rom_eaddress[2]>>se_sw->romstride)&0xff) | + (((rom_eaddress[3]>>se_sw->romstride)&0xff) << 8); + init_block.phys_addr_high = ((rom_eaddress[4]>>se_sw->romstride)&0xff) | + (((rom_eaddress[5]>>se_sw->romstride)&0xff) << 8); + + /* + * Allocate both descriptor rings at once. + * Note that the quadword alignment requirement is + * inherent in the way we perform allocation, + * but it does depend on the size of the init block. + */ + lptr = se_malloc(sc, sizeof (struct se_desc) * (NXMT + NRCV)); + + /* + * Initialize the buffer descriptors + */ + init_block.recv_ring_pointer_lo = Addr_lo(Lmem(lptr)); + init_block.recv_ring_pointer_hi = Addr_hi(Lmem(lptr)); + init_block.recv_ring_len = RLOG; + + for ( i = 0; i < NRCV ; i++, lptr += sizeof(struct se_desc)) { + ringaddr = (se_desc_t)Hmem(lptr); + sc->lnrring[i] = ringaddr; + sc->lnrbuf[i] = se_desc_alloc (sc, ringaddr); + } + + init_block.xmit_ring_pointer_lo = Addr_lo(Lmem(lptr)); + init_block.xmit_ring_pointer_hi = Addr_hi(Lmem(lptr)); + init_block.xmit_ring_len = TLOG; + + for ( i = 0 ; i < NXMT ; i++, lptr += sizeof(struct se_desc)) { + ringaddr = (se_desc_t)Hmem(lptr); + sc->lntring[i] = ringaddr; + sc->lntbuf[i] = se_desc_alloc (sc, ringaddr); + } + + /* + * No logical address filtering + */ + init_block.logical_addr_filter0 = 0; + init_block.logical_addr_filter1 = 0; + init_block.logical_addr_filter2 = 0; + init_block.logical_addr_filter3 = 0; + + /* + * Move init block into lance space + */ + (se_sw->desc_copyout)((vm_offset_t)&init_block, Hmem(sc->lninit_block), sizeof(init_block)); + wbflush(); +} + +/* + * Interface exists: make available by filling in network interface + * record. System will initialize the interface when it is ready + * to accept packets. + */ +private void +se_attach( + register struct bus_device *ui) +{ + unsigned char *enaddr; + struct ifnet *ifp; + long *rom_eaddress; + int unit = ui->unit; + se_softc_t sc = se_softc[unit]; + + rom_eaddress = (long *) sc->lnrom; + + /* + * Read the address from the prom and save it. + */ + enaddr = sc->is_addr; + enaddr[0] = (unsigned char) ((rom_eaddress[0] >> se_sw->romstride) & 0xff); + enaddr[1] = (unsigned char) ((rom_eaddress[1] >> se_sw->romstride) & 0xff); + enaddr[2] = (unsigned char) ((rom_eaddress[2] >> se_sw->romstride) & 0xff); + enaddr[3] = (unsigned char) ((rom_eaddress[3] >> se_sw->romstride) & 0xff); + enaddr[4] = (unsigned char) ((rom_eaddress[4] >> se_sw->romstride) & 0xff); + enaddr[5] = (unsigned char) ((rom_eaddress[5] >> se_sw->romstride) & 0xff); + + printf(": %x-%x-%x-%x-%x-%x", + (rom_eaddress[0] >> se_sw->romstride) & 0xff, + (rom_eaddress[1] >> se_sw->romstride) & 0xff, + (rom_eaddress[2] >> se_sw->romstride) & 0xff, + (rom_eaddress[3] >> se_sw->romstride) & 0xff, + (rom_eaddress[4] >> se_sw->romstride) & 0xff, + (rom_eaddress[5] >> se_sw->romstride) & 0xff); + + /* + * Initialize the standard interface descriptor + */ + ifp = &sc->is_if; + ifp->if_unit = unit; + ifp->if_header_size = sizeof(struct ether_header); + ifp->if_header_format = HDR_ETHERNET; + ifp->if_address_size = 6; + ifp->if_mtu = ETHERMTU; + ifp->if_flags |= IFF_BROADCAST; + + ifp->if_address = (char *) enaddr; + + if_init_queues(ifp); +#ifdef MAPPED + SE_attach(ui); +#endif /*MAPPED*/ + +} + +/* + * Use a different hardware address for interface + */ +void +se_setaddr( + unsigned char eaddr[6], + int unit) +{ + register se_softc_t sc = se_softc[unit]; + struct se_init_block init_block; + + /* + * Modify initialization block accordingly + */ + (se_sw->desc_copyin) (Hmem(sc->lninit_block), (vm_offset_t)&init_block, sizeof(init_block)); + bcopy(eaddr, &init_block.phys_addr_low, sizeof(*eaddr)); + (se_sw->desc_copyout)((vm_offset_t)&init_block, Hmem(sc->lninit_block), sizeof(init_block)); + /* + * Make a note of it + */ + bcopy(eaddr, sc->is_addr, sizeof(*eaddr)); + + /* + * Restart the interface + */ + se_restart(&sc->is_if); + se_init(unit); +} + +/* + * Restart interface + * + * We use this internally on those errors that hang the chip, + * not sure yet what use the MI code will make of it. + * + * After stopping the chip and effectively turning off the interface + * we release all pending buffers and cause the chip to init + * itself. We do not enable interrupts here. + */ +int +se_restart( register struct ifnet *ifp ) +{ + register se_softc_t sc = se_softc[ifp->if_unit]; + se_reg_t rdp; + register int i; + + rdp = sc->lnregs; + + /* + * stop the chip + */ + se_write_reg(rdp, LN_CSR0_STOP, LN_CSR0_STOP, "csr0"); + + /* + * stop network activity + */ + if (ifp->if_flags & IFF_RUNNING) { + ifp->if_flags &= ~(IFF_UP | IFF_RUNNING); + sc->se_flags &= ~(IFF_UP | IFF_RUNNING); + } + sc->rstrtcnt++; + + if (se_verbose) + printf("se%d: %d restarts\n", ifp->if_unit, sc->rstrtcnt); + + /* + * free up any buffers currently in use + */ + for (i = 0; i < NXMT; i++) + if (sc->tpkt[i]) { + iodone(sc->tpkt[i]); + sc->tpkt[i] = (io_req_t) 0; + } + /* + * INIT the chip again, no need to reload init block address. + */ + se_ship_init_block(sc, ifp->if_unit); + + return (0); +} + +/* + * Initialize the interface. + */ +private void +se_init( int unit ) +{ + register se_softc_t sc = se_softc[unit]; + register se_desc_t *rp; + register struct ifnet *ifp = &sc->is_if; + se_reg_t rdp; + short mode; + spl_t s; + int i; + + if (ifp->if_flags & IFF_RUNNING) + return; + + rdp = sc->lnregs; + + /* + * Init the buffer descriptors and indexes for each of the rings. + */ + for (i = 0, rp = sc->lnrring; i < NRCV; i++, rp++) + se_desc_set_status(*rp, LN_RSTATE_OWN); + + for (i = 0, rp = sc->lntring; i < NXMT; i++, rp++) + se_desc_set_status(*rp, 0); + + sc->xmt_count = sc->xmt_complete = sc->xmt_last = sc->rcv_last = 0; + + /* + * Deal with loopback mode operation + */ + s = splimp(); + + (se_sw->desc_copyin) (Hmem(sc->lninit_block), (vm_offset_t)&mode, sizeof(mode)); + + if (ifp->if_flags & IFF_LOOPBACK + && ((mode & LN_MODE_LOOP) == 0)) { + /* if not already in loopback mode, do external loopback */ + mode &= ~LN_MODE_INTL; + mode |= LN_MODE_LOOP; + (se_sw->desc_copyout) ((vm_offset_t)&mode, Hmem(sc->lninit_block), sizeof(mode)); + se_restart(ifp); + se_init(ifp->if_unit); + splx(s); + return; + } + + ifp->if_flags |= (IFF_UP | IFF_RUNNING); + sc->se_flags |= (IFF_UP | IFF_RUNNING); + + /* + * Start the Lance and enable interrupts + */ + *rdp = (LN_CSR0_STRT | LN_CSR0_INEA); + wbflush(); + + /* + * See if anything is already queued + */ + se_start(unit); + splx(s); +} + + +/* + * Shut off the lance + */ +void +se_stop(int unit) +{ + se_reg_t rdp = se_softc[unit]->lnregs; + + se_write_reg(rdp, LN_CSR0_STOP, LN_CSR0_STOP, "csr0"); +} + + +/* + * Open the device, declaring the interface up + * and enabling lance interrupts. + */ +/*ARGSUSED*/ +int +se_open( + int unit, + int flag) +{ + register se_softc_t sc = se_softc[unit]; + + if (unit >= NLN) + return EINVAL; + if (!se_open_state) + return ENXIO; + + sc->is_if.if_flags |= IFF_UP; + se_open_state++; + se_init(unit); + return (0); +} + +#ifdef MAPPED +int se_use_mapped_interface[NLN]; +#endif /*MAPPED*/ + +void +se_normal(int unit) +{ +#ifdef MAPPED + se_use_mapped_interface[unit] = 0; +#endif /*MAPPED*/ + if (se_softc[unit]) { + se_restart((struct ifnet *)se_softc[unit]); + se_init(unit); + } +} + +/* + * Ethernet interface interrupt routine + */ +void +se_intr( + int unit, + spl_t spllevel) +{ + register se_softc_t sc = se_softc[unit]; + se_reg_t rdp; + register struct ifnet *ifp = &sc->is_if; + register unsigned short csr; + +#ifdef MAPPED + if (se_use_mapped_interface[unit]) + { + SE_intr(unit,spllevel); + return; + } +#endif /*MAPPED*/ + + if (se_open_state < 2) { /* Stray, or not open for business */ + rdp = (sc ? sc->lnregs : (se_reg_t)se_unprobed_addr); + *rdp |= LN_CSR0_STOP; + wbflush(); + return; + } + rdp = sc->lnregs; + + /* + * Read the CSR and process any error condition. + * Later on, restart the lance by writing back + * the CSR (for set-to-clear bits). + */ + csr = *rdp; /* pick up the csr */ + + /* drop spurious interrupts */ + if ((csr & LN_CSR0_INTR) == 0) + return; + +#ifdef DECSTATION + splx(spllevel); /* drop priority now */ +#endif /*DECSTATION*/ +again: + /* + * Check for errors first + */ + if ( csr & LN_CSR0_ERR ) { + if (csr & LN_CSR0_MISS) { + /* + * Stop the chip to prevent a corrupt packet from + * being transmitted. There is a known problem with + * missed packet errors causing corrupted data to + * be transmitted to the same host as was just + * transmitted, with a valid crc appended to the + * packet. The only solution is to stop the chip, + * which will clear the Lance silo, thus preventing + * the corrupt data from being sent. + */ + se_write_reg(rdp, LN_CSR0_STOP, LN_CSR0_STOP, "csr0"); + + sc->misscnt++; + if (se_verbose) { + int me = 0, lance = 0, index; + struct se_desc r; + for (index = 0; index < NRCV; index++) { + (se_sw->desc_copyin)( + (vm_offset_t)sc->lnrring[index], + (vm_offset_t)&r, + sizeof(r)); + if (r.status & LN_RSTATE_OWN) + lance++; + else + me++; + } + printf("se%d: missed packet (%d) csr = %x, Lance %x, me %x\n", + unit, sc->misscnt, csr, lance, me); + } + se_restart(ifp); + se_init(unit); + return; + } + if (csr & LN_CSR0_BABL) { + sc->bablcnt++; + if (se_verbose) + printf("se%d: xmt timeout (%d)\n", + unit, sc->bablcnt); + } + if (csr & LN_CSR0_MERR) { + sc->merrcnt++; + printf("se%d: memory error (%d)\n", + unit, sc->merrcnt); + + if (((csr & LN_CSR0_RXON) == 0) + || ((csr & LN_CSR0_TXON) == 0)) { + se_restart(ifp); + se_init(unit); + return; + } + } + } + + *rdp = LN_CSR0_INEA | (csr & LN_CSR0_WTC); + wbflush(); + + if ( csr & LN_CSR0_RINT ) + se_rint( unit ); + + if ( csr & LN_CSR0_TINT ) + se_tint( unit ); + + if ((csr = *rdp) & (LN_CSR0_RINT | LN_CSR0_TINT)) + goto again; +} + +/* + * Handle a transmitter complete interrupt. + */ +void +se_tint(int unit) +{ + register se_softc_t sc = se_softc[unit]; + register index; + register status; + io_req_t request; + struct se_desc r; + + /* + * Free up descriptors for all packets in queue for which + * transmission is complete. Start from queue tail, stop at first + * descriptor we do not OWN, or which is in an inconsistent state + * (lance still working). + */ + + while ((sc->xmt_complete != sc->xmt_last) && (sc->xmt_count > 0)) { + + index = sc->xmt_complete; + (se_sw->desc_copyin) ((vm_offset_t)sc->lntring[index], + (vm_offset_t)&r, sizeof(r)); + status = r.status; + + /* + * Does lance still own it ? + */ + if (status & LN_TSTATE_OWN) + break; + + /* + * Packet sent allright, release queue slot. + */ + request = sc->tpkt[index]; + sc->tpkt[index] = (io_req_t) 0; + sc->xmt_complete = ++index & (NXMT - 1); + --sc->xmt_count; + + sc->is_if.if_opackets++; + if (status & (LN_TSTATE_DEF|LN_TSTATE_ONE|LN_TSTATE_MORE)) + sc->is_if.if_collisions++; + + /* + * Check for transmission errors. + */ + if (!se_loopback_hack && status & LN_TSTATE_ERR) { + sc->is_if.if_oerrors++; + if (se_verbose) + printf("se%d: xmt error (x%x)\n", unit, r.status2); + + if (r.status2 & (LN_TSTATE2_RTRY|LN_TSTATE2_LCOL)) + sc->is_if.if_collisions++; + + /* + * Restart chip on errors that disable the + * transmitter. + */ + iodone(request); + if (r.status2 & LN_TSTATE2_DISABLE) { + register struct ifnet *ifp = &sc->is_if; + se_restart(ifp); + se_init(ifp->if_unit); + return; + } + } else if (request) { + /* + * If this was a broadcast packet loop it back. + * Signal successful transmission of the packet. + */ + register struct ether_header *eh; + register int i; + + eh = (struct ether_header *) request->io_data; + /* ether broadcast address is in the spec */ + for (i = 0; (i < 6) && (eh->ether_dhost[i] == 0xff); i++) + ; /* nop */ + /* sending to ourselves makes sense sometimes */ + if (i != 6 && se_loopback_hack) + for (i = 0; + (i < 6) && (eh->ether_dhost[i] == sc->is_addr[i]); + i++) + ; /* nop */ + if (i == 6) + se_read(sc, 0, request->io_count, request); + iodone(request); + } + } + /* + * Dequeue next transmit request, if any. + */ + if (sc->xmt_count <= 0) + se_start(unit); +} + +/* + * Handle a receiver complete interrupt. + */ +void +se_rint(int unit) +{ + register se_softc_t sc = se_softc[unit]; + register index, first, len; + unsigned char status, status1; + int ring_cnt; + struct se_desc r; + + /* + * Starting from where we left off, look around the receive ring and + * pass on all complete packets. + */ + + for (;; sc->rcv_last = ++index & (NRCV - 1)) { + + /* + * Read in current descriptor + */ +read_descriptor: + (se_sw->desc_copyin) ((vm_offset_t)sc->lnrring[sc->rcv_last], + (vm_offset_t)&r, sizeof(r)); + status = r.status; + if (status & LN_RSTATE_OWN) + break; + first = index = sc->rcv_last; + + /* + * If not the start of a packet, error + */ + if (!(status & LN_RSTATE_STP)) { + if (se_verbose) + printf("se%d: Rring #%d, status=%x !STP\n", + unit, index, status); + break; + } + /* + * See if packet is chained (should not) by looking at + * the last descriptor (OWN clear and ENP set). + * Remember the status info in this last descriptor. + */ + ring_cnt = 1, status1 = status; + while (((status1 & (LN_RSTATE_ERR | LN_RSTATE_OWN | LN_RSTATE_ENP)) == 0) && + (ring_cnt++ <= NRCV)) { + struct se_desc r1; + index = (index + 1) & (NRCV - 1); + (se_sw->desc_copyin) ((vm_offset_t)sc->lnrring[index], + (vm_offset_t)&r1, sizeof(r1)); + status1 = r1.status; + } + + /* + * Chained packet (--> illegally sized!); re-init the + * descriptors involved and ignore this bogus packet. I + * donno how, but it really happens that we get these + * monsters. + */ + if (ring_cnt > 1) { + /* + * Return all descriptors to lance + */ + se_desc_set_status(sc->lnrring[first], LN_RSTATE_OWN); + while (first != index) { + first = (first + 1) & (NRCV - 1); + se_desc_set_status(sc->lnrring[first], LN_RSTATE_OWN); + } + if ((status1 & LN_RSTATE_ERR) && se_verbose) + printf("se%d: rcv error %x (chained)\n", unit, status1); + continue; + } + + /* + * Good packets must be owned by us and have the end of + * packet flag. And nothing else. + */ + if ((status & ~LN_RSTATE_STP) == LN_RSTATE_ENP) { + sc->is_if.if_ipackets++; + + if ((len = r.message_size) == 0) + /* race seen on pmaxen: the lance + * has not updated the size yet ?? + */ + goto read_descriptor; + /* + * Drop trailing CRC bytes from len and ship packet + * up + */ + se_read(sc, (volatile char*)sc->lnrbuf[first], len-4,0); + + /* + * Return descriptor to lance, and move on to next + * packet + */ + r.status = LN_RSTATE_OWN; + (se_sw->desc_copyout)((vm_offset_t)&r, + (vm_offset_t)sc->lnrring[first], + sizeof(r)); + continue; + } + /* + * Not a good packet, see what is wrong + */ + if (status & LN_RSTATE_ERR) { + sc->is_if.if_ierrors++; + + if (se_verbose) + printf("se%d: rcv error (x%x)\n", unit, status); + + /* + * Return descriptor to lance + */ + se_desc_set_status(sc->lnrring[first], LN_RSTATE_OWN); + } else { + /* + * Race condition viz lance, Wait for the next + * interrupt. + */ + return; + } + } +} + +/* + * Output routine. + * Call common function for wiring memory, + * come back later (to se_start) to get + * things going. + */ +io_return_t +se_output( + int dev, + io_req_t ior) +{ + return net_write(&se_softc[dev]->is_if, (int(*)())se_start, ior); +} + +/* + * Start output on interface. + * + */ +void +se_start(int unit) +{ + register se_softc_t sc = se_softc[unit]; + io_req_t request; + struct se_desc r; + int tlen; + spl_t s; + register int index; + + s = splimp(); + + for (index = sc->xmt_last; + sc->xmt_count < (NXMT - 1); + sc->xmt_last = index = (index + 1) & (NXMT - 1)) { + /* + * Dequeue the next transmit request, if any. + */ + IF_DEQUEUE(&sc->is_if.if_snd, request); + if (request == 0) { + /* + * Tell the lance to send the packet now + * instead of waiting until the next 1.6 ms + * poll interval expires. + */ + *sc->lnregs = LN_CSR0_TDMD | LN_CSR0_INEA; + splx(s); + return; /* Nothing on the queue */ + } + + /* + * Keep request around until transmission complete + */ + sc->tpkt[index] = request; + tlen = copy_to_lance(request, sc->lntbuf[index]); + + /* + * Give away buffer. Must copyin/out, set len, + * and set the OWN flag. We do not do chaining. + */ + (se_sw->desc_copyin)((vm_offset_t)sc->lntring[index], + (vm_offset_t)&r, sizeof(r)); + r.buffer_size = -(tlen) | 0xf000; + r.status = (LN_TSTATE_OWN | LN_TSTATE_STP | LN_TSTATE_ENP); + (se_sw->desc_copyout)((vm_offset_t)&r, + (vm_offset_t)sc->lntring[index], + sizeof(r)); + wbflush(); + + sc->xmt_count++; + } + /* + * Since we actually have queued new packets, tell + * the chip to rescan the descriptors _now_. + * It is quite unlikely that the ring be filled, + * but if it is .. the more reason to do it! + */ + *sc->lnregs = LN_CSR0_TDMD | LN_CSR0_INEA; + splx(s); +} + + +/* + * Pull a packet off the interface and + * hand it up to the higher levels. + * + * Simulate broadcast packets in software. + */ +void +se_read( + register se_softc_t sc, + volatile char *lnrbuf, + int len, + io_req_t loop_back) +{ + register struct ifnet *ifp = &sc->is_if; + register ipc_kmsg_t new_kmsg; + char *hdr, *pkt; + + if (len <= sizeof(struct ether_header)) + return; /* sanity */ + + /* + * Get a new kmsg to put data into. + */ + new_kmsg = net_kmsg_get(); + if (new_kmsg == IKM_NULL) { + /* + * No room, drop the packet + */ + ifp->if_rcvdrops++; + return; + } + + hdr = net_kmsg(new_kmsg)->header; + pkt = net_kmsg(new_kmsg)->packet; + +#define OFF0 (sizeof(struct ether_header) - sizeof(struct packet_header)) +#define OFF1 (OFF0 & ~3) + if (loop_back) { + bcopy(loop_back->io_data, hdr, sizeof(struct ether_header)); + bcopy(loop_back->io_data + OFF0, + pkt, len - OFF0); + } else + copy_from_lance(lnrbuf, len, (struct ether_header*)hdr, + (struct packet_header*)pkt); + + /* + * Set up the 'fake' header with length. Type has been left + * in the correct place. + */ + len = len - OFF0; + ((struct packet_header *)pkt)->length = len; + + /* + * Hand the packet to the network module. + */ + net_packet(ifp, new_kmsg, len, ethernet_priority(new_kmsg)); +} + + +/* + * Get a packet out of Lance memory and into main memory. + */ +private void +copy_from_lance( + register volatile unsigned char *rbuf, + register unsigned int nbytes, + struct ether_header *hdr, + struct packet_header *pkt) +{ + /* + * Read in ethernet header + */ + (se_sw->data_copyin) ((vm_offset_t)rbuf, (vm_offset_t)hdr, sizeof(struct ether_header)); + + nbytes -= sizeof(struct ether_header); + rbuf += (se_sw->mapoffs) (sizeof(struct ether_header)); + + pkt->type = (unsigned short) hdr->ether_type; + + (se_sw->data_copyin) ((vm_offset_t)rbuf, (vm_offset_t)(pkt + 1), nbytes); +} + + +/* + * Move a packet into Lance space + */ +private int +copy_to_lance( + register io_req_t request, + volatile char *sbuf) +{ + register unsigned short *dp; + register int len; + + dp = (unsigned short *) request->io_data; + len = request->io_count; + + if (len > (int)(ETHERMTU + sizeof(struct ether_header))) { + printf("se: truncating HUGE packet\n"); + len = ETHERMTU + sizeof(struct ether_header); + } + + (se_sw->data_copyout) ((vm_offset_t)dp, (vm_offset_t)sbuf, len); + + if (len < LN_MINBUF_NOCH) + /* + * The lance needs at least this much data in a packet. Who + * cares if I send some garbage that was left in the lance + * buffer ? If one can spoof packets then one can spoof + * packets! + */ + len = LN_MINBUF_NOCH; + return len; +} + +/* + * Reset a descriptor's flags. + * Optionally give the descriptor to the lance + */ +private void +se_desc_set_status ( + register se_desc_t lndesc, + int val) +{ + struct se_desc desc; + + (se_sw->desc_copyin) ((vm_offset_t)lndesc, (vm_offset_t)&desc, sizeof(desc)); + desc.desc4.bits = 0; + desc.status = val; + (se_sw->desc_copyout) ((vm_offset_t)&desc, (vm_offset_t)lndesc, sizeof(desc)); + wbflush(); +} + +/* + * Set/Get status functions + */ +int +se_get_status( + int dev, + dev_flavor_t flavor, + dev_status_t status, /* pointer to OUT array */ + natural_t *status_count) /* out */ +{ + return (net_getstat(&se_softc[dev]->is_if, + flavor, status, status_count)); +} + +int +se_set_status( + int unit, + dev_flavor_t flavor, + dev_status_t status, + natural_t status_count) +{ + register se_softc_t sc; + + sc = se_softc[unit]; + + + switch (flavor) { + + case NET_STATUS: + break; + + case NET_ADDRESS: { + + register union ether_cvt { + unsigned char addr[6]; + int lwd[2]; + } *ec = (union ether_cvt *) status; + + if (status_count < sizeof(*ec) / sizeof(int)) + return (D_INVALID_SIZE); + + ec->lwd[0] = ntohl(ec->lwd[0]); + ec->lwd[1] = ntohl(ec->lwd[1]); + + se_setaddr(ec->addr, unit); + + break; + } + + default: + return (D_INVALID_OPERATION); + } + + return (D_SUCCESS); +} + + +/* + * Install new filter. + * Nothing special needs to be done here. + */ +io_return_t +se_setinput( + int dev, + ipc_port_t receive_port, + int priority, + filter_t *filter, + natural_t filter_count) +{ + return (net_set_filter(&se_softc[dev]->is_if, + receive_port, priority, + filter, filter_count)); +} + +/* + * Allocate and initialize a ring descriptor. + * Allocates a buffer from the lance memory and writes a descriptor + * for that buffer to the host virtual address LNDESC. + */ +private volatile long +*se_desc_alloc ( + register se_softc_t sc, + register se_desc_t lndesc) +{ + register vm_offset_t dp; /* data pointer */ + struct se_desc desc; + + /* + * Allocate buffer in lance space + */ + dp = se_malloc(sc, LN_BUFFER_SIZE); + + /* + * Build a descriptor pointing to it + */ + desc.addr_low = Addr_lo(Lmem(dp)); + desc.addr_hi = Addr_hi(Lmem(dp)); + desc.status = 0; + desc.buffer_size = -LN_BUFFER_SIZE; + desc.desc4.bits = 0; + + /* + * Copy the descriptor to lance space + */ + (se_sw->desc_copyout) ((vm_offset_t)&desc, (vm_offset_t)lndesc, sizeof(desc)); + wbflush(); + + return (volatile long *) Hmem(dp); +} + +/* + * Allocate a chunk of lance RAM buffer. Since we never + * give lance RAM buffer memory back, we'll just step up the + * byte-count on a per-unit basis. + * + * The return value is an index into the lance memory, which can be + * passed with Hmem() and Lmem() to get the host and chip virtual addresses. + */ +private vm_offset_t +se_malloc( + se_softc_t sc, + int size) +{ + register vm_offset_t ret; + + /* + * On first call, zero lance memory + */ + if (sc->lnsbrk == 0) + (se_sw->bzero) (Hmem(0), LN_MEMORY_SIZE); + + /* + * Start out on the first double longword boundary + * (this accomodates some machines, with minimal loss) + */ + if (sc->lnsbrk & 0xf) + sc->lnsbrk = (sc->lnsbrk + 0x10) & ~0xf; + + ret = sc->lnsbrk; + sc->lnsbrk += size; + + if (sc->lnsbrk > LN_MEMORY_SIZE) + panic("se_malloc"); + + return ret; +} + +#endif NLN > 0 diff --git a/chips/lance.h b/chips/lance.h new file mode 100644 index 0000000..f799d7e --- /dev/null +++ b/chips/lance.h @@ -0,0 +1,284 @@ +/* + * Mach Operating System + * Copyright (c) 1992,1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: if_se.h + * Authors: Robert V. Baron and Alessandro Forin + * Date: 1989 + * + */ +/* + * AMD 7990 "Lance" Ethernet interface definitions. + * All structures are as seen from the Lance, + * both in the memory-alignment sense and in the + * byte-order sense. Mapping to host memory is + * model specific: on pmaxen there is a 16 bit gap + * every other 16 bits. + */ + +#include + +/* + * Selection of one of the four Lance CSR is done in a + * two-step process: select which CSR first by writing + * into the RAP, then access the register via the RDP. + * Note that (a) the selection remains, and (b) all + * but CSR0 can only be accessed when the chip is stopped. + * These registers are mapped in the 'registers' I/O segment. + */ +#ifndef se_reg_type +#define se_reg_type unsigned short +#endif +typedef volatile se_reg_type *se_reg_t; + +#define CSR0_SELECT 0x0 /* Valid RAP selections */ +#define CSR1_SELECT 0x1 +#define CSR2_SELECT 0x2 +#define CSR3_SELECT 0x3 + +/* + * Bit definitions for the CSR0. + * Legend: + * R=Readable W=Writeable + * S=Set-on-write-1 C=Clear-on-write-1 + */ + +#define LN_CSR0_INIT 0x0001 /* (RS) Initialize */ +#define LN_CSR0_STRT 0x0002 /* (RS) Start */ +#define LN_CSR0_STOP 0x0004 /* (RS) Stop */ +#define LN_CSR0_TDMD 0x0008 /* (RS) Transmit demand */ +#define LN_CSR0_TXON 0x0010 /* (R) Transmitter enabled */ +#define LN_CSR0_RXON 0x0020 /* (R) Receiver enabled */ +#define LN_CSR0_INEA 0x0040 /* (RW) Interrupt enable */ +#define LN_CSR0_INTR 0x0080 /* (R) Interrupt pending */ +#define LN_CSR0_IDON 0x0100 /* (RC) Initialization done */ +#define LN_CSR0_TINT 0x0200 /* (RC) Transmitter interrupt */ +#define LN_CSR0_RINT 0x0400 /* (RC) Receiver interrupt */ +#define LN_CSR0_MERR 0x0800 /* (RC) Memory error during DMA */ +#define LN_CSR0_MISS 0x1000 /* (RC) No available receive buffers */ +#define LN_CSR0_CERR 0x2000 /* (RC) Signal quality (SQE) test */ +#define LN_CSR0_BABL 0x4000 /* (RC) Babble error: xmit too long */ +#define LN_CSR0_ERR 0x8000 /* (R) Error summary: any of the 4 above */ + +#define LN_CSR0_WTC 0x7f00 /* Write-to-clear bits */ + +/* + * Bit definitions for the CSR1. + */ + +#define LN_CSR1_MBZ 0x0001 /* Must be zero */ +#define LN_CSR1_IADR 0xfffe /* (RW) Initialization block address (low) */ + +/* + * Bit definitions for the CSR2. + */ + +#define LN_CSR2_IADR 0x00ff /* (RW) Initialization block address (high) */ +#define LN_CSR2_XXXX 0xff00 /* (RW) Reserved */ + +/* + * Bit definitions for the CSR3. + */ + +#define LN_CSR3_BCON 0x0001 /* (RW) BM/HOLD Control */ +#define LN_CSR3_ACON 0x0002 /* (RW) ALE Control */ +#define LN_CSR3_BSWP 0x0004 /* (RW) Byte Swap */ +#define LN_CSR3_XXXX 0xfff8 /* (RW) Reserved */ + + +/* + * Initialization Block + * + * Read when the INIT command is sent to the lance. + */ + +struct se_init_block { + unsigned short mode; /* Mode Register, see below */ + unsigned short phys_addr_low; /* Ethernet address */ + unsigned short phys_addr_med; /* Ethernet address */ + unsigned short phys_addr_high; /* Ethernet address */ + unsigned short logical_addr_filter0; /* Multicast filter */ + unsigned short logical_addr_filter1; /* Multicast filter */ + unsigned short logical_addr_filter2; /* Multicast filter */ + unsigned short logical_addr_filter3; /* Multicast filter */ + unsigned short recv_ring_pointer_lo; /* Receive Ring ptr, low */ + BITFIELD_3(unsigned char, + recv_ring_pointer_hi, /* Receive Ring ptr, high */ + reserved0 : 5, + recv_ring_len : 3); /* Length: log2(nbuffers) */ + unsigned short xmit_ring_pointer_lo; /* Transmit Ring ptr, low */ + BITFIELD_3(unsigned char, + xmit_ring_pointer_hi, /* Transmit Ring ptr, high */ + reserved1 : 5, + xmit_ring_len : 3); /* Length: log2(nbuffers) */ +}; + +typedef volatile struct se_init_block *se_init_block_t; + +/* + * Bit definitions for the MODE word + * (Normally set to 0) + */ + +#define LN_MODE_DRX 0x0001 /* Disable Receiver */ +#define LN_MODE_DTX 0x0002 /* Disable Transmitter */ +#define LN_MODE_LOOP 0x0004 /* Loopback mode */ +#define LN_MODE_DTRC 0x0008 /* Disable CRC generation */ +#define LN_MODE_COLL 0x0010 /* Force collision */ +#define LN_MODE_DRTY 0x0020 /* Disable retry */ +#define LN_MODE_INTL 0x0040 /* Internal Loopback mode */ +#define LN_MODE_XXXX 0x7f80 /* Reserved */ +#define LN_MODE_PROM 0x8000 /* Promiscuous mode */ + +/* + * Bit definitions for the ring pointers + */ + +#define LN_RNGP_LOW 0xfffc /* longword aligned */ + + +/* + * Buffer Descriptors + * Legend: + * H-set-by-Host C-set-by-chip + */ + +struct se_desc { + unsigned short addr_low; /* (H) Buffer pointer low */ + BITFIELD_2(unsigned char, + addr_hi, /* (H) Buffer pointer high */ + status); /* (HC) Buffer status */ + unsigned short buffer_size; /* (H) Buffer length (bytes),*/ + /* bits 15..12 must be ones */ + union { + struct { + BITFIELD_2(unsigned short, + bcnt : 12, /* (C) Rcvd data size */ + res : 4); /* Reads as zeroes */ + } rcv; + struct { + BITFIELD_2(unsigned short, + TDR : 10, /* (C) Time Domain Reflectometry */ + flg2 : 6); /* (C) Xmit status */ + } xmt; + unsigned short bits; + } desc4; +#define message_size desc4.rcv.bcnt +#define tdr desc4.xmt.TDR +#define status2 desc4.xmt.flg2 +}; + +typedef volatile struct se_desc *se_desc_t; + +/* + * Bit definition for STATUS byte (receive case) + */ + +#define LN_RSTATE_ENP 0x01 /* (C) End of Packet */ +#define LN_RSTATE_STP 0x02 /* (C) Start of packet */ +#define LN_RSTATE_BUFF 0x04 /* (C) Buffer error */ +#define LN_RSTATE_CRC 0x08 /* (C) CRC error */ +#define LN_RSTATE_OFLO 0x10 /* (C) SILO Overflow */ +#define LN_RSTATE_FRAM 0x20 /* (C) Framing error */ +#define LN_RSTATE_ERR 0x40 /* (C) Error summary */ +#define LN_RSTATE_OWN 0x80 /* (C) Owned by Lance Chip (if set) */ + + +/* + * Bit definition for STATUS byte (transmit case) + */ + +#define LN_TSTATE_ENP 0x01 /* (H) End of Packet */ +#define LN_TSTATE_STP 0x02 /* (H) Start of packet */ +#define LN_TSTATE_DEF 0x04 /* (C) Deferred */ +#define LN_TSTATE_ONE 0x08 /* (C) Retried exactly once */ +#define LN_TSTATE_MORE 0x10 /* (C) Retried more than once */ +#define LN_TSTATE_XXXX 0x20 /* Reserved */ +#define LN_TSTATE_ERR 0x40 /* (C) Error summary (see status2) */ +#define LN_TSTATE_OWN 0x80 /* (H) Owned by Lance Chip (if set) */ + +/* + * Bit definitions for STATUS2 byte (transmit case) + */ + +#define LN_TSTATE2_RTRY 0x01 /* (C) Failed after 16 retransmissions */ +#define LN_TSTATE2_LCAR 0x02 /* (C) Loss of Carrier */ +#define LN_TSTATE2_LCOL 0x04 /* (C) Late collision */ +#define LN_TSTATE2_XXXX 0x08 /* Reserved */ +#define LN_TSTATE2_UFLO 0x10 /* (C) Underflow (late memory) */ +#define LN_TSTATE2_BUFF 0x20 /* (C) Buffering error (no ENP) */ + + /* Errors that disable the transmitter */ +#define LN_TSTATE2_DISABLE (LN_TSTATE2_UFLO|LN_TSTATE2_BUFF|LN_TSTATE2_RTRY) + +/* + * Other chip characteristics + */ + +#define LN_MINBUF_CH 100 /* Minimum size of first lance buffer, if + chaining */ + +#define LN_MINBUF_NOCH 60 /* Minimum size of a lance buffer, if + no chaining and DTCR==1 */ + +#define LN_MINBUF_NOCH_RAW 64 /* Minimum size of a lance buffer, if + no chaining and DTCR==0 */ + +/* + * Information for mapped ether + */ +typedef struct mapped_ether_info { + volatile unsigned int interrupt_count; + /* tot interrupts received */ + volatile unsigned short saved_csr0; + /* copy of csr0 at last intr */ + unsigned char rom_stride; + unsigned char ram_stride; + /* rom&ram strides */ + unsigned buffer_size; + /* how much ram for lance */ + natural_t buffer_physaddr; + /* where it is in phys memory */ + unsigned wait_event; +} *mapped_ether_info_t; + +#ifdef KERNEL +extern struct se_switch { + vm_offset_t regspace; + vm_offset_t bufspace; + vm_offset_t ln_bufspace; + vm_offset_t romspace; + short romstride; + short ramstride; + int ramsize; + void (*desc_copyin)( vm_offset_t, vm_offset_t, int); + void (*desc_copyout)( vm_offset_t, vm_offset_t, int); + void (*data_copyin)( vm_offset_t, vm_offset_t, int); + void (*data_copyout)( vm_offset_t, vm_offset_t, int); + void (*bzero)( vm_offset_t, int ); + vm_offset_t (*mapaddr)( vm_offset_t ); + vm_size_t (*mapoffs)( vm_size_t ); +} *se_sw; +#endif KERNEL diff --git a/chips/lance_mapped.c b/chips/lance_mapped.c new file mode 100644 index 0000000..26096bd --- /dev/null +++ b/chips/lance_mapped.c @@ -0,0 +1,417 @@ +/* + * Mach Operating System + * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: if_se_mapped.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 8/90 + * + * In-kernel side of the user-mapped ethernet driver. + */ + +#include +#if NLN > 0 +#include + +#include +#include /* spl definitions */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#ifdef DECSTATION + +#define machine_btop mips_btop + +#define kvctophys(v) K0SEG_TO_PHYS((v)) /* kernel virtual cached */ +#define phystokvc(p) PHYS_TO_K0SEG((p)) /* and back */ +#define kvutophys(v) K1SEG_TO_PHYS((v)) /* kernel virtual uncached */ +#define phystokvu(p) PHYS_TO_K1SEG((p)) /* and back */ + /* remap from k2 to k0 */ +#define kvirt(v) ((phystokvc(pmap_extract(pmap_kernel(),v)))) + +#include +/* + * Wired addresses and sizes + */ +#define SE0_REG_EMRG (se_reg_t)(0xb8000000) + +#define REGBASE(unit) (((u_int)SE_statii[unit].registers) - se_sw->regspace) + +#define SE_REG_PHYS(unit) kvutophys(REGBASE(unit)+se_sw->regspace) +#define SE_REG_SIZE PAGE_SIZE + +#define SE_BUF_PHYS(unit) kvutophys(REGBASE(unit)+se_sw->bufspace) +#define SE_BUF_SIZE (128*1024) + +#define SE_ADR_PHYS(unit) kvutophys(REGBASE(unit)+se_sw->romspace) +#define SE_ADR_SIZE PAGE_SIZE +#endif /*DECSTATION*/ + +#ifdef VAXSTATION +#define machine_btop vax_btop +#endif /*VAXSTATION*/ + +#ifdef LUNA88K +# define machine_btop m88k_btop +# define kvirt(v) (v) +# define kvctophys(v) pmap_extract(pmap_kernel(),(v)) +# define SE0_REG_EMRG ((se_reg_t)0xF1000000U) +# define REGBASE(unit) (((u_int)SE_statii[unit].registers) - se_sw->regspace) +# define SE_REG_PHYS(unit) (REGBASE(unit) + se_sw->regspace) +# define SE_REG_SIZE PAGE_SIZE +# define SE_BUF_PHYS(unit) (REGBASE(unit) + se_sw->bufspace) +# define SE_BUF_SIZE (64*1024) +# define SE_ADR_PHYS(unit) kvctophys(REGBASE(unit) + se_sw->romspace) +# define SE_ADR_SIZE PAGE_SIZE +# define wbflush() /*empty*/ +#endif /*LUNA88K*/ + +/* + * Autoconf info + */ + +static vm_offset_t SEstd[NLN] = { 0 }; +static struct bus_device *SEinfo[NLN]; + void SE_attach(); + int SE_probe(); + +struct bus_driver SEdriver = + { SE_probe, 0, SE_attach, 0, SEstd, "SE", SEinfo, }; + +/* + * Externally visible functions + */ +int SE_probe(); /* Kernel */ +void SE_intr(), SE_portdeath(); + /* User */ +int SE_open(), SE_close(); +vm_offset_t SE_mmap(); + + +/* forward declarations */ + +static void SE_stop(unsigned int unit); + +/* + * Status information for all interfaces + */ +/*static*/ struct SE_status { + se_reg_t registers; + mapped_ether_info_t info; + struct evc eventcounter; +} SE_statii[NLN]; + + +/* + * Probe the Lance to see (if) that it's there + */ +int +SE_probe(regbase, ui) + vm_offset_t regbase; + register struct bus_device *ui; +{ + int unit = ui->unit; + se_reg_t regs; + vm_offset_t addr; + mapped_ether_info_t info; + struct SE_status *self; + + + if (unit >= NLN) + return 0; + + self = &SE_statii[unit]; + + printf("[mappable] "); + + regs = (se_reg_t) (regbase + se_sw->regspace); + self->registers = regs; + + /* + * Reset the interface + */ + SE_stop(unit); + + /* + * Grab a page to be mapped later to users + */ + (void) kmem_alloc_wired(kernel_map, &addr, PAGE_SIZE); + /* + on the decstation, kmem_alloc_wired returns virtual addresses + in the k2 seg. Since this page is going to get mapped in + user space, we need to transform it to a better understood + virtual address. The kvirt function does this. + */ + bzero(addr, PAGE_SIZE); + info = (mapped_ether_info_t) kvirt(addr); + self->info = info; + + /* + * Set permanent info + */ + info->rom_stride = se_sw->romstride; + info->ram_stride = se_sw->ramstride; + info->buffer_size = se_sw->ramsize; + info->buffer_physaddr = se_sw->ln_bufspace; + + /* + * Synch setup + */ + evc_init(&self->eventcounter); + info->wait_event = self->eventcounter.ev_id; + + return 1; +} + +void +SE_attach(ui) + register struct bus_device *ui; +{ +} + + +/* + * Shut off the lance + */ +static void SE_stop(unsigned int unit) +{ + register se_reg_t regs = SE_statii[unit].registers; + + if (regs == 0) + /* Stray interrupt */ + regs = SE0_REG_EMRG; + + regs[2] = CSR0_SELECT; /* XXXX rap XXXX */ + wbflush(); + regs[0] = LN_CSR0_STOP; + wbflush(); +} + + +/* + * Ethernet interface interrupt routine + */ +void SE_intr(unit,spllevel) + int unit; + spl_t spllevel; +{ + register struct SE_status *self = &SE_statii[unit]; + register se_reg_t regs = self->registers; + register csr; + + if (regs == 0) { /* stray */ + SE_stop(unit); + return; + } + + /* Acknowledge interrupt request, drop spurious intr */ + csr = regs[0]; + if ((csr & LN_CSR0_INTR) == 0) + return; + regs[0] = csr & LN_CSR0_WTC; /* silence it */ + + splx(spllevel); /* drop priority now */ + + /* Pass csr state up to user thread */ + if (self->info) { + self->info->interrupt_count++; /* total interrupts */ + self->info->saved_csr0 = csr; + } + + /* Awake user thread */ + evc_signal(&self->eventcounter); +} + + +extern boolean_t se_use_mapped_interface[NLN]; + +/* + * Device open procedure + */ +int SE_open(dev, flag, ior) + io_req_t ior; +{ + int unit = dev; + register struct SE_status *self = &SE_statii[unit]; + + if (unit >= NLN) + return EINVAL; + + /* + * Silence interface, just in case + */ + SE_stop(unit); + + /* + * Reset eventcounter + */ + evc_signal(&self->eventcounter); + + se_use_mapped_interface[unit] = 1; + + /* + * Do not turn Ether interrupts on. The user can do it when ready + * to take them. + */ + + return 0; +} + +/* + * Device close procedure + */ +int SE_close(dev, flag) +{ + int unit = dev; + register struct SE_status *self = &SE_statii[unit]; + + if (unit >= NLN) + return EINVAL; + + /* + * Silence interface, in case user forgot + */ + SE_stop(unit); + evc_signal(&self->eventcounter); + + se_normal(unit); + + return 0; +} + + +/* + * Get status procedure. + * We need to tell that we are mappable. + */ +io_return_t +SE_get_status(ifp, flavor, status, status_count) +/* struct ifnet *ifp; not really..*/ + int flavor; + dev_status_t status; /* pointer to OUT array */ + unsigned int *status_count; /* OUT */ +{ + switch (flavor) { + case NET_STATUS: + { + register struct net_status *ns = (struct net_status *)status; + + ns->min_packet_size = sizeof(struct ether_header); + ns->max_packet_size = sizeof(struct ether_header) + ETHERMTU; + ns->header_format = HDR_ETHERNET; + ns->header_size = sizeof(struct ether_header); + ns->address_size = 6; + ns->flags = IFF_BROADCAST; + ns->mapped_size = SE_BUF_SIZE + (3 * PAGE_SIZE); + + *status_count = NET_STATUS_COUNT; + break; + } +/* case NET_ADDRESS: find it yourself */ + default: + return (D_INVALID_OPERATION); + } + return (D_SUCCESS); +} + +/* + * Should not refuse this either + */ +int SE_set_status(dev, flavor, status, status_count) + int dev; + int flavor; + dev_status_t status; + unsigned int status_count; +{ + return (D_SUCCESS); +} + +/* + * Port death notification routine + */ +void SE_portdeath(dev, dead_port) +{ +} + + +/* + * Virtual->physical mapping routine. + */ +vm_offset_t +SE_mmap(dev, off, prot) + int dev; + vm_offset_t off; + vm_prot_t prot; +{ + vm_offset_t page; + vm_offset_t addr; + int unit = dev; + + /* + * The offset (into the VM object) defines the following layout + * + * off size what + * 0 1pg mapping information (csr & #interrupts) + * 1pg 1pg lance registers + * 2pg 1pg lance station address (ROM) + * 3pg 128k lance buffers + */ +#define S0 PAGE_SIZE +#define S1 (S0+SE_REG_SIZE) +#define S2 (S1+SE_ADR_SIZE) +#define S3 (S2+SE_BUF_SIZE) + + if (off < S0) { + addr = kvctophys (SE_statii[unit].info); + } else if (off < S1) { + addr = (vm_offset_t) SE_REG_PHYS(unit); + off -= S0; + } else if (off < S2) { + addr = (vm_offset_t) SE_ADR_PHYS(unit); + off -= S1; + } else if (off < S3) { + addr = (vm_offset_t) SE_BUF_PHYS(unit); + off -= S2; + } else + return (EINVAL); + + page = machine_btop(addr + off); + return (page); +} + +#endif NLN > 0 diff --git a/chips/lk201.c b/chips/lk201.c new file mode 100644 index 0000000..d11b1e9 --- /dev/null +++ b/chips/lk201.c @@ -0,0 +1,695 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: lk201.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Routines for the LK201 Keyboard Driver + */ + +#include +#if NLK > 0 +#include + +#include + +#include +#include +#include /* spl definitions */ +#include +#include +#include +#include +#include + + +/* + * Structures describing the keyboard status + */ +typedef struct { + unsigned short kbd_flags; + unsigned short kbd_previous; + char kbd_gen_shift; + char kbd_ctrl; + char kbd_lock; + char kbd_meta; + char kbd_shift; +} lk201_kbd_state_t; + +#define mapLOCKtoCNTRL 0x1 /* flags */ + +typedef struct { + char led_active; + char led_pattern; + char led_increasing; + char led_lights; + int led_interval; + int led_light_count; +} lk201_led_state_t; + + +/* + * Keyboard state + */ + +struct lk201_softc { + lk201_kbd_state_t kbd; + lk201_led_state_t led; + int sl_unit; +} lk201_softc_data[NLK]; + +typedef struct lk201_softc *lk201_softc_t; + +lk201_softc_t lk201_softc[NLK]; + +/* + * Forward decls + */ +io_return_t +lk201_translation( + int key, + char c, + int tabcode ); + +int +lk201_input( + int unit, + unsigned short data); + + +/* + * Autoconf (sort-of) + */ +lk201_probe( + int unit) +{ + lk201_softc[unit] = &lk201_softc_data[unit]; + return 1; +} + +void lk201_attach( + int unit, + int sl_unit) +{ + lk201_softc[unit]->sl_unit = sl_unit; + lk201_selftest(unit); +} + +/* + * Keyboard initialization + */ + +static unsigned char lk201_reset_string[] = { + LK_CMD_LEDS_ON, LK_PARAM_LED_MASK(0xf), /* show we are resetting */ + LK_CMD_SET_DEFAULTS, + LK_CMD_MODE(LK_MODE_RPT_DOWN,1), + LK_CMD_MODE(LK_MODE_RPT_DOWN,2), + LK_CMD_MODE(LK_MODE_RPT_DOWN,3), + LK_CMD_MODE(LK_MODE_RPT_DOWN,4), + LK_CMD_MODE(LK_MODE_DOWN_UP,5), + LK_CMD_MODE(LK_MODE_DOWN_UP,6), + LK_CMD_MODE(LK_MODE_RPT_DOWN,7), + LK_CMD_MODE(LK_MODE_RPT_DOWN,8), + LK_CMD_MODE(LK_MODE_RPT_DOWN,9), + LK_CMD_MODE(LK_MODE_RPT_DOWN,10), + LK_CMD_MODE(LK_MODE_RPT_DOWN,11), + LK_CMD_MODE(LK_MODE_RPT_DOWN,12), + LK_CMD_MODE(LK_MODE_DOWN,13), + LK_CMD_MODE(LK_MODE_RPT_DOWN,14), + LK_CMD_ENB_RPT, +/* LK_CMD_ENB_KEYCLK, LK_PARAM_VOLUME(4), */ + LK_CMD_DIS_KEYCLK, + LK_CMD_RESUME, + LK_CMD_ENB_BELL, LK_PARAM_VOLUME(4), + LK_CMD_LEDS_OFF, LK_PARAM_LED_MASK(0xf) +}; + +void +lk201_reset( + int unit) +{ + register int i, sl; + register spl_t s; + lk201_softc_t lk; + + lk = lk201_softc[unit]; + sl = lk->sl_unit; + s = spltty(); + for (i = 0; i < sizeof(lk201_reset_string); i++) { + (*console_putc)(sl, + SCREEN_LINE_KEYBOARD, + lk201_reset_string[i]); + delay(100); + } + /* zero any state associated with previous keypresses */ + bzero(lk, sizeof(*lk)); + lk->sl_unit = sl; + splx(s); +} + +lk201_selftest( + int unit) +{ + int messg[4], sl; + spl_t s; + + sl = lk201_softc[unit]->sl_unit; + s = spltty(); + (*console_putc)(sl, SCREEN_LINE_KEYBOARD, LK_CMD_REQ_ID); + delay(10000);/* arbitrary */ + messg[0] = (*console_getc)(sl, SCREEN_LINE_KEYBOARD, TRUE, TRUE); + messg[1] = (*console_getc)(sl, SCREEN_LINE_KEYBOARD, TRUE, TRUE); + splx(s); + + printf("( lk201 id %x.%x", messg[0], messg[1]); + + s = spltty(); + (*console_putc)(sl, SCREEN_LINE_KEYBOARD, LK_CMD_POWER_UP); + + /* cannot do this, waiting too long might cause receiver overruns */ +/* delay(80000);/* spec says 70 msecs or less */ + + messg[0] = (*console_getc)(sl, SCREEN_LINE_KEYBOARD, TRUE, TRUE); + messg[1] = (*console_getc)(sl, SCREEN_LINE_KEYBOARD, TRUE, TRUE); + messg[2] = (*console_getc)(sl, SCREEN_LINE_KEYBOARD, TRUE, TRUE); + messg[3] = (*console_getc)(sl, SCREEN_LINE_KEYBOARD, TRUE, TRUE); + splx(s); + + printf(", self-test "); + if (messg[0] != 0x01 || messg[1] || messg[2] || messg[3]) + printf("bad [%x %x %x %x]", + messg[0], messg[1], messg[2], messg[3]); + else + printf("ok )"); + + lk201_reset(unit); +} + +/* + * Tinkerbell + */ +void +lk201_ring_bell( + int unit) +{ + spl_t s = spltty(); + (*console_putc)(lk201_softc[unit]->sl_unit, SCREEN_LINE_KEYBOARD, LK_CMD_BELL); + splx(s); +} + +/* + * Here is your LED toy, Bob + */ +void +lk201_lights( + int unit, + boolean_t on) +{ + unsigned int sl; + spl_t s; + + sl = lk201_softc[unit]->sl_unit; + s = spltty(); + (*console_putc)(sl, SCREEN_LINE_KEYBOARD, LK_CMD_LEDS_OFF); + (*console_putc)(sl, SCREEN_LINE_KEYBOARD, LK_PARAM_LED_MASK(0xf)); + if (on < 16 && on > 0) { + (*console_putc)(sl, SCREEN_LINE_KEYBOARD, LK_CMD_LEDS_ON); + (*console_putc)(sl, SCREEN_LINE_KEYBOARD, LK_PARAM_LED_MASK(on)); + } + splx(s); +} + + +lk201_led( + int unit) +{ + lk201_led_state_t *leds = &lk201_softc[unit]->led; + unsigned int sl; + spl_t s; + + sl = lk201_softc[unit]->sl_unit; + if (leds->led_interval) { /* leds are on */ + if (leds->led_light_count <= 0) { /* hit this lights */ + + if (leds->led_lights <= 0) leds->led_lights= 1; /* sanity */ + if (leds->led_lights > 16) leds->led_lights = 16;/* sanity */ + leds->led_light_count = leds->led_interval; /* reset */ + s = spltty(); + (*console_putc)(sl, SCREEN_LINE_KEYBOARD, LK_CMD_LEDS_OFF); + (*console_putc)(sl, SCREEN_LINE_KEYBOARD, LK_PARAM_LED_MASK(leds->led_lights)); + switch (leds->led_pattern) { + case LED_OFF: + leds->led_interval = 0; /* since you can now set */ + break; /* the interval even if off */ + case LED_COUNT: + leds->led_lights++; + if (leds->led_lights > 16) leds->led_lights = 1; + break; + case LED_ROTATE: + leds->led_lights <<= 1; + if (leds->led_lights > 8) leds->led_lights = 1; + break; + case LED_CYLON: + if (leds->led_increasing) { + leds->led_lights <<= 1; + if (leds->led_lights > 8) { + leds->led_lights >>= 2; + leds->led_increasing = 0; + } + } else { + leds->led_lights >>= 1; + if (leds->led_lights <= 0) { + leds->led_lights = 2; + leds->led_increasing = 1; + } + } + break; + } + (*console_putc)( sl, SCREEN_LINE_KEYBOARD, LK_CMD_LEDS_ON); + (*console_putc)( sl, SCREEN_LINE_KEYBOARD, LK_PARAM_LED_MASK(leds->led_lights)); + splx(s); + } + leds->led_light_count--; + } else { + if (leds->led_lights) { + s = spltty(); + (*console_putc)(sl, SCREEN_LINE_KEYBOARD, LK_CMD_LEDS_OFF); + (*console_putc)(sl, SCREEN_LINE_KEYBOARD, LK_PARAM_LED_MASK(0xf)); + leds->led_lights = 0; + splx(s); + } + leds->led_active = 0; +#if NBM > 0 + screen_enable_vretrace(unit, 0); /* interrupts off */ +#endif + } +} + + +/* + * Special user-visible ops + */ +io_return_t +lk201_set_status( + int unit, + dev_flavor_t flavor, + dev_status_t status, + natural_t status_count) +{ + lk201_led_state_t *leds = &lk201_softc[unit]->led; + lk201_kbd_state_t *kbd = &lk201_softc[unit]->kbd; + + switch( flavor ) { + case LK201_SEND_CMD:{ + register lk201_cmd_t *cmd = (lk201_cmd_t*)status; + unsigned int cnt, s, sl; + + if ((status_count < (sizeof(*cmd)/sizeof(int))) || + ((cnt = cmd->len) > 2)) + return D_INVALID_SIZE; + + if (cnt == 0) + cmd->command |= LK_PARAM; + else + cmd->params[cnt-1] |= LK_PARAM; + sl = lk201_softc[unit]->sl_unit; + s = spltty(); + (*console_putc)(sl, SCREEN_LINE_KEYBOARD, cmd->command); + if (cnt > 0) + (*console_putc)(sl, SCREEN_LINE_KEYBOARD, cmd->params[0]); + if (cnt > 1) + (*console_putc)(sl, SCREEN_LINE_KEYBOARD, cmd->params[1]); + splx(s); + return D_SUCCESS; + } + case LK201_LED_PATTERN:{ + register int ptn = * (int *) status; + if (ptn != LED_OFF && ptn != LED_COUNT && + ptn != LED_ROTATE && ptn != LED_CYLON ) { + return -1; + } else { + leds->led_pattern = ptn; + } + break; + } + case LK201_LED_INTERVAL:{ + register int lcnt = * (int *) status; + if (lcnt < 0) + lcnt = 1; + leds->led_interval = lcnt; + break; + } + case LK201_mapLOCKtoCNTRL:{ + boolean_t enable = * (boolean_t*) status; + if (enable) + kbd->kbd_flags |= mapLOCKtoCNTRL; + else + kbd->kbd_flags &= ~mapLOCKtoCNTRL; + return D_SUCCESS; + } + case LK201_REMAP_KEY:{ + register KeyMap *k = (KeyMap *) status; + int mode; + + if (status_count < (sizeof(KeyMap)/sizeof(int))) + return D_INVALID_SIZE; + + mode = k->shifted ? 1 : 0; + if (k->meta) mode += 2; + return lk201_translation( k->in_keyval, + k->out_keyval, + mode ); + } + default: + return D_INVALID_OPERATION; + } + leds->led_lights = 1; + leds->led_active = 1; +#if NBM > 0 + screen_enable_vretrace(unit, 1); /* interrupts on */ +#endif + return D_SUCCESS; +} + +/* + * Keycode translation tables + * + * NOTE: these tables have been compressed a little bit + * because the lk201 cannot generate very small codes. + */ + +unsigned char lk201_xlate_key[] = { + /* 86 */ 0 ,0 + /* 88 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 96 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 104 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 112 */ ,0 ,0x1b ,0x08 ,'\n' ,0 ,0 ,0 ,0 + /* 120 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 128 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 136 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 144 */ ,0 ,0 ,'0',0 ,'.','\r','1','2' + /* 152 */ ,'3','4','5','6',',','7','8','9' + /* 160 */ ,'-',0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 168 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 176 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 184 */ ,0 ,0 ,0 ,0 ,0x7f,'\r','\t','`' + /* 192 */ ,'1' ,'q' ,'a' ,'z' ,0 ,'2' ,'w' ,'s' + /* 200 */ ,'x' ,'<' ,0 ,'3' ,'e' ,'d' ,'c' ,0 + /* 208 */ ,'4' ,'r' ,'f' ,'v' ,' ' ,0 ,'5' ,'t' + /* 216 */ ,'g' ,'b' ,0 ,'6' ,'y' ,'h' ,'n' ,0 + /* 224 */ ,'7' ,'u' ,'j' ,'m' ,0 ,'8' ,'i' ,'k' + /* 232 */ ,',' ,0 ,'9' ,'o' ,'l' ,'.' ,0 ,'0' + /* 240 */ ,'p' ,0 ,';' ,'/' ,0 ,'=' ,']' ,'\\' + /* 248 */ ,0 ,'-' ,'[' ,'\'' ,0 ,0 ,0 ,0 +}; + +unsigned char lk201_xlate_shifted[] = { + /* 86 */ 0 ,0 + /* 88 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 96 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 104 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 112 */ ,0 ,0x1b ,0x08 ,'\n' ,0 ,0 ,0 ,0 + /* 120 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 128 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 136 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 144 */ ,0 ,0 ,'0',0 ,'.','\r','1','2' + /* 152 */ ,'3','4','5','6',',','7','8','9' + /* 160 */ ,'-',0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 168 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 176 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 184 */ ,0 ,0 ,0 ,0 ,0x7f ,'\r' ,'\t' ,'~' + /* 192 */ ,'!' ,'Q' ,'A' ,'Z' ,0 ,'@' ,'W' ,'S' + /* 200 */ ,'X' ,'>' ,0 ,'#' ,'E' ,'D' ,'C' ,0 + /* 208 */ ,'$' ,'R' ,'F' ,'V' ,' ' ,0 ,'%' ,'T' + /* 216 */ ,'G' ,'B' ,0 ,'^' ,'Y' ,'H' ,'N' ,0 + /* 224 */ ,'&' ,'U' ,'J' ,'M' ,0 ,'*' ,'I' ,'K' + /* 232 */ ,'<' ,0 ,'(' ,'O' ,'L' ,'>' ,0 ,')' + /* 240 */ ,'P' ,0 ,':' ,'?' ,0 ,'+' ,'}' ,'|' + /* 248 */ ,0 ,'_' ,'{' ,'"' ,0 ,0 ,0 ,0 +}; + +unsigned char lk201_xlate_meta[] = { + /* 86 */ 0 ,0 + /* 88 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 96 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 104 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 112 */ ,0 ,0x1b ,0x08 ,'\n' ,0 ,0 ,0 ,0 + /* 120 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 128 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 136 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 144 */ ,0 ,0 ,'0',0 ,'.','\r','1','2' + /* 152 */ ,'3','4','5','6',',','7','8','9' + /* 160 */ ,'-',0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 168 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 176 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 184 */ ,0 ,0 ,0 ,0 ,0x7f ,'\r' ,'\t' ,'~' + /* 192 */ ,'!' ,'Q' ,'A' ,'Z' ,0 ,'@' ,'W' ,'S' + /* 200 */ ,'X' ,'>' ,0 ,'#' ,'E' ,'D' ,'C' ,0 + /* 208 */ ,'$' ,'R' ,'F' ,'V' ,' ' ,0 ,'%' ,'T' + /* 216 */ ,'G' ,'B' ,0 ,'^' ,'Y' ,'H' ,'N' ,0 + /* 224 */ ,'&' ,'U' ,'J' ,'M' ,0 ,'*' ,'I' ,'K' + /* 232 */ ,'<' ,0 ,'(' ,'O' ,'L' ,'>' ,0 ,')' + /* 240 */ ,'P' ,0 ,':' ,'?' ,0 ,'+' ,'}' ,'|' + /* 248 */ ,0 ,'_' ,'{' ,'"' ,0 ,0 ,0 ,0 +}; + +unsigned char lk201_xlate_shifted_meta[] = { + /* 86 */ 0 ,0 + /* 88 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 96 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 104 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 112 */ ,0 ,0x1b ,0x08 ,'\n' ,0 ,0 ,0 ,0 + /* 120 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 128 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 136 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 144 */ ,0 ,0 ,'0',0 ,'.','\r','1','2' + /* 152 */ ,'3','4','5','6',',','7','8','9' + /* 160 */ ,'-',0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 168 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 176 */ ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 + /* 184 */ ,0 ,0 ,0 ,0 ,0x7f ,'\r' ,'\t' ,'~' + /* 192 */ ,'!' ,'Q' ,'A' ,'Z' ,0 ,'@' ,'W' ,'S' + /* 200 */ ,'X' ,'>' ,0 ,'#' ,'E' ,'D' ,'C' ,0 + /* 208 */ ,'$' ,'R' ,'F' ,'V' ,' ' ,0 ,'%' ,'T' + /* 216 */ ,'G' ,'B' ,0 ,'^' ,'Y' ,'H' ,'N' ,0 + /* 224 */ ,'&' ,'U' ,'J' ,'M' ,0 ,'*' ,'I' ,'K' + /* 232 */ ,'<' ,0 ,'(' ,'O' ,'L' ,'>' ,0 ,')' + /* 240 */ ,'P' ,0 ,':' ,'?' ,0 ,'+' ,'}' ,'|' + /* 248 */ ,0 ,'_' ,'{' ,'"' ,0 ,0 ,0 ,0 +}; + + +io_return_t +lk201_translation( + int key, + char c, + int tabcode ) +{ + unsigned char *table; + + if ((key &= 0xff) < LK_MINCODE) + return D_INVALID_OPERATION; + + switch (tabcode) { + case 3: + table = lk201_xlate_shifted_meta; + break; + case 2: + table = lk201_xlate_meta; + break; + case 1: + table = lk201_xlate_shifted; + break; + case 0: + default: + table = lk201_xlate_key; + break; + } + table[key - LK_MINCODE] = c; + return D_SUCCESS; +} + +/* + * Input character processing + */ + +lk201_rint( + int unit, + unsigned short data, + boolean_t handle_shift, + boolean_t from_kernel) +{ + int c; + lk201_kbd_state_t *kbd = &lk201_softc[unit]->kbd; + + /* + * Keyboard touched, clean char to 8 bits. + */ +#if NBM > 0 + ssaver_bump(unit); +#endif + + data &= 0xff; + + /* Translate keycode into ASCII */ + if ((c = lk201_input(unit, data)) == -1) + return -1; + +#if NBM > 0 + /* + * Notify X, unless we are called from inside kernel + */ + if (!from_kernel && + screen_keypress_event(unit, DEV_KEYBD, data, EVT_BUTTON_RAW)) + return -1; +#endif + + /* Handle shifting if need to */ + if (kbd->kbd_gen_shift) + return (handle_shift) ? cngetc() : -1; + + return c; +} + +/* + * Routine to grock a character from LK201 + */ +#if MACH_KDB +int lk201_allow_kdb = 1; +#endif + +int lk201_debug = 0; + +lk201_input( + int unit, + unsigned short data) +{ + int c, sl; + lk201_kbd_state_t *kbd = &lk201_softc[unit]->kbd; + + kbd->kbd_gen_shift = 0; + +#if MACH_KDB + if (lk201_allow_kdb && (data == LK_DO)) { + kdb_kintr(); + return -2; + } +#endif + + /* + * Sanity checks + */ + + if (data == LK_INPUT_ERR || data == LK_OUTPUT_ERR) { + printf(" Keyboard error, code = %x\n",data); + return -1; + } + if (data < LK_MINCODE) + return -1; + + /* + * Check special keys: shifts, ups, .. + */ + + if (data == LK_LOCK && (kbd->kbd_flags&mapLOCKtoCNTRL)) + data = LK_CNTRL; + + switch (data) { + case LK_LOCK: + kbd->kbd_lock ^= 1; + kbd->kbd_gen_shift = 1; + sl = lk201_softc[unit]->sl_unit; + /* called from interrupt, no need for spl */ + if (kbd->kbd_lock) + (*console_putc)(sl, SCREEN_LINE_KEYBOARD, LK_CMD_LEDS_ON); + else + (*console_putc)(sl,SCREEN_LINE_KEYBOARD, LK_CMD_LEDS_OFF); + (*console_putc)(sl, SCREEN_LINE_KEYBOARD, LK_PARAM_LED_MASK(0x4)); + return 0; + + case LK_ALT: + case LK_L_ALT: + case LK_R_ALT: + case LK_R_COMPOSE: + kbd->kbd_meta ^= 1; + kbd->kbd_gen_shift = 1; + return 0; + + case LK_SHIFT: + case LK_R_SHIFT: + kbd->kbd_shift ^= 1; + kbd->kbd_gen_shift = 1; + return 0; + + case LK_CNTRL: + kbd->kbd_ctrl ^= 1; + kbd->kbd_gen_shift = 1; + return 0; + + case LK_ALLUP: + kbd->kbd_ctrl = 0; + kbd->kbd_shift = 0; + kbd->kbd_meta = 0; + kbd->kbd_gen_shift = 1; + return 0; + + case LK_REPEAT: + c = kbd->kbd_previous; + break; + + default: + + /* + * Do the key translation to ASCII + */ + if (kbd->kbd_ctrl || kbd->kbd_lock || kbd->kbd_shift) { + c = ((kbd->kbd_meta) ? + lk201_xlate_shifted_meta : lk201_xlate_shifted) + [data - LK_MINCODE]; + if (kbd->kbd_ctrl) + c &= 0x1f; + } else + c = ((kbd->kbd_meta) ? + lk201_xlate_meta : lk201_xlate_key) + [data-LK_MINCODE]; + break; + + } + + kbd->kbd_previous = c; + + /* + * DEBUG code DEBUG + */ + if (lk201_debug && (c == 0)) { + printf("lk201: [%x]\n", data); + } + + return c; +} + +#endif /* NLK > 0 */ diff --git a/chips/lk201.h b/chips/lk201.h new file mode 100644 index 0000000..5c7bbba --- /dev/null +++ b/chips/lk201.h @@ -0,0 +1,241 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: lk201.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Definitions for the LK201 Keyboard Driver + */ + +/* + * KeyCodes generated by the LK201 board + * (labels as in the lk201-AA USA model) + */ + +#define LK_MINCODE 0x56 + /* Function keys */ +#define LK_F1 0x56 /* div 10 */ +#define LK_F2 0x57 +#define LK_F3 0x58 +#define LK_F4 0x59 +#define LK_F5 0x5a +#define LK_F6 0x64 /* div 11 */ +#define LK_F7 0x65 +#define LK_F8 0x66 +#define LK_F9 0x67 +#define LK_F10 0x68 +#define LK_F11 0x71 /* div 12 */ +#define LK_ESC LK_F11 +#define LK_F12 0x72 +#define LK_BS LK_F12 +#define LK_F13 0x73 +#define LK_LF LK_F13 +#define LK_F14 0x74 +#define LK_HELP 0x7c /* div 13 */ +#define LK_DO 0x7d +#define LK_F17 0x80 /* div 14 */ +#define LK_F18 0x81 +#define LK_F19 0x82 +#define LK_F20 0x83 + /* Editing keys */ +#define LK_FIND 0x8a /* div 9 */ +#define LK_INSERT 0x8b +#define LK_REMOVE 0x8c +#define LK_SELECT 0x8d +#define LK_PREV_SCREEN 0x8e +#define LK_NEXT_SCREEN 0x8f + /* Numeric keypad */ +#define LK_KP_0 0x92 /* div 2 */ +#define LK_KP_DOT 0x94 +#define LK_KP_ENTER 0x95 +#define LK_KP_1 0x96 +#define LK_KP_2 0x97 +#define LK_KP_3 0x98 +#define LK_KP_4 0x99 +#define LK_KP_5 0x9a +#define LK_KP_6 0x9b +#define LK_KP_COMMA 0x9c +#define LK_KP_7 0x9d +#define LK_KP_8 0x9e +#define LK_KP_9 0x9f +#define LK_KP_MINUS 0xa0 +#define LK_KP_PF1 0xa1 +#define LK_KP_PF2 0xa2 +#define LK_KP_PF3 0xa3 +#define LK_KP_PF4 0xa4 + /* Cursor keys */ +#define LK_LEFT 0xa7 /* div 7 */ +#define LK_RIGHT 0xa8 +#define LK_DOWN 0xa9 /* div 8 */ +#define LK_UP 0xaa + /* Shift & Co. */ +#define LK_R_SHIFT 0xab /* lk401 */ +#define LK_L_ALT 0xac /* lk401 */ +#define LK_R_COMPOSE 0xad /* lk401 */ +#define LK_SHIFT 0xae /* div 6 */ +#define LK_CNTRL 0xaf +#define LK_LOCK 0xb0 /* div 5 */ +#define LK_ALT 0xb1 +#define LK_R_ALT 0xb2 /* lk401 */ + /* Special codes */ +#define LK_ALLUP 0xb3 +#define LK_REPEAT 0xb4 +#define LK_OUTPUT_ERR 0xb5 +#define LK_INPUT_ERR 0xb6 +#define LK_KDBLOCK_ACK 0xb7 +#define LK_TESTMODE_ACK 0xb8 +#define LK_PFX_KEYDOWN 0xb9 +#define LK_MODECHG_ACK 0xba + /* Delete & Co. */ +#define LK_DEL 0xbc /* div 3 */ +#define LK_RETURN 0xbd /* div 4 */ +#define LK_TAB 0xbe + /* Graphic keys */ + +#define LK_TILDE 0xbf /* div 2 */ +#define LK_1 0xc0 +#define LK_Q 0xc1 +#define LK_A 0xc2 +#define LK_Z 0xc3 +#define LK_2 0xc5 +#define LK_W 0xc6 +#define LK_S 0xc7 +#define LK_X 0xc8 +#define LK_LESSGRT 0xc9 +#define LK_3 0xcb +#define LK_E 0xcc +#define LK_D 0xcd +#define LK_C 0xce +#define LK_4 0xd0 +#define LK_R 0xd1 +#define LK_F 0xd2 +#define LK_V 0xd3 +#define LK_SP 0xd4 +#define LK_5 0xd6 +#define LK_T 0xd7 +#define LK_G 0xd8 +#define LK_B 0xd9 +#define LK_6 0xdb +#define LK_Y 0xdc +#define LK_H 0xdd +#define LK_N 0xde +#define LK_7 0xe0 /* div 1 */ +#define LK_U 0xe1 +#define LK_J 0xe2 +#define LK_M 0xe3 +#define LK_8 0xe5 +#define LK_I 0xe6 +#define LK_K 0xe7 +#define LK_DQUOTE 0xe8 +#define LK_9 0xea +#define LK_O 0xeb +#define LK_L 0xec +#define LK_DOT 0xed +#define LK_0 0xef +#define LK_P 0xf0 +#define LK_COLON 0xf2 +#define LK_QMARK 0xf3 +#define LK_PLUS 0xf5 +#define LK_RBRACKET 0xf6 +#define LK_VBAR 0xf7 +#define LK_MINUS 0xf9 +#define LK_LBRACKET 0xfa +#define LK_COMMA 0xfb + + +/* + * Commands to the keyboard processor + */ + +#define LK_PARAM 0x80 /* start/end parameter list */ + +#define LK_CMD_RESUME 0x8b +#define LK_CMD_INHIBIT 0xb9 +#define LK_CMD_LEDS_ON 0x13 /* 1 param: led bitmask */ +#define LK_CMD_LEDS_OFF 0x11 /* 1 param: led bitmask */ +#define LK_CMD_DIS_KEYCLK 0x99 +#define LK_CMD_ENB_KEYCLK 0x1b /* 1 param: volume */ +#define LK_CMD_DIS_CTLCLK 0xb9 +#define LK_CMD_ENB_CTLCLK 0xbb +#define LK_CMD_SOUND_CLK 0x9f +#define LK_CMD_DIS_BELL 0xa1 +#define LK_CMD_ENB_BELL 0x23 /* 1 param: volume */ +#define LK_CMD_BELL 0xa7 +#define LK_CMD_TMP_NORPT 0xc1 +#define LK_CMD_ENB_RPT 0xe3 +#define LK_CMD_DIS_RPT 0xe1 +#define LK_CMD_RPT_TO_DOWN 0xd9 +#define LK_CMD_REQ_ID 0xab +#define LK_CMD_POWER_UP 0xfd +#define LK_CMD_TEST_MODE 0xcb +#define LK_CMD_SET_DEFAULTS 0xd3 + +/* there are 4 leds, represent them in the low 4 bits of a byte */ +#define LK_PARAM_LED_MASK(ledbmap) (LK_PARAM|(ledbmap)) + +/* max volume is 0, lowest is 0x7 */ +#define LK_PARAM_VOLUME(v) (LK_PARAM|((v)&0x7)) + +/* mode set command(s) details */ +#define LK_MODE_DOWN 0x0 +#define LK_MODE_RPT_DOWN 0x2 +#define LK_MODE_DOWN_UP 0x6 +#define LK_CMD_MODE(m,div) (LK_PARAM|(div<<3)|m) + + +/* + * Keyboard set_status codes and arguments + */ + +/* Send a command packet to the lk201 */ +typedef struct { + unsigned char len; /* how many params */ + unsigned char command; /* cmd to lk201 */ + unsigned char params[2]; /* extra params */ +} lk201_cmd_t; +#define LK201_SEND_CMD _IOW('q', 5, lk201_cmd_t)/* keybd. per. cmd */ + +/* Control rotation of lk201 leds */ +#define LK201_LED_PATTERN _IOW('q', 119, int) /* cylon, ... */ +# define LED_COUNT 1 /* led counter */ +# define LED_ROTATE 2 /* led rotate */ +# define LED_CYLON 3 /* led cylon mode */ + +#define LK201_LED_INTERVAL _IOW('q', 120, int) /* refresh interval */ +# define LED_OFF 0 /* no led movement */ + +/* Map the caps-lock key to act as the control key (skinny-fingers) */ +#define LK201_mapLOCKtoCNTRL _IOW('q', 121, int) /* 1 or 0 */ + +/* Remap a lk201 keycode to a different (ASCII) translation */ +typedef struct { + unsigned char in_keyval; + unsigned char shifted; + unsigned char out_keyval; + unsigned char meta; +} KeyMap; +#define LK201_REMAP_KEY _IOW('q', 122, KeyMap) /* 1 or 0 */ diff --git a/chips/mc_clock.c b/chips/mc_clock.c new file mode 100644 index 0000000..15fa049 --- /dev/null +++ b/chips/mc_clock.c @@ -0,0 +1,516 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: mc_clock.c + * Author: Alessandro Forin + * Date: 8/90 + * + * Driver for the MC146818 Clock + */ + +#include +#if NMC > 0 +#include + +#include +#include /* spl definitions */ +#include + +#include +#include +#include + +#ifdef DECSTATION +#include +#include +#endif /*DECSTATION*/ + +#ifdef FLAMINGO +#include +#endif /*FLAMINGO*/ + +#define private static +#define public + + +/* Architecture-specific defines */ + +#ifdef DECSTATION + +#define MC_DEFAULT_ADDRESS (mc_clock_ram_t *)PHYS_TO_K1SEG(0x1d000000) +#define MC_DOES_DELAYS 1 + +/* + * Both the Pmax and the 3max implementations of the chip map + * bytes of the chip's RAM to 32 bit words (low byte). + * For convenience, we redefine here the chip's RAM layout + * making padding explicit. + */ + +typedef struct { + volatile unsigned char mc_second; + char pad0[3]; + volatile unsigned char mc_alarm_second; + char pad1[3]; + volatile unsigned char mc_minute; + char pad2[3]; + volatile unsigned char mc_alarm_minute; + char pad3[3]; + volatile unsigned char mc_hour; + char pad4[3]; + volatile unsigned char mc_alarm_hour; + char pad5[3]; + volatile unsigned char mc_day_of_week; + char pad6[3]; + volatile unsigned char mc_day_of_month; + char pad7[3]; + volatile unsigned char mc_month; + char pad8[3]; + volatile unsigned char mc_year; + char pad9[3]; + volatile unsigned char mc_register_A; + char pad10[3]; + volatile unsigned char mc_register_B; + char pad11[3]; + volatile unsigned char mc_register_C; + char pad12[3]; + volatile unsigned char mc_register_D; + char pad13[3]; + unsigned char mc_non_volatile_ram[50 * 4]; /* unused */ +} mc_clock_ram_t; + +#define MC_CLOCK_PADDED 1 + +#endif /*DECSTATION*/ + + +#ifdef FLAMINGO +#define MC_DEFAULT_ADDRESS 0L + +/* padded, later */ + +#endif /* FLAMINGO */ + + + +#ifndef MC_CLOCK_PADDED +typedef mc_clock_t mc_clock_ram_t; /* No padding needed */ +#endif + +/* + * Functions provided herein + */ +int mc_probe( vm_offset_t addr, struct bus_ctlr * ); +private void mc_attach(); + +int mc_intr(); + +void mc_open(), mc_close(), mc_write(); +private unsigned int mc_read(); + +private void mc_wait_for_uip( mc_clock_ram_t *clock ); + + +/* + * Status + */ +boolean_t mc_running = FALSE; +boolean_t mc_new_century = FALSE; /* "year" info overfloweth */ + +private int days_per_month[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +private unsigned int mc_read(); /* forward */ +private void mc_wait_for_uip(); + +/* + * Where is the chip's RAM mapped + */ +private mc_clock_ram_t *rt_clock = MC_DEFAULT_ADDRESS; + +/* + * (Auto?)Configuration + */ +private vm_offset_t mc_std[NMC] = { 0 }; +private struct bus_device *mc_info[NMC]; + +struct bus_driver mc_driver = + { mc_probe, 0, mc_attach, 0, mc_std, "mc", mc_info, }; + + +mc_probe(vm_offset_t addr, struct bus_ctlr *ui) +{ + rt_clock = (mc_clock_ram_t *)addr; + return 1; +} + +private void +mc_attach() +{ + printf(": MC146818 or like Time-Of-Year chip"); +} + +/* + * Interrupt routine + */ +#if MC_DOES_DELAYS + +private int config_step = 3; +private volatile int had_intr; + +mc_intr(spllevel) + spl_t spllevel; +{ + /* + * Interrupt flags are read-to-clear. + */ + if (config_step > 2) + return (rt_clock->mc_register_C & MC_REG_C_IRQF); + had_intr = (rt_clock->mc_register_C & MC_REG_C_IRQF) ? 1 : 0; + if (config_step++ == 0) + accurate_config_delay(spllevel); + return had_intr; +} +#else /* MC_DOES_DELAYS */ + +mc_intr() +{ + return (rt_clock->mc_register_C); /* clear intr */ +} + +#endif /* MC_DOES_DELAYS */ + +/* + * Start real-time clock. + */ +void +mc_open() +{ + /* + * All we should need to do is to enable interrupts, but + * since we do not know what OS last ran on this box + * we'll reset it all over again. Just kidding.. + */ + unsigned unix_seconds_now; + + /* + * Check for battery backup power. If we do not have it, + * warn the user. Time will be bogus only after power up. + */ + if ((rt_clock->mc_register_D & MC_REG_D_VRT) == 0) + printf("WARNING: clock batteries are low\n"); + + /* + * Read the current time settings, check if the year info + * has been screwed up. + */ + unix_seconds_now = mc_read(); + + if (unix_seconds_now < (SECYR * (1990 - YRREF))) + printf("The prom has clobbered the clock\n"); + + time.tv_sec = (long)unix_seconds_now; + mc_write(); + + mc_running = TRUE; +} + +void +mc_close() +{ + /* + * Disable interrupts, but keep the chip running. + * Note we are called at splhigh and an interrupt + * might be pending already. + */ + + mc_intr(0); + rt_clock->mc_register_B &= ~(MC_REG_B_UIE|MC_REG_B_AIE|MC_REG_B_PIE); + mc_running = FALSE; +#if MC_DOES_DELAYS + config_step = 0; +#endif +} + + +/* + * Set time-of-day. Must be called at splhigh() + */ +void +mc_write() +{ + register mc_clock_ram_t *clock = rt_clock; + register unsigned years, months, days, hours, minutes, seconds; + register unsigned unix_seconds = time.tv_sec; + int frequence_selector, temp; + int bogus_hz = 0; + + /* + * Convert U*x time into absolute time + */ + + years = YRREF; + while (1) { + seconds = SECYR; + if (LEAPYEAR(years)) + seconds += SECDAY; + if (unix_seconds < seconds) + break; + unix_seconds -= seconds; + years++; + } + + months = 0; + while (1) { + seconds = days_per_month[months++] * SECDAY; + if (months == 2 /* February */ && LEAPYEAR(years)) + seconds += SECDAY; + if (unix_seconds < seconds) + break; + unix_seconds -= seconds; + } + + days = unix_seconds / SECDAY; + unix_seconds -= SECDAY * days++; + + hours = unix_seconds / SECHOUR; + unix_seconds -= SECHOUR * hours; + + minutes = unix_seconds / SECMIN; + unix_seconds -= SECMIN * minutes; + + seconds = unix_seconds; + + /* + * Trim years into 0-99 range. + */ + if ((years -= 1900) > 99) { + years -= 100; + mc_new_century = TRUE; + } + + /* + * Check for "hot dates" + */ + if (days >= 28 && days <= 30 && + hours == 23 && minutes == 59 && + seconds >= 58) + seconds = 57; + + /* + * Select the interrupt frequency based on system params + */ + switch (hz) { + case 1024: + frequence_selector = MC_BASE_32_KHz | MC_RATE_1024_Hz; + break; + case 512: + frequence_selector = MC_BASE_32_KHz | MC_RATE_512_Hz; + break; + case 256: + frequence_selector = MC_BASE_32_KHz | MC_RATE_256_Hz; + break; + case 128: + frequence_selector = MC_BASE_32_KHz | MC_RATE_128_Hz; + break; + case 64: +default_frequence: + frequence_selector = MC_BASE_32_KHz | MC_RATE_64_Hz; + break; + default: + bogus_hz = hz; + hz = 64; + tick = 1000000 / 64; + goto default_frequence; + } + + /* + * Stop updates while we fix it + */ + mc_wait_for_uip(clock); + clock->mc_register_B = MC_REG_B_STOP; + wbflush(); + + /* + * Ack any pending interrupts + */ + temp = clock->mc_register_C; + + /* + * Reset the frequency divider, in case we are changing it. + */ + clock->mc_register_A = MC_BASE_RESET; + + /* + * Now update the time + */ + clock->mc_second = seconds; + clock->mc_minute = minutes; + clock->mc_hour = hours; + clock->mc_day_of_month = days; + clock->mc_month = months; + clock->mc_year = years; + + /* + * Spec says the VRT bit can be validated, but does not say how. I + * assume it is via reading the register. + */ + temp = clock->mc_register_D; + + /* + * Reconfigure the chip and get it started again + */ + clock->mc_register_A = frequence_selector; + clock->mc_register_B = MC_REG_B_24HM | MC_REG_B_DM | MC_REG_B_PIE; + + /* + * Print warnings, if we have to + */ + if (bogus_hz != 0) + printf("Unacceptable value (%d Hz) for hz, reset to %d Hz\n", + bogus_hz, hz); +} + + +/* + * Internal functions + */ + +private void +mc_wait_for_uip(clock) + mc_clock_ram_t *clock; +{ + while (clock->mc_register_A & MC_REG_A_UIP) + delay(MC_UPD_MINIMUM >> 2); +} + +private unsigned int +mc_read() +{ + /* + * Note we only do this at boot time + */ + register unsigned years, months, days, hours, minutes, seconds; + register mc_clock_ram_t *clock = rt_clock;; + + /* + * If the chip is updating, wait + */ + mc_wait_for_uip(clock); + + years = clock->mc_year; + months = clock->mc_month; + days = clock->mc_day_of_month; + hours = clock->mc_hour; + minutes = clock->mc_minute; + seconds = clock->mc_second; + + /* + * Convert to Unix time + */ + seconds += minutes * SECMIN; + seconds += hours * SECHOUR; + seconds += (days - 1) * SECDAY; + if (months > 2 /* February */ && LEAPYEAR(years)) + seconds += SECDAY; + while (months > 1) + seconds += days_per_month[--months - 1]; + + /* + * Note that in ten years from today (Aug,1990) the new century will + * cause the trouble that mc_new_century attempts to avoid. + */ + if (mc_new_century) + years += 100; + years += 1900; /* chip base year in YRREF's century */ + + for (--years; years >= YRREF; years--) { + seconds += SECYR; + if (LEAPYEAR(years)) + seconds += SECDAY; + } + + return seconds; +} + +#ifdef MC_DOES_DELAYS + +/* + * Timed delays + */ +extern unsigned int cpu_speed; + +void +config_delay(speed) +{ + /* + * This is just an initial estimate, later on with the clock + * running we'll tune it more accurately. + */ + cpu_speed = speed; +} + +accurate_config_delay(spllevel) + spl_t spllevel; +{ + register unsigned int i; + register spl_t s; + int inner_loop_count; + +#ifdef mips + /* find "spllevel - 1" */ + s = spllevel | ((spllevel >> 1) & SR_INT_MASK); + splx(s); +#else +#endif + + /* wait till we have an interrupt pending */ + had_intr = 0; + while (!had_intr) + continue; + + had_intr = 0; + i = delay_timing_function(1, &had_intr, &inner_loop_count); + + splx(spllevel); + + i *= hz; + cpu_speed = i / (inner_loop_count * 1000000); + + /* roundup clock speed */ + i /= 100000; + if ((i % 10) >= 5) + i += 5; + printf("Estimating CPU clock at %d Mhz\n", i / 10); + if (isa_pmax() && cpu_speed != MC_DELAY_PMAX) { + printf("%s\n", "This machine looks like a DEC 2100"); + machine_slot[cpu_number()].cpu_subtype = CPU_SUBTYPE_MIPS_R2000; + } +} +#endif /* MC_DOES_DELAYS */ + +#endif NMC > 0 diff --git a/chips/mc_clock.h b/chips/mc_clock.h new file mode 100644 index 0000000..0cd5957 --- /dev/null +++ b/chips/mc_clock.h @@ -0,0 +1,147 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: mc_clock.h + * Author: Alessandro Forin + * Date: 8/90 + * + * Definitions for the MC146818 Clock Driver + */ + +/* + * Functions this module implements + */ + +extern void resettodr(/* */); /* reset time-of-day register */ +extern void startrtclock(/* */); /* start real-time clock */ +extern void stopclocks(/* */); /* stop real-time clock */ +extern boolean_t ackrtclock(/* */); /* acknowledge interrupt, if any */ +extern boolean_t todr_running; /* status */ + +extern boolean_t mc_new_century; /* patch this after year 2000 (honest!) */ + +extern void delay(/* int usecs */); /* waste that many microseconds */ +extern void config_delay(/* int speed */); /* for delay() */ +#define MC_DELAY_PMAX 8 +#define MC_DELAY_3MAX 12 + +extern void set_clock_addr(/* vm_offset_t addr */); /* RAM location */ + +/* + * Real-Time Clock plus RAM device (MC146818) + */ + +/* + * RAM Memory Map (as seen by the chip) + */ +typedef struct { + volatile unsigned char mc_second; + volatile unsigned char mc_alarm_second; + volatile unsigned char mc_minute; + volatile unsigned char mc_alarm_minute; + volatile unsigned char mc_hour; + volatile unsigned char mc_alarm_hour; + volatile unsigned char mc_day_of_week; + volatile unsigned char mc_day_of_month; + volatile unsigned char mc_month; + volatile unsigned char mc_year; + volatile unsigned char mc_register_A; + volatile unsigned char mc_register_B; + volatile unsigned char mc_register_C; + volatile unsigned char mc_register_D; + unsigned char mc_non_volatile_ram[50]; +} mc_clock_t; + +/* + * Register A defines (read/write) + */ + +#define MC_REG_A_RS 0x0f /* Interrupt rate (and SQwave) select */ +#define MC_REG_A_DV 0x70 /* Divider select */ +#define MC_REG_A_UIP 0x80 /* Update In Progress (read-only bit) */ + +/* Time base configuration */ +#define MC_BASE_4_MHz 0x00 +#define MC_BASE_1_MHz 0x10 +#define MC_BASE_32_KHz 0x20 +#define MC_BASE_NONE 0x60 /* actually, both of these reset */ +#define MC_BASE_RESET 0x70 + +/* Interrupt rate table */ +#define MC_RATE_NONE 0x0 /* disabled */ +#define MC_RATE_1 0x1 /* 256Hz if MC_BASE_32_KHz, else 32768Hz */ +#define MC_RATE_2 0x2 /* 128Hz if MC_BASE_32_KHz, else 16384Hz */ +#define MC_RATE_8192_Hz 0x3 /* Tpi: 122.070 usecs */ +#define MC_RATE_4096_Hz 0x4 /* Tpi: 244.141 usecs */ +#define MC_RATE_2048_Hz 0x5 /* Tpi: 488.281 usecs */ +#define MC_RATE_1024_Hz 0x6 /* Tpi: 976.562 usecs */ +#define MC_RATE_512_Hz 0x7 /* Tpi: 1.953125 ms */ +#define MC_RATE_256_Hz 0x8 /* Tpi: 3.90625 ms */ +#define MC_RATE_128_Hz 0x9 /* Tpi: 7.8125 ms */ +#define MC_RATE_64_Hz 0xa /* Tpi: 15.625 ms */ +#define MC_RATE_32_Hz 0xb /* Tpi: 31.25 ms */ +#define MC_RATE_16_Hz 0xc /* Tpi: 62.5 ms */ +#define MC_RATE_8_Hz 0xd /* Tpi: 125 ms */ +#define MC_RATE_4_Hz 0xe /* Tpi: 250 ms */ +#define MC_RATE_2_Hz 0xf /* Tpi: 500 ms */ + +/* Update cycle time */ +#define MC_UPD_4_MHz 248 /* usecs */ +#define MC_UPD_1_MHz 248 /* usecs */ +#define MC_UPD_32_KHz 1984 /* usecs */ +#define MC_UPD_MINIMUM 244 /* usecs, guaranteed if UIP=0 */ + +/* + * Register B defines (read/write) + */ + +#define MC_REG_B_DSE 0x01 /* Daylight Savings Enable */ +#define MC_REG_B_24HM 0x02 /* 24/12 Hour Mode */ +#define MC_REG_B_DM 0x04 /* Data Mode, 1=Binary 0=BCD */ +#define MC_REG_B_SQWE 0x08 /* Sqare Wave Enable */ +#define MC_REG_B_UIE 0x10 /* Update-ended Interrupt Enable */ +#define MC_REG_B_AIE 0x20 /* Alarm Interrupt Enable */ +#define MC_REG_B_PIE 0x40 /* Periodic Interrupt Enable */ +#define MC_REG_B_SET 0x80 /* Set NVram info, e.g. update time or ..*/ +#define MC_REG_B_STOP MC_REG_B_SET /* Stop updating the timing info */ + +/* + * Register C defines (read-only) + */ + +#define MC_REG_C_ZEROES 0x0f /* Reads as zero bits */ +#define MC_REG_C_UF 0x10 /* Update-ended interrupt flag */ +#define MC_REG_C_AF 0x20 /* Alarm interrupt flag */ +#define MC_REG_C_PF 0x40 /* Periodic interrupt flag */ +#define MC_REG_C_IRQF 0x80 /* Interrupt request flag */ + +/* + * Register D defines (read-only) + */ + +#define MC_REG_D_ZEROES 0x7f /* Reads as zero bits */ +#define MC_REG_D_VRT 0x80 /* Valid RAM and Time */ + diff --git a/chips/mouse.c b/chips/mouse.c new file mode 100644 index 0000000..85a2744 --- /dev/null +++ b/chips/mouse.c @@ -0,0 +1,321 @@ +/* + * Mach Operating System + * Copyright (c) 1992-1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: mouse.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Driver code for Digital's mouse AND tablet + */ + +/* + * XXX This should be rewritten to support other + * XXX sorts of mices and tablets. But for now + * XXX I have none to play with. Sorry about that. + */ + +#include /* one mouse per lk201 */ +#if NLK > 0 + +#include +#include /* spl definitions */ +#include +#include + +#include +#include + +#define MOUSE_INCREMENTAL 0x52 /* R */ +#define MOUSE_PROMPTED 0x44 /* D */ +#define MOUSE_REQ_POSITION 0x50 /* P */ +#define MOUSE_SELFTEST 0x54 /* T */ +#define MOUSE_RESERVED_FUNC 0x5a /* Z, param byte follows */ + +#define TABLET_SAMPLE_55 0x4b /* K */ /* in reps/sec */ +#define TABLET_SAMPLE_72 0x4c /* L */ +#define TABLET_SAMPLE_120 0x4d /* M */ +#define TABLET_9600 0x42 /* B */ + +#define TYPE_MOUSE 0x2 +#define TYPE_TABLET 0x4 + +#define START_REPORT 0x80 + +typedef union { + struct { + unsigned char r : 1, m : 1, l : 1, sy : 1, sx : 1; + unsigned char xpos; + unsigned char ypos; + } ms; + struct { + unsigned char pr : 1, buttons : 4; + unsigned char xlo, xhi; + unsigned char ylo, yhi; + } tb; + unsigned char raw[1]; +} mouse_report_t; + + +/* + * Mouse state + */ +struct mouse_softc { + user_info_t *up; + mouse_report_t report; + unsigned char rep_bytes; + unsigned char rep_ptr; + unsigned char prev_buttons; + unsigned char flags; +#define MS_TABLET 0x1 +#define MS_MOVING 0x2 + char screen_unit; + char sl_unit; +} mouse_softc_data[NLK]; + +typedef struct mouse_softc *mouse_softc_t; + +mouse_softc_t mouse_softc[NLK]; + + +mouse_notify_mapped( + int unit, + int screen_unit, + user_info_t *up) +{ + mouse_softc_t ms = &mouse_softc_data[unit]; + + ms->up = up; + ms->screen_unit = screen_unit; +} + +/* + * Autoconfiguration + */ +mouse_probe( + int unit) +{ + mouse_softc[unit] = &mouse_softc_data[unit]; +} + +mouse_attach( + int unit, + int sl_unit) +{ + int messg[4]; + spl_t s; + mouse_softc_t ms; + + ms = mouse_softc[unit]; + ms->sl_unit = sl_unit; + + s = spltty(); + (*console_putc)(sl_unit, SCREEN_LINE_POINTER, MOUSE_SELFTEST); + delay(1); + messg[0] = (*console_getc)(sl_unit, SCREEN_LINE_POINTER, TRUE, TRUE); + messg[1] = (*console_getc)(sl_unit, SCREEN_LINE_POINTER, TRUE, TRUE); + messg[2] = (*console_getc)(sl_unit, SCREEN_LINE_POINTER, TRUE, TRUE); + messg[3] = (*console_getc)(sl_unit, SCREEN_LINE_POINTER, TRUE, TRUE); + + delay(100000); /* spec says less than 500 msecs */ + (*console_putc)(sl_unit, SCREEN_LINE_POINTER, MOUSE_INCREMENTAL); + splx(s); + + ms->rep_bytes = 3;/* mouse */ + if (messg[2] | messg[3]) { + printf(" bad pointer [%x %x %x %x] ", + messg[0], messg[1], messg[2], messg[3]); + if (messg[2] >= 0x20) printf("fatal "); + if (messg[2] == 0x3e) printf("RAM/ROM"); + if (messg[2] == 0x3d) printf("button(s) %x", messg[3] & 0x1f); + } else { + int rev = messg[0] & 0xf; + int loc = (messg[1] & 0xf0) >> 4; + int tag = (messg[1] & 0xf); + printf("( %s rev. %x.%x )", + (tag == TYPE_MOUSE) ? "mouse" : "tablet", + rev, loc); + if (tag == TYPE_TABLET) { + ms->flags = MS_TABLET; + ms->rep_bytes = 5; + } + } +} + +/* + * Process a character from the mouse + */ +mouse_input( + int unit, + register unsigned short data) +{ + mouse_softc_t ms = mouse_softc[unit]; + register char flg, but; + + data &= 0xff; + + /* sanity: might miss a byte sometimes */ + if (data & START_REPORT) + ms->rep_ptr = 0; + + /* add byte to report */ + ms->report.raw[ms->rep_ptr++] = data; + + /* does this mean the mouse is moving */ + if (data && ((data & START_REPORT) == 0)) + ms->flags |= MS_MOVING; + + /* Report complete ? */ + if (ms->rep_ptr != ms->rep_bytes) + return; + ms->rep_ptr = 0; + + ssaver_bump(ms->screen_unit); + + /* check for mouse moved */ + flg = ms->flags; + if (flg & MS_MOVING) { + ms->flags = flg & ~MS_MOVING; + mouse_motion_event(ms, flg); + } + + /* check for button pressed */ + if (but = ms->prev_buttons ^ ms->report.raw[0]) { + mouse_button_event(ms, flg, but); + ms->prev_buttons = ms->report.raw[0]; + } +} + +/* + * The mouse/puck moved. + * Find how much and post an event + */ +mouse_motion_event( + mouse_softc_t ms, + int flg) +{ + register int x, y; + + if (flg & MS_TABLET) { + + flg = DEV_TABLET; + + x = (ms->report.tb.xhi << 8) | ms->report.tb.xlo; + y = (ms->report.tb.yhi << 8) | ms->report.tb.ylo; + + } else { + + flg = DEV_MOUSE; + + x = ms->report.ms.xpos; + if (!ms->report.ms.sx) /* ??? */ + x = -x; + + y = ms->report.ms.ypos; + if (ms->report.ms.sy) + y = -y; + + } + + screen_motion_event(ms->screen_unit, flg, x, y); +} + +/* + * A mouse/puck button was pressed/released. + * Find which one and post an event + */ +mouse_button_event( + mouse_softc_t ms, + int flg, + int bmask) +{ + register unsigned int buttons, i; + int key, type; + + buttons = ms->report.raw[0]; + if (flg & MS_TABLET) { + /* check each one of the four buttons */ + for (i = 0; i < 4; i += 1) { + if ((bmask & (2<screen_unit, + DEV_TABLET, key, type); + } + } else { + ms->up->mouse_buttons = buttons & 0x7; + /* check each one of the three buttons */ + for (i = 0; i < 3; i += 1) { + if ((bmask & (1<screen_unit, + DEV_MOUSE, key, type); + } + } +} + +/* + * Generate escape sequences for position reporting + * These are the same as xterm's. + * Prefix: + * ESC [ M button down + * ESC [ N button up + * Body: + * BUTTON COL ROW + * Button: + * 0 <-> left, 1 <-> middle, 2 <-> right + * All body values are offset by the ascii SPACE character + */ +#define ESC '\033' +#define SPACE ' ' + +mouse_report_position( + int unit, + int col, + int row, + int key, + int type) +{ + cons_input(SCREEN_LINE_KEYBOARD, ESC, 0); + cons_input(SCREEN_LINE_KEYBOARD, '[', 0); + cons_input(SCREEN_LINE_KEYBOARD, (type==EVT_BUTTON_DOWN) ? 'M':'N', 0); + + cons_input(SCREEN_LINE_KEYBOARD, (key - 1) + SPACE, 0);/* quick remapping */ + cons_input(SCREEN_LINE_KEYBOARD, SPACE + col + 2, 0); + cons_input(SCREEN_LINE_KEYBOARD, SPACE + row + 1, 0); +} + +#endif NLK > 0 diff --git a/chips/nc.c b/chips/nc.c new file mode 100644 index 0000000..adce0ae --- /dev/null +++ b/chips/nc.c @@ -0,0 +1,851 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +/*** NETWORK INTERFACE IMPLEMENTATION CORE ***/ + +#ifndef STUB +#include +#else +#include "nc.h" +#endif + +/*** Types and data structures ***/ + +#if PRODUCTION +#define MAX_HASH 701 +#define MAX_HOST 4000 +#else +#define MAX_HASH 7 +#define MAX_HOST 4 +#endif + +nw_dev_entry_s nc_failure_entry_table = {nc_fail, nc_fail, + nc_null, nc_null, + nc_null_poll, nc_null_send, nc_null_rpc, + nc_null_signal, nc_open_fail, nc_accept_fail, + nc_close_fail, nc_open_fail, nc_open_fail}; + +nw_dev_entry_s nc_local_entry_table = {nc_succeed, nc_succeed, + nc_null, nc_null, + nc_null_poll, nc_local_send, nc_local_rpc, + nc_null_signal, nc_open_fail, nc_accept_fail, + nc_close_fail, nc_open_fail, nc_open_fail}; + + +typedef struct { + nw_address_s address; + int name_next:16; + int ip_next:16; + int nw_next:16; + nw_ep line:16; +} nw_alist_s, *nw_alist_t; + + +boolean_t nc_initialized = FALSE; +nw_tx_header_s nw_tx[MAX_EP/2]; +nw_tx_header_t nw_free_tx_header; +nw_rx_header_s nw_rx[2*MAX_EP]; +nw_rx_header_t nw_free_rx_header; +nw_plist_s nw_peer[MAX_EP]; +nw_plist_t nw_free_peer; + +nw_devcb devct[MAX_DEV]; + +nw_ecb ect[MAX_EP]; + +int nw_free_ep_first, nw_free_ep_last; +int nw_free_line_first, nw_free_line_last; + +nw_alist_s nw_address[MAX_HOST]; +int nw_free_address; + +int nw_name[MAX_HASH]; +int nw_ip[MAX_HASH]; +int nw_nw[MAX_HASH]; + +int nw_fast_req; + +/*** System-independent functions ***/ + +void nc_initialize() { + int ep, last_ep; + + if (!nc_initialized) { + last_ep = sizeof(nw_tx)/sizeof(nw_tx_header_s) - 1; + for (ep = 0; ep < last_ep; ep++) + nw_tx[ep].next = &nw_tx[ep+1]; + nw_tx[last_ep].next = NULL; + nw_free_tx_header = &nw_tx[0]; + last_ep = sizeof(nw_rx)/sizeof(nw_rx_header_s) - 1; + for (ep = 0; ep < last_ep; ep++) + nw_rx[ep].next = &nw_rx[ep+1]; + nw_rx[last_ep].next = NULL; + nw_free_rx_header = &nw_rx[0]; + last_ep = sizeof(nw_peer)/sizeof(nw_plist_s) - 1; + for (ep = 0; ep < last_ep; ep++) + nw_peer[ep].next = &nw_peer[ep+1]; + nw_peer[last_ep].next = NULL; + nw_free_peer = &nw_peer[0]; + for (ep = 0; ep < MAX_DEV; ep++) { + devct[ep].status = NW_FAILURE; + devct[ep].type = NW_CONNECTIONLESS; + devct[ep].addr = NULL; + devct[ep].local_addr_1 = 0; + devct[ep].local_addr_2 = 0; + devct[ep].entry = &nc_failure_entry_table; + devct[ep].fast_req = 0; + } + devct[NW_NULL].status = NW_SUCCESS; + devct[NW_NULL].entry = &nc_local_entry_table; + last_ep = sizeof(ect)/sizeof(nw_ecb); + for (ep = 0; ep < last_ep; ep++) { + ect[ep].state = NW_INEXISTENT; + ect[ep].id = ep; + ect[ep].seqno = 0; + ect[ep].previous = ep - 1; + ect[ep].next = ep + 1; + } + ect[0].next = ect[0].previous = 0; + ect[last_ep-1].next = 0; + nw_free_ep_first = 1; + nw_free_ep_last = last_ep - 1; + nw_free_line_first = nw_free_line_last = 0; + for (ep = 0; ep < MAX_HOST; ep++) { + nw_address[ep].nw_next = ep + 1; + } + nw_address[MAX_HOST - 1].nw_next = -1; + nw_free_address = 0; + for (ep = 0; ep < MAX_HASH; ep++) { + nw_name[ep] = -1; + nw_ip[ep] = -1; + nw_nw[ep] = -1; + } + nw_fast_req = 0; + h_initialize(); + nc_initialized = TRUE; + } +} + +nw_tx_header_t nc_tx_header_allocate() { + nw_tx_header_t header; + + header = nw_free_tx_header; + if (header != NULL) + nw_free_tx_header = header->next; + return header; +} + +void nc_tx_header_deallocate(nw_tx_header_t header) { + nw_tx_header_t first_header; + + first_header = header; + while (header->next != NULL) + header = header->next; + header->next = nw_free_tx_header; + nw_free_tx_header = first_header; +} + +nw_rx_header_t nc_rx_header_allocate() { + nw_rx_header_t header; + + header = nw_free_rx_header; + if (header != NULL) + nw_free_rx_header = header->next; + return header; +} + +void nc_rx_header_deallocate(nw_rx_header_t header) { + + header->next = nw_free_rx_header; + nw_free_rx_header = header; +} + +nw_plist_t nc_peer_allocate() { + nw_plist_t peer; + + peer = nw_free_peer; + if (peer != NULL) + nw_free_peer = peer->next; + return peer; +} + +void nc_peer_deallocate(nw_plist_t peer) { + nw_plist_t first_peer; + + first_peer = peer; + while (peer->next != NULL) + peer = peer->next; + peer->next = nw_free_peer; + nw_free_peer = first_peer; +} + + +nw_result nc_device_register(u_int dev, nw_dev_type type, char *dev_addr, + nw_dev_entry_t dev_entry_table) { + nw_result rc; + + if (dev >= MAX_DEV) { + rc = NW_FAILURE; + } else { + devct[dev].status = NW_SUCCESS; + devct[dev].type = type; + devct[dev].addr = dev_addr; + devct[dev].entry = dev_entry_table; + devct[dev].fast_req = 0; + rc = NW_SUCCESS; + } + return rc; +} + +nw_result nc_device_unregister(u_int dev, nw_result status) { + nw_result rc; + + if (dev >= MAX_DEV) { + rc = NW_FAILURE; + } else { + devct[dev].status = status; + devct[dev].addr = NULL; + devct[dev].entry = &nc_failure_entry_table; + devct[dev].fast_req = 0; + rc = NW_SUCCESS; + } + return rc; +} + +void nc_slow_sweep() { + int dev; + + for (dev = 0; dev < MAX_DEV; dev++) { + if (devct[dev].status == NW_SUCCESS) { + (*(devct[dev].entry->slow_sweep)) (dev); + } + } +} + +void nc_fast_timer_set(int dev) { + + devct[dev].fast_req++; + if (nw_fast_req++ == 0) + h_fast_timer_set(); +} + +void nc_fast_timer_reset(int dev) { + + devct[dev].fast_req--; + if (nw_fast_req-- == 0) + h_fast_timer_reset(); +} + + +void nc_fast_sweep() { + int dev; + + for (dev = 0; dev < MAX_DEV; dev++) { + if (devct[dev].status == NW_SUCCESS && + devct[dev].fast_req > 0) { + devct[dev].fast_req = 0; + (*(devct[dev].entry->fast_sweep)) (dev); + } + } +} + +int nc_hash_name(char *cp) { + int h; + char ch; + char *cp_end; + + cp_end = cp + 19; + *cp_end = '\0'; + h = 0; + ch = *cp++; + while (ch != '\0') { + h = (h << 7) + ch; + ch = *cp++; + if (ch != '\0') { + h = (h << 7) + ch; + ch = *cp++; + if (ch != '\0') { + h = (h << 7) + ch; + ch = *cp++; + } + } + h %= MAX_HASH; + } + return h; +} + + +nw_result nc_update(nw_update_type up_type, int *up_info) { + nw_result rc; + nw_alist_t ad; + int h, slot, previous_slot, found_slot; + nw_address_1 n1; + nw_address_2 n2; + + if (up_type == NW_HOST_ADDRESS_REGISTER) { + if (nw_free_address == -1) { + rc = NW_NO_RESOURCES; + } else { + slot = nw_free_address; + ad = &nw_address[slot]; + nw_free_address = ad->nw_next; + ad->address = *((nw_address_t) up_info); + h = nc_hash_name(ad->address.name); + ad->name_next = nw_name[h]; + nw_name[h] = slot; + h = ad->address.ip_addr % MAX_HASH; + ad->ip_next = nw_ip[h]; + nw_ip[h] = slot; + h = (ad->address.nw_addr_1 % MAX_HASH + ad->address.nw_addr_2) + % MAX_HASH; + ad->nw_next = nw_nw[h]; + nw_nw[h] = slot; + ad->line = 0; + rc = NW_SUCCESS; + } + } else if (up_type == NW_HOST_ADDRESS_UNREGISTER) { + n1 = ((nw_address_t) up_info)->nw_addr_1; + n2 = ((nw_address_t) up_info)->nw_addr_2; + h = (n1 % MAX_HASH + n2) % MAX_HASH; + slot = nw_nw[h]; + previous_slot = -1; + ad = &nw_address[slot]; + while (slot != -1 && (ad->address.nw_addr_1 != n1 || + ad->address.nw_addr_2 != n2)) { + previous_slot = slot; + slot = ad->nw_next; + ad = &nw_address[slot]; + } + if (slot == -1) { + rc = NW_BAD_ADDRESS; + } else { + if (previous_slot == -1) + nw_nw[h] = ad->nw_next; + else + nw_address[previous_slot].nw_next = ad->nw_next; + ad->nw_next = nw_free_address; + nw_free_address = slot; + found_slot = slot; + if (ad->address.ip_addr != 0) { + h = ad->address.ip_addr % MAX_HASH; + slot = nw_ip[h]; + previous_slot = -1; + while (slot != -1 && slot != found_slot) { + previous_slot = slot; + slot = nw_address[slot].ip_next; + } + if (slot == found_slot) { + if (previous_slot == -1) + nw_ip[h] = ad->ip_next; + else + nw_address[previous_slot].ip_next = ad->ip_next; + } + } + if (ad->address.name[0] != '\0') { + h = nc_hash_name(ad->address.name); + slot = nw_name[h]; + previous_slot = -1; + while (slot != -1 && slot != found_slot) { + previous_slot = slot; + slot = nw_address[slot].name_next; + } + if (slot == found_slot) { + if (previous_slot == -1) + nw_name[h] = ad->name_next; + else + nw_address[previous_slot].name_next = ad->name_next; + } + } + rc = NW_SUCCESS; + } + } else { + rc = NW_INVALID_ARGUMENT; + } + return rc; +} + +nw_result nc_lookup(nw_lookup_type lt, int *look_info) { + nw_result rc; + nw_address_t addr; + nw_alist_t ad; + int h, slot; + ip_address ip; + nw_address_1 n1; + nw_address_2 n2; + + if (lt == NW_HOST_ADDRESS_LOOKUP) { + addr = (nw_address_t) look_info; + if (addr->ip_addr != 0) { + ip = addr->ip_addr; + h = ip % MAX_HASH; + slot = nw_ip[h]; + ad = &nw_address[slot]; + while (slot != -1 && ad->address.ip_addr != ip) { + slot = ad->ip_next; + ad = &nw_address[slot]; + } + if (slot != -1) { + strcpy(addr->name, ad->address.name); + addr->nw_addr_1 = ad->address.nw_addr_1; + addr->nw_addr_2 = ad->address.nw_addr_2; + return NW_SUCCESS; + } + } + if (addr->name[0] != '\0') { + h = nc_hash_name(addr->name); + slot = nw_name[h]; + ad = &nw_address[slot]; + while (slot != -1 && strcmp(ad->address.name, addr->name) != 0) { + slot = ad->name_next; + ad = &nw_address[slot]; + } + if (slot != -1) { + addr->ip_addr = ad->address.ip_addr; + addr->nw_addr_1 = ad->address.nw_addr_1; + addr->nw_addr_2 = ad->address.nw_addr_2; + return NW_SUCCESS; + } + } + if (addr->nw_addr_1 != 0 || addr->nw_addr_2 != 0) { + n1 = addr->nw_addr_1; + n2 = addr->nw_addr_2; + h = (n1 % MAX_HASH + n2) % MAX_HASH; + slot = nw_nw[h]; + ad = &nw_address[slot]; + while (slot != -1 && (ad->address.nw_addr_1 != n1 || + ad->address.nw_addr_2 != n2)) { + slot = ad->nw_next; + ad = &nw_address[slot]; + } + if (slot != -1) { + strcpy(addr->name, ad->address.name); + addr->ip_addr = ad->address.ip_addr; + return NW_SUCCESS; + } + } + rc = NW_BAD_ADDRESS; + } else { + rc = NW_INVALID_ARGUMENT; + } + return rc; +} + +nw_result nc_line_update(nw_peer_t peer, nw_ep line) { + nw_result rc; + nw_alist_t ad; + int h, slot; + nw_address_1 n1; + nw_address_2 n2; + + n1 = peer->rem_addr_1; + n2 = peer->rem_addr_2; + h = (n1 % MAX_HASH + n2) % MAX_HASH; + slot = nw_nw[h]; + ad = &nw_address[slot]; + while (slot != -1 && (ad->address.nw_addr_1 != n1 || + ad->address.nw_addr_2 != n2)) { + slot = ad->nw_next; + ad = &nw_address[slot]; + } + if (slot == -1) { + rc = NW_FAILURE; + } else { + ad->line = line; + rc = NW_SUCCESS; + } + return rc; +} + +nw_ep nc_line_lookup(nw_peer_t peer) { + nw_ep lep; + nw_alist_t ad; + int h, slot; + nw_address_1 n1; + nw_address_2 n2; + + n1 = peer->rem_addr_1; + n2 = peer->rem_addr_2; + h = (n1 % MAX_HASH + n2) % MAX_HASH; + slot = nw_nw[h]; + ad = &nw_address[slot]; + while (slot != -1 && (ad->address.nw_addr_1 != n1 || + ad->address.nw_addr_2 != n2)) { + slot = ad->nw_next; + ad = &nw_address[slot]; + } + if (slot == -1) { + lep = -1; + } else { + lep = ad->line; + } + return lep; +} + +nw_result nc_endpoint_allocate(nw_ep_t epp, nw_protocol protocol, + nw_acceptance accept, + char *buffer_address, u_int buffer_size) { + nw_result rc; + nw_ep ep; + nw_ecb_t ecb; + + if (ect[(ep = *epp)].state != NW_INEXISTENT) { + rc = NW_BAD_EP; + } else if (nw_free_ep_first == 0) { + *epp = nw_free_line_first; + rc = NW_NO_EP; + } else { + if (ep == 0) { + ecb = &ect[nw_free_ep_first]; + *epp = ep = ecb->id; + nw_free_ep_first = ecb->next; + if (nw_free_ep_first == 0) + nw_free_ep_last = 0; + } else { + ecb = &ect[ep]; + if (ecb->previous == 0) + nw_free_ep_first = ecb->next; + else + ect[ecb->previous].next = ecb->next; + if (ecb->next == 0) + nw_free_ep_last = ecb->previous; + else + ect[ecb->next].previous = ecb->previous; + } + if (protocol == NW_LINE) { + if (nw_free_line_last == 0) + nw_free_line_first = ep; + else + ect[nw_free_line_last].next = ep; + ecb->previous = nw_free_line_last; + ecb->next = 0; + nw_free_line_last = ep; + } + ecb->protocol = protocol; + ecb->accept = accept; + ecb->state = NW_UNCONNECTED; + ecb->conn = NULL; + ecb->buf_start = buffer_address; + ecb->buf_end = buffer_address + buffer_size; + ecb->free_buffer = (nw_unused_buffer_t) buffer_address; + ecb->free_buffer->buf_used = 0; + ecb->free_buffer->buf_length = buffer_size; + ecb->free_buffer->previous = NULL; + ecb->free_buffer->next = NULL; + ecb->overrun = 0; + ecb->seqno = 0; + ecb->tx_first = NULL; + ecb->tx_last = NULL; + ecb->tx_initial = NULL; + ecb->tx_current = NULL; + ecb->rx_first = NULL; + ecb->rx_last = NULL; + rc = NW_SUCCESS; + } + return rc; +} + +nw_result nc_endpoint_deallocate(nw_ep ep) { + nw_ecb_t ecb; + nw_rx_header_t rx_header; + + ecb = &ect[ep]; + if (ecb->conn != NULL) + nc_peer_deallocate(ecb->conn); + if (ecb->tx_first != NULL) + nc_tx_header_deallocate(ecb->tx_first); + if (ecb->tx_initial != NULL) + nc_tx_header_deallocate(ecb->tx_initial); + while (ecb->rx_first != NULL) { + rx_header = ecb->rx_first; + ecb->rx_first = rx_header->next; + nc_rx_header_deallocate(rx_header); + } + if (ecb->protocol == NW_LINE) { + if (ecb->previous == 0) + nw_free_line_first = ecb->next; + else + ect[ecb->previous].next = ecb->next; + if (ecb->next == 0) + nw_free_line_last = ecb->previous; + else + ect[ecb->next].previous = ecb->previous; + } + ecb->next = 0; + ecb->previous = nw_free_ep_last; + if (nw_free_ep_last == 0) + nw_free_ep_first = ep; + else + ect[nw_free_ep_last].next = ep; + nw_free_ep_last = ep; + ecb->id = ep; + ecb->state = NW_INEXISTENT; + return NW_SUCCESS; +} + +void nc_buffer_coalesce(nw_ecb_t ecb) { + nw_unused_buffer_t p, q, buf_free, buf_start, buf_end; + + buf_start = p = (nw_unused_buffer_t) ecb->buf_start; + buf_end = (nw_unused_buffer_t) ecb->buf_end; + buf_free = NULL; + while (p >= buf_start && p < buf_end) { + if (p->buf_length & 0x3) + goto trash_area; + if (p->buf_used) { + p = (nw_unused_buffer_t) ((char *) p + p->buf_length); + } else { + q = (nw_unused_buffer_t) ((char *) p + p->buf_length); + while (q >= buf_start && q < buf_end && !q->buf_used) { + if (q->buf_length & 0x3) + goto trash_area; + p->buf_length += q->buf_length; + q = (nw_unused_buffer_t) ((char *) q + q->buf_length); + } + p->next = buf_free; + p->previous = NULL; + if (buf_free != NULL) + buf_free->previous = p; + buf_free = p; + p = q; + } + } + ecb->free_buffer = buf_free; + return; + + trash_area: + ecb->free_buffer = NULL; + return; +} + + +nw_buffer_t nc_buffer_allocate(nw_ep ep, u_int size) { + nw_ecb_t ecb; + nw_unused_buffer_t buf, buf_start, buf_end; + + ecb = &ect[ep]; + buf_start = (nw_unused_buffer_t) ecb->buf_start; + buf_end = (nw_unused_buffer_t) (ecb->buf_end - sizeof(nw_buffer_s)); + if (size < sizeof(nw_buffer_s)) + size = sizeof(nw_buffer_s); + else + size = ((size + 3) >> 2) << 2; + buf = ecb->free_buffer; + if (buf != NULL) { + while (buf->buf_length < size) { + buf = buf->next; + if (buf < buf_start || buf > buf_end || ((int) buf & 0x3)) { + buf = NULL; + break; + } + } + } + if (buf == NULL) { + nc_buffer_coalesce(ecb); + buf = ecb->free_buffer; + while (buf != NULL && buf->buf_length < size) + buf = buf->next; + } + if (buf == NULL) { + ecb->overrun = 1; + } else { + if (buf->buf_length < size + sizeof(nw_buffer_s)) { + if (buf->previous == NULL) + ecb->free_buffer = buf->next; + else + buf->previous->next = buf->next; + if (buf->next != NULL) + buf->next->previous = buf->previous; + } else { + buf->buf_length -= size; + buf = (nw_unused_buffer_t) ((char *) buf + buf->buf_length); + buf->buf_length = size; + } + buf->buf_used = 1; + } + return (nw_buffer_t) buf; +} + +nw_result nc_buffer_deallocate(nw_ep ep, nw_buffer_t buffer) { + nw_ecb_t ecb; + nw_unused_buffer_t buf; + + ecb = &ect[ep]; + buf = (nw_unused_buffer_t) buffer; + buf->buf_used = 0; + buf->previous = NULL; + buf->next = ecb->free_buffer; + if (ecb->free_buffer != NULL) + ecb->free_buffer->previous = buf; + ecb->free_buffer = buf; + return NW_SUCCESS; +} + +nw_result nc_endpoint_status(nw_ep ep, nw_state_t state, nw_peer_t peer) { + nw_result rc; + nw_ecb_t ecb; + + ecb = &ect[ep]; + *state = ecb->state; + if (ecb->conn) + *peer = ecb->conn->peer; + if (ecb->overrun) { + ecb->overrun = 0; + rc = NW_OVERRUN; + } else if (ecb->rx_first != NULL) { + rc = NW_QUEUED; + } else { + rc = NW_SUCCESS; + } + return rc; +} + + +nw_result nc_local_send(nw_ep ep, nw_tx_header_t header, nw_options options) { + nw_result rc; + nw_ep receiver; + int length; + nw_buffer_t buffer; + nw_tx_header_t first_header; + nw_rx_header_t rx_header; + char *bufp; + nw_ecb_t ecb; + + receiver = header->peer.remote_ep; + length = header->msg_length; + buffer = nc_buffer_allocate(receiver, sizeof(nw_buffer_s) + length); + if (buffer == NULL) { + rc = NW_OVERRUN; + } else { + buffer->buf_next = NULL; + buffer->block_offset = sizeof(nw_buffer_s); + buffer->block_length = length; + buffer->peer.rem_addr_1 = NW_NULL << 28; + buffer->peer.rem_addr_2 = 0; + buffer->peer.remote_ep = ep; + buffer->peer.local_ep = receiver; + bufp = (char *) buffer + sizeof(nw_buffer_s); + first_header = header; + while (header != NULL) { + length = header->block_length; + bcopy(header->block, bufp, length); + bufp += length; + if (header->buffer != NULL) + nc_buffer_deallocate(ep, header->buffer); + header = header->next; + } + nc_tx_header_deallocate(first_header); + ecb = &ect[receiver]; + if (options == NW_URGENT) { + buffer->msg_seqno = 0; + if (nc_deliver_result(receiver, NW_RECEIVE_URGENT, (int) buffer)) + rc = NW_SUCCESS; + else + rc = NW_NO_RESOURCES; + } else { + if (ecb->seqno == 1023) + buffer->msg_seqno = ecb->seqno = 1; + else + buffer->msg_seqno = ++ecb->seqno; + if (nc_deliver_result(receiver, NW_RECEIVE, (int) buffer)) + rc = NW_SUCCESS; + else + rc = NW_NO_RESOURCES; + } + } + return rc; +} + +nw_buffer_t nc_local_rpc(nw_ep ep, nw_tx_header_t header, nw_options options) { + nw_buffer_t buf; + nw_ecb_t ecb; + nw_rx_header_t rx_header; + + ecb = &ect[ep]; + rx_header = ecb->rx_first; + if (nc_local_send(ep, header, options) != NW_SUCCESS) { + buf = NW_BUFFER_ERROR; + } else if (rx_header == NULL) { + buf = NULL; + } else { + buf = rx_header->buffer; + ecb->rx_first = rx_header->next; + if (ecb->rx_first == NULL) + ecb->rx_last = NULL; + nc_rx_header_deallocate(rx_header); + } + return buf; +} + + +nw_result nc_succeed(int dev) { + + return NW_SUCCESS; +} + +void nc_null(int dev) { + +} + +nw_result nc_fail(int dev) { + + return NW_FAILURE; +} + +int nc_null_poll(int dev) { + + return 1000000; +} + +nw_result nc_null_send(nw_ep ep, nw_tx_header_t header, nw_options options) { + + return NW_FAILURE; +} + +nw_buffer_t nc_null_rpc(nw_ep ep, nw_tx_header_t header, nw_options options) { + + return NW_BUFFER_ERROR; +} + +void nc_null_signal(nw_buffer_t msg) { + +} + +nw_result nc_open_fail(nw_ep lep, nw_address_1 a1, + nw_address_2 a2, nw_ep rep) { + + return NW_FAILURE; +} + +nw_result nc_close_fail(nw_ep ep) { + + return NW_FAILURE; +} + +nw_result nc_accept_fail(nw_ep ep, nw_buffer_t msg, nw_ep_t epp) { + + return NW_FAILURE; +} + diff --git a/chips/nc.h b/chips/nc.h new file mode 100644 index 0000000..0e481e8 --- /dev/null +++ b/chips/nc.h @@ -0,0 +1,232 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +/*** NETWORK INTERFACE IMPLEMENTATION CORE ***/ + +#ifndef _NC_H_ +#define _NC_H_ + +#ifndef STUB +#include +#else +#include "nw.h" +#endif + +/*** Types and data structures ***/ + +#if PRODUCTION +#define MAX_EP 1024 +#define MAX_DEV 16 +#else +#define MAX_EP 32 +#define MAX_DEV 3 +#endif + +#define MASTER_LINE_EP 0 +#define SIGNAL_EP 1 + +typedef struct nw_tx_headers { + nw_buffer_t buffer; + u_int msg_length; + char *block; + u_int block_length; + nw_peer_s peer; + nw_ep sender; + nw_options options; + struct nw_tx_headers *next; +} nw_tx_header_s; + +typedef nw_tx_header_s *nw_tx_header_t; + +typedef struct nw_rx_headers { + nw_buffer_t buffer; + nw_ep receiver; + u_int reply; + int time_stamp; + struct nw_rx_headers *next; +} nw_rx_header_s, *nw_rx_header_t; + +typedef enum { + NW_CONNECTIONLESS, + NW_CONNECTION_ORIENTED +} nw_dev_type; + + +typedef struct { + nw_result (*initialize)(int); + nw_result (*status)(int); + void (*slow_sweep)(int); + void (*fast_sweep)(int); + int (*poll)(int); + nw_result (*send)(nw_ep, nw_tx_header_t, nw_options); + nw_buffer_t (*rpc)(nw_ep, nw_tx_header_t, nw_options); + void (*signal)(nw_buffer_t); + nw_result (*open)(nw_ep, nw_address_1, nw_address_2, nw_ep); + nw_result (*accept)(nw_ep, nw_buffer_t, nw_ep_t); + nw_result (*close)(nw_ep); + nw_result (*add)(nw_ep, nw_address_1, nw_address_2, nw_ep); + nw_result (*drop)(nw_ep, nw_address_1, nw_address_2, nw_ep); +} nw_dev_entry_s, *nw_dev_entry_t; + +typedef struct { + nw_result status; + nw_dev_type type; + char *addr; + nw_address_1 local_addr_1; + nw_address_2 local_addr_2; + nw_dev_entry_t entry; + int fast_req; +} nw_devcb; + +extern nw_devcb devct[MAX_DEV]; + +typedef struct plists { + nw_peer_s peer; + struct plists *next; +} nw_plist_s, *nw_plist_t; + +typedef struct nw_unused_buffers { + u_int buf_used:1; + u_int buf_length:31; + struct nw_unused_buffers *next; + struct nw_unused_buffers *previous; +} nw_unused_buffer_s, *nw_unused_buffer_t; + +typedef struct ecbs{ + nw_protocol protocol; + nw_acceptance accept; + nw_state state; + nw_plist_t conn; + char *buf_start; + char *buf_end; + nw_unused_buffer_t free_buffer; + nw_ep id:16; + u_int overrun:1; + u_int seqno:14; + nw_tx_header_t tx_first; + nw_tx_header_t tx_last; + nw_tx_header_t tx_initial; + nw_tx_header_t tx_current; + nw_rx_header_t rx_first; + nw_rx_header_t rx_last; + nw_ep next:16; + nw_ep previous:16; +} nw_ecb, *nw_ecb_t; + +extern nw_ecb ect[MAX_EP]; + +extern int nw_free_ep_first, nw_free_ep_last; +extern int nw_free_line_first, nw_free_line_last; + +typedef enum { + NW_RECEIVE, + NW_RECEIVE_URGENT, + NW_SEND, + NW_SIGNAL +} nw_delivery; + + +/*** System-independent functions implemented in core ***/ + +extern void nc_initialize(); + +extern nw_tx_header_t nc_tx_header_allocate(); + +extern void nc_tx_header_deallocate(nw_tx_header_t header); + +extern nw_rx_header_t nc_rx_header_allocate(); + +extern void nc_rx_header_deallocate(nw_rx_header_t header); + +extern nw_plist_t nc_peer_allocate(); + +extern void nc_peer_deallocate(nw_plist_t peer); + +extern nw_result nc_device_register(u_int dev, nw_dev_type type, + char *dev_addr, + nw_dev_entry_t dev_entry_table); + +extern nw_result nc_device_unregister(u_int dev, nw_result status); + +extern void nc_fast_sweep(); + +extern void nc_fast_timer_set(); + +extern void nc_fast_timer_reset(); + +extern void nc_slow_sweep(); + +extern nw_result nc_update(nw_update_type up_type, int *up_info); + +extern nw_result nc_lookup(nw_lookup_type lt, int *look_info); + +extern nw_result nc_line_update(nw_peer_t peer, nw_ep line); + +extern nw_ep nc_line_lookup(nw_peer_t peer); + +extern nw_result nc_endpoint_allocate(nw_ep_t epp, nw_protocol protocol, + nw_acceptance accept, + char *buffer_address, u_int buffer_size); + +extern nw_result nc_endpoint_deallocate(nw_ep ep); + +extern nw_buffer_t nc_buffer_allocate(nw_ep ep, u_int size); + +extern nw_result nc_buffer_deallocate(nw_ep ep, nw_buffer_t buffer); + +extern nw_result nc_endpoint_status(nw_ep ep, + nw_state_t state, nw_peer_t peer); + + +/* System-dependent function implemented in wrapper*/ + +extern boolean_t nc_deliver_result(nw_ep ep, nw_delivery type, int result); + +/* Support required in wrapper */ + +extern void h_initialize(); + +extern void h_fast_timer_set(); + +extern void h_fast_timer_reset(); + + +/* Stubs for device table */ + +extern nw_result nc_succeed(int); +extern nw_result nc_fail(int); +extern void nc_null(int); +extern int nc_null_poll(int); +extern nw_result nc_null_send(nw_ep, nw_tx_header_t, nw_options); +extern nw_buffer_t nc_null_rpc(nw_ep, nw_tx_header_t, nw_options); +extern nw_result nc_local_send(nw_ep, nw_tx_header_t, nw_options); +extern nw_buffer_t nc_local_rpc(nw_ep, nw_tx_header_t, nw_options); +extern void nc_null_signal(nw_buffer_t); +extern nw_result nc_open_fail(nw_ep, nw_address_1, nw_address_2, nw_ep); +extern nw_result nc_accept_fail(nw_ep, nw_buffer_t, nw_ep_t); +extern nw_result nc_close_fail(nw_ep); + +#endif /* _NC_H_ */ diff --git a/chips/nw.h b/chips/nw.h new file mode 100644 index 0000000..63d497b --- /dev/null +++ b/chips/nw.h @@ -0,0 +1,494 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#ifndef _NW_H_ +#define _NW_H_ 1 + +#if defined(KMODE) || defined(KERNEL) +#include +#include +#else +#include "stub0.h" +#endif + +/*** NETWORK APPLICATION PROGRAMMING INTERFACE ***/ + +/*** TYPES ***/ + +typedef enum { + NW_SUCCESS, + NW_FAILURE, + NW_BAD_ADDRESS, + NW_OVERRUN, + NW_NO_CARRIER, + NW_NOT_SERVER, + NW_NO_EP, + NW_BAD_EP, + NW_INVALID_ARGUMENT, + NW_NO_RESOURCES, + NW_PROT_VIOLATION, + NW_BAD_BUFFER, + NW_BAD_LENGTH, + NW_NO_REMOTE_EP, + NW_TIME_OUT, + NW_INCONSISTENCY, + NW_ABORTED, + NW_SYNCH, + NW_QUEUED +} nw_result, *nw_result_t; + +typedef enum { + NW_INITIALIZE, + NW_HOST_ADDRESS_REGISTER, + NW_HOST_ADDRESS_UNREGISTER +} nw_update_type; + +typedef enum { + NW_STATUS, + NW_HOST_ADDRESS_LOOKUP +} nw_lookup_type; + +typedef u_int ip_address; + +typedef u_int nw_address_1; +typedef u_int nw_address_2; + +typedef struct { + char name[20]; /*Host name -- first 19 characters, zero-terminated*/ + ip_address ip_addr; + nw_address_1 nw_addr_1; /*4 most significant bits specify the device*/ + nw_address_2 nw_addr_2; +} nw_address_s, *nw_address_t; + +typedef enum { + NW_NULL, + NW_IP, /*Virtual network for IP addresses*/ + NW_TCA100_1, /*Fore Systems ATM network, first unit*/ + NW_TCA100_2 /*Fore Systems ATM network, second unit*/ +} nw_device, *nw_device_t; + +#define NW_DEVICE(addr) (addr >> 28) + +typedef u_int nw_ep, *nw_ep_t; + +typedef enum { + NW_RAW, /*Raw service provided by network*/ + NW_DATAGRAM, /*Connectionless service*/ + NW_SEQ_PACKET, /*Connection-oriented service*/ + NW_LINE /*Multiplexing line (system use only)*/ +} nw_protocol; + +typedef enum { + NW_NO_ACCEPT, /*Connection requests not accepted (client)*/ + NW_APPL_ACCEPT, /*Connection requests received as message by + application (msg_seqno 0), for examination + and approval (nw_connection_accept function)*/ + NW_AUTO_ACCEPT, /*Connection requests automatically accepted + if endpoint is connection-oriented and + not already connected*/ + NW_LINE_ACCEPT /*Connection requests automatically accepted + on a new endpoint (system use only)*/ +} nw_acceptance; + +typedef struct { + nw_address_1 rem_addr_1; + nw_address_2 rem_addr_2; + nw_ep remote_ep:16; + nw_ep local_ep:16; +} nw_peer_s, *nw_peer_t; + +typedef struct nw_buffer { + u_int buf_used:1; /*Read-only for applications (always 1)*/ + u_int buf_length:31; /*Read-only for applications*/ + struct nw_buffer *buf_next; /*Used only to gather on sends*/ + u_int msg_seqno:10; /*Sequential number of message, + automatically set by network interface*/ + u_int block_offset:22; /*Offset to the beginning of data (in bytes), + from the start of the buffer*/ + u_int block_deallocate:1; /*Used only to deallocate on sends*/ + u_int block_length:31; /*Length of data (in bytes) + beginning at offset*/ + nw_peer_s peer; /*Set on receives. Also required + in first block on datagram sends. + Ignored on sequenced packet sends.*/ +} nw_buffer_s, *nw_buffer_t; + + +/* msg_seqno is normally between 1 and 1023, and increases modulo 1024 + (skipping 0) between consecutive messages. In sequenced packets, msg_seqno + increases strictly by one. msg_seqno is assigned automatically. + The network interface writes in the buffer the msg_seqno used, + but only after the buffer has been transmitted and, in case of + sequenced packet, acknowledged. The application can use this update + to determine if a buffer can be reused, after a sending a message without + the deallocate option. + msg_seqno 0 is used when the corresponding send specifies the NW_URGENT + option. Such messages bypass any other messages possibly enqueued. + msg_seqno 0 is also used for open connection requests, in the case + of sequenced packet endpoints with the NW_APPL_ACCEPT option. + The type of msg_seqno 0 message is differentiated by the first word in the + message, which has type nw_options */ + +#define NW_BUFFER_ERROR ((nw_buffer_t) -1) /*Used for error indication + other than buffer overrun + (for which NULL is used)*/ + +typedef enum { + NW_INEXISTENT, + NW_UNCONNECTED, + NW_SIMPLEX_ORIGINATING, + NW_SIMPLEX_ORIGINATED, + NW_DUPLEX_ORIGINATING, + NW_DUPLEX_ORIGINATING_2, + NW_DUPLEX_ORIGINATED, + NW_ORIGINATOR_CLOSING, + NW_ORIGINATOR_RCLOSING, + NW_ACCEPTING, + NW_SIMPLEX_ACCEPTED, + NW_DUPLEX_ACCEPTING, + NW_DUPLEX_ACCEPTED, + NW_ACCEPTOR_CLOSING, + NW_ACCEPTOR_RCLOSING +} nw_state, *nw_state_t; + + +typedef enum nw_options { + NW_NORMAL, + NW_URGENT, + NW_SYNCHRONIZATION /*System use only*/ +} nw_options; + + +/*** FUNCTIONS ***/ + +extern nw_result nw_update(mach_port_t master_port, nw_update_type up_type, + int *up_info); + +/***************************************************************************** + Allows privileged applications to update network tables. The + application must present the device master port. up_type selects the + type of update, and up_info is cast accordingly to the correct type. + + For NW_HOST_ADDRESS_REGISTER and NW_HOST_ADDRESS_UNREGISTER, + up_info has type nw_address_t. For NW_HOST_ADDRESS_UNREGISTER, + however, only the network address field is used. + + up_info is not used for NW_INITIALIZE. This option is used to + initialize network interface tables, but does not initialize + devices. Initialization of hardware and network tables occurs + automatically at probe/boot time, so this option is normally + unnecessary. + + Returns NW_SUCCESS if operation completed successfully. + NW_FAILURE if master port not presented. + NW_NO_RESOURCES if network tables full (NW_HOST_ADDRESS_REGISTER). + NW_BAD_ADDRESS if host not found (NW_HOST_ADDRESS_UNREGISTER). + NW_INVALID_ARGUMENT if up_type is invalid or up_info is + a bad pointer. + *****************************************************************************/ + + +extern nw_result nw_lookup(nw_lookup_type lt, int *look_info); + +/***************************************************************************** + Allows applications to lookup network tables. The type of + lookup is selected by lt, and look_info is cast to the correct type + accordingly. + + For lt equal to NW_HOST_ADDRESS_LOOKUP, look_info has type + nw_address_t. In this option, the host is looked up first using the + IP address as a key (if non-zero), then by name (if non-empty), + and finally by network address (if non-zero). The function + returns NW_SUCCESS on the first match it finds, and sets the non-key + fields of look_info to the values found. No consistency check is + made if more than one key is supplied. The function returns + NW_BAD_ADDRESS if the host was not found, and NW_INVALID_ARGUMENT + if lt is invalid or look_info is a bad pointer. + + For lt equal to NW_STATUS, look_info has type nw_device_t on input + and nw_result_t on output. The function returns NW_INVALID_ARGUMENT + if the device chosen is invalid or look_info is a bad pointer; + otherwise, the function returns NW_SUCCESS. look_info is + set to: NW_FAILURE if the device is not present, NW_NOT_SERVER + if the device is not serviced by this interface, or a + device-dependent value otherwise (NW_SUCCESS if there is no device error). + + *****************************************************************************/ + + +extern nw_result nw_endpoint_allocate(nw_ep_t epp, nw_protocol protocol, + nw_acceptance accept, u_int buffer_size); + +/***************************************************************************** + Allocates a communication endpoint. On input, epp should point to the + the endpoint number desired, or to 0 if any number is adequate. + On output, epp points to the actual number allocated for the endpoint. + protocol specifies the transport discipline applied to data transmitted + or received through the endpoint. accept selects how open connection + requests received for the endpoint should be handled (connection-oriented + protocol), or whether the endpoint can receive messages (connectionless + protocol). buffer_size specifies the length in bytes of the buffer area + for data sent or received through the endpoint. + + Returns NW_SUCCESS if endpoint successfully allocated. + NW_INVALID_ARGUMENT if epp is a bad pointer or the + protocol or accept arguments are invalid. + NW_NO_EP if the endpoint name space is exhausted. + NW_BAD_EP if there already is an endpoint with the + number selected, or the number selected is + out of bounds. + NW_NO_RESOURCES if not enough memory for buffer. + *****************************************************************************/ + + +extern nw_result nw_endpoint_deallocate(nw_ep ep); + +/***************************************************************************** + Deallocates the given endpoint. + + Returns NW_SUCCESS if successfully deallocated endpoint. + NW_BAD_EP if endpoint does not exist. + NW_PROT_VIOLATION if access to endpoint not authorized. + *****************************************************************************/ + + +extern nw_buffer_t nw_buffer_allocate(nw_ep ep, u_int size); + +/***************************************************************************** + Allocates a buffer of the given size (in bytes) from the buffer area + of the given endpoint. + + Returns NW_BUFFER_ERROR if endpoint does not exist or access to endpoint + is not authorized. + NULL if no buffer with given size could be allocated. + Pointer to allocated buffer, otherwise. + *****************************************************************************/ + + +extern nw_result nw_buffer_deallocate(nw_ep ep, nw_buffer_t buffer); + +/***************************************************************************** + Deallocates the given buffer. + + Returns NW_SUCCESS if successfully deallocated buffer. + NW_BAD_EP if endpoint does not exist. + NW_PROT_VIOLATION if access to endpoint not authorized. + NW_BAD_BUFFER if buffer does not belong to endpoint's + buffer area or is malformed. + *****************************************************************************/ + + +extern nw_result nw_connection_open(nw_ep local_ep, nw_address_1 rem_addr_1, + nw_address_2 rem_addr_2, nw_ep remote_ep); + +/***************************************************************************** + Opens a connection. + + Returns NW_SUCCESS if connection successfully opened. + NW_BAD_EP if local endpoint does not exist, uses connectionless + protocol or is already connected. + NW_PROT_VIOLATION if access to local or remote endpoint + not authorized. + NW_BAD_ADDRESS if address of remote host is invalid. + NW_NO_REMOTE_EP if connection name space exhausted at + remote host. + NW_TIME_OUT if attempt to open connection timed out repeatedly. + NW_FAILURE if remote endpoint does not exist, uses connectionless + protocol or is already connected, or if remote + application did not accept open request. + *****************************************************************************/ + + +extern nw_result nw_connection_accept(nw_ep ep, nw_buffer_t msg, + nw_ep_t new_epp); + +/***************************************************************************** + Accepts open request (at the remote host). On input, new_epp equal to + NULL indicates that the application does not accept the request. + new_epp pointing to the value 0 indicates that the application wants + to accept the connection on a new endpoint, created dynamically, + with the same attributes as the original endpoint; new_epp pointing + to the value ep indicates that the application wants to simply + accept the open request. On output, new_epp points to the endpoint + actually connected, if any. msg points to the open request, which is + automatically deallocated. + + Returns NW_SUCCESS if connection correctly accepted or refused. + NW_BAD_EP if endpoint does not exist or has no outstanding + open request. + NW_PROT_VIOLATION if access to endpoint not authorized. + NW_BAD_BUFFER if msg does not belong to the endpoint's + buffer area, or is malformed. + NW_INVALID_ARGUMENT if new_epp is a bad pointer or points to + invalid value. + NW_NO_EP if endpoint name space exhausted. + NW_NO_RESOURCES if no buffer available for new endpoint. + NW_TIME_OUT if attempt to accept at different endpoint + repeatedly timed out. + *****************************************************************************/ + + +extern nw_result nw_connection_close(nw_ep ep); + +/***************************************************************************** + Closes the endpoint's connection. + + Returns NW_SUCCESS if successfully closed connection. + NW_BAD_EP if endpoint does not exist or is not connected. + NW_PROT_VIOLATION if access to endpoint not authorized. + *****************************************************************************/ + + +extern nw_result nw_multicast_add(nw_ep local_ep, nw_address_1 rem_addr_1, + nw_address_2 rem_addr_2, nw_ep remote_ep); + +/***************************************************************************** + Open multicast group or add one more member to multicast group. + + Returns NW_SUCCESS if successfully opened multicast group + or added member. + NW_BAD_EP if local endpoint does not exist, uses connectionless + protocol or is already connected point-to-point. + NW_PROT_VIOLATION if access to local or remote endpoint + not authorized. + NW_BAD_ADDRESS if address of remote host is invalid. + NW_NO_REMOTE_EP if connection name space exhausted at + remote host. + NW_TIME_OUT if attempt to open or add to multicast + timed out repeatedly. + NW_FAILURE if remote endpoint does not exist, uses connectionless + protocol or is already connected, or if remote + application did not accept open or add request. + *****************************************************************************/ + + +extern nw_result nw_multicast_drop(nw_ep local_ep, nw_address_1 rem_addr_1, + nw_address_2 rem_addr_2, nw_ep remote_ep); + +/***************************************************************************** + Drop member from multicast group, or close group if last member. + + Returns NW_SUCCESS if successfully dropped member or closed group. + NW_BAD_EP if local endpoint does not exist or is not connected in + multicast to the given remote endpoint. + NW_PROT_VIOLATION if access to local endpoint not authorized. + *****************************************************************************/ + + +extern nw_result nw_endpoint_status(nw_ep ep, nw_state_t state, + nw_peer_t peer); + +/***************************************************************************** + Returns the state of the given endpoint and peer to which it is + connected, if any. In case of multicast group, the first peer is + returned. + + Returns NW_SUCCESS if status correctly returned. + NW_BAD_EP if endpoint does not exist. + NW_PROT_VIOLATION if access to endpoint not authorized. + NW_INVALID_ARGUMENT if state or peer is a bad pointer. + *****************************************************************************/ + + +extern nw_result nw_send(nw_ep ep, nw_buffer_t msg, nw_options options); + +/***************************************************************************** + Sends message through endpoint with the given options. + + Returns NW_SUCCESS if message successfully queued for sending + (connectionless protocol) or sent and acknowledged + (connection-oriented protocol). + NW_BAD_EP if endpoint does not exist or uses connection-oriented + protocol but is unconnected. + NW_PROT_VIOLATION if access to endpoint not authorized. + NW_BAD_BUFFER if msg (or one of the buffers linked by buf_next) + is not a buffer in the endpoint's buffer area, or + is malformed (e.g., block_length extends beyond + end of buffer). + NW_NO_RESOURCES if unable to queue message due to resource + exhaustion. + NW_BAD_LENGTH if the total message length is too long for the + network and protocol used. + NW_BAD_ADDRESS if address of remote host is invalid + (connectionless protocol). + NW_FAILURE if repeated errors in message transmission + (connection-oriented). + NW_TIME_OUT if repeated time-outs in message transmission + (connection-oriented). + NW_OVERRUN if no buffer available in receiver's buffer area. + (connection-oriented). + *****************************************************************************/ + + +extern nw_buffer_t nw_receive(nw_ep ep, int time_out); + +/***************************************************************************** + Receive message destined to endpoint. Return if request not + satisfied within time_out msec. time_out 0 means non-blocking receive, + while -1 means block indefinitely. + + Returns NW_BUFFER_ERROR if endpoint does not exist or access + to endpoint is not authorized. + NULL if no message available for reception within the + specified time-out period. + Pointer to message, otherwise. + *****************************************************************************/ + + +extern nw_buffer_t nw_rpc(nw_ep ep, nw_buffer_t send_msg, nw_options options, + int time_out); + +/***************************************************************************** + Send message through given endpoint with given options and then + receive message through the same endpoint. Receive waiting time + is limited to time_out msec. + + Returns NW_BUFFER_ERROR if endpoint does not exist, access to + endpoint is not authorized, or there was + some transmission error. + NULL if no message available for reception within the + specified time-out period. + Pointer to message received, otherwise. + *****************************************************************************/ + + +extern nw_buffer_t nw_select(u_int nep, nw_ep_t epp, int time_out); + +/***************************************************************************** + Receive message from one of the nep endpoints in the array epp. + Waiting time is limited to time_out msec. + + Returns NW_BUFFER_ERROR if epp does not point to a valid array of nep + endpoint numbers, one of the endpoints does + not exist or has restricted access or the request + could not be correctly queued because of resource + exhaustion. + NULL if no message arrived within the specified time-out period. + Pointer to message received, otherwise. + *****************************************************************************/ + + +#endif /* _NW_H_ */ diff --git a/chips/nw_mk.c b/chips/nw_mk.c new file mode 100644 index 0000000..067cf7d --- /dev/null +++ b/chips/nw_mk.c @@ -0,0 +1,1323 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Scienctxe + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +/*** MACH KERNEL WRAPPER ***/ + +#ifndef STUB +#include +#include +#include +#include +#include +#include /* spl definitions */ +#include +#include +#include + +decl_simple_lock_data(, nw_simple_lock); +u_int previous_spl; + +#define nw_lock() \ + previous_spl = splimp(); \ + simple_lock(&nw_simple_lock) + +#define nw_unlock() \ + simple_unlock(&nw_simple_lock); \ + splx(previous_spl) + +typedef struct nw_pvs { + task_t owner; + char *buf_start; + char *buf_end; + struct nw_pvs *next; +} nw_pv_s, *nw_pv_t; + +typedef struct nw_waiters { + thread_t waiter; + struct nw_waiters *next; +} nw_waiter_s, *nw_waiter_t; + +typedef struct { + nw_pv_t pv; + thread_t sig_waiter; + nw_waiter_t rx_first; + nw_waiter_t rx_last; + nw_waiter_t tx_first; + nw_waiter_t tx_last; +} nw_hecb, *nw_hecb_t; + +#else +#include "nc.h" +#include "nw_mk.h" +#endif + +/*** Types and data structures ***/ + +int h_initialized = FALSE; +nw_pv_s nw_pv[2*MAX_EP]; +nw_pv_t nw_free_pv; +nw_waiter_s nw_waiter[2*MAX_EP]; +nw_waiter_t nw_free_waiter; +nw_ep_owned_s nw_waited[3*MAX_EP]; +nw_ep_owned_t nw_free_waited; +nw_hecb hect[MAX_EP]; +timer_elt_data_t nw_fast_timer, nw_slow_timer; + +/*** Initialization ***/ + +void h_initialize() { + int ep, last_ep; + + if (!h_initialized) { + last_ep = sizeof(nw_pv)/sizeof(nw_pv_s) - 1; + for (ep = 0; ep < last_ep; ep++) { + nw_pv[ep].next = &nw_pv[ep+1]; + } + nw_pv[last_ep].next = NULL; + nw_free_pv = &nw_pv[0]; + last_ep = sizeof(nw_waiter)/sizeof(nw_waiter_s) - 1; + for (ep = 0; ep < last_ep; ep++) { + nw_waiter[ep].next = &nw_waiter[ep+1]; + } + nw_waiter[last_ep].next = NULL; + nw_free_waiter = &nw_waiter[0]; + last_ep = sizeof(nw_waited)/sizeof(nw_ep_owned_s) - 1; + for (ep = 0; ep < last_ep; ep++) { + nw_waited[ep].next = &nw_waited[ep+1]; + } + nw_waited[last_ep].next = NULL; + nw_free_waited = &nw_waited[0]; + last_ep = sizeof(hect)/sizeof(nw_hecb); + for (ep = 0; ep < last_ep; ep++) { + hect[ep].pv = NULL; + hect[ep].sig_waiter = NULL; + hect[ep].rx_first = NULL; + hect[ep].rx_last = NULL; + hect[ep].tx_first = NULL; + hect[ep].tx_last = NULL; + } + nw_fast_timer.fcn = mk_fast_sweep; + nw_fast_timer.param = NULL; + nw_fast_timer.set = TELT_UNSET; + nw_slow_timer.fcn = mk_slow_sweep; + nw_slow_timer.param = NULL; +#if PRODUCTION + set_timeout(&nw_slow_timer, 2*hz); +#endif + h_initialized = TRUE; + } +} + +/*** User-trappable functions ***/ + +nw_result mk_update(mach_port_t master_port, nw_update_type up_type, + int *up_info) { + nw_result rc; + + if (master_port == 0) { /* XXX */ + rc = NW_FAILURE; + } else { + nw_lock(); + switch (up_type) { + case NW_HOST_ADDRESS_REGISTER: + case NW_HOST_ADDRESS_UNREGISTER: + if (invalid_user_access(current_task()->map, (vm_offset_t) up_info, + (vm_offset_t) up_info + sizeof(nw_address_s) - 1, + VM_PROT_READ | VM_PROT_WRITE)) { + rc = NW_INVALID_ARGUMENT; + } else { + rc = nc_update(up_type, up_info); + } + break; + case NW_INITIALIZE: + nc_initialize(); + rc = NW_SUCCESS; + break; + default: + rc = NW_INVALID_ARGUMENT; + } + nw_unlock(); + } + return rc; +} + + + +nw_result mk_lookup(nw_lookup_type lt, int *look_info) { + nw_result rc; + int max_size, dev; + + nw_lock(); + switch (lt) { + case NW_HOST_ADDRESS_LOOKUP: + if (invalid_user_access(current_task()->map, (vm_offset_t) look_info, + (vm_offset_t) look_info + sizeof(nw_address_s) - 1, + VM_PROT_READ | VM_PROT_WRITE)) { + rc = NW_INVALID_ARGUMENT; + } else { + rc = nc_lookup(lt, look_info); + } + break; + case NW_STATUS: + max_size = sizeof(nw_device); + if (max_size < sizeof(nw_result)) + max_size = sizeof(nw_result); + if (invalid_user_access(current_task()->map, (vm_offset_t) look_info, + (vm_offset_t) look_info + max_size - 1, + VM_PROT_READ | VM_PROT_WRITE) || + (dev = look_info[0]) >= MAX_DEV || dev < 0) { + rc = NW_INVALID_ARGUMENT; + } else { + if (devct[dev].status != NW_SUCCESS) { + look_info[0] = (int) devct[dev].status; + rc = NW_SUCCESS; + } else { + rc = (*(devct[dev].entry->status)) (dev); + } + } + break; + default: + rc = NW_INVALID_ARGUMENT; + } + nw_unlock(); + return rc; +} + + +nw_result mk_endpoint_allocate_internal(nw_ep_t epp, nw_protocol protocol, + nw_acceptance accept, + u_int buffer_size, boolean_t system) { + nw_result rc; + u_int ep; + vm_offset_t kernel_addr, user_addr; + nw_pv_t pv; + nw_ep_owned_t owned; + + ep = *epp; + if (buffer_size == 0) + buffer_size = 0x1000; + else + buffer_size = (buffer_size + 0xfff) & ~0xfff; + nw_lock(); + if (ep >= MAX_EP || (pv = hect[ep].pv) != NULL) { + rc = NW_BAD_EP; + } else if (nw_free_pv == NULL || nw_free_waited == NULL) { + rc = NW_NO_EP; + } else if (projected_buffer_allocate(current_task()->map, buffer_size, 0, + &kernel_addr, &user_addr, + VM_PROT_READ | VM_PROT_WRITE, + VM_INHERIT_NONE) != KERN_SUCCESS) { + rc = NW_NO_RESOURCES; + } else { + rc = nc_endpoint_allocate(epp, protocol, accept, + (char *) kernel_addr, buffer_size); + if (rc == NW_NO_EP && (ep = *epp) != 0) { + rc = (*(devct[NW_DEVICE(ect[ep].conn->peer.rem_addr_1)].entry-> + close)) (ep); + if (rc == NW_SYNCH) { + hect[ep].sig_waiter = current_thread(); + assert_wait(0, TRUE); + simple_unlock(&nw_simple_lock); + thread_block((void (*)()) 0); + } + rc = nc_endpoint_deallocate(ep); + if (rc == NW_SUCCESS) { + nc_line_update(&ect[ep].conn->peer, 0); + rc = nc_endpoint_allocate(epp, protocol, accept, + (char *) kernel_addr, buffer_size); + } + } + if (rc == NW_SUCCESS) { + ep = *epp; + if (system) { + hect[ep].pv = NULL; + } else { + hect[ep].pv = nw_free_pv; + nw_free_pv = nw_free_pv->next; + hect[ep].pv->owner = current_task(); + hect[ep].pv->buf_start = (char *) user_addr; + hect[ep].pv->buf_end = (char *) user_addr + buffer_size; + hect[ep].pv->next = NULL; + } + hect[ep].sig_waiter = NULL; + hect[ep].rx_first = NULL; + hect[ep].rx_last = NULL; + hect[ep].tx_first = NULL; + hect[ep].tx_last = NULL; + owned = nw_free_waited; + nw_free_waited = nw_free_waited->next; + owned->ep = ep; + owned->next = current_task()->nw_ep_owned; + current_task()->nw_ep_owned = owned; + } else { + projected_buffer_deallocate(current_task()->map, user_addr, + user_addr + buffer_size); + } + } + nw_unlock(); + return rc; +} + + +nw_result mk_endpoint_allocate(nw_ep_t epp, nw_protocol protocol, + nw_acceptance accept, u_int buffer_size) { + nw_result rc; + + if (invalid_user_access(current_task()->map, (vm_offset_t) epp, + (vm_offset_t) epp + sizeof(nw_ep) - 1, + VM_PROT_READ | VM_PROT_WRITE) || + (protocol != NW_RAW && protocol != NW_DATAGRAM && + protocol != NW_SEQ_PACKET) || (accept != NW_NO_ACCEPT && + accept != NW_APPL_ACCEPT && accept != NW_AUTO_ACCEPT)) { + rc = NW_INVALID_ARGUMENT; + } else { + rc = mk_endpoint_allocate_internal(epp, protocol, accept, + buffer_size, FALSE); + } + return rc; +} + +nw_result mk_endpoint_deallocate_internal(nw_ep ep, task_t task, + boolean_t shutdown) { + nw_result rc; + nw_pv_t pv, pv_previous; + nw_ep_owned_t owned, owned_previous; + nw_waiter_t w, w_previous, w_next; + + nw_lock(); + if (ep >= MAX_EP || (pv = hect[ep].pv) == NULL) { + rc = NW_BAD_EP; + } else { + pv_previous = NULL; + while (pv != NULL && pv->owner != task) { + pv_previous = pv; + pv = pv->next; + } + if (pv == NULL) { + rc = NW_PROT_VIOLATION; + } else { + if (projected_buffer_deallocate(task->map, pv->buf_start, + pv->buf_end) != KERN_SUCCESS) { + rc = NW_INCONSISTENCY; + printf("Endpoint deallocate: inconsistency p. buffer\n"); + } else { + if (pv_previous == NULL) + hect[ep].pv = pv->next; + else + pv_previous->next = pv->next; + pv->next = nw_free_pv; + nw_free_pv = pv; + owned = task->nw_ep_owned; + owned_previous = NULL; + while (owned != NULL && owned->ep != ep) { + owned_previous = owned; + owned = owned->next; + } + if (owned == NULL) { + rc = NW_INCONSISTENCY; + printf("Endpoint deallocate: inconsistency owned\n"); + } else { + if (owned_previous == NULL) + task->nw_ep_owned = owned->next; + else + owned_previous->next = owned->next; + owned->next = nw_free_waited; + nw_free_waited = owned; + if (hect[ep].sig_waiter != NULL && + hect[ep].sig_waiter->task == task) { +/* if (!shutdown)*/ + mk_deliver_result(hect[ep].sig_waiter, NW_ABORTED); + hect[ep].sig_waiter = NULL; + } + w = hect[ep].rx_first; + w_previous = NULL; + while (w != NULL) { + if (w->waiter->task == task) { +/* if (!shutdown)*/ + mk_deliver_result(w->waiter, NULL); + w_next = w->next; + if (w_previous == NULL) + hect[ep].rx_first = w_next; + else + w_previous->next = w_next; + w->next = nw_free_waiter; + nw_free_waiter = w; + w = w_next; + } else { + w_previous = w; + w = w->next; + } + } + if (hect[ep].rx_first == NULL) + hect[ep].rx_last = NULL; + w = hect[ep].tx_first; + w_previous = NULL; + while (w != NULL) { + if (w->waiter->task == task) { +/* if (!shutdown)*/ + mk_deliver_result(w->waiter, NW_ABORTED); + w_next = w->next; + if (w_previous == NULL) + hect[ep].tx_first = w_next; + else + w_previous->next = w_next; + w->next = nw_free_waiter; + nw_free_waiter = w; + w = w_next; + } else { + w_previous = w; + w = w->next; + } + } + if (hect[ep].tx_first == NULL) + hect[ep].tx_last = NULL; + if (hect[ep].pv == NULL) { + if (ect[ep].state != NW_UNCONNECTED) { + rc = (*(devct[NW_DEVICE(ect[ep].conn->peer.rem_addr_1)].entry-> + close)) (ep); + if (rc == NW_SYNCH) { + hect[ep].sig_waiter = current_thread(); + assert_wait(0, TRUE); + simple_unlock(&nw_simple_lock); + thread_block((void (*)()) 0); + } + } + rc = nc_endpoint_deallocate(ep); + } + } + } + } + } + nw_unlock(); + return rc; +} + +nw_result mk_endpoint_deallocate(nw_ep ep) { + + mk_endpoint_deallocate_internal(ep, current_task(), FALSE); +} + + +nw_buffer_t mk_buffer_allocate(nw_ep ep, u_int size) { + nw_buffer_t buf; + nw_pv_t pv; + + nw_lock(); + if (ep >= MAX_EP || (pv = hect[ep].pv) == NULL) { + buf = NW_BUFFER_ERROR; + } else { + while (pv != NULL && pv->owner != current_task()) + pv = pv->next; + if (pv == NULL) { + buf = NW_BUFFER_ERROR; + } else { + buf = nc_buffer_allocate(ep, size); + if (buf != NULL) { + buf = (nw_buffer_t) ((char *) buf - ect[ep].buf_start + pv->buf_start); + } + } + } + nw_unlock(); + return buf; +} + + + +nw_result mk_buffer_deallocate(nw_ep ep, nw_buffer_t buffer) { + nw_result rc; + nw_pv_t pv; + + nw_lock(); + if (ep >= MAX_EP || (pv = hect[ep].pv) == NULL) { + rc = NW_BAD_EP; + } else { + while (pv != NULL && pv->owner != current_task()) + pv = pv->next; + if (pv == NULL) { + rc = NW_PROT_VIOLATION; + } else { + if ((char *) buffer < pv->buf_start || + (char *) buffer + sizeof(nw_buffer_s) > pv->buf_end || + !buffer->buf_used || + (char *) buffer + buffer->buf_length > pv->buf_end) { + rc = NW_BAD_BUFFER; + } else { + buffer = (nw_buffer_t) ((char *) buffer - pv->buf_start + + ect[ep].buf_start); + rc = nc_buffer_deallocate(ep, buffer); + } + } + } + nw_unlock(); + return rc; +} + + +nw_result mk_connection_open_internal(nw_ep local_ep, nw_address_1 rem_addr_1, + nw_address_2 rem_addr_2, nw_ep remote_ep) { + nw_result rc; + + rc = (*devct[NW_DEVICE(rem_addr_1)].entry->open) (local_ep, + rem_addr_1, rem_addr_2, + remote_ep); + if (rc == NW_SYNCH) { + hect[local_ep].sig_waiter = current_thread(); + assert_wait(0, TRUE); + simple_unlock(&nw_simple_lock); + thread_block((void (*)()) 0); + } + return rc; +} + +nw_result mk_connection_open(nw_ep local_ep, nw_address_1 rem_addr_1, + nw_address_2 rem_addr_2, nw_ep remote_ep) { + nw_result rc; + nw_pv_t pv; + + nw_lock(); + if (local_ep >= MAX_EP || (pv = hect[local_ep].pv) == NULL) { + rc = NW_BAD_EP; + } else { + while (pv != NULL && pv->owner != current_task()) + pv = pv->next; + if (pv == NULL) { + rc = NW_PROT_VIOLATION; + } else { + rc = (*(devct[NW_DEVICE(rem_addr_1)].entry->open)) + (local_ep, rem_addr_1, rem_addr_2, remote_ep); + if (rc == NW_SYNCH) { + hect[local_ep].sig_waiter = current_thread(); + assert_wait(0, TRUE); + current_thread()->nw_ep_waited = NULL; + simple_unlock(&nw_simple_lock); + thread_block(mk_return); + } + } + } + nw_unlock(); + return rc; +} + + +nw_result mk_connection_accept(nw_ep ep, nw_buffer_t msg, + nw_ep_t new_epp) { + nw_result rc; + nw_pv_t pv; + + nw_lock(); + if (ep >= MAX_EP || (pv = hect[ep].pv) == NULL) { + rc = NW_BAD_EP; + } else { + while (pv != NULL && pv->owner != current_task()) + pv = pv->next; + if (pv == NULL) { + rc = NW_PROT_VIOLATION; + } else if ((char *) msg < pv->buf_start || + (char *) msg + sizeof(nw_buffer_s) > pv->buf_end || + !msg->buf_used || + (char *) msg + msg->buf_length > pv->buf_end) { + rc = NW_BAD_BUFFER; + } else if (new_epp != NULL && + (invalid_user_access(current_task()->map, (vm_offset_t) new_epp, + (vm_offset_t) new_epp + sizeof(nw_ep) - 1, + VM_PROT_READ | VM_PROT_WRITE) || + (*new_epp != 0 && *new_epp != ep))) { + rc = NW_INVALID_ARGUMENT; + } else { + rc = (*(devct[NW_DEVICE(ect[ep].conn->peer.rem_addr_1)].entry->accept)) + (ep, msg, new_epp); + if (rc == NW_SYNCH) { + hect[ep].sig_waiter = current_thread(); + assert_wait(0, TRUE); + current_thread()->nw_ep_waited = NULL; + simple_unlock(&nw_simple_lock); + thread_block(mk_return); + } + } + } + nw_unlock(); + return rc; +} + +nw_result mk_connection_close(nw_ep ep) { + nw_result rc; + nw_pv_t pv; + + nw_lock(); + if (ep >= MAX_EP || (pv = hect[ep].pv) == NULL) { + rc = NW_BAD_EP; + } else { + while (pv != NULL && pv->owner != current_task()) + pv = pv->next; + if (pv == NULL) { + rc = NW_PROT_VIOLATION; + } else { + rc = (*devct[NW_DEVICE(ect[ep].conn->peer.rem_addr_1)].entry->close) + (ep); + if (rc == NW_SYNCH) { + hect[ep].sig_waiter = current_thread(); + assert_wait(0, TRUE); + current_thread()->nw_ep_waited = NULL; + simple_unlock(&nw_simple_lock); + thread_block(mk_return); + } + } + } + nw_unlock(); + return rc; +} + + +nw_result mk_multicast_add(nw_ep local_ep, nw_address_1 rem_addr_1, + nw_address_2 rem_addr_2, nw_ep remote_ep) { + nw_result rc; + nw_pv_t pv; + + nw_lock(); + if (local_ep >= MAX_EP || (pv = hect[local_ep].pv) == NULL) { + rc = NW_BAD_EP; + } else { + while (pv != NULL && pv->owner != current_task()) + pv = pv->next; + if (pv == NULL) { + rc = NW_PROT_VIOLATION; + } else { + rc = (*(devct[NW_DEVICE(rem_addr_1)].entry->add)) + (local_ep, rem_addr_1, rem_addr_2, remote_ep); + if (rc == NW_SYNCH) { + hect[local_ep].sig_waiter = current_thread(); + assert_wait(0, TRUE); + current_thread()->nw_ep_waited = NULL; + simple_unlock(&nw_simple_lock); + thread_block(mk_return); + } + } + } + nw_unlock(); + return rc; +} + + +nw_result mk_multicast_drop(nw_ep local_ep, nw_address_1 rem_addr_1, + nw_address_2 rem_addr_2, nw_ep remote_ep) { + nw_result rc; + nw_pv_t pv; + + nw_lock(); + if (local_ep >= MAX_EP || (pv = hect[local_ep].pv) == NULL) { + rc = NW_BAD_EP; + } else { + while (pv != NULL && pv->owner != current_task()) + pv = pv->next; + if (pv == NULL) { + rc = NW_PROT_VIOLATION; + } else { + rc = (*(devct[NW_DEVICE(rem_addr_1)].entry->drop)) + (local_ep, rem_addr_1, rem_addr_2, remote_ep); + if (rc == NW_SYNCH) { + hect[local_ep].sig_waiter = current_thread(); + assert_wait(0, TRUE); + current_thread()->nw_ep_waited = NULL; + simple_unlock(&nw_simple_lock); + thread_block(mk_return); + } + } + } + nw_unlock(); + return rc; +} + + +nw_result mk_endpoint_status(nw_ep ep, nw_state_t state, + nw_peer_t peer) { + nw_result rc; + nw_pv_t pv; + + nw_lock(); + if (ep >= MAX_EP || (pv = hect[ep].pv) == NULL) { + rc = NW_BAD_EP; + } else { + while (pv != NULL && pv->owner != current_task()) + pv = pv->next; + if (pv == NULL) { + rc = NW_PROT_VIOLATION; + } else { + if (invalid_user_access(current_task()->map, (vm_offset_t) state, + (vm_offset_t) state + sizeof(nw_state) - 1, + VM_PROT_WRITE) || + invalid_user_access(current_task()->map, (vm_offset_t) peer, + (vm_offset_t) peer + sizeof(nw_peer_s) - 1, + VM_PROT_WRITE)) { + rc = NW_INVALID_ARGUMENT; + } else { + rc = nc_endpoint_status(ep, state, peer); + } + } + } + nw_unlock(); + return rc; +} + + +nw_result mk_send(nw_ep ep, nw_buffer_t msg, nw_options options) { + nw_result rc; + nw_pv_t pv; + nw_ep sender; + int dev; + nw_ecb_t ecb; + nw_tx_header_t header, first_header, previous_header; + nw_hecb_t hecb; + nw_waiter_t w; + + nw_lock(); + if (ep >= MAX_EP || (pv = hect[ep].pv) == NULL) { + rc = NW_BAD_EP; + } else { + while (pv != NULL && pv->owner != current_task()) + pv = pv->next; + if (pv == NULL) { + rc = NW_PROT_VIOLATION; + } else { + ecb = &ect[ep]; + if (ecb->state == NW_INEXISTENT || + (ecb->protocol == NW_SEQ_PACKET && ecb->conn == NULL)) { + rc = NW_BAD_EP; + } else { + first_header = header = nc_tx_header_allocate(); + previous_header = NULL; + rc = NW_SUCCESS; + while (header != NULL) { + if ((char *) msg < pv->buf_start || + (char *) msg + sizeof(nw_buffer_s) > pv->buf_end || + ((int) msg & 0x3) || (msg->block_offset & 0x3) || + (msg->block_length & 0x3) || !msg->buf_used || + (char *) msg + msg->buf_length > pv->buf_end || + msg->block_offset + msg->block_length > msg->buf_length) { + rc = NW_BAD_BUFFER; + break; + } else { + if (previous_header == NULL) { + if (ecb->protocol == NW_SEQ_PACKET) + header->peer = ecb->conn->peer; + else + header->peer = msg->peer; + } else { + previous_header->next = header; + } + header->buffer = (nw_buffer_t) ((char *) msg - pv->buf_start + + ecb->buf_start); + header->block = (char *) header->buffer + msg->block_offset; + if (!msg->block_deallocate) + header->buffer = NULL; + header->msg_length = 0; + header->block_length = msg->block_length; + first_header->msg_length += header->block_length; + header->next = NULL; + if (msg->buf_next == NULL) + break; + msg = msg->buf_next; + previous_header = header; + header = nc_tx_header_allocate(); + } + } + if (header == NULL) { + nc_tx_header_deallocate(first_header); + rc = NW_NO_RESOURCES; + } else if (rc == NW_SUCCESS) { + dev = NW_DEVICE(first_header->peer.rem_addr_1); + if (ecb->protocol != NW_DATAGRAM || + devct[dev].type != NW_CONNECTION_ORIENTED) { + sender = first_header->peer.local_ep; + rc = NW_SUCCESS; + } else { + sender = nc_line_lookup(&first_header->peer); + if (sender == -1) { + rc = NW_BAD_ADDRESS; + } else if (sender > 0) { + rc = NW_SUCCESS; + } else { + rc = mk_endpoint_allocate_internal(&sender, NW_LINE, + NW_AUTO_ACCEPT, 0, TRUE); + if (rc == NW_SUCCESS) { + rc = mk_connection_open_internal(sender, + first_header->peer.rem_addr_1, + first_header->peer.rem_addr_2, + MASTER_LINE_EP); + if (rc == NW_SUCCESS) + nc_line_update(&first_header->peer, sender); + } + } + } + if (rc == NW_SUCCESS) { + first_header->sender = sender; + first_header->options = options; + rc = (*(devct[dev].entry->send)) (sender, first_header, options); + if ((rc == NW_SYNCH || rc == NW_QUEUED) && + nw_free_waiter != NULL) { + w = nw_free_waiter; + nw_free_waiter = w->next; + w->waiter = current_thread(); + w->next = NULL; + hecb = &hect[sender]; + if (hecb->tx_last == NULL) { + hecb->tx_first = hecb->tx_last = w; + } else { + hecb->tx_last = hecb->tx_last->next = w; + } + assert_wait(0, TRUE); + current_thread()->nw_ep_waited = NULL; + simple_unlock(&nw_simple_lock); + thread_block(mk_return); + } + } + } + } + } + } + nw_unlock(); + return rc; +} + + +nw_buffer_t mk_receive(nw_ep ep, int time_out) { + nw_buffer_t rc; + nw_pv_t pv; + nw_ecb_t ecb; + nw_rx_header_t header; + nw_hecb_t hecb; + nw_waiter_t w; + nw_ep_owned_t waited; + + nw_lock(); + if (ep >= MAX_EP || (pv = hect[ep].pv) == NULL) { + rc = NW_BUFFER_ERROR; + } else { + while (pv != NULL && pv->owner != current_task()) + pv = pv->next; + if (pv == NULL) { + rc = NW_BUFFER_ERROR; + } else { + ecb = &ect[ep]; + header = ecb->rx_first; + if (header != NULL) { + rc = (nw_buffer_t) ((char *) header->buffer - ecb->buf_start + + pv->buf_start); + ecb->rx_first = header->next; + if (ecb->rx_first == NULL) + ecb->rx_last = NULL; + nc_rx_header_deallocate(header); + } else if (time_out != 0 && nw_free_waiter != NULL && + (time_out == -1 || nw_free_waited != NULL)) { + w = nw_free_waiter; + nw_free_waiter = w->next; + w->waiter = current_thread(); + w->next = NULL; + hecb = &hect[ep]; + if (hecb->rx_last == NULL) + hecb->rx_first = hecb->rx_last = w; + else + hecb->rx_last = hecb->rx_last->next = w; + assert_wait(0, TRUE); + if (time_out != -1) { + waited = nw_free_waited; + nw_free_waited = waited->next; + waited->ep = ep; + waited->next = NULL; + current_thread()->nw_ep_waited = waited; + current_thread()->wait_result = NULL; + if (!current_thread()->timer.set) + thread_set_timeout(time_out); + } else { + current_thread()->nw_ep_waited = NULL; + } + simple_unlock(&nw_simple_lock); + thread_block(mk_return); + } else { + rc = NULL; + } + } + } + nw_unlock(); + return rc; +} + + +nw_buffer_t mk_rpc(nw_ep ep, nw_buffer_t msg, nw_options options, + int time_out) { + nw_buffer_t rc; + nw_result nrc; + nw_ep sender; + int dev; + nw_pv_t pv; + nw_ecb_t ecb; + nw_tx_header_t header, first_header, previous_header; + nw_hecb_t hecb; + nw_waiter_t w; + nw_ep_owned_t waited; + + nw_lock(); + if (ep >= MAX_EP || (pv = hect[ep].pv) == NULL) { + rc = NW_BUFFER_ERROR; + } else { + while (pv != NULL && pv->owner != current_task()) + pv = pv->next; + if (pv == NULL) { + rc = NW_BUFFER_ERROR; + } else { + ecb = &ect[ep]; + if (ecb->state == NW_INEXISTENT || + (ecb->protocol == NW_SEQ_PACKET && ecb->conn == NULL)) { + rc = NW_BUFFER_ERROR; + } else { + first_header = header = nc_tx_header_allocate(); + previous_header = NULL; + rc = NULL; + while (header != NULL) { + if ((char *) msg < pv->buf_start || + (char *) msg + sizeof(nw_buffer_s) > pv->buf_end || + ((int) msg & 0x3) || (msg->block_offset & 0x3) || + (msg->block_length & 0x3) || !msg->buf_used || + (char *) msg + msg->buf_length > pv->buf_end || + msg->block_offset + msg->block_length > msg->buf_length) { + rc = NW_BUFFER_ERROR; + break; + } else { + if (previous_header == NULL) { + if (ecb->protocol == NW_SEQ_PACKET) + header->peer = ecb->conn->peer; + else + header->peer = msg->peer; + } else { + previous_header->next = header; + } + header->buffer = (nw_buffer_t) ((char *) msg - pv->buf_start + + ecb->buf_start); + header->block = (char *) header->buffer + msg->block_offset; + if (!msg->block_deallocate) + header->buffer = NULL; + header->msg_length = 0; + header->block_length = msg->block_length; + first_header->msg_length += header->block_length; + header->next = NULL; + if (msg->buf_next == NULL) + break; + msg = msg->buf_next; + previous_header = header; + header = nc_tx_header_allocate(); + } + } + if (header == NULL) { + nc_tx_header_deallocate(first_header); + rc = NW_BUFFER_ERROR; + } else if (rc != NW_BUFFER_ERROR) { + dev = NW_DEVICE(first_header->peer.rem_addr_1); + if (ecb->protocol != NW_DATAGRAM || + devct[dev].type != NW_CONNECTION_ORIENTED) { + sender = first_header->peer.local_ep; + nrc = NW_SUCCESS; + } else { + sender = nc_line_lookup(&first_header->peer); + if (sender == -1) { + nrc = NW_BAD_ADDRESS; + } else if (sender > 0) { + nrc = NW_SUCCESS; + } else { + nrc = mk_endpoint_allocate_internal(&sender, NW_LINE, + NW_AUTO_ACCEPT, 0, TRUE); + if (nrc == NW_SUCCESS) { + nrc = mk_connection_open_internal(sender, + first_header->peer.rem_addr_1, + first_header->peer.rem_addr_2, + MASTER_LINE_EP); + if (nrc == NW_SUCCESS) + nc_line_update(&first_header->peer, sender); + } + } + } + if (nrc == NW_SUCCESS) { + first_header->sender = sender; + first_header->options = options; + rc = (*(devct[dev].entry->rpc)) (sender, first_header, options); + if (rc != NULL && rc != NW_BUFFER_ERROR) { + rc = (nw_buffer_t) ((char *) rc - ecb->buf_start + + pv->buf_start); + } else if (rc == NULL && time_out != 0 && nw_free_waiter != NULL && + (time_out == -1 || nw_free_waited != NULL)) { + w = nw_free_waiter; + nw_free_waiter = w->next; + w->waiter = current_thread(); + w->next = NULL; + hecb = &hect[ep]; + if (hecb->rx_last == NULL) + hecb->rx_first = hecb->rx_last = w; + else + hecb->rx_last = hecb->rx_last->next = w; + assert_wait(0, TRUE); + if (time_out != -1) { + waited = nw_free_waited; + nw_free_waited = waited->next; + waited->ep = ep; + waited->next = NULL; + current_thread()->nw_ep_waited = waited; + current_thread()->wait_result = NULL; + if (!current_thread()->timer.set) + thread_set_timeout(time_out); + } else { + current_thread()->nw_ep_waited = NULL; + } + simple_unlock(&nw_simple_lock); + thread_block(mk_return); + } + } + } + } + } + } + nw_unlock(); + return rc; +} + +nw_buffer_t mk_select(u_int nep, nw_ep_t epp, int time_out) { + nw_buffer_t rc; + nw_pv_t pv; + int i; + nw_ep ep; + nw_ecb_t ecb; + nw_rx_header_t header; + nw_hecb_t hecb; + nw_waiter_t w, w_next; + nw_ep_owned_t waited; + + if (invalid_user_access(current_task()->map, (vm_offset_t) epp, + (vm_offset_t) epp + nep*sizeof(nw_ep) - 1, + VM_PROT_READ)) { + rc = NW_BUFFER_ERROR; + } else { + nw_lock(); + for (i = 0; i < nep; i++) { + ep = epp[i]; + if (ep >= MAX_EP || (pv = hect[ep].pv) == NULL) { + rc = NW_BUFFER_ERROR; + break; + } else { + while (pv != NULL && pv->owner != current_task()) + pv = pv->next; + if (pv == NULL) { + rc = NW_BUFFER_ERROR; + break; + } else { + ecb = &ect[ep]; + header = ecb->rx_first; + if (header != NULL) { + rc = (nw_buffer_t) ((char *) header->buffer - ecb->buf_start + + pv->buf_start); + ecb->rx_first = header->next; + if (ecb->rx_first == NULL) + ecb->rx_last = NULL; + nc_rx_header_deallocate(header); + break; + } + } + } + } + if (i == nep) { + if (time_out == 0) { + rc = NULL; + } else { + w = nw_free_waiter; + waited = nw_free_waited; + i = 0; + while (i < nep && + nw_free_waiter != NULL && nw_free_waited != NULL) { + nw_free_waiter = nw_free_waiter->next; + nw_free_waited = nw_free_waited->next; + i++; + } + if (i < nep) { + nw_free_waiter = w; + nw_free_waited = waited; + rc = NW_BUFFER_ERROR; + } else { + current_thread()->nw_ep_waited = waited; + for (i = 0; i < nep; i++) { + ep = epp[i]; + waited->ep = ep; + if (i < nep-1) + waited = waited->next; + else + waited->next = NULL; + w->waiter = current_thread(); + w_next = w->next; + w->next = NULL; + hecb = &hect[ep]; + if (hecb->rx_last == NULL) + hecb->rx_first = hecb->rx_last = w; + else + hecb->rx_last = hecb->rx_last->next = w; + w = w_next; + } + assert_wait(0, TRUE); + if (time_out != -1) { + current_thread()->wait_result = NULL; + if (!current_thread()->timer.set) + thread_set_timeout(time_out); + } + simple_unlock(&nw_simple_lock); + thread_block(mk_return); + } + } + } + nw_unlock(); + } + return rc; +} + + +/*** System-dependent support ***/ + +void mk_endpoint_collect(task_t task) { + + while (task->nw_ep_owned != NULL) { + mk_endpoint_deallocate_internal(task->nw_ep_owned->ep, task, TRUE); + } +} + +void mk_waited_collect(thread_t thread) { + nw_hecb_t hecb; + nw_waiter_t w, w_previous; + nw_ep_owned_t waited, waited_previous; + + waited = thread->nw_ep_waited; + if (waited != NULL) { + while (waited != NULL) { + hecb = &hect[waited->ep]; + w = hecb->rx_first; + w_previous = NULL; + while (w != NULL && w->waiter != thread) { + w_previous = w; + w = w->next; + } + if (w != NULL) { + if (w_previous == NULL) + hecb->rx_first = w->next; + else + w_previous->next = w->next; + if (w->next == NULL) + hecb->rx_last = w_previous; + w->next = nw_free_waiter; + nw_free_waiter = w; + } + waited_previous = waited; + waited = waited->next; + } + waited_previous->next = nw_free_waited; + nw_free_waited = thread->nw_ep_waited; + thread->nw_ep_waited = NULL; + } +} + +void mk_return() { + + thread_syscall_return(current_thread()->wait_result); +} + + +boolean_t mk_deliver_result(thread_t thread, int result) { + boolean_t rc; + int state, s; + + s = splsched(); + thread_lock(thread); + state = thread->state; + + reset_timeout_check(&thread->timer); + + switch (state & TH_SCHED_STATE) { + case TH_WAIT | TH_SUSP | TH_UNINT: + case TH_WAIT | TH_UNINT: + case TH_WAIT: + /* + * Sleeping and not suspendable - put on run queue. + */ + thread->state = (state &~ TH_WAIT) | TH_RUN; + thread->wait_result = (kern_return_t) result; + simpler_thread_setrun(thread, TRUE); + rc = TRUE; + break; + + case TH_WAIT | TH_SUSP: + case TH_RUN | TH_WAIT: + case TH_RUN | TH_WAIT | TH_SUSP: + case TH_RUN | TH_WAIT | TH_UNINT: + case TH_RUN | TH_WAIT | TH_SUSP | TH_UNINT: + /* + * Either already running, or suspended. + */ + thread->state = state &~ TH_WAIT; + thread->wait_result = (kern_return_t) result; + rc = FALSE; + break; + + default: + /* + * Not waiting. + */ + rc = FALSE; + break; + } + thread_unlock(thread); + splx(s); + return rc; +} + + +boolean_t nc_deliver_result(nw_ep ep, nw_delivery type, int result) { + boolean_t rc; + nw_hecb_t hecb; + nw_ecb_t ecb; + nw_waiter_t w; + thread_t thread; + task_t task; + nw_pv_t pv; + nw_buffer_t buf; + nw_rx_header_t rx_header; + nw_tx_header_t tx_header; + nw_ep lep; + + hecb = &hect[ep]; + ecb = &ect[ep]; + + thread = NULL; + if (type == NW_RECEIVE || type == NW_RECEIVE_URGENT) { + w = hecb->rx_first; + if (w != NULL) { + thread = w->waiter; + hecb->rx_first = w->next; + if (hecb->rx_first == NULL) + hecb->rx_last = NULL; + w->next = nw_free_waiter; + nw_free_waiter = w; + task = thread->task; + pv = hecb->pv; + while (pv != NULL && pv->owner != task) + pv = pv->next; + if (pv == NULL) { + rc = FALSE; + } else { + buf = (nw_buffer_t) ((char *) result - ecb->buf_start + pv->buf_start); + rc = mk_deliver_result(thread, (int) buf); + } + } else { + rx_header = nc_rx_header_allocate(); + if (rx_header == NULL) { + rc = FALSE; + } else { + rx_header->buffer = (nw_buffer_t) result; + if (type == NW_RECEIVE) { + rx_header->next = NULL; + if (ecb->rx_last == NULL) + ecb->rx_first = rx_header; + else + ecb->rx_last->next = rx_header; + ecb->rx_last = rx_header; + } else { + rx_header->next = ecb->rx_first; + if (ecb->rx_first == NULL) + ecb->rx_last = rx_header; + ecb->rx_first = rx_header; + } + rc = TRUE; + } + } + } else if (type == NW_SEND) { + w = hecb->tx_first; + if (w == NULL) { + rc = FALSE; + } else { + thread = w->waiter; + hecb->tx_first = w->next; + if (hecb->tx_first == NULL) + hecb->tx_last = NULL; + w->next = nw_free_waiter; + nw_free_waiter = w; + rc = mk_deliver_result(thread, result); + } + tx_header = ect[ep].tx_initial; + if (result == NW_SUCCESS) { + lep = tx_header->peer.local_ep; + while (tx_header != NULL) { + if (tx_header->buffer != NULL) + nc_buffer_deallocate(lep, tx_header->buffer); + tx_header = tx_header->next; + } + } + nc_tx_header_deallocate(ect[ep].tx_initial); + ect[ep].tx_initial = ect[ep].tx_current = NULL; + } else if (type == NW_SIGNAL) { + thread = hecb->sig_waiter; + hecb->sig_waiter = NULL; + if (thread == NULL) { + rc = FALSE; + } else { + rc = mk_deliver_result(thread, result); + } + } + return rc; +} + +int mk_fast_sweep() { + + nw_lock(); + nc_fast_sweep(); + nw_unlock(); + return 0; +} + +void h_fast_timer_set() { + +#ifdef PRODUCTION + if (!nw_fast_timer.set) + set_timeout(&nw_fast_timer, 1); +#endif +} + +void h_fast_timer_reset() { + + if (nw_fast_timer.set) + reset_timeout(&nw_fast_timer); +} + +int mk_slow_sweep() { + +#ifdef PRODUCTION + nw_lock(); + nc_slow_sweep(); + nw_unlock(); + set_timeout(&nw_slow_timer, 2*hz); + return 0; +#endif +} + diff --git a/chips/nw_mk.h b/chips/nw_mk.h new file mode 100644 index 0000000..d7ba503 --- /dev/null +++ b/chips/nw_mk.h @@ -0,0 +1,97 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#ifndef _NW_MK_H_ +#define _NW_MK_H_ 1 + +#ifndef STUB +#include +#include +#else +#include "nw.h" +#include "stub.h" +#endif + +/*** NETWORK INTERFACE -- WRAPPER FOR MACH KERNEL ***/ + +/*** User-trappable functions ***/ + +extern nw_result mk_update(mach_port_t master_port, nw_update_type up_type, + int *up_info); + +extern nw_result mk_lookup(nw_lookup_type lt, int *look_info); + +extern nw_result mk_endpoint_allocate(nw_ep_t epp, nw_protocol protocol, + nw_acceptance accept, u_int buffer_size); + +extern nw_result mk_endpoint_deallocate(nw_ep ep); + +extern nw_buffer_t mk_buffer_allocate(nw_ep ep, u_int size); + +extern nw_result mk_buffer_deallocate(nw_ep ep, nw_buffer_t buffer); + +extern nw_result mk_connection_open(nw_ep local_ep, nw_address_1 rem_addr_1, + nw_address_2 rem_addr_2, nw_ep remote_ep); + +extern nw_result mk_connection_accept(nw_ep ep, nw_buffer_t msg, + nw_ep_t new_epp); + +extern nw_result mk_connection_close(nw_ep ep); + +extern nw_result mk_multicast_add(nw_ep local_ep, nw_address_1 rem_addr_1, + nw_address_2 rem_addr_2, nw_ep remote_ep); + +extern nw_result mk_multicast_drop(nw_ep local_ep, nw_address_1 rem_addr_1, + nw_address_2 rem_addr_2, nw_ep remote_ep); + +extern nw_result mk_endpoint_status(nw_ep ep, nw_state_t state, + nw_peer_t peer); + +extern nw_result mk_send(nw_ep ep, nw_buffer_t msg, nw_options options); + +extern nw_buffer_t mk_receive(nw_ep ep, int time_out); + +extern nw_buffer_t mk_rpc(nw_ep ep, nw_buffer_t send_msg, + nw_options options, int time_out); + +extern nw_buffer_t mk_select(u_int nep, nw_ep_t epp, int time_out); + + +/*** System-dependent support ***/ + +extern void mk_endpoint_collect(task_t task); + +extern void mk_waited_collect(thread_t thread); + +extern void mk_return(); + +extern boolean_t mk_deliver_result(thread_t thread, int result); + +extern int mk_fast_sweep(); + +extern int mk_slow_sweep(); + +#endif /* _NW_MK_H_ */ diff --git a/chips/pm_defs.h b/chips/pm_defs.h new file mode 100644 index 0000000..623f65e --- /dev/null +++ b/chips/pm_defs.h @@ -0,0 +1,57 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: pm_defs.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Definitions specific to the "pm" simple framebuffer driver, + * exported across sub-modules. Some other framebuffer drivers + * that share code with pm use these defs also. + */ + +/* Hardware state (to be held in the screen descriptor) */ + +typedef struct { + char *cursor_registers; /* opaque, for sharing */ + unsigned short cursor_state; /* some regs are W-only */ + short unused; /* padding, free */ + char *vdac_registers; /* opaque, for sharing */ + unsigned char *framebuffer; + unsigned char *plane_mask; +} pm_softc_t; + +extern pm_softc_t *pm_alloc(/* unit, curs, framebuf, planem */); + +/* user mapping sizes */ +#define USER_INFO_SIZE PAGE_SIZE +#define PMASK_SIZE PAGE_SIZE +#define BITMAP_SIZE(sc) \ + ((sc)->frame_height * (((sc)->flags & COLOR_SCREEN) ? \ + sc->frame_scanline_width : \ + sc->frame_scanline_width>>3)) + +#define PM_SIZE(sc) (USER_INFO_SIZE+PMASK_SIZE+BITMAP_SIZE(sc)) diff --git a/chips/pm_hdw.c b/chips/pm_hdw.c new file mode 100644 index 0000000..8ac9492 --- /dev/null +++ b/chips/pm_hdw.c @@ -0,0 +1,201 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: pm_hdw.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Driver for the VFB01/02 Mono/Color framebuffer (pmax) + * Hardware-level operations. + */ + +#include +#if NBM>0 +#include + +#include /* spl definitions */ +#include +#include +#include +#include + +#ifdef DECSTATION +#include +#include + +#define KN01_CSR_ADDR PHYS_TO_K1SEG(KN01_SYS_CSR) +#define KN01_FBUF_ADDR PHYS_TO_K1SEG(KN01_PHYS_FBUF_START) +#define KN01_PLM_ADDR PHYS_TO_K1SEG(KN01_PHYS_COLMASK_START) +#define KN01_BT478_ADDR PHYS_TO_K1SEG(KN01_SYS_VDAC) +#define KN01_DC503_ADDR PHYS_TO_K1SEG(KN01_SYS_PCC) + +#define VRETRACE dc503_vretrace +#define MONO_FRAME_WIDTH 2048 +#define ISA_MONO ((*(volatile short*)KN01_CSR_ADDR)&KN01_CSR_MONO) + +#endif /*DECSTATION*/ + +#ifdef VAXSTATION +#include +#define VRETRACE ka42_vretrace +#define ISA_MONO 1 +#define MONO_FRAME_WIDTH 1024 +#endif /*VAXSTATION*/ + +/* + * Definition of the driver for the auto-configuration program. + */ + +int pm_probe(), pm_intr(); +static void pm_attach(); + +vm_offset_t pm_std[] = { 0 }; +struct bus_device *pm_info[1]; +struct bus_driver pm_driver = + { pm_probe, 0, pm_attach, 0, pm_std, "pm", pm_info, }; + +/* + * Probe/Attach functions + */ + +pm_probe( /* reg, ui */) +{ + static probed_once = 0; +#ifdef DECSTATION + if (!isa_pmax()) + return 0; + if (check_memory(KN01_FBUF_ADDR, 0)) + return 0; +#endif /*DECSTATION*/ + if (probed_once++ > 1) + printf("[mappable] "); + return 1; +} + +static void +pm_attach(ui) + struct bus_device *ui; +{ + int isa_mono = ISA_MONO; + + printf(": %s%s", + isa_mono ? "monochrome" : "color", + " display"); +} + + +/* + * Interrupt routine + */ +#ifdef DECSTATION +pm_intr(unit,spllevel) + spl_t spllevel; +{ + /* this is the vertical retrace one */ + splx(spllevel); + lk201_led(unit); +} +#endif /*DECSTATION*/ + +#ifdef VAXSTATION +pm_intr(unit) +{ + lk201_led(unit); +} +#endif /*VAXSTATION*/ + +/* + * Boot time initialization: must make device + * usable as console asap. + */ +extern int + pm_cons_init(), pm_soft_reset(), + dc503_video_on(), dc503_video_off(), + pm_char_paint(), dc503_pos_cursor(), + pm_insert_line(), pm_remove_line(), pm_clear_bitmap(), + pm_set_status(), pm_get_status(), + VRETRACE(), pm_map_page(); + +static struct screen_switch pm_sw = { + screen_noop, /* graphic_open */ + pm_soft_reset, /* graphic_close */ + pm_set_status, /* set_status */ + pm_get_status, /* set_status */ + pm_char_paint, /* char_paint */ + dc503_pos_cursor, /* pos_cursor */ + pm_insert_line, /* insert_line */ + pm_remove_line, /* remove_line */ + pm_clear_bitmap, /* clear_bitmap */ + dc503_video_on, /* video_on */ + dc503_video_off, /* video_off */ + VRETRACE, /* enable vert retrace intr */ + pm_map_page /* map_page */ +}; + +pm_cold_init(unit, up) + user_info_t *up; +{ + pm_softc_t *pm; + screen_softc_t sc = screen(unit); + int isa_mono = ISA_MONO; + + bcopy(&pm_sw, &sc->sw, sizeof(sc->sw)); + if (isa_mono) { + sc->flags |= MONO_SCREEN; + sc->frame_scanline_width = MONO_FRAME_WIDTH; + } else { + sc->flags |= COLOR_SCREEN; + sc->frame_scanline_width = 1024; + } + sc->frame_height = 864; + sc->frame_visible_width = 1024; + sc->frame_visible_height = 864; + + pm_init_screen_params(sc, up); + (void) screen_up(unit, up); + +#ifdef DECSTATION + pm = pm_alloc(unit, KN01_DC503_ADDR, KN01_FBUF_ADDR, KN01_PLM_ADDR); + pm->vdac_registers = (char*)KN01_BT478_ADDR; +#endif /*DECSTATION*/ +#ifdef VAXSTATION + pm = pm_alloc(unit, cur_xxx, bm_mem, 0); +#endif /*VAXSTATION*/ + + screen_default_colors(up); + + dc503_init(pm); + + pm_soft_reset(sc); + + /* + * Clearing the screen at boot saves from scrolling + * much, and speeds up booting quite a bit. + */ + screen_blitc( unit, 'C'-'@');/* clear screen */ +} + +#endif NBM>0 diff --git a/chips/pm_misc.c b/chips/pm_misc.c new file mode 100644 index 0000000..d423645 --- /dev/null +++ b/chips/pm_misc.c @@ -0,0 +1,594 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: pm_misc.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Driver for the VFB01/02 Mono/Color framebuffer (pmax) + * Hardware-independent operations, mostly shared with + * the CFB driver (see each individual function header), + * and possibly others. + */ + + +#include + +#include + +#if defined(DECSTATION) || defined(FLAMINGO) +#include +#include +#include +#include +#define NPM (NFB+NCFB+NMFB+NXCFB+NSFB) +#endif /*DECSTATION*/ + +#ifdef VAXSTATION +#define NPM (NFB) +#endif /*VAXSTATION*/ + + +#if (NPM > 0) + +#include /* PAGE_SIZE */ +#include +#include /* kernel_pmap */ + +#include +#include + + +#ifdef DECSTATION +#define machine_btop mips_btop +#define MONO_BM (256*1024) +#endif /*DECSTATION*/ + +#ifdef VAXSTATION +#define machine_btop vax_btop +/* + For now we use the last page of the frame for + the user_info structure. +*/ +#define MONO_BM (256*1024-PAGE_SIZE) +#endif /*VAXSTATION*/ + +#ifdef FLAMINGO +#define machine_btop alpha_btop +#define MONO_BM (256*1024) +#define LOG2_SIZEOF_LONG 3 /* 64bit archies */ +#endif /* FLAMINGO */ + +#ifndef LOG2_SIZEOF_LONG +#define LOG2_SIZEOF_LONG 2 /* 32bit archies */ +#endif + + +/* Hardware state */ +pm_softc_t pm_softc_data[NPM]; + +pm_softc_t* +pm_alloc( + int unit, + char *cur, + unsigned char *fb, + unsigned char *pl) +{ + pm_softc_t *pm = &pm_softc_data[unit]; + + pm->cursor_registers = cur; + pm->framebuffer = fb; + pm->plane_mask = pl; + pm->vdac_registers = 0; /* later, if ever */ + + screen_attach(unit, (char *) pm); + + return pm; +} + + +/* + * Routine to paint a char on a simple framebuffer. + * This is common to the pm, fb and cfb drivers. + */ +pm_char_paint( + screen_softc_t sc, + int c, + int row, + int col) +{ + register int incr; + int line_size; + register unsigned char *font, *bmap; + pm_softc_t *pm = (pm_softc_t*)sc->hw_state; + + /* + * Here are the magic numbers that drive the loops below: + * incr bytes between scanlines of the glyph + * line_size bytes in a row, using the system font + * + * This code has been optimized to avoid multiplications, + * and is therefore much less obvious than it could be. + */ + if (sc->flags & MONO_SCREEN) { + /* + * B&W screen: 1 bit/pixel + * incr --> 1 * BytesPerLine, with possible stride + */ + incr = sc->frame_scanline_width >> 3; + } else { + /* + * Color screen: 8 bits/pixel + * incr --> 8 * BytesPerLine, with possible stride + */ + incr = sc->frame_scanline_width; + col <<= 3; + } + + /* not all compilers are smart about multiply by 15 */ +#if (KfontHeight==15) +# define TIMES_KfontHeight(w) (((w)<<4)-(w)) +#else +# define TIMES_KfontHeight(w) ((w)*KfontHeight) +#endif + line_size = TIMES_KfontHeight(incr); + + bmap = pm->framebuffer + col + (row * line_size); + font = &kfont_7x14[ (int)(c - ' ') * 15]; + if (sc->flags & MONO_SCREEN) { + /* + * Unroll simple loops, take note of common cases + */ + if (sc->standout) { +# define mv() *bmap = ~*font++; bmap += incr; + mv();mv();mv();mv();mv();mv();mv();mv(); + mv();mv();mv();mv();mv();mv();mv(); +# undef mv + } else if (c == ' ') { +# define mv() *bmap = 0; bmap += incr; + mv();mv();mv();mv();mv();mv();mv();mv(); + mv();mv();mv();mv();mv();mv();mv(); +# undef mv + } else { +# define mv() *bmap = *font++; bmap += incr; + mv();mv();mv();mv();mv();mv();mv();mv(); + mv();mv();mv();mv();mv();mv();mv(); +# undef mv + } + } else { + /* + * 8 bits per pixel --> paint one byte per each font bit. + * In order to spread out the 8 bits of a glyph line over + * the 64 bits per scanline use a simple vector multiply, + * taking 4 bits at a time to get the two resulting words + */ + static unsigned int spread[16] = { + 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00010000, 0x00010001, 0x00010100, 0x00010101, + 0x01000000, 0x01000001, 0x01000100, 0x01000101, + 0x01010000, 0x01010001, 0x01010100, 0x01010101, + }; + register int rev_video = sc->standout; + register int j; + for (j = 0; j < KfontHeight; j++) { + register unsigned char c = *font++; + if (rev_video) c = ~c; +#if (LOG2_SIZEOF_LONG==3) + *((long*)bmap) = (long)spread[ c & 0xf ] | + ((long)(spread[ (c>>4) & 0xf ]) << 32); +#else + ((int*)bmap)[0] = spread[ c & 0xf ]; + ((int*)bmap)[1] = spread[ (c>>4) & 0xf ]; +#endif + bmap += incr; + } + } +} + +/* + * Delete the line at the given row. + * This is common to the pm, fb and cfb drivers. + */ +pm_remove_line( + screen_softc_t sc, + short row) +{ + register long *dest, *src; + register long *end; + register long temp0,temp1,temp2,temp3; + register long i, scaninc, blockcnt; + long line_size, incr; + unsigned char *framebuffer; + pm_softc_t *pm = (pm_softc_t*)sc->hw_state; + long CharRows, CharCols; + + CharRows = sc->up->max_row; + CharCols = sc->up->max_col; + framebuffer = pm->framebuffer; + + /* Inner loop works 4 long words at a time (writebuffer deep) */ +# define BlockSizeShift (2+LOG2_SIZEOF_LONG) + + /* To copy one (MONO) line, we need to iterate this many times */ +# define Blocks (CharCols>>BlockSizeShift) + + /* Skip this many bytes to get to the next line */ +# define Slop(w) ((w) - (blockcnt<flags & MONO_SCREEN) { + blockcnt = Blocks; + /* See comments in pm_char_paint() */ + incr = sc->frame_scanline_width >> 3; + } else { + blockcnt = Blocks << 3; + /* See comments in pm_char_paint() */ + incr = sc->frame_scanline_width; + } + line_size = TIMES_KfontHeight(incr); + + scaninc = (Slop(incr)) >> LOG2_SIZEOF_LONG; /* pointers are long* */ + + dest = (long *)(framebuffer + row * line_size); + src = (long *)((char*)dest + line_size); + end = (long *)(framebuffer + CharRows * line_size); + while (src < end) { + i = 0; + do { + temp0 = src[0]; + temp1 = src[1]; + temp2 = src[2]; + temp3 = src[3]; + dest[0] = temp0; + dest[1] = temp1; + dest[2] = temp2; + dest[3] = temp3; + dest += 4; + src += 4; + i++; + } while (i < blockcnt); + src += scaninc; + dest += scaninc; + } + + /* Now zero out the last line */ + bzero(framebuffer + (CharRows - 1) * line_size, line_size); + + ascii_screen_rem_update(sc, row); +} + + +/* + * Open a new blank line at the given row. + * This is common to the pm, fb and cfb drivers. + */ +pm_insert_line( + screen_softc_t sc, + short row) +{ + register long *dest, *src; + register long *end; + register long temp0,temp1,temp2,temp3; + register long i, scaninc, blockcnt; + long line_size, incr; + unsigned char *framebuffer; + pm_softc_t *pm = (pm_softc_t*)sc->hw_state; + long CharRows, CharCols; + + CharRows = sc->up->max_row; + CharCols = sc->up->max_col; + + framebuffer = pm->framebuffer; + + /* See above for comments */ + if (sc->flags & MONO_SCREEN) { + blockcnt = Blocks; + /* See comments in pm_char_paint() */ + incr = sc->frame_scanline_width >> 3; + } else { + blockcnt = Blocks << 3; + /* See comments in pm_char_paint() */ + incr = sc->frame_scanline_width; + } + line_size = TIMES_KfontHeight(incr); + + scaninc = Slop(incr) + ((2 * blockcnt) << BlockSizeShift); + scaninc >>= LOG2_SIZEOF_LONG; /* pointers are long* */ + dest = (long *)(framebuffer + (CharRows - 1) * line_size); + src = (long *)((char*)dest - line_size); + end = (long *)(framebuffer + row * line_size); + while (src >= end) { + i = 0; + do { + temp0 = src[0]; + temp1 = src[1]; + temp2 = src[2]; + temp3 = src[3]; + dest[0] = temp0; + dest[1] = temp1; + dest[2] = temp2; + dest[3] = temp3; + dest += 4; + src += 4; + i++; + } while (i < blockcnt); + src -= scaninc; + dest -= scaninc; + } + + /* Now zero out the line being opened */ + bzero(framebuffer + row * line_size, line_size); + + ascii_screen_ins_update(sc, row); +} + +#undef Slop + + +/* + * Initialize screen parameters in the + * user-mapped descriptor. + * This is common to various drivers. + */ +pm_init_screen_params( + screen_softc_t sc, + user_info_t *up) +{ + register int vis_x, vis_y; + + up->frame_scanline_width = sc->frame_scanline_width; + up->frame_height = sc->frame_height; + + vis_x = sc->frame_visible_width; + vis_y = sc->frame_visible_height; + + up->max_x = vis_x; + up->max_y = vis_y; + up->max_cur_x = vis_x - 1; + up->max_cur_y = vis_y - 1; + up->min_cur_x = -15; + up->min_cur_y = -15; + up->max_row = vis_y / KfontHeight; + up->max_col = vis_x / KfontWidth; + + up->version = 11; + + up->mouse_threshold = 4; + up->mouse_scale = 2; + + up->dev_dep_2.pm.tablet_scale_x = ((vis_x - 1) * 1000) / 2200; + up->dev_dep_2.pm.tablet_scale_y = ((vis_y - 1) * 1000) / 2200; +} + +/* + * Clear the screen + * Used by pm, fb and cfb + */ +pm_clear_bitmap( + screen_softc_t sc) +{ + pm_softc_t *pm = (pm_softc_t *) sc->hw_state; + unsigned int screen_size; + + /* Do not touch the non visible part */ + screen_size = sc->frame_scanline_width * sc->frame_visible_height; + blkclr((char *)pm->framebuffer, + (sc->flags & MONO_SCREEN) ? (screen_size>>3) : screen_size); + + /* clear ascii screenmap */ + ascii_screen_fill(sc, ' '); +} + + +/* + * Size of the user-mapped structure + * Used by both pm and cfb + */ +pm_mem_need() +{ + return USER_INFO_SIZE; +} + +/* + * Device-specific get status. + * Used by fb and cfb also. + */ +pm_get_status( + screen_softc_t sc, + dev_flavor_t flavor, + dev_status_t status, + natural_t *status_count) +{ + if (flavor == SCREEN_GET_OFFSETS) { + unsigned *offs = (unsigned *) status; + + offs[0] = PM_SIZE(sc); /* virtual size */ + offs[1] = 0; /* offset of user_info_t */ + *status_count = 2; + return D_SUCCESS; + } else + return D_INVALID_OPERATION; +} + +/* + * Driver-specific set status + * Only partially used by fb and cfb. + */ +pm_set_status( + screen_softc_t sc, + dev_flavor_t flavor, + dev_status_t status, + natural_t status_count) +{ + switch (flavor) { + case SCREEN_ADJ_MAPPED_INFO: { + unsigned user_addr = *(unsigned *) status; + user_info_t *up = sc->up; + + /* Make it point to the event_queue, in user virtual */ + up->evque.events = (screen_event_t *)(user_addr + + ((char*)up->event_queue - (char*)up)); + + /* Make it point to the point_track, in user virtual */ + up->evque.track = (screen_timed_point_t *)(user_addr + + ((char*)up->point_track - (char*)up)); + + up->dev_dep_1.pm.planemask = (unsigned char *)(user_addr + USER_INFO_SIZE); + + up->dev_dep_1.pm.bitmap = up->dev_dep_1.pm.planemask + PMASK_SIZE; + + break; + } + + case SCREEN_LOAD_CURSOR: { + + sc->flags |= SCREEN_BEING_UPDATED; + dc503_load_cursor(sc->hw_state, (unsigned short*)status); + sc->flags &= ~SCREEN_BEING_UPDATED; + + break; + } + +#ifdef DECSTATION + case SCREEN_SET_CURSOR_COLOR: { + pm_softc_t *pm = (pm_softc_t*) sc->hw_state; + + sc->flags |= SCREEN_BEING_UPDATED; + bt478_cursor_color (pm->vdac_registers, (cursor_color_t*) status); + sc->flags &= ~SCREEN_BEING_UPDATED; + + break; + } + + case SCREEN_SET_CMAP_ENTRY: { + pm_softc_t *pm = (pm_softc_t*) sc->hw_state; + color_map_entry_t *e = (color_map_entry_t*) status; + + if (e->index < 256) { + sc->flags |= SCREEN_BEING_UPDATED; + bt478_load_colormap_entry( pm->vdac_registers, e->index, &e->value); + sc->flags &= ~SCREEN_BEING_UPDATED; + } + + break; + } +#endif /*DECSTATION*/ + default: + return D_INVALID_OPERATION; + } + return D_SUCCESS; +} + +/* + * Map pages to user space + */ +vm_offset_t pm_map_page_empty = (vm_offset_t) 0; + +integer_t +pm_map_page( + screen_softc_t sc, + vm_offset_t off, + int prot) +{ + int bitmapsize; + integer_t addr; + pm_softc_t *pm = (pm_softc_t *)sc->hw_state; + extern vm_offset_t pmap_extract( pmap_t map, vm_offset_t addr); + + bitmapsize = BITMAP_SIZE(sc); + +#define OFF0 USER_INFO_SIZE /* user mapped info */ +#define OFF1 OFF0+PMASK_SIZE /* plane mask register */ +#define OFF2 OFF1+bitmapsize /* frame buffer mem */ + + if (off < OFF0) +#ifdef DECSTATION + addr = kvtophys(sc->up); +#else + addr = (integer_t) pmap_extract(kernel_pmap, + (vm_offset_t)sc->up); +#endif + else + if (off < OFF1) { +#ifdef VAXSTATION + if (pm_map_page_empty == 0) { + pm_map_page_empty = vm_page_grab_phys_addr(); + } + addr = (integer_t)pmap_extract(kernel_pmap, pm_map_page_empty); +#else + addr = (integer_t) pm->plane_mask; +#endif + off -= OFF0; + } else + if (off < OFF2) { +#ifdef DECSTATION + addr = (integer_t)pm->framebuffer; +#else + addr = (integer_t)pmap_extract(kernel_pmap, + (vm_offset_t)pm->framebuffer); +#endif + off -= OFF1; + } else + return D_INVALID_SIZE; /* ??? */ + + addr = machine_btop(addr + off); + return (addr); +} + + +/* + *----------------------------------------------------------- + * The rest of this file is stricly pmax/pvax-specific + *----------------------------------------------------------- + */ +#if (NFB > 0) + +/* + * Do what's needed when the X server exits + */ +pm_soft_reset( + screen_softc_t sc) +{ + pm_softc_t *pm = (pm_softc_t*) sc->hw_state; + user_info_t *up = sc->up; + + /* + * Restore params in mapped structure + */ + pm_init_screen_params(sc, up); + up->row = up->max_row - 2; + dc503_init(pm); + +#ifdef DECSTATION + if (sc->flags & MONO_SCREEN) + bt478_init_bw_map(pm->vdac_registers, pm->plane_mask); + else + bt478_init_color_map(pm->vdac_registers, pm->plane_mask); +#endif /*DECSTATION*/ +} +#endif /* NFB > 0 */ + + +#endif /* NPM > 0 */ diff --git a/chips/scc_8530.h b/chips/scc_8530.h new file mode 100644 index 0000000..96a7964 --- /dev/null +++ b/chips/scc_8530.h @@ -0,0 +1,355 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: scc_8530.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 6/91 + * + * Definitions for the Zilog Z8530 SCC serial line chip + */ + +#ifndef _SCC_8530_H_ +#define _SCC_8530_H_ + +/* + * Register map, needs definition of the alignment + * used on the specific machine. + * #define the 'scc_register_t' data type before + * including this header file. For restrictions on + * access modes define the set/get_datum macros. + * We provide defaults ifnot. + */ + +#ifndef scc_register_t + +typedef struct scc_register { + volatile unsigned char datum; +} scc_register_t; + +#endif + + +#define SCC_CHANNEL_A 1 +#define SCC_CHANNEL_B 0 + +typedef struct { + /* Channel B is first, then A */ + struct { + scc_register_t scc_command; /* reg select */ + scc_register_t scc_data; /* Rx/Tx buffer */ + } scc_channel[2]; +} scc_regmap_t; + + +#ifndef scc_set_datum +#define scc_set_datum(d,v) (d) = (v) +#define scc_get_datum(d,v) (v) = (d) +#endif + +#define scc_init_reg(scc,chan) { \ + char tmp; \ + scc_get_datum((scc)->scc_channel[(chan)].scc_command.datum,tmp); \ + scc_get_datum((scc)->scc_channel[(chan)].scc_command.datum,tmp); \ + } + +#define scc_read_reg(scc,chan,reg,val) { \ + scc_set_datum((scc)->scc_channel[(chan)].scc_command.datum,reg); \ + scc_get_datum((scc)->scc_channel[(chan)].scc_command.datum,val); \ + } + +#define scc_read_reg_zero(scc,chan,val) { \ + scc_get_datum((scc)->scc_channel[(chan)].scc_command.datum,val); \ + } + +#define scc_write_reg(scc,chan,reg,val) { \ + scc_set_datum((scc)->scc_channel[(chan)].scc_command.datum,reg); \ + scc_set_datum((scc)->scc_channel[(chan)].scc_command.datum,val); \ + } + +#define scc_write_reg_zero(scc,chan,val) { \ + scc_set_datum((scc)->scc_channel[(chan)].scc_command.datum,val); \ + } + +#define scc_read_data(scc,chan,val) { \ + scc_get_datum((scc)->scc_channel[(chan)].scc_data.datum,val); \ + } + +#define scc_write_data(scc,chan,val) { \ + scc_set_datum((scc)->scc_channel[(chan)].scc_data.datum,val); \ + } + +/* + * Addressable registers + */ + +#define SCC_RR0 0 /* status register */ +#define SCC_RR1 1 /* special receive conditions */ +#define SCC_RR2 2 /* (modified) interrupt vector */ +#define SCC_RR3 3 /* interrupts pending (cha A only) */ +#define SCC_RR8 8 /* recv buffer (alias for data) */ +#define SCC_RR10 10 /* sdlc status */ +#define SCC_RR12 12 /* BRG constant, low part */ +#define SCC_RR13 13 /* BRG constant, high part */ +#define SCC_RR15 15 /* interrupts currently enabled */ + +#define SCC_WR0 0 /* reg select, and commands */ +#define SCC_WR1 1 /* interrupt and DMA enables */ +#define SCC_WR2 2 /* interrupt vector */ +#define SCC_WR3 3 /* receiver params and enables */ +#define SCC_WR4 4 /* clock/char/parity params */ +#define SCC_WR5 5 /* xmit params and enables */ +#define SCC_WR6 6 /* synchr SYNCH/address */ +#define SCC_WR7 7 /* synchr SYNCH/flag */ +#define SCC_WR8 8 /* xmit buffer (alias for data) */ +#define SCC_WR9 9 /* vectoring and resets */ +#define SCC_WR10 10 /* synchr params */ +#define SCC_WR11 11 /* clocking definitions */ +#define SCC_WR12 12 /* BRG constant, low part */ +#define SCC_WR13 13 /* BRG constant, high part */ +#define SCC_WR14 14 /* BRG enables and commands */ +#define SCC_WR15 15 /* interrupt enables */ + +/* + * Read registers defines + */ + +#define SCC_RR0_BREAK 0x80 /* break detected (rings twice), or */ +#define SCC_RR0_ABORT 0x80 /* abort (synchr) */ +#define SCC_RR0_TX_UNDERRUN 0x40 /* xmit buffer empty/end of message */ +#define SCC_RR0_CTS 0x20 /* clear-to-send pin active (sampled + only on intr and after RESI cmd */ +#define SCC_RR0_SYNCH 0x10 /* SYNCH found/still hunting */ +#define SCC_RR0_DCD 0x08 /* carrier-detect (same as CTS) */ +#define SCC_RR0_TX_EMPTY 0x04 /* xmit buffer empty */ +#define SCC_RR0_ZERO_COUNT 0x02 /* ? */ +#define SCC_RR0_RX_AVAIL 0x01 /* recv fifo not empty */ + +#define SCC_RR1_EOF 0x80 /* end-of-frame, SDLC mode */ +#define SCC_RR1_CRC_ERR 0x40 /* incorrect CRC or.. */ +#define SCC_RR1_FRAME_ERR 0x40 /* ..bad frame */ +#define SCC_RR1_RX_OVERRUN 0x20 /* rcv fifo overflow */ +#define SCC_RR1_PARITY_ERR 0x10 /* incorrect parity in data */ +#define SCC_RR1_RESIDUE0 0x08 +#define SCC_RR1_RESIDUE1 0x04 +#define SCC_RR1_RESIDUE2 0x02 +#define SCC_RR1_ALL_SENT 0x01 + +/* RR2 contains the interrupt vector unmodified (channel A) or + modified as follows (channel B, if vector-include-status) */ + +#define SCC_RR2_STATUS(val) ((val)&0xf) + +#define SCC_RR2_B_XMIT_DONE 0x0 +#define SCC_RR2_B_EXT_STATUS 0x2 +#define SCC_RR2_B_RECV_DONE 0x4 +#define SCC_RR2_B_RECV_SPECIAL 0x6 +#define SCC_RR2_A_XMIT_DONE 0x8 +#define SCC_RR2_A_EXT_STATUS 0xa +#define SCC_RR2_A_RECV_DONE 0xc +#define SCC_RR2_A_RECV_SPECIAL 0xe + +/* Interrupts pending, to be read from channel A only (B raz) */ +#define SCC_RR3_zero 0xc0 +#define SCC_RR3_RX_IP_A 0x20 +#define SCC_RR3_TX_IP_A 0x10 +#define SCC_RR3_EXT_IP_A 0x08 +#define SCC_RR3_RX_IP_B 0x04 +#define SCC_RR3_TX_IP_B 0x02 +#define SCC_RR3_EXT_IP_B 0x01 + +/* RR8 is the receive data buffer, a 3 deep FIFO */ +#define SCC_RECV_BUFFER SCC_RR8 +#define SCC_RECV_FIFO_DEEP 3 + +#define SCC_RR10_1CLKS 0x80 +#define SCC_RR10_2CLKS 0x40 +#define SCC_RR10_zero 0x2d +#define SCC_RR10_LOOP_SND 0x10 +#define SCC_RR10_ON_LOOP 0x02 + +/* RR12/RR13 hold the timing base, upper byte in RR13 */ + +#define scc_get_timing_base(scc,chan,val) { \ + register char tmp; \ + scc_read_reg(scc,chan,SCC_RR12,val);\ + scc_read_reg(scc,chan,SCC_RR13,tmp);\ + (val) = ((val)<<8)|(tmp&0xff);\ + } + +#define SCC_RR15_BREAK_IE 0x80 +#define SCC_RR15_TX_UNDERRUN_IE 0x40 +#define SCC_RR15_CTS_IE 0x20 +#define SCC_RR15_SYNCH_IE 0x10 +#define SCC_RR15_DCD_IE 0x08 +#define SCC_RR15_zero 0x05 +#define SCC_RR15_ZERO_COUNT_IE 0x02 + + +/* + * Write registers defines + */ + +/* WR0 is used for commands too */ +#define SCC_RESET_TXURUN_LATCH 0xc0 +#define SCC_RESET_TX_CRC 0x80 +#define SCC_RESET_RX_CRC 0x40 +#define SCC_RESET_HIGHEST_IUS 0x38 /* channel A only */ +#define SCC_RESET_ERROR 0x30 +#define SCC_RESET_TX_IP 0x28 +#define SCC_IE_NEXT_CHAR 0x20 +#define SCC_SEND_SDLC_ABORT 0x18 +#define SCC_RESET_EXT_IP 0x10 + +#define SCC_WR1_DMA_ENABLE 0x80 /* dma control */ +#define SCC_WR1_DMA_MODE 0x40 /* drive ~req for DMA controller */ +#define SCC_WR1_DMA_RECV_DATA 0x20 /* from wire to host memory */ + /* interrupt enable/conditions */ +#define SCC_WR1_RXI_SPECIAL_O 0x18 /* on special only */ +#define SCC_WR1_RXI_ALL_CHAR 0x10 /* on each char, or special */ +#define SCC_WR1_RXI_FIRST_CHAR 0x08 /* on first char, or special */ +#define SCC_WR1_RXI_DISABLE 0x00 /* never on recv */ +#define SCC_WR1_PARITY_IE 0x04 /* on parity errors */ +#define SCC_WR1_TX_IE 0x02 +#define SCC_WR1_EXT_IE 0x01 + +/* WR2 is common and contains the interrupt vector (high nibble) */ + +#define SCC_WR3_RX_8_BITS 0xc0 +#define SCC_WR3_RX_6_BITS 0x80 +#define SCC_WR3_RX_7_BITS 0x40 +#define SCC_WR3_RX_5_BITS 0x00 +#define SCC_WR3_AUTO_ENABLE 0x20 +#define SCC_WR3_HUNT_MODE 0x10 +#define SCC_WR3_RX_CRC_ENABLE 0x08 +#define SCC_WR3_SDLC_SRCH 0x04 +#define SCC_WR3_INHIBIT_SYNCH 0x02 +#define SCC_WR3_RX_ENABLE 0x01 + +/* Should be re-written after reset */ +#define SCC_WR4_CLK_x64 0xc0 /* clock divide factor */ +#define SCC_WR4_CLK_x32 0x80 +#define SCC_WR4_CLK_x16 0x40 +#define SCC_WR4_CLK_x1 0x00 +#define SCC_WR4_EXT_SYNCH_MODE 0x30 /* synch modes */ +#define SCC_WR4_SDLC_MODE 0x20 +#define SCC_WR4_16BIT_SYNCH 0x10 +#define SCC_WR4_8BIT_SYNCH 0x00 +#define SCC_WR4_2_STOP 0x0c /* asynch modes */ +#define SCC_WR4_1_5_STOP 0x08 +#define SCC_WR4_1_STOP 0x04 +#define SCC_WR4_SYNCH_MODE 0x00 +#define SCC_WR4_EVEN_PARITY 0x02 +#define SCC_WR4_PARITY_ENABLE 0x01 + +#define SCC_WR5_DTR 0x80 /* drive DTR pin */ +#define SCC_WR5_TX_8_BITS 0x60 +#define SCC_WR5_TX_6_BITS 0x40 +#define SCC_WR5_TX_7_BITS 0x20 +#define SCC_WR5_TX_5_BITS 0x00 +#define SCC_WR5_SEND_BREAK 0x10 +#define SCC_WR5_TX_ENABLE 0x08 +#define SCC_WR5_CRC_16 0x04 /* CRC if non zero, .. */ +#define SCC_WR5_SDLC 0x00 /* ..SDLC otherwise */ +#define SCC_WR5_RTS 0x02 /* drive RTS pin */ +#define SCC_WR5_TX_CRC_ENABLE 0x01 + +/* Registers WR6 and WR7 are for synch modes data, with among other things: */ + +#define SCC_WR6_BISYNCH_12 0x0f +#define SCC_WR6_SDLC_RANGE_MASK 0x0f +#define SCC_WR7_SDLC_FLAG 0x7e + +/* WR8 is the transmit data buffer (no FIFO) */ +#define SCC_XMT_BUFFER SCC_WR8 + +#define SCC_WR9_HW_RESET 0xc0 /* force hardware reset */ +#define SCC_WR9_RESET_CHA_A 0x80 +#define SCC_WR9_RESET_CHA_B 0x40 +#define SCC_WR9_NON_VECTORED 0x20 /* mbz for Zilog chip */ +#define SCC_WR9_STATUS_HIGH 0x10 +#define SCC_WR9_MASTER_IE 0x08 +#define SCC_WR9_DLC 0x04 /* disable-lower-chain */ +#define SCC_WR9_NV 0x02 /* no vector */ +#define SCC_WR9_VIS 0x01 /* vector-includes-status */ + +#define SCC_WR10_CRC_PRESET 0x80 +#define SCC_WR10_FM0 0x60 +#define SCC_WR10_FM1 0x40 +#define SCC_WR10_NRZI 0x20 +#define SCC_WR10_NRZ 0x00 +#define SCC_WR10_ACTIVE_ON_POLL 0x10 +#define SCC_WR10_MARK_IDLE 0x08 /* flag if zero */ +#define SCC_WR10_ABORT_ON_URUN 0x04 /* flag if zero */ +#define SCC_WR10_LOOP_MODE 0x02 +#define SCC_WR10_6BIT_SYNCH 0x01 +#define SCC_WR10_8BIT_SYNCH 0x00 + +#define SCC_WR11_RTxC_XTAL 0x80 /* RTxC pin is input (ext oscill) */ +#define SCC_WR11_RCLK_DPLL 0x60 /* clock received data on dpll */ +#define SCC_WR11_RCLK_BAUDR 0x40 /* .. on BRG */ +#define SCC_WR11_RCLK_TRc_PIN 0x20 /* .. on TRxC pin */ +#define SCC_WR11_RCLK_RTc_PIN 0x00 /* .. on RTxC pin */ +#define SCC_WR11_XTLK_DPLL 0x18 +#define SCC_WR11_XTLK_BAUDR 0x10 +#define SCC_WR11_XTLK_TRc_PIN 0x08 +#define SCC_WR11_XTLK_RTc_PIN 0x00 +#define SCC_WR11_TRc_OUT 0x04 /* drive TRxC pin as output from..*/ +#define SCC_WR11_TRcOUT_DPLL 0x03 /* .. the dpll */ +#define SCC_WR11_TRcOUT_BAUDR 0x02 /* .. the BRG */ +#define SCC_WR11_TRcOUT_XMTCLK 0x01 /* .. the xmit clock */ +#define SCC_WR11_TRcOUT_XTAL 0x00 /* .. the external oscillator */ + +/* WR12/WR13 are for timing base preset */ +#define scc_set_timing_base(scc,chan,val) { \ + scc_write_reg(scc,chan,SCC_RR12,val);\ + scc_write_reg(scc,chan,SCC_RR13,(val)>>8);\ + } + +/* More commands in this register */ +#define SCC_WR14_NRZI_MODE 0xe0 /* synch modulations */ +#define SCC_WR14_FM_MODE 0xc0 +#define SCC_WR14_RTc_SOURCE 0xa0 /* clock is from pin .. */ +#define SCC_WR14_BAUDR_SOURCE 0x80 /* .. or internal BRG */ +#define SCC_WR14_DISABLE_DPLL 0x60 +#define SCC_WR14_RESET_CLKMISS 0x40 +#define SCC_WR14_SEARCH_MODE 0x20 +/* ..and more bitsy */ +#define SCC_WR14_LOCAL_LOOPB 0x10 +#define SCC_WR14_AUTO_ECHO 0x08 +#define SCC_WR14_DTR_REQUEST 0x04 +#define SCC_WR14_BAUDR_SRC 0x02 +#define SCC_WR14_BAUDR_ENABLE 0x01 + +#define SCC_WR15_BREAK_IE 0x80 +#define SCC_WR15_TX_UNDERRUN_IE 0x40 +#define SCC_WR15_CTS_IE 0x20 +#define SCC_WR15_SYNCHUNT_IE 0x10 +#define SCC_WR15_DCD_IE 0x08 +#define SCC_WR15_zero 0x05 +#define SCC_WR15_ZERO_COUNT_IE 0x02 + + +#endif /*_SCC_8530_H_*/ diff --git a/chips/scc_8530_hdw.c b/chips/scc_8530_hdw.c new file mode 100644 index 0000000..68c6e9d --- /dev/null +++ b/chips/scc_8530_hdw.c @@ -0,0 +1,1145 @@ +/* + * Mach Operating System + * Copyright (c) 1993-1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: scc_8530_hdw.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 6/91 + * + * Hardware-level operations for the SCC Serial Line Driver + */ + +#include +#if NSCC > 0 +#include +#include + +#include + +#include /* spl definitions */ +#include +#include +#include + +#include +#include +#include + +/* Alignment and padding */ +#if defined(DECSTATION) +/* + * 3min's padding + */ +typedef struct { + char pad0; + volatile unsigned char datum; + char pad1[2]; +} scc_padded1_register_t; + +#define scc_register_t scc_padded1_register_t +#endif + +#if defined(FLAMINGO) +typedef struct { + volatile unsigned int datum; + unsigned int pad1; +} scc_padded1_register_t; + +#define scc_register_t scc_padded1_register_t + +#define scc_set_datum(d,v) (d) = (volatile unsigned int) (v) << 8, wbflush() +#define scc_get_datum(d,v) (v) = ((d) >> 8) & 0xff + +#endif + +#include /* needs the above defs */ + +#define private static +#define public + +/* + * Forward decls + */ +private check_car( struct tty *, boolean_t ); + +/* + * On the 3min keyboard and mouse come in on channels A + * of the two units. The MI code expects them at 'lines' + * 0 and 1, respectively. So we map here back and forth. + * Note also the MI code believes unit 0 has four lines. + */ + +#define SCC_KBDUNIT 1 +#define SCC_PTRUNIT 0 + +mi_to_scc(unitp, linep) + int *unitp, *linep; +{ + /* only play games on MI 'unit' 0 */ + if (*unitp) { + /* e.g. by mapping the first four lines specially */ + *unitp++; + return; + } + + /* always get unit=0 (console) and line = 0|1 */ + if (*linep == SCREEN_LINE_KEYBOARD) { + *unitp = SCC_KBDUNIT; + *linep = SCC_CHANNEL_A; + } else if (*linep == SCREEN_LINE_POINTER) { + *unitp = SCC_PTRUNIT; + *linep = SCC_CHANNEL_A; + } else { + *unitp = (*linep & 1); + *linep = SCC_CHANNEL_B; + } +/* line 0 is channel B, line 1 is channel A */ +} + +#define NSCC_LINE 2 /* 2 ttys per chip */ + +/* only care for mapping to ttyno */ +scc_to_mi(sccunit, sccline) +{ + if (sccunit > 1) + return (sccunit * NSCC_LINE + sccline); + /* only for console (first pair of SCCs): */ + if (sccline == SCC_CHANNEL_A) + return ((!sccunit) & 1); + return 2+sccunit; +} + + +/* + * Driver status + */ +struct scc_softc { + scc_regmap_t *regs; + + /* software copy of some write regs, for reg |= */ + struct softreg { + unsigned char wr1; + unsigned char wr4; + unsigned char wr5; + unsigned char wr14; + } softr[2]; /* per channel */ + + unsigned char last_rr0[2]; /* for modem signals */ + unsigned short fake; /* missing rs232 bits, channel A */ + char polling_mode; + char softCAR, osoftCAR; + char probed_once; + + boolean_t full_modem; + boolean_t isa_console; + +} scc_softc_data[NSCC]; + +typedef struct scc_softc *scc_softc_t; + +scc_softc_t scc_softc[NSCC]; + +scc_softCAR(unit, line, on) +{ + mi_to_scc(&unit, &line); + if (on) + scc_softc[unit]->softCAR |= 1<softCAR &= ~(1 << line); +} + + +/* + * BRG formula is: + * ClockFrequency + * BRGconstant = --------------------------- - 2 + * 2 * BaudRate * ClockDivider + */ +/* Speed selections with Pclk=7.3728Mhz, clock x16 */ +static +short scc_speeds[] = + /* 0 50 75 110 134.5 150 200 300 600 1200 1800 2400 */ + { 0, 4606, 3070, 2093, 1711, 1534, 1150, 766, 382, 190, 126, 94, + + /* 4800 9600 19.2k 38.4k */ + 46, 22, 10, 4}; + +/* + * Definition of the driver for the auto-configuration program. + */ + +int scc_probe(), scc_intr(); +static void scc_attach(); + +vm_offset_t scc_std[NSCC] = { 0 }; +struct bus_device *scc_info[NSCC]; +struct bus_driver scc_driver = + { scc_probe, 0, scc_attach, 0, scc_std, "scc", scc_info,}; + +/* + * Adapt/Probe/Attach functions + */ +boolean_t scc_uses_modem_control = FALSE;/* patch this with adb */ + +set_scc_address( + int sccunit, + vm_offset_t regs, + boolean_t has_modem, + boolean_t isa_console) +{ + extern int scc_probe(), scc_param(), scc_start(), + scc_putc(), scc_getc(), + scc_pollc(), scc_mctl(), scc_softCAR(); + + scc_std[sccunit] = regs; + scc_softc_data[sccunit].full_modem = has_modem & scc_uses_modem_control; + scc_softc_data[sccunit].isa_console = isa_console; + + /* Do this here */ + console_probe = scc_probe; + console_param = scc_param; + console_start = scc_start; + console_putc = scc_putc; + console_getc = scc_getc; + console_pollc = scc_pollc; + console_mctl = scc_mctl; + console_softCAR = scc_softCAR; + +} + +scc_probe( + int xxx, + struct bus_device *ui) +{ + int sccunit = ui->unit; + scc_softc_t scc; + register int val; + register scc_regmap_t *regs; + + regs = (scc_regmap_t *)scc_std[sccunit]; + if (regs == 0) + return 0; + + /* + * See if we are here + */ + if (check_memory(regs, 0)) { + /* no rides today */ + return 0; + } + + scc = &scc_softc_data[sccunit]; + + if (scc->probed_once++){ + return 1; + } + /* + * Chip once-only initialization + * + * NOTE: The wiring we assume is the one on the 3min: + * + * out A-TxD --> TxD keybd or mouse + * in A-RxD --> RxD keybd or mouse + * out A-DTR~ --> DTR comm + * out A-RTS~ --> RTS comm + * in A-CTS~ --> SI comm + * in A-DCD~ --> RI comm + * in A-SYNCH~--> DSR comm + * out B-TxD --> TxD comm + * in B-RxD --> RxD comm + * in B-RxC --> TRxCB comm + * in B-TxC --> RTxCB comm + * out B-RTS~ --> SS comm + * in B-CTS~ --> CTS comm + * in B-DCD~ --> CD comm + */ + + scc_softc[sccunit] = scc; + scc->regs = regs; + + scc->fake = 1<t_addr = (char*)(0x80000000L + (sccunit<<1) + (i&1)); + /* do min buffering */ + tp->t_state |= TS_MIN; + } + } + + /* make sure reg pointer is in known state */ + scc_init_reg(regs, SCC_CHANNEL_A); + scc_init_reg(regs, SCC_CHANNEL_B); + + /* reset chip, fully */ + scc_write_reg(regs, SCC_CHANNEL_A, SCC_WR9, SCC_WR9_HW_RESET); + delay(50000);/*enough ? */ + scc_write_reg(regs, SCC_CHANNEL_A, SCC_WR9, 0); + + /* program the interrupt vector */ + scc_write_reg(regs, SCC_CHANNEL_A, SCC_WR2, 0xf0); + scc_write_reg(regs, SCC_CHANNEL_B, SCC_WR2, 0xf0); + scc_write_reg(regs, SCC_CHANNEL_A, SCC_WR9, SCC_WR9_VIS); + + /* most of the init is in scc_param() */ + + /* timing base defaults */ + scc->softr[SCC_CHANNEL_A].wr4 = SCC_WR4_CLK_x16; + scc->softr[SCC_CHANNEL_B].wr4 = SCC_WR4_CLK_x16; + + /* enable DTR, RTS and dont SS */ +#if 0 + /* According to one book I have this signal (pin 23, "SS") + is "specified by the provider", meaning the EIA-232-D + standard does not define what it is. Better leave + it alone */ + scc->softr[SCC_CHANNEL_B].wr5 = SCC_WR5_RTS; +#else + scc->softr[SCC_CHANNEL_B].wr5 = 0; +#endif + scc->softr[SCC_CHANNEL_A].wr5 = SCC_WR5_RTS | SCC_WR5_DTR; + + /* baud rates */ + val = SCC_WR14_BAUDR_ENABLE|SCC_WR14_BAUDR_SRC; + scc->softr[SCC_CHANNEL_B].wr14 = val; + scc->softr[SCC_CHANNEL_A].wr14 = val; + + /* interrupt conditions */ + val = SCC_WR1_RXI_ALL_CHAR | SCC_WR1_PARITY_IE | + SCC_WR1_EXT_IE | SCC_WR1_TX_IE; + scc->softr[SCC_CHANNEL_A].wr1 = val; + scc->softr[SCC_CHANNEL_B].wr1 = val; + + scc_read_reg_zero(regs, SCC_CHANNEL_A, scc->last_rr0[SCC_CHANNEL_A]); + scc_read_reg_zero(regs, SCC_CHANNEL_B, scc->last_rr0[SCC_CHANNEL_B]); + + /* + * After probing, any line that should be active + * (keybd,mouse,rcline) is activated via scc_param(). + */ + + scc_set_modem_control(scc, scc->full_modem); + +#if defined(KMIN) || defined (FLAMINGO) || defined(KN03) + /* + * Crock: MI code knows of unit 0 as console, we need + * unit 1 as well since the keyboard is there + * This is acceptable on maxine, which has to call its + * only one chip unit 1 so that rconsole is happy. + */ + if (sccunit == 0) { + struct bus_device d; + d = *ui; + d.unit = 1; + scc_probe( xxx, &d); + } +#endif + return 1; +} + +boolean_t scc_timer_started = FALSE; + +static void +scc_attach( + register struct bus_device *ui) +{ + int sccunit = ui->unit; + extern scc_scan(); + extern int tty_inq_size; + int i; + + /* We only have 4 ttys, but always at 9600 + * Give em a lot of room (plus dma..) + */ + tty_inq_size = 4096; + if (!scc_timer_started) { + /* do all of them, before we call scc_scan() */ + /* harmless if done already */ + for (i = 0; i < NSCC*NSCC_LINE; i++) + ttychars(console_tty[i]); + + scc_timer_started = TRUE; + scc_scan(); + } + +#if NBM > 0 + if (SCREEN_ISA_CONSOLE() && scc_softc[sccunit]->isa_console) { + printf("\n sl0: "); + if (sccunit && rcline == 3) printf("( rconsole )"); + + if (sccunit == SCC_KBDUNIT) { + printf("\n sl1: "); lk201_attach(0, sccunit >> 1); + } else if (sccunit == SCC_PTRUNIT) { + printf("\n sl1: "); mouse_attach(0, sccunit >> 1); + } + } else +#endif /*NBM > 0*/ + { + printf("%s", (sccunit == 1) ? + "\n sl0: ( alternate console )\n sl1:" : + "\n sl0:\n sl1:"); + } +} + +/* + * Would you like to make a phone call ? + */ +scc_set_modem_control( + scc_softc_t scc, + boolean_t on) +{ + if (on) + /* your problem if the hardware then is broke */ + scc->fake = 0; + else + scc->fake = 3; + scc->full_modem = on; + /* user should do an scc_param() ifchanged */ +} + +/* + * Polled I/O (debugger) + */ +scc_pollc( + int unit, + boolean_t on) +{ + scc_softc_t scc; + int line = SCREEN_LINE_KEYBOARD, + sccunit = unit; + + mi_to_scc(&sccunit, &line); + + scc = scc_softc[sccunit]; + if (on) { + scc->polling_mode++; +#if NBM > 0 + screen_on_off(unit, TRUE); +#endif NBM > 0 + } else + scc->polling_mode--; +} + +/* + * Interrupt routine + */ +int scc_intr_count; + +scc_intr( + int unit, + spl_t spllevel) +{ + scc_softc_t scc = scc_softc[unit]; + register scc_regmap_t *regs = scc->regs; + register int rr1, rr2; + register int c; + +scc_intr_count++; + +#if mips + splx(spllevel); /* lower priority */ +#endif + + while (1) { + + scc_read_reg(regs, SCC_CHANNEL_B, SCC_RR2, rr2); + + rr2 = SCC_RR2_STATUS(rr2); + + /* are we done yet ? */ + if (rr2 == 6) { /* strange, distinguished value */ + register int rr3; + scc_read_reg(regs, SCC_CHANNEL_A, SCC_RR3, rr3); + if (rr3 == 0) + return; + } + + if ((rr2 == SCC_RR2_A_XMIT_DONE) || (rr2 == SCC_RR2_B_XMIT_DONE)) { + + register chan = (rr2 == SCC_RR2_A_XMIT_DONE) ? + SCC_CHANNEL_A : SCC_CHANNEL_B; + + scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); + c = cons_simple_tint(scc_to_mi(unit,chan), FALSE); + + if (c == -1) { + /* no more data for this line */ + + scc_read_reg(regs, chan, SCC_RR15, c); + c &= ~SCC_WR15_TX_UNDERRUN_IE; + scc_write_reg(regs, chan, SCC_WR15, c); + + c = scc->softr[chan].wr1 & ~SCC_WR1_TX_IE; + scc_write_reg(regs, chan, SCC_WR1, c); + scc->softr[chan].wr1 = c; + + c = cons_simple_tint(scc_to_mi(unit,chan), TRUE); + if (c != -1) + /* funny race, scc_start has been called already */ + scc_write_data(regs, chan, c); + } else { + scc_write_data(regs, chan, c); + /* and leave it enabled */ + } + } + + else if (rr2 == SCC_RR2_A_RECV_DONE) { + int err = 0; + + scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); + if (scc->polling_mode) + continue; + + scc_read_data(regs, SCC_CHANNEL_A, c); + rr1 = scc_to_mi(unit,SCC_CHANNEL_A); + cons_simple_rint (rr1, rr1, c, 0); + } + + else if (rr2 == SCC_RR2_B_RECV_DONE) { + int err = 0; + + scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); + if (scc->polling_mode) + continue; + + scc_read_data(regs, SCC_CHANNEL_B, c); + rr1 = scc_to_mi(unit,SCC_CHANNEL_B); + cons_simple_rint (rr1, rr1, c, 0); + } + + else if ((rr2 == SCC_RR2_A_EXT_STATUS) || (rr2 == SCC_RR2_B_EXT_STATUS)) { + int chan = (rr2 == SCC_RR2_A_EXT_STATUS) ? + SCC_CHANNEL_A : SCC_CHANNEL_B; + scc_write_reg(regs, chan, SCC_RR0, SCC_RESET_EXT_IP); + scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); + scc_modem_intr(scc, chan, unit); + } + + else if ((rr2 == SCC_RR2_A_RECV_SPECIAL) || (rr2 == SCC_RR2_B_RECV_SPECIAL)) { + register int chan = (rr2 == SCC_RR2_A_RECV_SPECIAL) ? + SCC_CHANNEL_A : SCC_CHANNEL_B; + + scc_read_reg(regs, chan, SCC_RR1, rr1); + if (rr1 & (SCC_RR1_PARITY_ERR | SCC_RR1_RX_OVERRUN | SCC_RR1_FRAME_ERR)) { + int err; + /* map to CONS_ERR_xxx MI error codes */ + err = ((rr1 & SCC_RR1_PARITY_ERR)<<8) | + ((rr1 & SCC_RR1_RX_OVERRUN)<<9) | + ((rr1 & SCC_RR1_FRAME_ERR)<<7); + scc_write_reg(regs, chan, SCC_RR0, SCC_RESET_ERROR); + rr1 = scc_to_mi(unit,chan); + cons_simple_rint(rr1, rr1, 0, err); + } + scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); + } + + } + +} + +boolean_t +scc_start( + struct tty *tp) +{ + register scc_regmap_t *regs; + register int chan, temp; + register struct softreg *sr; + + temp = (natural_t)tp->t_addr; + chan = (temp & 1); /* channel */ + temp = (temp >> 1)&0xff;/* sccunit */ + regs = scc_softc[temp]->regs; + sr = &scc_softc[temp]->softr[chan]; + + scc_read_reg(regs, chan, SCC_RR15, temp); + temp |= SCC_WR15_TX_UNDERRUN_IE; + scc_write_reg(regs, chan, SCC_WR15, temp); + + temp = sr->wr1 | SCC_WR1_TX_IE; + scc_write_reg(regs, chan, SCC_WR1, temp); + sr->wr1 = temp; + + /* but we need a first char out or no cookie */ + scc_read_reg(regs, chan, SCC_RR0, temp); + if (temp & SCC_RR0_TX_EMPTY) + { + register char c; + + c = getc(&tp->t_outq); + scc_write_data(regs, chan, c); + } +} + +/* + * Get a char from a specific SCC line + * [this is only used for console&screen purposes] + */ +scc_getc( + int unit, + int line, + boolean_t wait, + boolean_t raw) +{ + scc_softc_t scc; + register scc_regmap_t *regs; + unsigned char c; + int value, mi_line, rcvalue, from_line; + + mi_line = line; + mi_to_scc(&unit, &line); + + scc = scc_softc[unit]; + regs = scc->regs; + + /* + * wait till something available + * + * NOTE: we know! that rcline==3 + */ + if (rcline) rcline = 3; +again: + rcvalue = 0; + while (1) { + scc_read_reg_zero(regs, line, value); + if (rcline && (mi_line == SCREEN_LINE_KEYBOARD)) { + scc_read_reg_zero(regs, SCC_CHANNEL_B, rcvalue); + value |= rcvalue; + } + if (((value & SCC_RR0_RX_AVAIL) == 0) && wait) + delay(10); + else + break; + } + + /* + * if nothing found return -1 + */ + from_line = (rcvalue & SCC_RR0_RX_AVAIL) ? SCC_CHANNEL_B : line; + + if (value & SCC_RR0_RX_AVAIL) { + scc_read_reg(regs, from_line, SCC_RR1, value); + scc_read_data(regs, from_line, c); + } else { +/* splx(s);*/ + return -1; + } + + /* + * bad chars not ok + */ + if (value&(SCC_RR1_PARITY_ERR | SCC_RR1_RX_OVERRUN | SCC_RR1_FRAME_ERR)) { +/* scc_state(unit,from_line); */ + scc_write_reg(regs, from_line, SCC_RR0, SCC_RESET_ERROR); + if (wait) { + scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); + goto again; + } + } + scc_write_reg(regs, SCC_CHANNEL_A, SCC_RR0, SCC_RESET_HIGHEST_IUS); +/* splx(s);*/ + + +#if NBM > 0 + if ((mi_line == SCREEN_LINE_KEYBOARD) && (from_line == SCC_CHANNEL_A) && + !raw && SCREEN_ISA_CONSOLE() && scc->isa_console) + return lk201_rint(SCREEN_CONS_UNIT(), c, wait, scc->polling_mode); + else +#endif NBM > 0 + return c; +} + +/* + * Put a char on a specific SCC line + */ +scc_putc( + int unit, + int line, + int c) +{ + scc_softc_t scc; + register scc_regmap_t *regs; + spl_t s = spltty(); + register int value; + + mi_to_scc(&unit, &line); + + scc = scc_softc[unit]; + regs = scc->regs; + + do { + scc_read_reg(regs, line, SCC_RR0, value); + if (value & SCC_RR0_TX_EMPTY) + break; + delay(100); + } while (1); + + scc_write_data(regs, line, c); +/* wait for it to swallow the char ? */ + + splx(s); +} + +scc_param( + struct tty *tp, + int line) +{ + scc_regmap_t *regs; + int value, sccline, unit; + struct softreg *sr; + scc_softc_t scc; + + line = tp->t_dev; + /* MI code wants us to handle 4 lines on unit 0 */ + unit = (line < 4) ? 0 : (line / NSCC_LINE); + sccline = line; + mi_to_scc(&unit, &sccline); + + if ((scc = scc_softc[unit]) == 0) return; /* sanity */ + regs = scc->regs; + + sr = &scc->softr[sccline]; + + /* + * Do not let user fool around with kbd&mouse + */ +#if NBM > 0 + if (screen_captures(line)) { + tp->t_ispeed = tp->t_ospeed = B4800; + tp->t_flags |= TF_LITOUT; + } +#endif NBM > 0 + + if (tp->t_ispeed == 0) { + (void) scc_mctl(tp->t_dev, TM_HUP, DMSET); /* hang up line */ + return; + } + + /* reset line */ + value = (sccline == SCC_CHANNEL_A) ? SCC_WR9_RESET_CHA_A : SCC_WR9_RESET_CHA_B; + scc_write_reg(regs, sccline, SCC_WR9, value); + delay(25); + + /* stop bits, normally 1 */ + value = sr->wr4 & 0xf0; + value |= (tp->t_ispeed == B110) ? SCC_WR4_2_STOP : SCC_WR4_1_STOP; + + /* .. and parity */ + if ((tp->t_flags & (TF_ODDP | TF_EVENP)) == TF_ODDP) + value |= SCC_WR4_PARITY_ENABLE; + + /* set it now, remember it must be first after reset */ + sr->wr4 = value; + scc_write_reg(regs, sccline, SCC_WR4, value); + + /* vector again */ + scc_write_reg(regs, sccline, SCC_WR2, 0xf0); + + /* we only do 8 bits per char */ + value = SCC_WR3_RX_8_BITS; + scc_write_reg(regs, sccline, SCC_WR3, value); + + /* clear break, keep rts dtr */ + value = sr->wr5 & (SCC_WR5_DTR|SCC_WR5_RTS); + value |= SCC_WR5_TX_8_BITS; + sr->wr5 = value; + scc_write_reg(regs, sccline, SCC_WR5, value); + /* some are on the other channel, which might + never be used (e.g. maxine has only one line) */ + { + register int otherline = (sccline+1)&1; + + scc_write_reg(regs, otherline, SCC_WR5, scc->softr[otherline].wr5); + } + + scc_write_reg(regs, sccline, SCC_WR6, 0); + scc_write_reg(regs, sccline, SCC_WR7, 0); + + scc_write_reg(regs, sccline, SCC_WR9, SCC_WR9_VIS); + + scc_write_reg(regs, sccline, SCC_WR10, 0); + + /* clock config */ + value = SCC_WR11_RCLK_BAUDR | SCC_WR11_XTLK_BAUDR | + SCC_WR11_TRc_OUT | SCC_WR11_TRcOUT_BAUDR; + scc_write_reg(regs, sccline, SCC_WR11, value); + + value = scc_speeds[tp->t_ispeed]; + scc_set_timing_base(regs,sccline,value); + + value = sr->wr14; + scc_write_reg(regs, sccline, SCC_WR14, value); + +#if FLAMINGO + if (unit != 1) +#else + if (1) +#endif + { + /* Chan-A: CTS==SI DCD==RI DSR=SYNCH */ + value = SCC_WR15_CTS_IE | SCC_WR15_DCD_IE | SCC_WR15_SYNCHUNT_IE; + scc_write_reg(regs, SCC_CHANNEL_A, SCC_WR15, value); + + /* Chan-B: CTS==CTS DCD==DCD */ + value = SCC_WR15_BREAK_IE | SCC_WR15_CTS_IE | SCC_WR15_DCD_IE; + scc_write_reg(regs, SCC_CHANNEL_B, SCC_WR15, value); + } else { + /* Here if modem bits are floating noise, keep quiet */ + value = SCC_WR15_BREAK_IE; + scc_write_reg(regs, sccline, SCC_WR15, value); + } + + /* and now the enables */ + value = SCC_WR3_RX_8_BITS | SCC_WR3_RX_ENABLE; + scc_write_reg(regs, sccline, SCC_WR3, value); + + value = sr->wr5 | SCC_WR5_TX_ENABLE; + sr->wr5 = value; + scc_write_reg(regs, sccline, SCC_WR5, value); + + /* master inter enable */ + scc_write_reg(regs,sccline,SCC_WR9,SCC_WR9_MASTER_IE|SCC_WR9_VIS); + + scc_write_reg(regs, sccline, SCC_WR1, sr->wr1); + +} + +/* + * Modem control functions + */ +scc_mctl( + int dev, + int bits, + int how) +{ + register scc_regmap_t *regs; + struct softreg *sra, *srb, *sr; + int unit, sccline; + int b = 0; + spl_t s; + scc_softc_t scc; + + /* MI code wants us to handle 4 lines on unit 0 */ + unit = (dev < 4) ? 0 : (dev / NSCC_LINE); + sccline = dev; + mi_to_scc(&unit, &sccline); + + if ((scc = scc_softc[unit]) == 0) return 0; /* sanity */ + regs = scc->regs; + + sr = &scc->softr[sccline]; + sra = &scc->softr[SCC_CHANNEL_A]; + srb = &scc->softr[SCC_CHANNEL_B]; + + if (bits == TM_HUP) { /* close line (internal) */ + bits = TM_DTR | TM_RTS; + how = DMBIC; + /* xxx interrupts too ?? */ + } + + if (bits & TM_BRK) { + switch (how) { + case DMSET: + case DMBIS: + sr->wr5 |= SCC_WR5_SEND_BREAK; + break; + case DMBIC: + sr->wr5 &= ~SCC_WR5_SEND_BREAK; + break; + default: + goto dontbrk; + } + s = spltty(); + scc_write_reg(regs, sccline, SCC_WR5, sr->wr5); + splx(s); +dontbrk: + b |= (sr->wr5 & SCC_WR5_SEND_BREAK) ? TM_BRK : 0; + } + + /* no modem support on channel A */ + if (sccline == SCC_CHANNEL_A) + return (b | TM_LE | TM_DTR | TM_CTS | TM_CAR | TM_DSR); + + sra = &scc->softr[SCC_CHANNEL_A]; + srb = &scc->softr[SCC_CHANNEL_B]; + +#if 0 + /* do I need to do something on this ? */ + if (bits & TM_LE) { /* line enable */ + } +#endif + + if (bits & (TM_DTR|TM_RTS)) { /* data terminal ready, request to send */ + register int w = 0; + + if (bits & TM_DTR) w |= SCC_WR5_DTR; + if (bits & TM_RTS) w |= SCC_WR5_RTS; + + switch (how) { + case DMSET: + case DMBIS: + sra->wr5 |= w; + break; + case DMBIC: + sra->wr5 &= ~w; + break; + default: + goto dontdtr; + } + s = spltty(); + scc_write_reg(regs, SCC_CHANNEL_A, SCC_WR5, sra->wr5); + splx(s); +dontdtr: + b |= (sra->wr5 & w) ? (bits & (TM_DTR|TM_RTS)) : 0; + } + + s = spltty(); + +#if 0 + /* Unsupported */ + if (bits & TM_ST) { /* secondary transmit */ + } + if (bits & TM_SR) { /* secondary receive */ + } +#endif + + if (bits & TM_CTS) { /* clear to send */ + register int value; + scc_read_reg(regs, SCC_CHANNEL_B, SCC_RR0, value); + b |= (value & SCC_RR0_CTS) ? TM_CTS : 0; + } + + if (bits & TM_CAR) { /* carrier detect */ + register int value; + scc_read_reg(regs, SCC_CHANNEL_B, SCC_RR0, value); + b |= (value & SCC_RR0_DCD) ? TM_CAR : 0; + } + + if (bits & TM_RNG) { /* ring */ + register int value; + scc_read_reg(regs, SCC_CHANNEL_A, SCC_RR0, value); + b |= (value & SCC_RR0_DCD) ? TM_RNG : 0; + } + + if (bits & TM_DSR) { /* data set ready */ + register int value; + scc_read_reg(regs, SCC_CHANNEL_A, SCC_RR0, value); + b |= (value & SCC_RR0_SYNCH) ? TM_DSR : 0; + } + + splx(s); + + return b; +} + +#define debug 0 + +scc_modem_intr( + scc_softc_t scc, + int chan, + int unit) +{ + register int value, changed; + + scc_read_reg_zero(scc->regs, chan, value); + + /* See what changed */ + changed = value ^ scc->last_rr0[chan]; + scc->last_rr0[chan] = value; + +#if debug +printf("sccmodem: chan %c now %x, changed %x : ", + (chan == SCC_CHANNEL_B) ? 'B' : 'A', + value, changed); +#endif + + if (chan == SCC_CHANNEL_A) { + if (changed & SCC_RR0_CTS) { + /* Speed indicator, ignore XXX */ +#if debug +printf("%s-speed ", (value & SCC_RR0_CTS) ? "Full" : "Half"); +#endif + } + if (changed & SCC_RR0_DCD) { + /* Ring indicator */ +#if debug +printf("Ring "); +#endif + } + if (changed & SCC_RR0_SYNCH) { + /* Data Set Ready */ +#if debug +printf("DSR "); +#endif + /* If modem went down then CD will also go down, + or it did already. + If modem came up then we have to wait for CD + anyways before enabling the line. + Either way, nothing to do here */ + } + } else { + if (changed & SCC_RR0_CTS) { + /* Clear To Send */ +#if debug +printf("CTS "); +#endif + tty_cts(console_tty[scc_to_mi(unit,chan)], + value & SCC_RR0_CTS); + } + if (changed & SCC_RR0_DCD) { +#if debug +printf("CD "); +#endif + check_car(console_tty[scc_to_mi(unit,chan)], + value & SCC_RR0_DCD); + } + } +#if debug +printf(".\n"); +#endif +} + +private check_car( + register struct tty *tp, + boolean_t car) + +{ + if (car) { +#if notyet + /* cancel modem timeout if need to */ + if (car & (SCC_MSR_CD2 | SCC_MSR_CD3)) + untimeout(scc_hup, (vm_offset_t)tp); +#endif + + /* I think this belongs in the MI code */ + if (tp->t_state & TS_WOPEN) + tp->t_state |= TS_ISOPEN; + /* carrier present */ + if ((tp->t_state & TS_CARR_ON) == 0) + (void)ttymodem(tp, 1); + } else if ((tp->t_state&TS_CARR_ON) && ttymodem(tp, 0) == 0) + scc_mctl( tp->t_dev, TM_DTR, DMBIC); +} + +/* + * Periodically look at the CD signals: + * they do generate interrupts but we + * must fake them on channel A. We might + * also fake them on channel B. + */ +scc_scan() +{ + register i; + spl_t s = spltty(); + + for (i = 0; i < NSCC; i++) { + register scc_softc_t scc; + register int car; + register struct tty **tpp; + + scc = scc_softc[i]; + if (scc == 0) + continue; + car = scc->softCAR | scc->fake; + + tpp = &console_tty[i * NSCC_LINE]; + + while (car) { + if (car & 1) + check_car(*tpp, 1); + tpp++; + car = car>>1; + } + + } + splx(s); + timeout(scc_scan, (vm_offset_t)0, 5*hz); +} + + +#if debug +scc_rr0(unit,chan) +{ + int val; + scc_read_reg_zero(scc_softc[unit]->regs, chan, val); + return val; +} + +scc_rreg(unit,chan,n) +{ + int val; + scc_read_reg(scc_softc[unit]->regs, chan, n, val); + return val; +} + +scc_wreg(unit,chan,n,val) +{ + scc_write_reg(scc_softc[unit]->regs, chan, n, val); +} + +scc_state(unit,soft) +{ + int rr0, rr1, rr3, rr12, rr13, rr15; + + rr0 = scc_rreg(unit, SCC_CHANNEL_A, SCC_RR0); + rr1 = scc_rreg(unit, SCC_CHANNEL_A, SCC_RR1); + rr3 = scc_rreg(unit, SCC_CHANNEL_A, SCC_RR3); + rr12 = scc_rreg(unit, SCC_CHANNEL_A, SCC_RR12); + rr13 = scc_rreg(unit, SCC_CHANNEL_A, SCC_RR13); + rr15 = scc_rreg(unit, SCC_CHANNEL_A, SCC_RR15); + printf("{%d intr, A: R0 %x R1 %x R3 %x baudr %x R15 %x}\n", + scc_intr_count, rr0, rr1, rr3, + (rr13 << 8) | rr12, rr15); + + rr0 = scc_rreg(unit, SCC_CHANNEL_B, SCC_RR0); + rr1 = scc_rreg(unit, SCC_CHANNEL_B, SCC_RR1); + rr3 = scc_rreg(unit, SCC_CHANNEL_B, SCC_RR2); + rr12 = scc_rreg(unit, SCC_CHANNEL_B, SCC_RR12); + rr13 = scc_rreg(unit, SCC_CHANNEL_B, SCC_RR13); + rr15 = scc_rreg(unit, SCC_CHANNEL_B, SCC_RR15); + printf("{B: R0 %x R1 %x R2 %x baudr %x R15 %x}\n", + rr0, rr1, rr3, + (rr13 << 8) | rr12, rr15); + + if (soft) { + struct softreg *sr; + sr = scc_softc[unit]->softr; + printf("{B: W1 %x W4 %x W5 %x W14 %x}", + sr->wr1, sr->wr4, sr->wr5, sr->wr14); + sr++; + printf("{A: W1 %x W4 %x W5 %x W14 %x}\n", + sr->wr1, sr->wr4, sr->wr5, sr->wr14); + } +} + +#endif + +#endif NSCC > 0 diff --git a/chips/screen.c b/chips/screen.c new file mode 100644 index 0000000..2251281 --- /dev/null +++ b/chips/screen.c @@ -0,0 +1,1103 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: screen.c + * Author: Alessandro Forin, Robert V. Baron, Joseph S. Barrera, + * at Carnegie Mellon University + * Date: 9/90 + * + * Generic Screen Driver routines. + */ + +#include +#if NBM > 0 +#include + +#include /* spl definitions */ +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#define Ctrl(x) ((x)-'@') + +#define SCREEN_BLITC_NORMAL 0 +#define SCREEN_BLITC_ROW 1 +#define SCREEN_BLITC_COL 2 + +#define SCREEN_ASCII_INVALID '\0' /* ascii_screen not valid here */ + +struct screen_softc screen_softc_data[NBM]; +struct screen_softc *screen_softc[NBM]; + +short screen_console = 0; + +/* Forward decls */ + +void screen_blitc( + int unit, + register unsigned char c); + +void screen_blitc_at( + register screen_softc_t sc, + unsigned char c, + short row, + short col); + + +/* + 8-D A "Screen" has a bitmapped display, a keyboard and a mouse + * + */ + +#if NDTOP > 0 +extern int dtop_kbd_probe(), dtop_set_status(), dtop_kbd_reset(), + dtop_ring_bell(); +#endif /* NDTOP */ +extern int lk201_probe(), lk201_set_status(), lk201_reset(), + lk201_ring_bell(); + +struct kbd_probe_vector { + int (*probe)(); + int (*set_status)(); + int (*reset)(); + int (*beep)(); +} kbd_vector[] = { +#if NDTOP > 0 + {dtop_kbd_probe, dtop_set_status, dtop_kbd_reset, dtop_ring_bell}, +#endif + {lk201_probe, lk201_set_status, lk201_reset, lk201_ring_bell}, + {0,} +}; + +screen_find_kbd(int unit) +{ + struct kbd_probe_vector *p = kbd_vector; + + for (; p->probe; p++) { + if ((*p->probe) (unit)) { + screen_softc[unit]->kbd_set_status = p->set_status; + screen_softc[unit]->kbd_reset = p->reset; + screen_softc[unit]->kbd_beep = p->beep; + return 1; + } + } + return 0; +} + +/* + * The screen probe routine looks for the associated + * keyboard and mouse, at the same unit number. + */ +screen_probe(int unit) +{ + if (unit >= NBM) + return 0; + screen_softc[unit] = &screen_softc_data[unit]; + if (!screen_find()) + return 0; + if (!screen_find_kbd(unit)) + return 0; + mouse_probe(unit); + return 1; +} + +screen_softc_t +screen(int unit) +{ + return screen_softc[unit]; +} + +/* + * This is an upcall from the specific display + * hardware, to register its descriptor + */ +screen_attach( + int unit, + char **hwp) +{ + register screen_softc_t sc = screen_softc[unit]; + + sc->hw_state = hwp; + sc->blitc_state = SCREEN_BLITC_NORMAL; +} + +/* + * This is another upcall (for now) to register + * the user-mapped information + */ +void +screen_up( + int unit, + user_info_t *screen_data) +{ + register screen_softc_t sc = screen_softc[unit]; + + sc->up = screen_data; + mouse_notify_mapped(unit, unit, screen_data); + screen_event_init(screen_data); + ascii_screen_initialize(sc); +} + +/* + * Screen saver + */ +#define SSAVER_MIN_TIME (2*60) /* Minimum fade interval */ +long ssaver_last = 0; /* Last tv_sec that the keyboard was touched */ +long ssaver_time = 0; /* Number of seconds before screen is blanked */ + +void +ssaver_bump(int unit) +{ + register long tnow = time.tv_sec; + + if ((tnow - ssaver_last) > ssaver_time) + screen_on_off(unit, TRUE); + ssaver_last = tnow; +} + +void +screen_saver(int unit) +{ + register screen_softc_t sc = screen_softc[unit]; + + /* wakeup each minute */ + timeout(screen_saver, unit, hz * 60); + if ((time.tv_sec - ssaver_last) >= ssaver_time) + /* this does nothing if already off */ + screen_on_off(unit, FALSE); +} + +/* + * Screen open routine. We are also notified + * of console operations if our screen is acting + * as a console display. + */ +screen_open( + int unit, + boolean_t console_only) +{ + register screen_softc_t sc = screen_softc[unit]; + + /* + * Start screen saver on first (console) open + */ + if (!ssaver_time) { + ssaver_time = 10*60; /* 10 minutes to fade */ + ssaver_bump(unit); /* .. from now */ + screen_saver(unit); /* Start timer */ + } + /* + * Really opening the screen or just notifying ? + */ + if (!console_only) { +#if 0 + (*sc->sw.init_colormap)(sc); +#endif + screen_event_init(sc->up); + ascii_screen_initialize(sc); + (*sc->sw.graphic_open)(sc->hw_state); + sc->mapped = TRUE; + } +} + +/* + * Screen close + */ +screen_close( + int unit, + boolean_t console_only) +{ + register screen_softc_t sc = screen_softc[unit]; + + /* + * Closing of the plain console has no effect + */ + if (!console_only) { + user_info_t *up = sc->up; + + screen_default_colors(up); + /* mapped info, cursor and colormap resetting */ + (*sc->sw.graphic_close)(sc); + + /* turn screen on, and blank it */ + screen_on_off(unit, TRUE); + ascii_screen_initialize(sc); + (*sc->sw.clear_bitmap)(sc); + + /* position cursor circa page end */ + up->row = up->max_row - 1; + up->col = 0; + + /* set keyboard back our way */ + (*sc->kbd_reset)(unit); + lk201_lights(unit, LED_OFF); + + sc->mapped = FALSE; + } +} + +screen_default_colors( + user_info_t *up) +{ + register int i; + + /* restore bg and fg colors */ + for (i = 0; i < 3; i++) { + up->dev_dep_2.pm.Bg_color[i] = 0x00; + up->dev_dep_2.pm.Fg_color[i] = 0xff; + } +} + +/* + * Write characters to the screen + */ +screen_write( + int unit, + register io_req_t ior) +{ + register int count; + register unsigned char *data; + vm_offset_t addr; + + if (unit == 1) /* no writes to the mouse */ + return D_INVALID_OPERATION; + + data = (unsigned char*) ior->io_data; + count = ior->io_count; + if (count == 0) + return (D_SUCCESS); + + if (!(ior->io_op & IO_INBAND)) { + vm_map_copy_t copy = (vm_map_copy_t) data; + kern_return_t kr; + + kr = vm_map_copyout(device_io_map, &addr, copy); + if (kr != KERN_SUCCESS) + return (kr); + data = (unsigned char *) addr; + } + + /* Spill chars out, might fault data in */ + while (count--) + screen_blitc(unit, *data++); + + if (!(ior->io_op & IO_INBAND)) + (void) vm_deallocate(device_io_map, addr, ior->io_count); + + return (D_SUCCESS); +} + +/* + * Read from the screen. This really means waiting + * for an event, which can be either a keypress on + * the keyboard (or pointer) or a mouse movement. + * If there are no available events we queue the + * request for later. + */ +queue_head_t screen_read_queue = { &screen_read_queue, &screen_read_queue }; +boolean_t screen_read_done(); + +screen_read( + int unit, + register io_req_t ior) +{ + register user_info_t *up = screen_softc[unit]->up; + register spl_t s = spltty(); + + if (up->evque.q_head != up->evque.q_tail) { + splx(s); + return (D_SUCCESS); + } + ior->io_dev_ptr = (char *) up; + ior->io_done = screen_read_done; + enqueue_tail(&screen_read_queue, (queue_entry_t) ior); + splx(s); + return (D_IO_QUEUED); +} + +boolean_t +screen_read_done( + register io_req_t ior) +{ + register user_info_t *up = (user_info_t *) ior->io_dev_ptr; + register spl_t s = spltty(); + + if (up->evque.q_head != up->evque.q_tail) { + splx(s); + (void) ds_read_done(ior); + return (TRUE); + } + enqueue_tail(&screen_read_queue, (queue_entry_t) ior); + splx(s); + return (FALSE); +} + +static +screen_event_posted( + register user_info_t *up) +{ + if (up->evque.q_head != up->evque.q_tail) { + register io_req_t ior; + while ((ior = (io_req_t)dequeue_head(&screen_read_queue))) + iodone(ior); + } +} + +boolean_t compress_mouse_events = TRUE; + +/* + * Upcall from input pointer devices + */ +screen_motion_event( + int unit, + int device, + int x, + int y) +{ + register screen_softc_t sc = screen_softc[unit]; + register user_info_t *up = sc->up; + register unsigned next; + unsigned int ev_time; + + /* + * Take care of scale/threshold issues + */ + if (device == DEV_MOUSE) { + register int scale; + + scale = up->mouse_scale; + + if (scale >= 0) { + register int threshold; + register boolean_t neg; + + threshold = up->mouse_threshold; + + neg = (x < 0); + if (neg) x = -x; + if (x >= threshold) + x += (x - threshold) * scale; + if (neg) x = -x; + + neg = (y < 0); + if (neg) y = -y; + if (y >= threshold) + y += (y - threshold) * scale; + if (neg) y = -y; + + } + + /* we expect mices in incremental mode */ + x += up->mouse_loc.x; + y += up->mouse_loc.y; + + } else if (device == DEV_TABLET) { + + /* we expect tablets in absolute mode */ + x = (x * up->dev_dep_2.pm.tablet_scale_x) / 1000; + y = ((2200 - y) * up->dev_dep_2.pm.tablet_scale_y) / 1000; + + } /* else who are you */ + + /* + * Clip if necessary + */ + { + register int max; + + if (x > (max = up->max_cur_x)) + x = max; + if (y > (max = up->max_cur_y)) + y = max; + } + + /* + * Did it actually move + */ + if ((up->mouse_loc.x == x) && + (up->mouse_loc.y == y)) + return; + + /* + * Update mouse location, and cursor + */ + up->mouse_loc.x = x; + up->mouse_loc.y = y; + + screen_set_cursor(sc, x, y); + + /* + * Add point to track. + */ + { + register screen_timed_point_t *tr; + + /* simply add and overflow if necessary */ + next = up->evque.t_next; + if (next >= MAX_TRACK) + next = MAX_TRACK-1; + tr = &up->point_track[next++]; + up->evque.t_next = (next == MAX_TRACK) ? 0 : next; + + ev_time = (unsigned) approx_time_in_msec(); + tr->time = ev_time; + tr->x = x; + tr->y = y; + } + + /* + * Don't post event if mouse is within bounding box, + * Note our y-s are upside down + */ + if (y < up->mouse_box.bottom && + y >= up->mouse_box.top && + x < up->mouse_box.right && + x >= up->mouse_box.left) + return; + up->mouse_box.bottom = 0; /* X11 wants it ? */ + + /* + * Post motion event now + */ +#define round(x) ((x) & (MAX_EVENTS - 1)) + { + register unsigned int head = up->evque.q_head; + register unsigned int tail = up->evque.q_tail; + register screen_event_t *ev; + + if (round(tail + 1) == head) /* queue full, drop it */ + return; + + /* see if we can spare too many motion events */ + next = round(tail - 1); + if (compress_mouse_events && + (tail != head) && (next != head)) { + ev = & up->event_queue[next]; + if (ev->type == EVT_PTR_MOTION) { + ev->x = x; + ev->y = y; + ev->time = ev_time; + ev->device = device; + screen_event_posted(up); + return; + } + } + ev = & up->event_queue[tail]; + ev->type = EVT_PTR_MOTION; + ev->time = ev_time; + ev->x = x; + ev->y = y; + ev->device = device; + + /* added to queue */ + up->evque.q_tail = round(tail + 1); + } + + /* + * Wakeup any sleepers + */ + screen_event_posted(up); +} + +/* + * Upcall from keypress input devices + * Returns wether the event was consumed or not. + */ +boolean_t +screen_keypress_event( + int unit, + int device, + int key, + int type) +{ + register screen_softc_t sc = screen_softc[unit]; + register user_info_t *up = sc->up; + register unsigned int head, tail; + register screen_event_t *ev; + + if (!sc->mapped) { + int col, row; + + if (device != DEV_MOUSE) + return FALSE; + /* generate escapes for mouse position */ + col = up->mouse_loc.x / 8; + row = up->mouse_loc.y / 15; + mouse_report_position(unit, col, row, key, type); + return TRUE; + } + + head = up->evque.q_head; + tail = up->evque.q_tail; + + if (round(tail + 1) == head) /* queue full */ + return TRUE; + + ev = & up->event_queue[tail]; + ev->key = key; + ev->type = type; + ev->device = device; + ev->time = approx_time_in_msec(); + ev->x = up->mouse_loc.x; + ev->y = up->mouse_loc.y; + + up->evque.q_tail = round(tail + 1); + + screen_event_posted(up); + + return TRUE; +} +#undef round + +/* + * Event queue initialization + */ +screen_event_init( + user_info_t *up) +{ + up->evque.q_size = MAX_EVENTS; + up->evque.q_head = 0; + up->evque.q_tail = 0; +; up->evque.t_size = MAX_TRACK; + up->evque.t_next = 0; + up->evque.timestamp = approx_time_in_msec(); + +} + +/* + * Set/Get status functions. + * ... + */ +io_return_t +screen_set_status( + int unit, + dev_flavor_t flavor, + dev_status_t status, + natural_t status_count) +{ + register screen_softc_t sc = screen_softc[unit]; + register user_info_t *up = sc->up; + io_return_t ret = D_SUCCESS; + +/* XXX checks before getting here */ + + switch (flavor) { + + case SCREEN_INIT: + ascii_screen_initialize(sc); + break; + + case SCREEN_ON: + screen_on_off(unit, TRUE); + break; + + case SCREEN_OFF: + screen_on_off(unit, FALSE); + break; + + case SCREEN_FADE: { + register int tm = * (int *) status; + + untimeout(screen_saver, unit); /* stop everything and */ + if (tm == -1) /* don't reschedule a fade */ + break; + if (tm < SSAVER_MIN_TIME) + tm = SSAVER_MIN_TIME; + ssaver_time = tm; + ssaver_bump(unit); + screen_saver(unit); + break; + } + + case SCREEN_SET_CURSOR: { + screen_point_t *loc = (screen_point_t*) status; + + if (status_count < sizeof(screen_point_t)/sizeof(int)) + return D_INVALID_SIZE; + + sc->flags |= SCREEN_BEING_UPDATED; + up->mouse_loc = *loc; + sc->flags &= ~SCREEN_BEING_UPDATED; + + screen_set_cursor(sc, loc->x, loc->y); + + break; + } + + /* COMPAT: these codes do nothing, but we understand */ + case _IO('q', 8): /* KERNLOOP */ + case _IO('q', 9): /* KERNUNLOOP */ + case _IO('g', 21): /* KERN_UNLOOP */ + break; + + /* + * Anything else is either device-specific, + * or for the keyboard + */ + default: + ret = (*sc->sw.set_status)(sc, flavor, status, status_count); + if (ret == D_INVALID_OPERATION) + ret = (*sc->kbd_set_status)(unit, flavor, + status, status_count); + break; + } + return ret; +} + +io_return_t +screen_get_status( + int unit, + dev_flavor_t flavor, + dev_status_t status, + natural_t *count) +{ + register screen_softc_t sc = screen_softc[unit]; + + if (flavor == SCREEN_STATUS_FLAGS) { + *(int *)status = sc->flags; + *count = 1; + return D_SUCCESS; + } else if (flavor == SCREEN_HARDWARE_INFO) { + screen_hw_info_t *hinfo; + + hinfo = (screen_hw_info_t*)status; + hinfo->frame_width = sc->frame_scanline_width; + hinfo->frame_height = sc->frame_height; + hinfo->frame_visible_width = sc->frame_visible_width; + hinfo->frame_visible_height = sc->frame_visible_height; + *count = sizeof(screen_hw_info_t)/sizeof(int); + return D_SUCCESS; + } else + + return (*sc->sw.get_status)(sc, flavor, status, count); +} + +/* + * Routine to handle display and control characters sent to screen + */ +void +screen_blitc( + int unit, + register unsigned char c) +{ + register screen_softc_t sc = screen_softc[unit]; + register user_info_t *up = sc->up; + register unsigned char *ap; + register int i; + + /* + * Handle cursor positioning sequence + */ + switch (sc->blitc_state) { + case SCREEN_BLITC_NORMAL: + break; + + case SCREEN_BLITC_ROW: + c -= ' '; + if (c >= up->max_row) { + up->row = up->max_row - 1; + } else { + up->row = c; + } + sc->blitc_state = SCREEN_BLITC_COL; + return; + + case SCREEN_BLITC_COL: + c -= ' '; + if (c >= up->max_col) { + up->col = up->max_col - 1; + } else { + up->col = c; + } + sc->blitc_state = SCREEN_BLITC_NORMAL; + goto move_cursor; + } + + c &= 0xff; + + /* echo on rconsole line */ + rcputc(c); + + /* we got something to say, turn on the TV */ + ssaver_bump(unit); + + switch (c) { + /* Locate cursor*/ + case Ctrl('A'): /* ^A -> cm */ + sc->blitc_state = SCREEN_BLITC_ROW; + return; + + /* Home cursor */ + case Ctrl('B'): /* ^B -> ho */ + up->row = 0; + up->col = 0; + break; + + /* Clear screen */ + case Ctrl('C'): /* ^C -> cl */ + up->row = 0; + up->col = 0; + (*sc->sw.clear_bitmap)(sc); + break; + + /* Move forward */ + case Ctrl('D'): /* ^D -> nd */ + screen_advance_position(sc); + break; + + /* Clear to eol */ + case Ctrl('E'): /* ^E -> ce */ + ap = &sc->ascii_screen[up->max_col*up->row + up->col]; + for (i = up->col; i < up->max_col; i++, ap++) { + if (sc->standout || *ap != ' ') { + if (sc->standout) { + *ap = SCREEN_ASCII_INVALID; + } else { + *ap = ' '; + } + screen_blitc_at(sc, ' ', up->row, i); + } + } + return; + + /* Cursor up */ + case Ctrl('F'): /* ^F -> up */ + if (up->row != 0) up->row--; + break; + + case Ctrl('G'): /* ^G -> bell */ + (*sc->kbd_beep)(unit); + return; + + /* Backspace */ + case Ctrl('H'): /* ^H -> bs */ + if (--up->col < 0) + up->col = 0; + break; + + case Ctrl('I'): /* ^I -> tab */ + up->col += (8 - (up->col & 0x7)); + break; + + case Ctrl('J'): /* ^J -> lf */ + if (up->row+1 >= up->max_row) + (*sc->sw.remove_line)(sc, 0); + else + up->row++; + break; + + /* Start rev-video */ + case Ctrl('K'): /* ^K -> so */ + sc->standout = 1; + return; + + /* End rev-video */ + case Ctrl('L'): /* ^L -> se */ + sc->standout = 0; + return; + + case Ctrl('M'): /* ^M -> return */ + up->col = 0; + break; + + /* Save cursor position */ + case Ctrl('N'): /* ^N -> sc */ + sc->save_col = up->col; + sc->save_row = up->row; + return; + + /* Restore cursor position */ + case Ctrl('O'): /* ^O -> rc */ + up->row = sc->save_row; + up->col = sc->save_col; + break; + + /* Add blank line */ + case Ctrl('P'): /* ^P -> al */ + (*sc->sw.insert_line)(sc, up->row); + return; + + /* Delete line */ + case Ctrl('Q'): /* ^Q -> dl */ + (*sc->sw.remove_line)(sc, up->row); + return; + + default: + /* + * If the desired character is already there, then don't + * bother redrawing it. Always redraw standout-ed chars, + * so that we can assume that all cached characters are + * un-standout-ed. (This could be fixed.) + */ + ap = &sc->ascii_screen[up->max_col*up->row + up->col]; + if (sc->standout || c != *ap) { + if (sc->standout) { + *ap = SCREEN_ASCII_INVALID; + } else { + *ap = c; + } + screen_blitc_at(sc, c, up->row, up->col); + } + screen_advance_position(sc); + break; + } + +move_cursor: + screen_set_cursor(sc, up->col*8, up->row*15); + +} + + +/* + * Advance current position, wrapping and scrolling when necessary + */ +screen_advance_position( + register screen_softc_t sc) +{ + register user_info_t *up = sc->up; + + if (++up->col >= up->max_col) { + up->col = 0 ; + if (up->row+1 >= up->max_row) { + (*sc->sw.remove_line)(sc, 0); + } else { + up->row++; + } + } +} + + +/* + * Routine to display a character at a given position + */ +void +screen_blitc_at( + register screen_softc_t sc, + unsigned char c, + short row, + short col) +{ + /* + * Silently ignore non-printable chars + */ + if (c < ' ' || c > 0xfd) + return; + (*sc->sw.char_paint)(sc, c, row, col); +} + +/* + * Update sc->ascii_screen array after deleting ROW + */ +ascii_screen_rem_update( + register screen_softc_t sc, + int row) +{ + register user_info_t *up = sc->up; + register unsigned int col_w, row_w; + register unsigned char *c, *end; + + /* cache and sanity */ + col_w = up->max_col; + if (col_w > MaxCharCols) + col_w = MaxCharCols; + row_w = up->max_row; + if (row_w > MaxCharRows) + row_w = MaxCharRows; + + /* scroll up */ + c = &sc->ascii_screen[row * col_w]; + end = &sc->ascii_screen[(row_w-1) * col_w]; + for (; c < end; c++) /* bcopy ? XXX */ + *c = *(c + col_w); + + /* zero out line that entered at end */ + c = end; + end = &sc->ascii_screen[row_w * col_w]; + for (; c < end; c++) + *c = ' '; + +} + +/* + * Update sc->ascii_screen array after opening new ROW + */ +ascii_screen_ins_update( + register screen_softc_t sc, + int row) +{ + register user_info_t *up = sc->up; + register unsigned int col_w, row_w; + register unsigned char *c, *end; + + /* cache and sanity */ + col_w = up->max_col; + if (col_w > MaxCharCols) + col_w = MaxCharCols; + row_w = up->max_row; + if (row_w > MaxCharRows) + row_w = MaxCharRows; + + /* scroll down */ + c = &sc->ascii_screen[row_w * col_w - 1]; + end = &sc->ascii_screen[(row + 1) * col_w]; + for (; c >= end; c--) + *c = *(c - col_w); + + /* zero out line that entered at row */ + c = end - 1; + end = &sc->ascii_screen[row * col_w]; + for (; c >= end; c--) + *c = ' '; +} + +/* + * Init charmap + */ +ascii_screen_fill( + register screen_softc_t sc, + char c) +{ + register user_info_t *up = sc->up; + register int i, to; + + to = up->max_row * up->max_col; + for (i = 0; i < to; i++) { + sc->ascii_screen[i] = c; + } +} + +ascii_screen_initialize( + register screen_softc_t sc) +{ + ascii_screen_fill(sc, SCREEN_ASCII_INVALID); +} + +/* + * Cursor positioning + */ +screen_set_cursor( + register screen_softc_t sc, + register int x, + register int y) +{ + register user_info_t *up = sc->up; + + /* If we are called from interrupt level.. */ + if (sc->flags & SCREEN_BEING_UPDATED) + return; + sc->flags |= SCREEN_BEING_UPDATED; + /* + * Note that that was not atomic, but this is + * a two-party game on the same processor and + * not a real parallel program. + */ + + /* Sanity checks (ignore noise) */ + if (y < up->min_cur_y || y > up->max_cur_y) + y = up->cursor.y; + if (x < up->min_cur_x || x > up->max_cur_x) + x = up->cursor.x; + + /* + * Track cursor position + */ + up->cursor.x = x; + up->cursor.y = y; + + (*sc->sw.pos_cursor)(*(sc->hw_state), x, y); + + sc->flags &= ~SCREEN_BEING_UPDATED; +} + +screen_on_off( + int unit, + boolean_t on) +{ + register screen_softc_t sc = screen_softc[unit]; + + if (sc->sw.video_on == 0) /* sanity */ + return; + + if (on) + (*sc->sw.video_on)(sc->hw_state, sc->up); + else + (*sc->sw.video_off)(sc->hw_state, sc->up); +} + +screen_enable_vretrace( + int unit, + boolean_t on) +{ + register screen_softc_t sc = screen_softc[unit]; + (*sc->sw.intr_enable)(sc->hw_state, on); +} + +/* + * For our purposes, time does not need to be + * precise but just monotonic and approximate + * to about the millisecond. Instead of div/ + * mul by 1000 we div/mul by 1024 (shifting). + * + * Well, it almost worked. The only problem + * is that X somehow checks the time against + * gettimeofday() and .. turns screen off at + * startup if we use approx time. SO we are + * back to precise time, sigh. + */ +approx_time_in_msec() +{ +#if 0 + return ((time.seconds << 10) + (time.microseconds >> 10)); +#else + return ((time.seconds * 1000) + (time.microseconds / 1000)); +#endif +} + +/* + * Screen mapping to user space + * This is called on a per-page basis + */ +screen_mmap( + int dev, + vm_offset_t off, + int prot) +{ + /* dev is safe, but it is the mouse's one */ + register screen_softc_t sc = screen_softc[dev-1]; + + (*sc->sw.map_page)(sc, off, prot); +} + +#endif NBM > 0 diff --git a/chips/screen.h b/chips/screen.h new file mode 100644 index 0000000..69154d4 --- /dev/null +++ b/chips/screen.h @@ -0,0 +1,289 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: screen.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Definitions for the Generic Screen Driver. + */ + +/* + * Most of these structures are defined so that the + * resulting structure mapped to user space appears + * to be compatible with the one used by the DEC X + * servers (pm_info..). Keep it that way and the + * X servers will keep on running. + */ + +/* + * Generic structures and defines + */ + +/* colors */ +typedef struct { + unsigned short red; + unsigned short green; + unsigned short blue; +} color_map_t; + +typedef struct { + short unused; + unsigned short index; + color_map_t value; +} color_map_entry_t; + +typedef struct { + unsigned int Bg_rgb[3]; + unsigned int Fg_rgb[3]; +} cursor_color_t; + +/* generic input event */ +typedef struct { + short x; /* x position */ + short y; /* y position */ + unsigned int time; /* 1 millisecond units */ + + unsigned char type; /* button up/down/raw or motion */ +# define EVT_BUTTON_UP 0 +# define EVT_BUTTON_DOWN 1 +# define EVT_BUTTON_RAW 2 +# define EVT_PTR_MOTION 3 + + unsigned char key; /* the key (button only) */ +# define KEY_LEFT_BUTTON 1 +# define KEY_MIDDLE_BUTTON 2 +# define KEY_RIGHT_BUTTON 3 +# define KEY_TBL_LEFT_BUTTON 0 +# define KEY_TBL_FRONT_BUTTON 1 +# define KEY_TBL_RIGHT_BUTTON 2 +# define KEY_TBL_BACK_BUTTON 3 + + unsigned char index; /* which instance of device */ + + unsigned char device; /* which device */ +# define DEV_NULL 0 +# define DEV_MOUSE 1 +# define DEV_KEYBD 2 +# define DEV_TABLET 3 +# define DEV_AUX 4 +# define DEV_CONSOLE 5 +# define DEV_KNOB 8 +# define DEV_JOYSTICK 9 + +} screen_event_t; + +/* timed coordinate info */ +typedef struct { + unsigned int time; + short x, y; +} screen_timed_point_t; + +/* queue of input events, and ring of mouse motions track */ +typedef struct { + screen_event_t *events; + unsigned int q_size; + unsigned int q_head; + unsigned int q_tail; + unsigned long timestamp; + screen_timed_point_t *track; + unsigned int t_size; + unsigned int t_next; +} screen_evque_t; + +/* mouse/cursor position */ +typedef struct { + short x; + short y; +} screen_point_t; + +/* mouse motion bounding boxes */ +typedef struct { + short bottom; + short right; + short left; + short top; +} screen_rect_t; + +/* + * Here it is, each field is marked as + * + * Kset : kernel sets it unconditionally + * Kuse : kernel uses it, safely + * Kdep : kernel might depend on it + */ +typedef struct { + screen_evque_t evque; /* Kset, Kuse */ + short mouse_buttons; /* Kset */ + screen_point_t xx3 /*tablet*/; + short xx4 /*tswitches*/; + screen_point_t cursor; /* Kset */ + short row; /* Kdep */ + short col; /* Kdep */ + short max_row; /* Kdep */ + short max_col; /* Kdep */ + short max_x; /* Kset */ + short max_y; /* Kset */ + short max_cur_x; /* Kdep */ + short max_cur_y; /* Kdep */ + int version; /* Kset */ + union { + struct { + unsigned char * bitmap; /* Kset */ + short * x16 /*scanmap*/; + short * x17 /*cursorbits*/; + short * x18 /*pmaddr*/; + unsigned char * planemask; /* Kset */ + } pm; + struct { + int x15 /* flags */; + int * gram /* Kset */; + int * rb_addr /* Kset */; + int rb_phys /* Kset */; + int rb_size /* Kset */; + } gx; + } dev_dep_1; + screen_point_t mouse_loc; /* Kdep */ + screen_rect_t mouse_box; /* Kdep */ + short mouse_threshold;/* Kuse */ + short mouse_scale; /* Kuse */ + short min_cur_x; /* Kdep */ + short min_cur_y; /* Kdep */ + union { + struct { + int x26 /*dev_type*/; + char * x27 /*framebuffer*/; + char * x28 /*volatile struct bt459 *bt459*/; + int x29 /*slot*/; + char cursor_sprite[1024];/* Kset */ + unsigned char Bg_color[3]; /* Kset */ + unsigned char Fg_color[3]; /* Kset */ + int tablet_scale_x; /* Kuse */ + int tablet_scale_y; /* Kuse */ + } pm; + struct { + char * gxo /* Kset */; + char stamp_width /* Kset */; + char stamp_height /* Kset */; + char nplanes /* Kset */; + char x27_4 /* n10_present */; + char x28_1 /* dplanes */; + char zplanes /* Kset */; + char zzplanes /* Kset */; + unsigned char cursor_sprite[1024] /* Kuse */; + char x285_0 /* padding for next, which was int */; + unsigned char Fg_color[4] /* Kuse */; + unsigned char Bg_color[4] /* Kuse */; + unsigned short cmap_index /* Kuse */; + unsigned short cmap_count /* Kuse */; + unsigned int colormap[256] /* Kuse */; + int * stic_dma_rb /* Kset */; + int * stic_reg /* Kset */; + int ptpt_phys /* Kdep */; + int ptpt_size /* Kdep */; + int * ptpt_pgin /* Kset */; + } gx; + } dev_dep_2; + short frame_scanline_width; /* in pixels, Kset */ + short frame_height; /* in scanlines, Kset */ + /* + * Event queues are allocated right after that + */ +#define MAX_EVENTS 64 +#define MAX_TRACK 100 + screen_event_t event_queue[MAX_EVENTS]; /* Kset */ + screen_timed_point_t point_track[MAX_TRACK]; /* Kset */ + /* + * Some like it hot + */ + unsigned int event_id; + int interrupt_info; +} user_info_t; + + +/* + * Screen get_status codes and arguments + */ +#include + + /* Get size (and offset) of mapped info */ +#define SCREEN_GET_OFFSETS _IOR('q', 6, unsigned **) + + /* Get screen status flags */ +#define SCREEN_STATUS_FLAGS _IOR('q', 22, int *) +# define MONO_SCREEN 0x01 +# define COLOR_SCREEN 0x02 +# define SCREEN_BEING_UPDATED 0x04 + +/* + * Screen set_status codes and arguments + */ + + /* start/stop screen saver, control fading interval */ +#define SCREEN_FADE _IOW('q', 114, int) /* fade screen */ +# define NO_FADE -1 + + /* Turn video on/off manually */ +#define SCREEN_ON _IO('q', 10) +#define SCREEN_OFF _IO('q', 11) + + /* Fixup pointers inside mapped info structure */ +#define SCREEN_ADJ_MAPPED_INFO _IOR('q', 1, user_info_t *) + + /* Initialize anything that needs to, hw-wise */ +#define SCREEN_INIT _IO('q', 4) + + /* Position cursor to a specific spot */ +#define SCREEN_SET_CURSOR _IOW('q', 2, screen_point_t) + + /* Load Bg/Fg colors for cursor */ +#define SCREEN_SET_CURSOR_COLOR _IOW('q', 3, cursor_color_t) + + /* Load cursor sprite, small cursor form */ +typedef unsigned short cursor_sprite_t[32]; + +#define SCREEN_LOAD_CURSOR _IOW('q', 7, cursor_sprite_t) + + /* Load cursor sprite, large 64x64 cursor form */ +typedef char cursor_sprite_long_t[1024]; + +#define SCREEN_LOAD_CURSOR_LONG _IOW('q', 13, cursor_sprite_long_t) + + /* Modify a given entry in the color map (VDAC) */ +#define SCREEN_SET_CMAP_ENTRY _IOW('q', 12, color_map_entry_t) + + /* Return some other information about hardware (optional) */ +typedef struct { + int frame_width; + int frame_height; + int frame_visible_width; + int frame_visible_height; +} screen_hw_info_t; +#define SCREEN_HARDWARE_INFO _IOR('q', 23, screen_hw_info_t) + + /* Screen-dependent, unspecified (and despised) */ +#define SCREEN_HARDWARE_DEP _IO('q', 24) + diff --git a/chips/screen_defs.h b/chips/screen_defs.h new file mode 100644 index 0000000..083e11e --- /dev/null +++ b/chips/screen_defs.h @@ -0,0 +1,97 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: screen_defs.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 11/90 + * + * Definitions for the Generic Screen Driver. + */ + +#include +#include +#include + +/* + * Driver state + */ +typedef struct screen_softc { + user_info_t *up; + char **hw_state; /* semi-opaque */ + + struct screen_switch sw; + + /* should also be a switch */ + io_return_t (*kbd_set_status)(); + int (*kbd_reset)(); + int (*kbd_beep)(); + + char flags; + char mapped; + char blitc_state; + char standout; + short save_row; + short save_col; + /* + * Eventually move here all that is Kdep in the user structure, + * to avoid crashing because of a bogus graphic server + */ + short frame_scanline_width; /* in pixels */ + short frame_height; /* in scanlines */ + short frame_visible_width; /* in pixels */ + short frame_visible_height; /* in pixels */ + +/* This is used by all screens, therefore it is sized maximally */ +# define MaxCharRows 68 /* 2DA screen & PMAG-AA */ +# define MaxCharCols 160 /* PMAG-AA */ +# define MinCharRows 57 /* pmax */ + unsigned char ascii_screen[MaxCharRows*MaxCharCols]; + +} *screen_softc_t; + +extern screen_softc_t screen(/* int unit */); + +/* + * This global says if we have a graphic console + * and where it is and if it is enabled + */ +extern short screen_console; +#define SCREEN_CONS_ENBL (0x0100) +#define SCREEN_ISA_CONSOLE() (screen_console & SCREEN_CONS_ENBL) +#define SCREEN_CONS_UNIT() (screen_console & 0x00ff) + +/* + * A graphic screen needs a keyboard and a mouse/tablet + */ +#define SCREEN_LINE_KEYBOARD 0 +#define SCREEN_LINE_POINTER 1 +#define SCREEN_LINE_OTHER (-1) + +/* kernel font */ +#define KfontWidth 8 +#define KfontHeight 15 +extern unsigned char kfont_7x14[]; + diff --git a/chips/screen_switch.c b/chips/screen_switch.c new file mode 100644 index 0000000..e216a53 --- /dev/null +++ b/chips/screen_switch.c @@ -0,0 +1,154 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: screen_switch.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 9/90 + * + * Autoconfiguration code for the Generic Screen Driver. + */ + +#include + +#if defined(DECSTATION) || defined(FLAMINGO) +#include +#include +#include +#include +#include +#include +#endif + +#ifdef VAXSTATION +#define NGX 0 +#define NCFB 0 +#define NXCFB 0 +#endif + +#include + +/* When nothing needed */ +int screen_noop() +{} + +/* + * Vector of graphic interface drivers to probe. + * Zero terminate this list. + */ + + +#if NGX > 0 +extern int gq_probe(), gq_cold_init(); +extern unsigned int gq_mem_need(); + +extern int ga_probe(), ga_cold_init(); +extern unsigned int ga_mem_need(); +#endif /* NGX > 0 */ + +#if NCFB > 0 +extern int cfb_probe(), cfb_cold_init(); +extern unsigned int pm_mem_need(); +#endif /* NCFB > 0 */ + +#if NMFB > 0 +extern int fb_probe(), fb_cold_init(); +extern unsigned int pm_mem_need(); +#endif /* NMFB > 0 */ + +#if NXCFB > 0 +extern int xcfb_probe(), xcfb_cold_init(); +extern unsigned int pm_mem_need(); +#endif /* NXCFB > 0 */ + +#if NSFB > 0 +extern int sfb_probe(), sfb_cold_init(); +extern unsigned int pm_mem_need(); +#endif /* NSFB > 0 */ + +#if NFB > 0 +extern int pm_probe(), pm_cold_init(); +extern unsigned int pm_mem_need(); +#endif /* NFB > 0 */ + +struct screen_probe_vector screen_probe_vector[] = { + +#if NGX > 0 + gq_probe, gq_mem_need, gq_cold_init, /* 3max 3D color option */ + ga_probe, ga_mem_need, ga_cold_init, /* 3max 2D color option */ +#endif /* NGX > 0 */ + +#if NSFB > 0 + sfb_probe, pm_mem_need, sfb_cold_init, /* Smart frame buffer */ +#endif /* NSFB > 0 */ + +#if NMFB > 0 + fb_probe, pm_mem_need, fb_cold_init, /* 3max/3min 1D(?) mono option */ +#endif /* NMFB > 0 */ + +#if NCFB > 0 + cfb_probe, pm_mem_need, cfb_cold_init, /* 3max 1D(?) color option */ +#endif /* NCFB > 0 */ + +#if NXCFB > 0 + xcfb_probe, pm_mem_need, xcfb_cold_init,/* MAXine frame buffer */ +#endif /* NXCFB > 0 */ + +#if NFB > 0 + pm_probe, pm_mem_need, pm_cold_init, /* "pm" mono/color (pmax) */ +#endif + 0, +}; + +char *screen_data; /* opaque */ + +int screen_find() +{ + struct screen_probe_vector *p = screen_probe_vector; + for (;p->probe; p++) + if ((*p->probe)()) { + (*p->setup)(0/*XXX*/, screen_data); + return 1; + } + return 0; +} + +unsigned int +screen_memory_alloc(avail) + char *avail; +{ + struct screen_probe_vector *p = screen_probe_vector; + int size; + for (; p->probe; p++) + if ((*p->probe) ()) { + screen_data = avail; + size = (*p->alloc) (); + bzero(screen_data, size); + return size; + } + return 0; + +} + diff --git a/chips/screen_switch.h b/chips/screen_switch.h new file mode 100644 index 0000000..a84b4e7 --- /dev/null +++ b/chips/screen_switch.h @@ -0,0 +1,85 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: screen_switch.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 10/90 + * + * Definitions of things that must be tailored to + * specific hardware boards for the Generic Screen Driver. + */ + +#ifndef SCREEN_SWITCH_H +#define SCREEN_SWITCH_H 1 + +/* + * List of probe routines, scanned at cold-boot time + * to see which, if any, graphic display is available. + * This is done before autoconf, so that printing on + * the console works early on. The alloc routine is + * called only on the first device that answers. + * Ditto for the setup routine, called later on. + */ +struct screen_probe_vector { + int (*probe)(); + unsigned int (*alloc)(); + int (*setup)(); +}; + +/* + * Low-level operations on the graphic device, used + * by the otherwise device-independent interface code + */ +struct screen_switch { + int (*graphic_open)(); /* when X11 opens */ + int (*graphic_close)(); /* .. or closes */ + int (*set_status)(); /* dev-specific ops */ + int (*get_status)(); /* dev-specific ops */ + int (*char_paint)(); /* blitc */ + int (*pos_cursor)(); /* cursor positioning */ + int (*insert_line)(); /* ..and scroll down */ + int (*remove_line)(); /* ..and scroll up */ + int (*clear_bitmap)(); /* blank screen */ + int (*video_on)(); /* screen saver */ + int (*video_off)(); + int (*intr_enable)(); + int (*map_page)(); /* user-space mapping */ +}; + +/* + * Each graphic device needs page-aligned memory + * to be mapped in user space later (for events + * and such). Size and content of this memory + * is unfortunately device-dependent, even if + * it did not need to (puns). + */ +extern char *screen_data; + +extern struct screen_probe_vector screen_probe_vector[]; + +extern int screen_noop(), screen_find(); + +#endif SCREEN_SWITCH_H diff --git a/chips/serial_console.c b/chips/serial_console.c new file mode 100644 index 0000000..7b15dd4 --- /dev/null +++ b/chips/serial_console.c @@ -0,0 +1,694 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: serial_console.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 7/91 + * + * Console driver for serial-line based consoles. + */ + +#include +#if NCONSTTY > 0 +#include +#include + +#include + +#include /* spl definitions */ +#include +#include +#include + +#include +#include +#include + +#ifdef DECSTATION +#include +#define find_rconsole(p) dec_check_rcline(p) +#define CONSOLE_SERIAL_LINE_NO 3 +#endif /*DECSTATION*/ + +#ifdef VAXSTATION +#define find_rconsole(p) +#define cnputc ser_putc +#define cngetc ser_getc +#define cnpollc ser_pollc +#define cnmaygetc ser_maygetc +#define CONSOLE_SERIAL_LINE_NO 3 +#endif /*VAXSTATION*/ + +#ifdef FLAMINGO +#define CONSOLE_SERIAL_LINE_NO 3 +#endif + +#ifndef CONSOLE_SERIAL_LINE_NO +#define CONSOLE_SERIAL_LINE_NO 0 +#endif + +/* Size this as max possible number of lines in any serial chip we might use */ +static struct tty console_tty_data[NCONSTTY]; +struct tty *console_tty[NCONSTTY]; /* exported */ + +#define DEFAULT_SPEED B9600 +#define DEFAULT_FLAGS (TF_EVENP|TF_ODDP|TF_ECHO) + + +/* + * A machine MUST have a console. In our case + * things are a little complicated by the graphic + * display: people expect it to be their "console", + * but we'd like to be able to live without it. + * This is not to be confused with the "rconsole" thing: + * that just duplicates the console I/O to + * another place (for debugging/logging purposes). + * + * There is then another historical kludge: if + * there is a graphic display it is assumed that + * the minor "1" is the mouse, with some more + * magic attached to it. And again, one might like to + * use the serial line 1 as a regular one. + * + */ +#define user_console 0 + +int console = 0; + +int (*console_probe)() = 0, + (*console_param)() = 0, + (*console_start)() = 0, + (*console_putc)() = 0, + (*console_getc)() = 0, + (*console_pollc)() = 0, + (*console_mctl)() = 0, + (*console_softCAR)() = 0; + +/* + * Lower-level (internal) interfaces, for printf and gets + */ +int cnunit = 0; /* which unit owns the 'console' */ +int cnline = 0; /* which line of that unit */ +int rcline = 3; /* alternate, "remote console" line */ + +rcoff() +{ + spl_t s = splhigh(); + cnpollc(FALSE); + rcline = 0; + cnpollc(TRUE); + splx(s); +} + +rcputc(c) +{ + if (rcline) + (*console_putc)( cnunit, rcline, c); +} + +cnputc(c) +{ +#if NBM > 0 + if (SCREEN_ISA_CONSOLE()) { + /* this does its own rcputc */ + screen_blitc(SCREEN_CONS_UNIT(), c); + } else +#endif NBM > 0 + { + rcputc(c); + (*console_putc)( cnunit, cnline, c);/* insist on a console still */ + } + if (c == '\n') + cnputc('\r'); +} + +cngetc() +{ + return (*console_getc)( cnunit, cnline, TRUE, FALSE); +} + +cnpollc(bool) +{ + (*console_pollc)(cnunit, bool); +} + + +/* Debugger support */ +cnmaygetc() +{ + return (*console_getc)( cnunit, cnline, FALSE, FALSE); +} + + +#if NBM > 0 +boolean_t +screen_captures(line) + register int line; +{ + return (SCREEN_ISA_CONSOLE() && + ((line == SCREEN_LINE_KEYBOARD) || + (line == SCREEN_LINE_POINTER))); +} +#endif + +/* + * Higher level (external) interface, for GP use + */ + + +/* + * This is basically a special form of autoconf, + * to get printf() going before true autoconf. + */ +cons_find(tube) + boolean_t tube; +{ + static struct bus_device d; + register int i; + struct tty *tp; + + for (i = 0; i < NCONSTTY; i++) + console_tty[i] = &console_tty_data[i]; + /* the hardware device will set tp->t_addr for valid ttys */ + + d.unit = 0; + + if ((console_probe == 0) || + ((*console_probe)(0, &d) == 0)) { + /* we have no console, but maybe that's ok */ +#if defined(DECSTATION) || defined(FLAMINGO) + /* no, it is not */ + dprintf("%s", "no console!\n"); + halt(); +#endif + return 0; + } + + /* + * Remote console line + */ + find_rconsole(&rcline); + + /* + * Console always on unit 0. Fix if you need to + */ + cnunit = 0; + +#if NBM > 0 + if (tube && screen_probe(0)) { + + /* associate screen to console iff */ + if (console == user_console) + screen_console = cnunit | SCREEN_CONS_ENBL; + cnline = SCREEN_LINE_KEYBOARD; + + /* mouse and keybd */ + tp = console_tty[SCREEN_LINE_KEYBOARD]; + tp->t_ispeed = B4800; + tp->t_ospeed = B4800; + tp->t_flags = TF_LITOUT|TF_EVENP|TF_ECHO|TF_XTABS|TF_CRMOD; + tp->t_dev = SCREEN_LINE_KEYBOARD; + (*console_param)(tp, SCREEN_LINE_KEYBOARD); + + tp = console_tty[SCREEN_LINE_POINTER]; + tp->t_ispeed = B4800; + tp->t_ospeed = B4800; + tp->t_flags = TF_LITOUT|TF_ODDP; + tp->t_dev = SCREEN_LINE_POINTER; + (*console_param)(tp, SCREEN_LINE_POINTER); + /* console_scan will turn on carrier */ + + } else { +#endif NBM > 0 + /* use non-graphic console as console */ + cnline = CONSOLE_SERIAL_LINE_NO; + + tp = console_tty[cnline]; + tp->t_ispeed = B9600; + tp->t_ospeed = B9600; + tp->t_flags = TF_LITOUT|TF_EVENP|TF_ECHO|TF_XTABS|TF_CRMOD; + (*console_softCAR)(cnunit, cnline, TRUE); + console = cnline; + tp->t_dev = console; + (*console_param)(tp, SCREEN_LINE_OTHER); +#if NBM > 0 + } + + /* + * Enable rconsole interrupts for KDB + */ + if (tube && rcline != cnline) { + tp = console_tty[rcline]; + tp->t_ispeed = B9600; + tp->t_ospeed = B9600; + tp->t_flags = TF_LITOUT|TF_EVENP|TF_ECHO|TF_XTABS|TF_CRMOD; + tp->t_dev = rcline; + (*console_softCAR)(cnunit, rcline, TRUE); + (*console_param)(tp, SCREEN_LINE_OTHER); + } else + rcline = 0; +#endif NBM > 0 +} + +/* + * Open routine + */ +extern int + cons_start(struct tty *), + cons_stop(struct tty *, int), + cons_mctl(struct tty *, int, int); + +cons_open(dev, flag, ior) + int dev; + int flag; + io_req_t ior; +{ + register struct tty *tp; + register int ttyno; + + if (dev == user_console) + dev = console; + + ttyno = dev; + if (ttyno >= NCONSTTY) + return D_NO_SUCH_DEVICE; + tp = console_tty[ttyno]; + + /* But was it there at probe time */ + if (tp->t_addr == 0) + return D_NO_SUCH_DEVICE; + + tp->t_start = cons_start; + tp->t_stop = cons_stop; + tp->t_mctl = cons_mctl; + +#if NBM > 0 + if (screen_captures(ttyno)) + screen_open(SCREEN_CONS_UNIT(), ttyno==SCREEN_LINE_KEYBOARD); +#endif NBM > 0 + + if ((tp->t_state & TS_ISOPEN) == 0) { + if (tp->t_ispeed == 0) { + tp->t_ispeed = DEFAULT_SPEED; + tp->t_ospeed = DEFAULT_SPEED; + tp->t_flags = DEFAULT_FLAGS; + } + tp->t_dev = dev; + (*console_param)(tp, ttyno); + } + + return (char_open(dev, tp, flag, ior)); +} + + +/* + * Close routine + */ +cons_close(dev, flag) + int dev; +{ + register struct tty *tp; + register int ttyno; + spl_t s; + + if (dev == user_console) + dev = console; + + ttyno = dev; + +#if NBM > 0 + if (screen_captures(ttyno)) + screen_close(SCREEN_CONS_UNIT(), ttyno==SCREEN_LINE_KEYBOARD); +#endif NBM > 0 + + tp = console_tty[ttyno]; + + s = spltty(); + simple_lock(&tp->t_lock); + + ttyclose(tp); + + simple_unlock(&tp->t_lock); + splx(s); +} + +cons_read(dev, ior) + int dev; + register io_req_t ior; +{ + register struct tty *tp; + register ttyno; + + if (dev == user_console) + dev = console; + + ttyno = dev; +#if NBM > 0 + if (SCREEN_ISA_CONSOLE() && (ttyno == SCREEN_LINE_POINTER)) + return screen_read(SCREEN_CONS_UNIT(), ior); +#endif NBM > 0 + + tp = console_tty[ttyno]; + return char_read(tp, ior); +} + + +cons_write(dev, ior) + int dev; + register io_req_t ior; +{ + register struct tty *tp; + register ttyno; + + if (dev == user_console) + dev = console; + + ttyno = dev; +#if NBM > 0 + if (screen_captures(ttyno)) + return screen_write(SCREEN_CONS_UNIT(), ior); +#endif NBM > 0 + + tp = console_tty[ttyno]; + return char_write(tp, ior); +} + +/* + * Start output on a line + */ +cons_start(tp) + register struct tty *tp; +{ + spl_t s; + + s = spltty(); + if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) + goto out; + + if (tp->t_outq.c_cc == 0) + goto out; + + tp->t_state |= TS_BUSY; + + (*console_start)(tp); + +out: + splx(s); +} + +/* + * Stop output on a line. + */ +cons_stop(tp, flag) + register struct tty *tp; +{ + register spl_t s; + + s = spltty(); + if (tp->t_state & TS_BUSY) { + if ((tp->t_state&TS_TTSTOP)==0) + tp->t_state |= TS_FLUSH; + } + splx(s); +} + + +/* + * Modem control + */ +cons_mctl( + struct tty *tp, + int bits, + int how) +{ + return (*console_mctl)(tp->t_dev, bits, how); +} + +/* + * Abnormal close + */ +cons_portdeath(dev, port) + int dev; + mach_port_t port; +{ + if (dev == user_console) + dev = console; + return (tty_portdeath(console_tty[dev], port)); +} + +/* + * Get/Set status rotuines + */ +io_return_t +cons_get_status(dev, flavor, data, status_count) + int dev; + dev_flavor_t flavor; + int * data; /* pointer to OUT array */ + unsigned int *status_count; /* out */ +{ + register struct tty *tp; + register int ttyno; + + if (dev == user_console) + dev = console; + + ttyno = dev; + +#if NBM > 0 + if (screen_captures(ttyno) && + (screen_get_status(SCREEN_CONS_UNIT(), + flavor, data, status_count) == D_SUCCESS)) + return D_SUCCESS; +#endif NBM > 0 + + tp = console_tty[ttyno]; + + switch (flavor) { + case TTY_MODEM: + /* Take all bits */ + *data = (*console_mctl)(dev, -1, DMGET); + *status_count = 1; + break; + default: + return (tty_get_status(tp, flavor, data, status_count)); + } + return (D_SUCCESS); +} + +io_return_t +cons_set_status(dev, flavor, data, status_count) + int dev; + dev_flavor_t flavor; + int * data; + unsigned int status_count; +{ + register struct tty *tp; + register int ttyno; + + if (dev == user_console) + dev = console; + + ttyno = dev; + +#if NBM > 0 + if (screen_captures(ttyno) && + (screen_set_status(SCREEN_CONS_UNIT(), + flavor, data, status_count) == D_SUCCESS)) + return D_SUCCESS; +#endif NBM > 0 + + tp = console_tty[ttyno]; + + switch (flavor) { + case TTY_MODEM: + if (status_count < TTY_MODEM_COUNT) + return (D_INVALID_OPERATION); + (void) (*console_mctl)(dev, *data, DMSET); + break; + + case TTY_SET_BREAK: + (void) (*console_mctl)(dev, TM_BRK, DMBIS); + break; + + case TTY_CLEAR_BREAK: + (void) (*console_mctl)(dev, TM_BRK, DMBIC); + break; + + case TTY_STATUS: + { + register int error = D_SUCCESS; + struct tty_status *tsp; + + /* + * Defend from noise. The cshell... + */ + tsp = (struct tty_status *)data; + if ((tsp->tt_ispeed != tp->t_ispeed) || + (tsp->tt_ospeed != tp->t_ospeed) || + (tsp->tt_breakc != tp->t_breakc) || + ((tsp->tt_flags & ~TF_HUPCLS) != tp->t_flags)) { + + error = tty_set_status(tp, flavor, data, status_count); + if (error == 0) { + spl_t s = spltty(); + tp->t_state &= ~(TS_BUSY|TS_FLUSH); + (*console_param)(tp, ttyno); + splx(s); + } + } else + if (tsp->tt_flags & TF_HUPCLS) + tp->t_state |= TS_HUPCLS; + return (error); + } + default: + return (tty_set_status(tp, flavor, data, status_count)); + } + return (D_SUCCESS); +} + + +/* + * A simple scheme to dispatch interrupts. + * + * This deals with the fairly common case where we get an + * interrupt on each rx/tx character. A more elaborate + * scheme [someday here too..] would handle instead many + * characters per interrupt, perhaps using a DMA controller + * or a large SILO. Note that it is also possible to simulate + * a DMA chip with 'pseudo-dma' code that runs directly down + * in the interrupt routine. + */ + +/* + * We just received a character, ship it up for further processing. + * Arguments are the tty number for which it is meant, a flag that + * indicates a keyboard or mouse is potentially attached to that + * tty (-1 if not), the character proper stripped down to 8 bits, + * and an indication of any error conditions associated with the + * receipt of the character. + * We deal here with rconsole input handling and dispatching to + * mouse or keyboard translation routines. cons_input() does + * the rest. + */ +#if MACH_KDB +int l3break = 0x10; /* dear old ^P, we miss you so bad. */ +#endif MACH_KDB + +cons_simple_rint(ttyno, line, c, err) + int line; + int c; +{ + /* + * Rconsole. Drop in the debugger on break or ^P. + * Otherwise pretend input came from keyboard. + */ + if (rcline && ttyno == rcline) { +#if MACH_KDB + if ((err & CONS_ERR_BREAK) || + ((c & 0x7f) == l3break)) + return gimmeabreak(); +#endif /* MACH_KDB */ + ttyno = console; + goto process_it; + } + +#if NBM > 0 + if (screen_captures(line)) { + if (line == SCREEN_LINE_POINTER) + return mouse_input(SCREEN_CONS_UNIT(), c); + if (line == SCREEN_LINE_KEYBOARD) { + c = lk201_rint(SCREEN_CONS_UNIT(), c, FALSE, FALSE); + if (c == -1) + return; /* shift or bad char */ + } + } +#endif NBM > 0 +process_it: + cons_input(ttyno, c, err); +} + +/* + * Send along a character on a tty. If we were waiting for + * this char to complete the open procedure do so; check + * for errors; if all is well proceed to ttyinput(). + */ +cons_input(ttyno, c, err) +{ + register struct tty *tp; + + tp = console_tty[ttyno]; + + if ((tp->t_state & TS_ISOPEN) == 0) { + tt_open_wakeup(tp); + return; + } + if (err) { + if (err & CONS_ERR_OVERRUN) + log(LOG_WARNING, "sl%d: silo overflow\n", ttyno); + + if (err & CONS_ERR_PARITY) + if (((tp->t_flags & (TF_EVENP|TF_ODDP)) == TF_EVENP) + || ((tp->t_flags & (TF_EVENP|TF_ODDP)) == TF_ODDP)) + return; + if (err & CONS_ERR_BREAK) /* XXX autobaud XXX */ + c = tp->t_breakc; + } + ttyinput(c, tp); +} + +/* + * Transmission of a character is complete. + * Return the next character or -1 if none. + */ +cons_simple_tint(ttyno, all_sent) + boolean_t all_sent; +{ + register struct tty *tp; + + tp = console_tty[ttyno]; + if ((tp->t_addr == 0) || /* not probed --> stray */ + (tp->t_state & TS_TTSTOP)) + return -1; + + if (all_sent) { + tp->t_state &= ~TS_BUSY; + if (tp->t_state & TS_FLUSH) + tp->t_state &= ~TS_FLUSH; + + cons_start(tp); + } + + if (tp->t_outq.c_cc == 0 || (tp->t_state&TS_BUSY)==0) + return -1; + + return getc(&tp->t_outq); +} + + + + + +#endif /*NCONSTTY > 0*/ diff --git a/chips/serial_defs.h b/chips/serial_defs.h new file mode 100644 index 0000000..97027b0 --- /dev/null +++ b/chips/serial_defs.h @@ -0,0 +1,53 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: serial_defs.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 7/91 + * + * Generic console driver for serial-line based consoles. + */ + + +/* + * Common defs + */ + +extern int (*console_probe)(), (*console_param)(), (*console_start)(), + (*console_putc)(), (*console_getc)(), + (*console_pollc)(), (*console_mctl)(), (*console_softCAR)(); +extern cngetc(), cnmaygetc(), cnputc(), rcputc(); + +extern struct tty *console_tty[]; +extern int rcline, cnline; +extern int console; + +/* Simple one-char-at-a-time scheme */ +extern cons_simple_tint(), cons_simple_rint(); + +#define CONS_ERR_PARITY 0x1000 +#define CONS_ERR_BREAK 0x2000 +#define CONS_ERR_OVERRUN 0x4000 diff --git a/chips/sfb_hdw.c b/chips/sfb_hdw.c new file mode 100644 index 0000000..ff2b1f6 --- /dev/null +++ b/chips/sfb_hdw.c @@ -0,0 +1,253 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: sfb_hdw.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 11/92 + * + * Driver for the Smart Color Frame Buffer Display, + * hardware-level operations. + */ + +#include +#if (NSFB > 0) +#include + +#include +#include +#include +#include +#include +#include + +typedef pm_softc_t sfb_softc_t; + +#ifdef DECSTATION +#include +#include +#endif + +#ifdef FLAMINGO +#include /* XXXX fixme */ +#include +#define sparsify(x) ((1L << 28) | (((x) & 0x7ffffff) << 1) | \ + ((x) & ~0x7ffffffL)) +#endif + +#ifndef sparsify +#define sparsify(x) x +#endif + +/* + * Definition of the driver for the auto-configuration program. + */ + +int sfb_probe(), sfb_intr(); +void sfb_attach(); + +vm_offset_t sfb_std[NSFB] = { 0 }; +struct bus_device *sfb_info[NSFB]; +struct bus_driver sfb_driver = + { sfb_probe, 0, sfb_attach, 0, sfb_std, "sfb", sfb_info, + 0, 0, BUS_INTR_DISABLED}; + +/* + * Probe/Attach functions + */ + +sfb_probe( + vm_offset_t addr, + struct bus_device *device) +{ + static probed_once = 0; + + /* + * Probing was really done sweeping the TC long ago + */ + if (tc_probe("sfb") == 0) + return 0; + if (probed_once++ > 1) { + printf("[mappable] "); + device->address = addr; + } + return 1; +} + +void sfb_attach( + struct bus_device *ui) +{ + /* ... */ + printf(": smart frame buffer"); +} + + +/* + * Interrupt routine + */ + +sfb_intr( + int unit, + spl_t spllevel) +{ + register volatile char *ack; + + /* acknowledge interrupt */ + ack = (volatile char *) sfb_info[unit]->address + SFB_OFFSET_ICLR; + *ack = 0; + +#if mips + splx(spllevel); +#endif + lk201_led(unit); +} + +sfb_vretrace( + sfb_softc_t *sfb, + boolean_t on) +{ + sfb_regs *regs; + + regs = (sfb_regs *) ((char *)sfb->framebuffer - SFB_OFFSET_VRAM + SFB_OFFSET_REGS); + + regs->intr_enable = (on) ? 1 : 0; +} + +/* + * Boot time initialization: must make device + * usable as console asap. + */ +#define sfb_set_status cfb_set_status + +extern int + sfb_soft_reset(), sfb_set_status(), + sfb_pos_cursor(), bt459_video_on(), + bt459_video_off(), sfb_vretrace(), + pm_get_status(), pm_char_paint(), + pm_insert_line(), pm_remove_line(), + pm_clear_bitmap(), pm_map_page(); + +static struct screen_switch sfb_sw = { + screen_noop, /* graphic_open */ + sfb_soft_reset, /* graphic_close */ + sfb_set_status, /* set_status */ + pm_get_status, /* get_status */ + pm_char_paint, /* char_paint */ + sfb_pos_cursor, /* pos_cursor */ + pm_insert_line, /* insert_line */ + pm_remove_line, /* remove_line */ + pm_clear_bitmap, /* clear_bitmap */ + bt459_video_on, /* video_on */ + bt459_video_off, /* video_off */ + sfb_vretrace, /* intr_enable */ + pm_map_page /* map_page */ +}; + +sfb_cold_init( + int unit, + user_info_t *up) +{ + sfb_softc_t *sfb; + screen_softc_t sc = screen(unit); + vm_offset_t base = tc_probe("sfb"); + int hor_p, ver_p; + boolean_t makes_sense; + + bcopy(&sfb_sw, &sc->sw, sizeof(sc->sw)); + sc->flags |= COLOR_SCREEN; + + /* + * I am confused here by the documentation. One document + * sez there are three boards: + * "PMAGB-BA" can do 1280x1024 @66Hz or @72Hz + * "PMAGB-BC" can do 1024x864 @60Hz or 1280x1024 @72Hz + * "PMAGB-BE" can do 1024x768 @72Hz or 1280x1024 @72Hz + * Another document sez things differently: + * "PMAGB-BB" can do 1024x768 @72Hz + * "PMAGB-BD" can do 1024x864 @60Hz or 1280x1024 @72Hz + * + * I would be inclined to believe the first one, which came + * with an actual piece of hardware attached (a PMAGB-BA). + * But I could swear I got a first board (which blew up + * instantly) and it was calling itself PMAGB-BB... + * + * Since I have not seen any other hardware I will make + * this code as hypothetical as I can. Should work :-)) + */ + + makes_sense = FALSE; + + { + sfb_regs *regs; + + regs = (sfb_regs *) ((char *)base + SFB_OFFSET_REGS); + hor_p = (regs->vhor_setup & 0x1ff) * 4; + ver_p = regs->vvert_setup & 0x7ff; + + if (((hor_p == 1280) && (ver_p == 1024)) || + ((hor_p == 1024) && (ver_p == 864)) || + ((hor_p == 1024) && (ver_p == 768))) + makes_sense = TRUE; + } + + if (makes_sense) { + sc->frame_scanline_width = hor_p; + sc->frame_height = ver_p; + sc->frame_visible_width = hor_p; + sc->frame_visible_height = ver_p; + } else { + sc->frame_scanline_width = 1280; + sc->frame_height = 1024; + sc->frame_visible_width = 1280; + sc->frame_visible_height = 1024; + } + + pm_init_screen_params(sc,up); + (void) screen_up(unit, up); + + sfb = pm_alloc( unit, sparsify(base + SFB_OFFSET_BT459), + base + SFB_OFFSET_VRAM, -1); + + screen_default_colors(up); + + sfb_soft_reset(sc); + + /* + * Clearing the screen at boot saves from scrolling + * much, and speeds up booting quite a bit. + */ + screen_blitc( unit, 'C'-'@');/* clear screen */ +} + +#if 0 /* this is how you find out about a new screen */ +fill(addr,n,c) + char *addr; +{ + while (n-- > 0) *addr++ = c; +} +#endif + + +#endif (NSFB > 0) diff --git a/chips/sfb_misc.c b/chips/sfb_misc.c new file mode 100644 index 0000000..a51e9a4 --- /dev/null +++ b/chips/sfb_misc.c @@ -0,0 +1,133 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: sfb_misc.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 11/92 + * + * Driver for the PMAGB-BA smart color framebuffer + * + */ + +#include +#if (NSFB > 0) +#include + +/* + * NOTE: This driver relies heavily on the pm one, as well as the cfb. + */ + +#include +#include +#include +typedef pm_softc_t sfb_softc_t; + +#include +#define bt459 cursor_registers + +#ifdef DECSTATION +#include +#endif + +#ifdef FLAMINGO +#include /* XXXX */ +#endif + +/* + * Initialize color map, for kernel use + */ +#define sfb_init_colormap cfb_init_colormap + +/* + * Position cursor + */ +sfb_pos_cursor( + bt459_regmap_t *regs, + int x, + int y) +{ + bt459_pos_cursor( regs, x + 368 - 219, y + 37 - 34); +} + +/* + * Large viz small cursor + */ +#define sfb_small_cursor_to_large cfb_small_cursor_to_large + +/* + * Device-specific set status + */ +#define sfb_set_status cfb_set_status + +/* + * Hardware initialization + */ +sfb_init_screen( + sfb_softc_t *sfb) +{ + bt459_init( sfb->bt459, + sfb->bt459 + (SFB_OFFSET_RESET - SFB_OFFSET_BT459), + 4 /* 4:1 MUX */); +} + +/* + * Do what's needed when X exits + */ +sfb_soft_reset( + screen_softc_t sc) +{ + sfb_softc_t *sfb = (sfb_softc_t*) sc->hw_state; + user_info_t *up = sc->up; + extern cursor_sprite_t dc503_default_cursor; + + /* + * Restore params in mapped structure + */ + pm_init_screen_params(sc,up); + up->row = up->max_row - 1; + + up->dev_dep_2.pm.x26 = 2; /* you do not want to know */ + up->dev_dep_1.pm.x18 = (short*)2; + + /* + * Restore RAMDAC chip to default state + */ + sfb_init_screen(sfb); + + /* + * Load kernel's cursor sprite: just use the same pmax one + */ + sfb_small_cursor_to_large(up, dc503_default_cursor); + bt459_cursor_sprite(sfb->bt459, up->dev_dep_2.pm.cursor_sprite); + + /* + * Color map and cursor color + */ + sfb_init_colormap(sc); +} + + +#endif (NSFB > 0) diff --git a/chips/spans.c b/chips/spans.c new file mode 100644 index 0000000..4529f8b --- /dev/null +++ b/chips/spans.c @@ -0,0 +1,114 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +/*** SPANS SIGNALING ***/ + +#ifndef STUB +#include +#include +#else +#include "spans.h" +#include "tca100_if.h" +#endif + +nw_result spans_initialize(int dev) { + +#if !PERMANENT_VIRTUAL_CONNECTIONS +#endif + +} + + +void spans_input(nw_buffer_t msg) { + +#if !PERMANENT_VIRTUAL_CONNECTIONS +#endif + +} + +nw_result spans_open(nw_ep ep, nw_address_1 rem_addr_1, + nw_address_2 rem_addr_2, nw_ep remote_ep) { + nw_result rc; + +#if PERMANENT_VIRTUAL_CONNECTIONS + rc = NW_FAILURE; +#else +#endif + + return rc; +} + +nw_result spans_accept(nw_ep ep, nw_buffer_t msg, nw_ep_t new_epp) { + nw_result rc; + +#if PERMANENT_VIRTUAL_CONNECTIONS + rc = NW_FAILURE; +#else +#endif + + return rc; +} + +nw_result spans_close(nw_ep ep) { + nw_result rc; + + tct[ep].rx_sar_header = 0; + rc = NW_SUCCESS; + return rc; +} + +nw_result spans_add(nw_ep ep, nw_address_1 rem_addr_1, + nw_address_2 rem_addr_2, nw_ep remote_ep) { + nw_result rc; + +#if PERMANENT_VIRTUAL_CONNECTIONS + rc = NW_FAILURE; +#else +#endif + + return rc; +} + +nw_result spans_drop(nw_ep ep, nw_address_1 rem_addr_1, + nw_address_2 rem_addr_2, nw_ep remote_ep) { + nw_result rc; + +#if PERMANENT_VIRTUAL_CONNECTIONS + rc = NW_FAILURE; +#else +#endif + + return rc; +} + +void spans_timer_sweep() { + +#if !PERMANENT_VIRTUAL_CONNECTIONS +#endif + +} + + diff --git a/chips/spans.h b/chips/spans.h new file mode 100644 index 0000000..7cb3500 --- /dev/null +++ b/chips/spans.h @@ -0,0 +1,58 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +/*** SPANS SIGNALING ***/ + +#ifndef _SPANS_H_ +#define _SPANS_H_ 1 + +#ifndef STUB +#include +#else +#include "nc.h" +#endif + +extern nw_result spans_initialize(int dev); + +extern void spans_input(nw_buffer_t msg); + +extern nw_result spans_open(nw_ep ep, nw_address_1 rem_addr_1, + nw_address_2 rem_addr_2, nw_ep remote_ep); + +extern nw_result spans_accept(nw_ep ep, nw_buffer_t msg, nw_ep_t new_epp); + +extern nw_result spans_close(nw_ep ep); + +extern nw_result spans_add(nw_ep ep, nw_address_1 rem_addr_1, + nw_address_2 rem_addr_2, nw_ep remote_ep); + +extern nw_result spans_drop(nw_ep ep, nw_address_1 rem_addr_1, + nw_address_2 rem_addr_2, nw_ep remote_ep); + +extern void spans_timer_sweep(); + + +#endif /* _SPANS_H_ */ diff --git a/chips/tca100.c b/chips/tca100.c new file mode 100644 index 0000000..7ad4fec --- /dev/null +++ b/chips/tca100.c @@ -0,0 +1,360 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#ifndef STUB +#include +#else +#include "atm.h" +#endif + +#if NATM > 0 + +#ifndef STUB +#include +#include +#include +#include +#include /* spl definitions */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +decl_simple_lock_data(, atm_simple_lock); + +#else +#include "stub.h" +#include "nc.h" +#include "tca100_if.h" +#include "tca100.h" + +int atm_simple_lock; + +#endif + +struct bus_device *atm_info[NATM]; + +int atm_probe(); +void atm_attach(); +struct bus_driver atm_driver = + { atm_probe, 0, atm_attach, 0, /* csr */ 0, "atm", atm_info, + "", 0, /* flags */ 0 }; + +atm_device_t atmp[NATM] = {NULL}; +u_int atm_open_count[NATM]; +u_int atm_mapped[NATM]; +u_int atm_control_mask[NATM]; +struct evc atm_event_counter[NATM]; + +#define DEVICE(unit) ((unit == 0) ? NW_TCA100_1 : NW_TCA100_2) + +void atm_initialize(int unit) { + + atmp[unit]->creg = (CR_RX_RESET | CR_TX_RESET); + atmp[unit]->creg = 0; + atmp[unit]->rxtimerv = 0; + atmp[unit]->rxthresh = 1; + atmp[unit]->txthresh = 0; + atmp[unit]->sreg = 0; + atmp[unit]->creg = atm_control_mask[unit] = (CR_RX_ENABLE | CR_TX_ENABLE); + atm_open_count[unit] = 0; + atm_mapped[unit] = 0; +} + +/*** Device entry points ***/ + +int atm_probe(vm_offset_t reg, struct bus_device *ui) { + int un; + + un = ui->unit; + if (un >= NATM || check_memory(reg, 0)) { + return 0; + } + + atm_info[un] = ui; + atmp[un] = (atm_device_t) reg; + nc_initialize(); + if (nc_device_register(DEVICE(un), NW_CONNECTION_ORIENTED, (char *) reg, + &tca100_entry_table) == NW_SUCCESS && + tca100_initialize(DEVICE(un)) == NW_SUCCESS) { + atm_initialize(un); + evc_init(&atm_event_counter[un]); + return 1; + } else { + atmp[un] = NULL; + (void) nc_device_unregister(DEVICE(un), NW_FAILURE); + return 0; + } +} + +void atm_attach(struct bus_device *ui) { + int un; + + un = ui->unit; + if (un >= NATM) { + printf("atm: stray attach\n"); + } else { + atmp[un]->creg = + atm_control_mask[un] = CR_TX_ENABLE | CR_RX_ENABLE | RX_COUNT_INTR; + /*Enable ATM interrupts*/ + } +} + +void atm_intr(int unit, int spl_level) { + + if (unit >= NATM || atmp[unit] == NULL) { + printf("atm: stray interrupt\n"); + } else { + atmp[unit]->creg = CR_TX_ENABLE | CR_RX_ENABLE; /*Disable ATM interrupts*/ + wbflush(); + if (atm_mapped[unit]) { + splx(spl_level); + evc_signal(&atm_event_counter[unit]); + } else { + simple_lock(&atm_simple_lock); + tca100_poll(DEVICE(unit)); + atmp[unit]->creg = atm_control_mask[unit]; + simple_unlock(&atm_simple_lock); + splx(spl_level); + } + } +} + +io_return_t atm_open(dev_t dev, int mode, io_req_t ior) { + int un; + + un = minor(dev); + if (un >= NATM || atmp[un] == NULL) { + return D_NO_SUCH_DEVICE; +/* + } else if (atm_open_count[un] > 0 && (atm_mapped[un] || (mode & D_WRITE))) { + return D_ALREADY_OPEN; +*/ + } else { + atm_open_count[un]++; + atm_mapped[un] = ((mode & D_WRITE) != 0); + if (atm_mapped[un]) + (void) nc_device_unregister(DEVICE(un), NW_NOT_SERVER); + return D_SUCCESS; + } +} + +io_return_t atm_close(dev_t dev) { + int un; + + un = minor(dev); + if (un >= NATM || atmp[un] == NULL) { + return D_NO_SUCH_DEVICE; + } else if (atm_open_count[un] == 0) { + return D_INVALID_OPERATION; + } else { + if (atm_mapped[un]) { + (void) nc_device_register(DEVICE(un), NW_CONNECTION_ORIENTED, + (char *) atmp[un], + &tca100_entry_table); + atm_mapped[un] = 0; + } + atm_open_count[un]--; + return D_SUCCESS; + } +} + +unsigned int *frc = 0xbe801000; +char data[66000]; + +io_return_t atm_read(dev_t dev, io_req_t ior) { + unsigned int ck1, ck2; + int i, j; + char c[16]; + + ck1 = *frc; + device_read_alloc(ior, ior->io_count); + for (i = 0, j = 0; i < ior->io_count; i += 4096, j++) + c[j] = (ior->io_data)[i]; + ck2 = *frc; + ((int *) ior->io_data)[0] = ck1; + ((int *) ior->io_data)[1] = ck2; + return D_SUCCESS; +} + +io_return_t atm_write(dev_t dev, io_req_t ior) { + int i, j; + char c[16]; + boolean_t wait; + + device_write_get(ior, &wait); + for (i = 0, j = 0; i < ior->io_total; i += 4096, j++) + c[j] = (ior->io_data)[i]; + ior->io_residual = ior->io_total - *frc; + return D_SUCCESS; +} + +io_return_t atm_get_status(dev_t dev, int flavor, dev_status_t status, + u_int *status_count) { + int un; + + un = minor(dev); + if (un >= NATM || atmp[un] == NULL) { + return D_NO_SUCH_DEVICE; + } else { + switch ((atm_status) flavor) { + case ATM_MAP_SIZE: + status[0] = sizeof(atm_device_s); + *status_count = sizeof(int); + return D_SUCCESS; + case ATM_MTU_SIZE: + status[0] = 65535; /*MTU size*/ + *status_count = sizeof(int); + return D_SUCCESS; + case ATM_EVC_ID: + status[0] = atm_event_counter[un].ev_id; + *status_count = sizeof(int); + return D_SUCCESS; + case ATM_ASSIGNMENT: + status[0] = atm_mapped[un]; + status[1] = atm_open_count[un]; + *status_count = 2 * sizeof(int); + return D_SUCCESS; + default: + return D_INVALID_OPERATION; + } + } +} + +io_return_t atm_set_status(dev_t dev, int flavor, dev_status_t status, + u_int status_count) { + io_return_t rc; + int un, s; + nw_pvc_t pvcp; + nw_plist_t pel; + nw_ep lep; + + un = minor(dev); + if (un >= NATM || atmp[un] == NULL) { + return D_NO_SUCH_DEVICE; + } else switch ((atm_status) flavor) { + case ATM_INITIALIZE: + if (status_count != 0) { + return D_INVALID_OPERATION; + } else { + s = splsched(); + if (nc_device_register(DEVICE(un), NW_CONNECTION_ORIENTED, + (char *) atmp[un], + &tca100_entry_table) == NW_SUCCESS && + tca100_initialize(DEVICE(un)) == NW_SUCCESS) { + atm_initialize(un); + rc = D_SUCCESS; + } else { + atmp[un] = NULL; + (void) nc_device_unregister(DEVICE(un), NW_FAILURE); + rc = D_INVALID_OPERATION; + } + splx(s); + return rc; + } + break; + +#if PERMANENT_VIRTUAL_CONNECTIONS + case ATM_PVC_SET: + pvcp = (nw_pvc_t) status; + if (status_count != sizeof(nw_pvc_s) || pvcp->pvc.local_ep >= MAX_EP) { + rc = D_INVALID_OPERATION; + } else if ((pel = nc_peer_allocate()) == NULL) { + rc = D_INVALID_OPERATION; + } else { + lep = pvcp->pvc.local_ep; + tct[lep].rx_sar_header = SSM | 1; + tct[lep].tx_atm_header = pvcp->tx_vp << ATM_VPVC_SHIFT; + tct[lep].tx_sar_header = 1; + ect[lep].state = NW_DUPLEX_ACCEPTED; + pel->peer = pvcp->pvc; + pel->next = NULL; + ect[lep].conn = pel; + if (pvcp->protocol == NW_LINE) { + if (nc_line_update(&pel->peer, lep) == NW_SUCCESS) { + ect[lep].protocol = pvcp->protocol; + if (nw_free_line_last == 0) + nw_free_line_first = lep; + else + ect[nw_free_line_last].next = lep; + ect[lep].previous = nw_free_line_last; + ect[lep].next = 0; + nw_free_line_last = lep; + rc = D_SUCCESS; + } else { + rc = D_INVALID_OPERATION; + } + } else { + rc = D_SUCCESS; + } + } + return rc; +#endif + + default: + return D_INVALID_OPERATION; + } +} + +int atm_mmap(dev_t dev, vm_offset_t off, int prot) { + int un; + vm_offset_t addr; + + un = minor(dev); + if (un >= NATM || atmp[un] == NULL || !atm_mapped[un] || + off >= sizeof(atm_device_s)) { + return -1; + } else { + return mips_btop(K1SEG_TO_PHYS( (vm_offset_t) atmp[un] ) + off ); + } +} + +io_return_t atm_restart(int u) { + + return D_INVALID_OPERATION; +} + +io_return_t atm_setinput(dev_t dev, ipc_port_t receive_port, int priority, + filter_array_t *filter, u_int filter_count) { + + return D_INVALID_OPERATION; +} + +int atm_portdeath(dev_t dev, mach_port_t port) { + + return D_INVALID_OPERATION; +} + + +#endif NATM > 0 + + + diff --git a/chips/tca100.h b/chips/tca100.h new file mode 100644 index 0000000..2931225 --- /dev/null +++ b/chips/tca100.h @@ -0,0 +1,200 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#ifndef _TCA100_H_ +#define _TCA100_H_ 1 + +#ifndef STUB +#include +#else +#include "nw.h" +#endif + +/*** FORE TCA-100 Turbochannel ATM computer interface ***/ + +/*** HARDWARE REGISTERS ***/ + +typedef volatile unsigned int vol_u_int; + +typedef struct atm_device { + unsigned int prom[64 * 1024 / 4]; + vol_u_int sreg; + vol_u_int creg_set; + vol_u_int creg_clr; + vol_u_int creg; + vol_u_int rxtimer; + unsigned int pad1; + vol_u_int rxtimerv; + unsigned int pad2; + vol_u_int rxcount; + unsigned int pad3; + vol_u_int rxthresh; + unsigned int pad4; + vol_u_int txcount; + unsigned int pad5; + vol_u_int txthresh; + unsigned int pad6[64*1024/4 - 15]; + vol_u_int rxfifo[14]; + unsigned int pad7[64*1024/4 - 14]; + vol_u_int txfifo[14]; + unsigned int pad8[64*1024/4 - 14]; +} atm_device_s, *atm_device_t; + + +/*** DEFINITION OF BITS IN THE STATUS AND CONTROL REGISTERS ***/ + +#define RX_COUNT_INTR 0x0001 +#define RX_EOM_INTR 0x0002 +#define RX_TIME_INTR 0x0004 +#define TX_COUNT_INTR 0x0008 +#define RX_CELL_LOST 0x0010 +#define RX_NO_CARRIER 0x0020 +#define CR_RX_ENABLE 0x0040 +#define CR_TX_ENABLE 0x0080 +#define CR_RX_RESET 0x0100 +#define CR_TX_RESET 0x0200 + +#define RX_COUNTER_MASK 0x03ff + +/*** DEFINITION OF FIELDS FOR AAL3/4 WITH THE TCA-100 PADDING ***/ + +/*Header -- ATM header*/ + +#define VPI 0x0ff00000 +#define VCI 0x000ffff0 + +#define ATM_HEADER_RSV_BITS 0x00000004 + +#define PERMANENT_VIRTUAL_CONNECTIONS 1 + +#if PERMANENT_VIRTUAL_CONNECTIONS +#define ATM_VPVC_MASK 0x3ff00000 +#define ATM_VPVC_SHIFT 20 +#else +#define ATM_VPVC_MASK 0x00003ff0 +#define ATM_VPVC_SHIFT 4 +#endif + + +/*First payload word -- SAR header*/ + +#define ATM_HEADER_CRC 0xff000000 +#define ATM_HEADER_CRC_SYNDROME 0x00ff0000 + +#define SEG_TYPE 0x0000c000 +#define BOM 0x00008000 +#define COM 0x00000000 +#define EOM 0x00004000 +#define SSM 0x0000c000 + +#define BOM_DATA_SIZE 40 +#define COM_DATA_SIZE 44 +#define EOM_DATA_SIZE 40 +#define SSM_DATA_SIZE 36 + +#define SEQ_NO 0x00003c00 +#define SEQ_INC 0x00000400 + +#define MID 0x000003ff +#define MID_INC 0x00000001 + +#define SAR_HEADER_MASK (ATM_HEADER_CRC_SYNDROME | SEG_TYPE | SEQ_NO | MID) + +/*Trailer -- SAR trailer and error flags*/ + +#define PAYLOAD_LENGTH 0xfc000000 +#define FULL_SEGMENT_TRAILER (44 << 26) +#define EMPTY_SEGMENT_TRAILER (4 << 26) +#define SYNCH_SEGMENT_TRAILER (16 << 26) + +#define FRAMING_ERROR 0x0001 +#define HEADER_CRC_ERROR 0x0002 +#define PAYLOAD_CRC_ERROR 0x0004 +#define PAD2_ERROR 0x0007 + +#define SAR_TRAILER_MASK (PAYLOAD_LENGTH | PAD2_ERROR) + /*This field should be FULL_SEGMENT_TRAILER IN BOM OR COM*/ + + +/*CS header and trailer fields*/ + +#define CS_PDU_TYPE 0xff000000 +#define BE_TAG 0x00ff0000 +#define BA_SIZE 0x0000ffff + +#define CS_PROTOCOL_CONTROL_FIELD 0xff000000 +#define CS_LENGTH 0x0000ffff + +/*** DEVICE STATUS ***/ + +typedef enum { /*"Flavors" for device_get_status and device_set_status*/ + ATM_MAP_SIZE, /* device_get_status options */ + ATM_MTU_SIZE, + ATM_EVC_ID, /* ID of event counter assigned to device */ + ATM_ASSIGNMENT, /* Returns two words indicating whether device is mapped + and number of tasks with the device open */ + /* device_set_status options */ + ATM_INITIALIZE, /* Restarts hardware and low-level driver */ + ATM_PVC_SET /* Sets up a permanent virtual connection -- + the status argument array is cast to a nw_pvc_s + structure */ + +} atm_status; + +typedef struct { + nw_peer_s pvc; /* Permanent virtual connection */ + u_int tx_vp; /* VPI used for transmissions to permanent virtual + connection. The VPI used for reception is the + local endpoint number. VCIs are 0 */ + nw_protocol protocol; /* Protocol of connection (possibly NW_LINE) */ +} nw_pvc_s, *nw_pvc_t; + +/*** BYTE ORDER ***/ + +/*The ATM header and SAR header and trailer are converted to and from + host byte order by hardware. CS headers and trailers and + signaling messages need byte order conversion in software. + Conversion in software is also necessary for application messages + if the communicating hosts have different byte orders (e.g. DECstation + and SPARCstation). */ + +#define HTONL(x) \ + ((x << 24) | ((x & 0xff00) << 8) | ((x >> 8) & 0xff00) | ((u_int) x >> 24)) + +#define NTOHL(x) HTONL(x) + +#if 0 +unsigned int htonl(unsigned int x) { + + return ((x << 24) | ((x & 0xff00) << 8) | ((x >> 8) & 0xff00) | (x >> 24)); +} + +#define ntohl(x) htonl(x) + +#endif + +#endif /* _TCA100_H_ */ + diff --git a/chips/tca100_if.c b/chips/tca100_if.c new file mode 100644 index 0000000..5eeec10 --- /dev/null +++ b/chips/tca100_if.c @@ -0,0 +1,1377 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +/*** TCA 100 ATM NETWORK INTERFACE ***/ + +#ifndef STUB +#include +# else +#include "tca100_if.h" +#endif + +#define SMALL_WINDOW_SIZE (BOM_DATA_SIZE + EOM_DATA_SIZE) +#define INITIAL_WINDOW_SIZE BOM_DATA_SIZE +#define CONTINUATION_WINDOW_SIZE (71 * COM_DATA_SIZE) +#define FINAL_WINDOW_SIZE (70 * COM_DATA_SIZE + EOM_DATA_SIZE) +#define MAX_LONG_RX 2 +#define MAX_LONG_TX 5 +#define BASE_TIME_OUT 5 +#define DELAYED_TIME_OUT 15 +#define MAX_RETRY 3 +#define POLL_LIMIT 100000 +#define POLL_IDLE_TIME 1 +#define POLL_CELL_TIME 8 + +#define TCA_SYNCH 0xfc00 +#define TCA_ACK (NW_SUCCESS << 10) +#define TCA_NAK (NW_FAILURE << 10) +#define TCA_OVR (NW_OVERRUN << 10) +#define TCA_SEQ (NW_INCONSISTENCY << 10) + +int tca100_verbose = 0; + +int tick[MAX_DEV]; + +nw_control_s nw_tx_control[MAX_DEV][MAX_LONG_TX]; +nw_control_s nw_rx_control[MAX_DEV][MAX_LONG_RX]; + +int long_tx_count[MAX_DEV], long_rx_count[MAX_DEV]; + +nw_tx_header_t delayed_tx_first[MAX_DEV], delayed_tx_last[MAX_DEV]; +nw_rx_header_t delayed_rx_first[MAX_DEV], delayed_rx_last[MAX_DEV]; + +nw_tcb tct[MAX_EP]; + +u_int MTU[] = {9244, 65528, 65532, 65528}; +u_int MTU_URGENT[] = {32, 28, 32, 28}; + +nw_dev_entry_s tca100_entry_table = { + tca100_initialize, tca100_status, spans_timer_sweep, tca100_timer_sweep, + tca100_poll, tca100_send, tca100_rpc, spans_input, spans_open, spans_accept, + spans_close, spans_add, spans_drop}; + +typedef enum { + ATM_HEADER, + SAR_HEADER, + SAR_TRAILER, + CS_HEADER, + CS_TRAILER, + FRAME_ERROR, + DELIVERY_ERROR, + SYNCH_ERROR, + SEQ_ERROR, + OVERRUN_ERROR, + RX_RETRANSMISSION, + TX_RETRANSMISSION +} tca_error; + +int tca_ec[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +nw_result tca100_initialize(int dev) { + nw_result rc; + int i; + + rc = spans_initialize(dev); + if (rc = NW_SUCCESS) { + tick[dev] = 0; + for (i = 0; i < MAX_LONG_TX; i++) + nw_tx_control[dev][i].ep = 0; + long_tx_count[dev] = 0; + delayed_tx_first[dev] = delayed_tx_last[dev] = NULL; + for (i = 0; i < MAX_LONG_RX; i++) + nw_rx_control[dev][i].ep = 0; + long_rx_count[dev] = 0; + delayed_rx_first[dev] = delayed_rx_last[dev] = NULL; + for (i = 0; i < MAX_EP; i++) { + tct[i].rx_sar_header = 0; + tct[i].rx_control = NULL; + tct[i].tx_queued_count = 0; + tct[i].tx_control = NULL; + } + rc = NW_SUCCESS; + } + return rc; +} + +nw_result tca100_status(int dev) { + nw_result rc; + atm_device_t atmp; + u_int status; + + atmp = (atm_device_t) devct[dev].addr; + status = atmp->sreg; + if (status & RX_NO_CARRIER) { + atmp->creg_set = CR_RX_RESET; + atmp->creg_clr = ~CR_RX_RESET; + atmp->creg_set = CR_RX_ENABLE; + atmp->sreg = 0; + rc = NW_NO_CARRIER; + } else if (status & RX_CELL_LOST) { + atmp->sreg = RX_COUNT_INTR; + rc = NW_OVERRUN; + } else { + rc = NW_SUCCESS; + } + return rc; +} + + +void tca100_synch_send(int dev, nw_tcb_t tcb, u_int reply) { + vol_u_int *tx_fifo = &((atm_device_t) devct[dev].addr)->txfifo[0]; + +#ifdef TRACING + printf("Synch sent %x\n", reply); +#endif + + tx_fifo[0] = tcb->tx_atm_header; + tx_fifo[1] = SSM; + tx_fifo[2] = HTONL(8); + tx_fifo[3] = HTONL(NW_SYNCHRONIZATION); + tx_fifo[4] = htonl(reply); + tx_fifo[5] = HTONL(8); + tx_fifo[6] = 0; + tx_fifo[7] = 0; + tx_fifo[8] = 0; + tx_fifo[9] = 0; + tx_fifo[10] = 0; + tx_fifo[11] = 0; + tx_fifo[12] = 0; + tx_fifo[13] = SYNCH_SEGMENT_TRAILER; +} + +#define broken_cell_mend(length) { \ + missing = length; \ + while (missing != 0) { \ + if (missing > block_count) { \ + limit = 0; \ + missing -= block_count; \ + } else { \ + limit = block_count - missing; \ + missing = 0; \ + } \ + while (block_count > limit) { \ + t1 = block[0]; \ + block++; \ + tx_fifo[1] = t1; \ + block_count -= 4; \ + } \ + if (block_count == 0) { \ + ecb->tx_current = tx_header = ecb->tx_current->next; \ + if (tx_header != NULL) { \ + block_count = tx_header->block_length; \ + block = (vol_u_int *) tx_header->block; \ + } \ + } \ + } \ +} + + +nw_result tca100_window_send(int dev, nw_ecb_t ecb, nw_tcb_t tcb, + boolean_t initial) { + nw_result rc; + register vol_u_int *tx_fifo = &((atm_device_t) devct[dev].addr)->txfifo[0]; + register vol_u_int *block; + register u_int block_count, msg_count; + register int com_count; + int eom_count; + register u_int atm_header, sar_header, sar_trailer; + u_int cs_header, end_count; + int limit, missing; + register u_int t1, t2; + nw_tx_header_t tx_header; + nw_options options; + + atm_header = tcb->tx_atm_header; + if (initial) { + sar_header = tcb->tx_sar_header & MID; + tx_header = ecb->tx_initial; + block = (vol_u_int *) tx_header->block; + block_count = tx_header->block_length; + options = tx_header->options; + msg_count = tx_header->msg_length; + if (ecb->protocol == NW_LINE) + msg_count += 4; + if (options == NW_URGENT) + msg_count += 4; + cs_header = ecb->protocol | (sar_header & 0xff) << 8 | + (msg_count & 0xff00) << 8 | msg_count << 24; + tcb->tx_cs_header = cs_header; + + if (msg_count <= SSM_DATA_SIZE) { /*Single segment message*/ + tx_fifo[0] = atm_header; + sar_trailer = (msg_count + 8) << 26; + tx_fifo[1] = SSM | sar_header; /*Sequence number 0 is implicit*/ + end_count = msg_count + 4; + tx_fifo[1] = cs_header; + if (options == NW_URGENT) { + tx_fifo[1] = HTONL(NW_URGENT); + msg_count -= 4; + } + if (ecb->protocol == NW_LINE) { + tx_fifo[1] = tx_header->peer.local_ep >> 8 | + (tx_header->peer.local_ep & 0x00ff) << 8 | + (tx_header->peer.remote_ep & 0xff00) << 8 | + tx_header->peer.remote_ep << 24; + msg_count -= 4; + } + if (ecb->protocol == NW_SEQ_PACKET) { + tcb->tx_synch = 0; + } else { + tcb->tx_synch = -1; + } + goto EOM_payload; + + } else { /*Beginning of message*/ + tx_fifo[0] = atm_header; + sar_trailer = FULL_SEGMENT_TRAILER; + tx_fifo[1] = BOM | sar_header; /*Sequence number 0 is implicit*/ + tx_fifo[2] = cs_header; + if (block_count < BOM_DATA_SIZE) { + if (ecb->protocol == NW_LINE) { + t1 = tx_header->peer.local_ep >> 8 | + (tx_header->peer.local_ep & 0x00ff) << 8 | + (tx_header->peer.remote_ep & 0xff00) << 8 | + tx_header->peer.remote_ep << 24; + missing = BOM_DATA_SIZE - 4; + tx_fifo[3] = t1; + } else { + missing = BOM_DATA_SIZE; + } + broken_cell_mend(missing); + } else { + if (ecb->protocol == NW_LINE) { + t1 = tx_header->peer.local_ep >> 8 | + (tx_header->peer.local_ep & 0x00ff) << 8 | + (tx_header->peer.remote_ep & 0xff00) << 8 | + tx_header->peer.remote_ep << 24; + } else { + t1 = block[0]; + block_count -= 4; + block++; + } + t2 = block[0]; + tx_fifo[3] = t1; + tx_fifo[4] = t2; + t1 = block[1]; + t2 = block[2]; + tx_fifo[5] = t1; + tx_fifo[6] = t2; + t1 = block[3]; + t2 = block[4]; + tx_fifo[7] = t1; + tx_fifo[8] = t2; + t1 = block[5]; + t2 = block[6]; + tx_fifo[9] = t1; + tx_fifo[10] = t2; + t1 = block[7]; + t2 = block[8]; + tx_fifo[11] = t1; + tx_fifo[12] = t2; + block_count -= (BOM_DATA_SIZE - 4); + block += 9; + } + if (ecb->protocol == NW_RAW) { + msg_count -= BOM_DATA_SIZE; + com_count = msg_count / COM_DATA_SIZE; + msg_count = msg_count % COM_DATA_SIZE; + eom_count = 1; + tcb->tx_synch = -1; + } else if (msg_count > SMALL_WINDOW_SIZE) { + com_count = eom_count = 0; + tcb->tx_synch = msg_count; + msg_count -= BOM_DATA_SIZE; + } else { + com_count = 0; + eom_count = 1; + if (ecb->protocol == NW_SEQ_PACKET) { + tcb->tx_synch = 0; + } else { + tcb->tx_synch = -1; + } + msg_count -= BOM_DATA_SIZE; + } + tx_fifo[13] = sar_trailer; + sar_header += SEQ_INC; + } + + } else { + sar_header = tcb->tx_sar_header; + sar_trailer = FULL_SEGMENT_TRAILER; + block = (vol_u_int *) tcb->tx_p; + block_count = tcb->tx_block_count; + msg_count = tcb->tx_msg_count; + if (msg_count > FINAL_WINDOW_SIZE) { + com_count = (CONTINUATION_WINDOW_SIZE / COM_DATA_SIZE); + eom_count = 0; + tcb->tx_synch = msg_count; + msg_count -= CONTINUATION_WINDOW_SIZE; + } else { + com_count = msg_count / COM_DATA_SIZE; + msg_count = msg_count % COM_DATA_SIZE; + eom_count = 1; + if (ecb->protocol == NW_SEQ_PACKET) { + tcb->tx_synch = 0; + } else { + tcb->tx_synch = -1; + } + } + } + + while (com_count-- > 0) { /*Continuation of message*/ + tx_fifo[0] = atm_header; + tx_fifo[1] = sar_header; /*COM is 0 and is implicit*/ + if (block_count >= COM_DATA_SIZE) { + t1 = block[0]; + t2 = block[1]; + tx_fifo[2] = t1; + tx_fifo[3] = t2; + t1 = block[2]; + t2 = block[3]; + tx_fifo[4] = t1; + tx_fifo[5] = t2; + t1 = block[4]; + t2 = block[5]; + tx_fifo[6] = t1; + tx_fifo[7] = t2; + t1 = block[6]; + t2 = block[7]; + tx_fifo[8] = t1; + tx_fifo[9] = t2; + t1 = block[8]; + t2 = block[9]; + tx_fifo[10] = t1; + tx_fifo[11] = t2; + t1 = block[10]; + block_count -= COM_DATA_SIZE; + tx_fifo[12] = t1; + tx_fifo[13] = sar_trailer; + block += 11; + sar_header = (sar_header + SEQ_INC) & (SEQ_NO | MID); + } else { + broken_cell_mend(COM_DATA_SIZE); + tx_fifo[13] = sar_trailer; + sar_header = (sar_header + SEQ_INC) & (SEQ_NO | MID); + } + } + + if (eom_count != 0) { /*End of message*/ + tx_fifo[0] = atm_header; + tx_fifo[1] = EOM | sar_header; + end_count = msg_count; + sar_trailer = (msg_count + 4) << 26; + + EOM_payload: + if (block_count >= msg_count) { + if (msg_count & 0x4) { + t1 = block[0]; + tx_fifo[1] = t1; + } + block = (vol_u_int *) ((char *) block + msg_count); + switch (msg_count >> 3) { + case 5: + t1 = block[-10]; + t2 = block[-9]; + tx_fifo[1] = t1; + tx_fifo[1] = t2; + case 4: + t1 = block[-8]; + t2 = block[-7]; + tx_fifo[1] = t1; + tx_fifo[1] = t2; + case 3: + t1 = block[-6]; + t2 = block[-5]; + tx_fifo[1] = t1; + tx_fifo[1] = t2; + case 2: + t1 = block[-4]; + t2 = block[-3]; + tx_fifo[1] = t1; + tx_fifo[1] = t2; + case 1: + t1 = block[-2]; + t2 = block[-1]; + tx_fifo[1] = t1; + tx_fifo[1] = t2; + } + msg_count = 0; + } else { + broken_cell_mend(msg_count); + msg_count = 0; + } + + EOM_cs_trailer: + tx_fifo[1] = tcb->tx_cs_header; + switch (end_count) { + case 0: tx_fifo[1] = 0; + case 4: tx_fifo[1] = 0; + case 8: tx_fifo[1] = 0; + case 12: tx_fifo[1] = 0; + case 16: tx_fifo[1] = 0; + case 20: tx_fifo[1] = 0; + case 24: tx_fifo[1] = 0; + case 28: tx_fifo[1] = 0; + case 32: tx_fifo[1] = 0; + case 36: tx_fifo[1] = 0; + } + tx_fifo[13] = sar_trailer; + } + + if (tcb->tx_synch == -1) { + +#ifdef TRACING + printf("Final window sent\n"); +#endif + + sar_header = (sar_header + MID_INC) & MID; + if (sar_header == 0) + sar_header = 1; + tcb->tx_sar_header = sar_header; + rc = NW_SUCCESS; + } else { + +#ifdef TRACING + printf("Window synch at %x\n", msg_count); +#endif + + tcb->tx_sar_header = sar_header; + tcb->tx_p = (u_int *) block; + tcb->tx_block_count = block_count; + tcb->tx_msg_count = msg_count; + rc = NW_SYNCH; + } + return rc; +} + +nw_result tca100_send(nw_ep ep, nw_tx_header_t header, nw_options options) { + nw_result rc; + int i, dev; + nw_ecb_t ecb; + nw_tcb_t tcb; + nw_control_t control; + nw_tx_header_t tx_header, tx_previous; + + dev = NW_DEVICE(header->peer.rem_addr_1); + ecb = &ect[ep]; + tcb = &tct[ep]; + if ((options == NW_URGENT && header->msg_length > + MTU_URGENT[ecb->protocol]) || header->msg_length > MTU[ecb->protocol]) { + rc = NW_BAD_LENGTH; + } else if (tcb->tx_queued_count != 0 || + (ecb->protocol != NW_RAW && + long_tx_count[dev] >= MAX_LONG_TX && + (header->msg_length > SMALL_WINDOW_SIZE || + ecb->protocol == NW_SEQ_PACKET))) { + if (options == NW_URGENT && tcb->tx_queued_count != 0) { + tx_header = delayed_tx_first[dev]; + tx_previous = NULL; + while (tx_header != NULL && tx_header->sender != ep) { + tx_previous = tx_header; + tx_header = tx_header->next; + } + if (tx_previous == NULL) + delayed_tx_first[dev] = header; + else + tx_previous->next = header; + while (header->next != NULL) + header = header->next; + header->next = tx_header; + } else { + if (delayed_tx_first[dev] == NULL) + delayed_tx_first[dev] = header; + else + delayed_tx_last[dev]->next = header; + delayed_tx_last[dev] = header; + } + tcb->tx_queued_count++; + rc = NW_QUEUED; + +#ifdef TRACING + printf("Send enqueued ep %d\n", ep); +#endif + + } else { + + +#ifdef TRACING + printf("Send ep %d\n", ep); +#endif + + ecb->tx_initial = ecb->tx_current = header; + rc = tca100_window_send(dev, ecb, tcb, TRUE); + if (rc == NW_SUCCESS) { + while (header != NULL) { + if (header->buffer != NULL) + nc_buffer_deallocate(ep, header->buffer); + header = header->next; + } + nc_tx_header_deallocate(ecb->tx_initial); + ecb->tx_initial = ecb->tx_current = NULL; + } else { + control = &nw_tx_control[dev][0]; + while (control->ep != 0) + control++; + control->ep = ep; + control->time_out = tick[dev] + BASE_TIME_OUT; + control->retry = 0; + tcb->reply = TCA_SYNCH; + tcb->tx_control = control; + tcb->tx_queued_count++; + if (long_tx_count[dev] + long_rx_count[dev] == 0) + nc_fast_timer_set(dev); + long_tx_count[dev]++; + } + } + return rc; +} + + +nw_result tx_slot_free(int dev, nw_control_t control) { + nw_result rc; + nw_tcb_t tcb; + nw_ecb_t ecb; + nw_tx_header_t tx_header; + nw_ep ep; + + tcb = &tct[control->ep]; + tcb->tx_control = NULL; + tcb->tx_queued_count--; + do { + tx_header = delayed_tx_first[dev]; + if (tx_header == NULL) { + control->ep = 0; + long_tx_count[dev]--; + rc = NW_FAILURE; + } else { + ep = tx_header->sender; + +#ifdef TRACING + printf("Send dequeued ep %d\n", ep); +#endif + + ecb = &ect[ep]; + tcb = &tct[ep]; + ecb->tx_initial = ecb->tx_current = tx_header; + while (tx_header->next != NULL && + tx_header->next->msg_length == 0) { + tx_header = tx_header->next; + } + delayed_tx_first[dev] = tx_header->next; + if (tx_header->next == NULL) + delayed_tx_last[dev] = NULL; + tx_header->next = NULL; + rc = tca100_window_send(dev, ecb, tcb, TRUE); + if (rc == NW_SYNCH) { + control->ep = ep; + tcb->tx_control = control; + tcb->reply = TCA_SYNCH; + control->time_out = tick[dev] + BASE_TIME_OUT; + control->retry = 0; + } + } + } while (rc == NW_SUCCESS); + return rc; +} + +nw_result rx_slot_free(int dev, nw_control_t control) { + nw_result rc; + nw_rx_header_t rx_header; + nw_ep ep; + nw_tcb_t tcb; + + if (control == NULL) { + rc = NW_SUCCESS; + } else { + tct[control->ep].rx_control = NULL; + while ((rx_header = delayed_rx_first[dev]) != NULL && + tick[dev] >= rx_header->time_stamp) { + delayed_rx_first[dev] = rx_header->next; + nc_buffer_deallocate(rx_header->buffer->peer.local_ep, + rx_header->buffer); + ep = rx_header->receiver; + tcb = &tct[ep]; + tcb->rx_sar_header = SSM | (tcb->rx_sar_header & MID); + nc_rx_header_deallocate(rx_header); + } + if (rx_header == NULL) { + delayed_rx_last[dev] = NULL; + control->ep = 0; + long_rx_count[dev]--; + rc = NW_FAILURE; + } else { + delayed_rx_first[dev] = rx_header->next; + if (rx_header->next == NULL) + delayed_rx_last[dev] = NULL; + ep = rx_header->receiver; + tcb = &tct[ep]; + tca100_synch_send(dev, tcb, rx_header->reply); + control->ep = ep; + control->time_out = tick[dev] + BASE_TIME_OUT; + tcb->rx_control = control; + nc_rx_header_deallocate(rx_header); + } + } +} + + +int tca100_poll(int dev) { + vol_u_int *status = &((atm_device_t) devct[dev].addr)->sreg; + vol_u_int *ctl_set = &((atm_device_t) devct[dev].addr)->creg_set; + vol_u_int *rx_counter = &((atm_device_t) devct[dev].addr)->rxcount; + register vol_u_int *rx_fifo = &((atm_device_t) devct[dev].addr)->rxfifo[0]; + register u_int rx_cell_count; + register u_int predicted_atm_header = 0; + register u_int predicted_sar_header; + u_int atm_header, sar_header, predicted_sar_trailer, + cs_header, end_count, cs_pad, rx_cell_total, reply, + block_length, initial_offset; + register vol_u_int *msg; + register int msg_count; + register int next_synch; + register u_int t1, t2; + nw_ecb_t ecb, tx_ecb; + nw_tcb_t new_tcb, tx_tcb; + nw_tcb dummy_tcb_s; + nw_tcb_t tcb = &dummy_tcb_s; + nw_control_t control; + nw_buffer_t buffer; + nw_protocol protocol; + nw_ep lep, rep; + nw_delivery delivery_type = NW_RECEIVE; + nw_rx_header_t rx_header; + nw_tx_header_t tx_header; + int i; + u_int tx_seqno, rx_seqno, tx_count, rx_count; + + rx_cell_total = 0; + while ((rx_cell_count = *rx_counter & RX_COUNTER_MASK) != 0) { + rx_cell_total += rx_cell_count; + while (rx_cell_count-- > 0) { + atm_header = rx_fifo[0]; /*Check ATM header and SAR header*/ + sar_header = (rx_fifo[1] & SAR_HEADER_MASK); + if (atm_header != predicted_atm_header) { + /*Must be cell from a different connection*/ + if (atm_header & ~(ATM_VPVC_MASK | ATM_HEADER_RSV_BITS)) { + atm_header_error: + tca_ec[ATM_HEADER]++; + if (tca100_verbose) + printf("ATM header error %x\n", atm_header); + discard_cell: + *((char *) rx_fifo) = 0; + delivery_type = NW_RECEIVE; + continue; + } else { + t1 = (atm_header & ATM_VPVC_MASK) >> ATM_VPVC_SHIFT; + new_tcb = &tct[t1]; + ecb = &ect[t1]; + + /*Switch cached connection*/ + if (new_tcb->rx_sar_header == 0) + goto atm_header_error; + tcb->rx_sar_header = predicted_sar_header; + tcb->rx_p = (u_int *) msg; + tcb->rx_count = msg_count; + tcb->rx_next_synch = next_synch; + predicted_atm_header = atm_header; + tcb = new_tcb; + predicted_sar_header = tcb->rx_sar_header; + msg = tcb->rx_p; + msg_count = tcb->rx_count; + next_synch = tcb->rx_next_synch; + } + } + + if (sar_header != predicted_sar_header) { + if ((sar_header ^ predicted_sar_header) == EOM && + ((predicted_sar_header & BOM) || msg_count <= EOM_DATA_SIZE)) { + /*Difference on end of message bit only*/ + predicted_sar_header = sar_header; + } else if (sar_header == SSM) { /*MID 0*/ + cs_header = rx_fifo[2]; + t1 = rx_fifo[3]; + if (cs_header == HTONL(8) && t1 == HTONL(NW_SYNCHRONIZATION)) { + reply = rx_fifo[4]; /*Synch cell*/ + if (rx_fifo[5] != cs_header) + goto cs_header_error; + cs_pad = rx_fifo[6]; + t1 = rx_fifo[7]; + t2 = rx_fifo[8]; + cs_pad |= t1; + cs_pad |= t2; + t1 = rx_fifo[9]; + t2 = rx_fifo[10]; + cs_pad |= t1; + cs_pad |= t2; + t1 = rx_fifo[11]; + t2 = rx_fifo[12]; + cs_pad |= t1; + cs_pad |= t2; + t1 = rx_fifo[13]; + if (cs_pad) + goto cs_trailer_error; + if ((t1 & SAR_TRAILER_MASK) != SYNCH_SEGMENT_TRAILER) + goto sar_trailer_error; + if (tcb->tx_control == NULL) { + tca_ec[SYNCH_ERROR]++; + if (tca100_verbose) + printf("Synch error %x\n", ntohl(reply)); + } else { + tcb->reply = ntohl(reply); + +#ifdef TRACING + printf("Received synch ep %d %x\n", ecb->id, tcb->reply); +#endif + + } + continue; + } else if (t1 == HTONL(NW_URGENT)) { /*Urgent cell*/ + delivery_type = NW_RECEIVE_URGENT; + goto cs_header_check; + } else { /*Bad segment*/ + goto sar_header_error; + } + } else if (!(sar_header & ATM_HEADER_CRC_SYNDROME) && + (sar_header & BOM) && (sar_header & SEQ_NO) == 0) { + if ((sar_header & MID) == (predicted_sar_header & MID)) { + /*Retransmission*/ + if (tcb->rx_control != NULL) { + tcb->rx_control->ep = 0; + long_rx_count[dev]--; + } + nc_buffer_deallocate(tcb->rx_buffer->peer.local_ep, + tcb->rx_buffer); + predicted_sar_header = sar_header; + tca_ec[RX_RETRANSMISSION]++; + if (tca100_verbose) + printf("Receiving retransmission ep %d sar %x\n", + ecb->id, sar_header); + } else if (predicted_sar_header & BOM) { + /*Sequence number error*/ + if (tca100_verbose) + printf("Sequence error ep %d pred %x real %x\n", ecb->id, + predicted_sar_header, sar_header); + if (ecb->protocol == NW_SEQ_PACKET) { + reply = 0xffff0000 | TCA_SEQ | (predicted_sar_header & MID); + tca100_synch_send(dev, tcb, reply); + tca_ec[SEQ_ERROR]++; + goto discard_cell; + } else { + predicted_sar_header = sar_header; + } + } else { + goto sar_header_error; /*Badly out of synch*/ + } + } else { /*Cell loss*/ + + sar_header_error: + if (!(predicted_sar_header & BOM)) { + rx_slot_free(dev, tcb->rx_control); + nc_buffer_deallocate(tcb->rx_buffer->peer.local_ep, + tcb->rx_buffer); + predicted_sar_header = SSM | (predicted_sar_header & MID); + } + tca_ec[SAR_HEADER]++; + if (tca100_verbose) + printf("SAR header error ep %d pred %x real %x\n", ecb->id, + predicted_sar_header, sar_header); + goto discard_cell; + } + } + + if ((predicted_sar_header & SEG_TYPE) == COM) { + /*Continuation of message*/ + if (msg_count <= next_synch) { + if (msg_count == next_synch && + msg_count >= CONTINUATION_WINDOW_SIZE) { + reply = (msg_count << 16) | TCA_ACK | (predicted_sar_header & MID); + tca100_synch_send(dev, tcb, reply); + if (msg_count > (CONTINUATION_WINDOW_SIZE + FINAL_WINDOW_SIZE)) { + next_synch = msg_count - CONTINUATION_WINDOW_SIZE; + } else if (ecb->protocol == NW_SEQ_PACKET) { + next_synch = 0; + } else { + next_synch = -1; + } + tcb->rx_control->time_out = tick[dev] + BASE_TIME_OUT; + } else { + rx_slot_free(dev, tcb->rx_control); + nc_buffer_deallocate(tcb->rx_buffer->peer.local_ep, + tcb->rx_buffer); + predicted_sar_header = SSM | (predicted_sar_header & MID); + tca_ec[FRAME_ERROR]++; + if (tca100_verbose) + printf("Frame error ep %d\n", ecb->id); + goto discard_cell; + } + } + t1 = rx_fifo[2]; + t2 = rx_fifo[3]; + msg[0] = t1; + msg[1] = t2; + t1 = rx_fifo[4]; + t2 = rx_fifo[5]; + msg[2] = t1; + msg[3] = t2; + t1 = rx_fifo[6]; + t2 = rx_fifo[7]; + msg[4] = t1; + msg[5] = t2; + t1 = rx_fifo[8]; + t2 = rx_fifo[9]; + msg[6] = t1; + msg[7] = t2; + t1 = rx_fifo[10]; + t2 = rx_fifo[11]; + msg[8] = t1; + msg[9] = t2; + t1 = rx_fifo[12]; + t2 = rx_fifo[13]; + msg[10] = t1; + if ((t2 & SAR_TRAILER_MASK) != FULL_SEGMENT_TRAILER) { + t1 = t2; + goto sar_trailer_error; + } + predicted_sar_header = (predicted_sar_header + SEQ_INC) & + (SEQ_NO | MID); + msg_count -= COM_DATA_SIZE; + msg += 11; + + } else if ((predicted_sar_header & BOM) != 0) { + cs_header = rx_fifo[2]; + + cs_header_check: + block_length = msg_count = (((cs_header >> 8) & 0xff00) | + (cs_header >> 24)); + protocol = cs_header & 0x00ff; + if (protocol == NW_RAW || protocol == NW_SEQ_PACKET) { + lep = ecb->conn->peer.local_ep; + rep = ecb->conn->peer.remote_ep; + if (delivery_type == NW_RECEIVE) + initial_offset = 0; + else + initial_offset = 4; + } else { + t1 = rx_fifo[3]; + block_length -= 4; + lep = (t1 >> 8) & 0xff00 | t1 >> 24; + rep = (t1 & 0xff00) >> 8 | (t1 & 0x00ff) << 8; + if (delivery_type == NW_RECEIVE) + initial_offset = 4; + else + initial_offset = 8; + } + if (protocol != ecb->protocol || (protocol == NW_DATAGRAM) || + (protocol == NW_LINE && ect[lep].protocol != NW_DATAGRAM) || + ((predicted_sar_header & 0x00ff) << 8) != (cs_header & 0xff00) || + ((delivery_type != NW_RECEIVE) && + msg_count - initial_offset > MTU_URGENT[protocol]) || + msg_count > MTU[protocol] || (msg_count & 0x3)) { + + cs_header_error: + if ((protocol != NW_RAW && msg_count > SMALL_WINDOW_SIZE) || + protocol == NW_SEQ_PACKET) { + reply = 0xffff0000 | TCA_NAK | (predicted_sar_header & MID); + tca100_synch_send(dev, tcb, reply); + } + tca_ec[CS_HEADER]++; + if (tca100_verbose) + printf("CS header error ep %d sar %x cs %x\n", ecb->id, + predicted_sar_header, cs_header); + goto discard_cell; + } + buffer = nc_buffer_allocate(lep, sizeof(nw_buffer_s) + block_length); + if (buffer == NULL) { + if ((protocol != NW_RAW && msg_count > SMALL_WINDOW_SIZE) || + protocol == NW_SEQ_PACKET) { + reply = 0xffff0000 | TCA_OVR | (predicted_sar_header & MID); + tca100_synch_send(dev, tcb, reply); + } + tca_ec[OVERRUN_ERROR]++; + if (tca100_verbose) + printf("Overrun error ep %d\n", ecb->id); + goto discard_cell; + } + if (protocol == NW_RAW) { + next_synch = -1; + } else if (msg_count > SMALL_WINDOW_SIZE) { + reply = (msg_count << 16) | TCA_ACK | (predicted_sar_header & MID); + if (long_rx_count[dev] >= MAX_LONG_RX) { + rx_header = nc_rx_header_allocate(); + if (rx_header == NULL) { + nc_buffer_deallocate(lep, buffer); + tca_ec[OVERRUN_ERROR]++; + goto discard_cell; + } + rx_header->buffer = buffer; + rx_header->receiver = ecb->id; + rx_header->reply = reply; + rx_header->time_stamp = tick[dev] + DELAYED_TIME_OUT; + rx_header->next = NULL; + if (delayed_rx_last[dev] == NULL) + delayed_rx_first[dev] = rx_header; + else + delayed_rx_last[dev]->next = rx_header; + delayed_rx_last[dev] = rx_header; + } else { + tca100_synch_send(dev, tcb, reply); + control = &nw_rx_control[dev][0]; + while (control->ep != 0) + control++; + control->ep = ecb->id; + control->time_out = tick[dev] + BASE_TIME_OUT; + tcb->rx_control = control; + if (long_rx_count[dev] + long_tx_count[dev] == 0) + nc_fast_timer_set(dev); + long_rx_count[dev]++; + } + if (msg_count > INITIAL_WINDOW_SIZE + FINAL_WINDOW_SIZE) + next_synch = msg_count - INITIAL_WINDOW_SIZE; + else if (protocol == NW_SEQ_PACKET) + next_synch = 0; + else + next_synch = -1; + } else if (protocol == NW_SEQ_PACKET) { + next_synch = 0; + } else { + next_synch = -1; + } + msg = (vol_u_int *) ((char *) buffer + sizeof(nw_buffer_s)); + tcb->rx_cs_header = cs_header; + tcb->rx_buffer = buffer; + buffer->buf_next = NULL; + buffer->msg_seqno = sar_header & MID; + buffer->block_offset = sizeof(nw_buffer_s); + buffer->block_length = block_length; + buffer->peer.rem_addr_1 = ecb->conn->peer.rem_addr_1; + buffer->peer.rem_addr_2 = ecb->conn->peer.rem_addr_2; + buffer->peer.local_ep = lep; + buffer->peer.remote_ep = rep; + + if ((predicted_sar_header & EOM) == 0) { /*BOM*/ + if (initial_offset == 0) { + t1 = rx_fifo[3]; + t2 = rx_fifo[4]; + msg[0] = t1; + msg[1] = t2; + msg += 2; + } else { + msg[0] = rx_fifo[4]; + msg++; + } + t1 = rx_fifo[5]; + t2 = rx_fifo[6]; + msg[0] = t1; + msg[1] = t2; + t1 = rx_fifo[7]; + t2 = rx_fifo[8]; + msg[2] = t1; + msg[3] = t2; + t1 = rx_fifo[9]; + t2 = rx_fifo[10]; + msg[4] = t1; + msg[5] = t2; + t1 = rx_fifo[11]; + t2 = rx_fifo[12]; + msg[6] = t1; + t1 = rx_fifo[13]; + msg[7] = t2; + if ((t1 & SAR_TRAILER_MASK) != FULL_SEGMENT_TRAILER) + goto sar_trailer_error; + msg_count -= BOM_DATA_SIZE; + msg += 8; + predicted_sar_header = (predicted_sar_header + SEQ_INC) & + (SEQ_NO | MID); + + } else { /*SSM*/ + end_count = msg_count + 4; + predicted_sar_trailer = (msg_count + 8) << 26; + if (delivery_type != NW_RECEIVE) { + msg[0] = NW_URGENT; + msg++; + } + msg_count -= initial_offset; + goto EOM_payload; + } + } else { /*EOM*/ + end_count = msg_count; + predicted_sar_trailer = (msg_count + 4) << 26; + + EOM_payload: + if (msg_count & 0x4) { + msg[0] = rx_fifo[2]; + } + msg = (vol_u_int *) ((char *) msg + msg_count); + /*Fall-through the cases is intentional*/ + switch (msg_count >> 3) { + case 5: + t1 = rx_fifo[2]; + t2 = rx_fifo[2]; + msg[-10] = t1; + msg[-9] = t2; + case 4: + t1 = rx_fifo[2]; + t2 = rx_fifo[2]; + msg[-8] = t1; + msg[-7] = t2; + case 3: + t1 = rx_fifo[2]; + t2 = rx_fifo[2]; + msg[-6] = t1; + msg[-5] = t2; + case 2: + t1 = rx_fifo[2]; + t2 = rx_fifo[2]; + msg[-4] = t1; + msg[-3] = t2; + case 1: + t1 = rx_fifo[2]; + t2 = rx_fifo[2]; + msg[-2] = t1; + msg[-1] = t2; + } + + /*CS trailer should be equal to the CS header, followed by + padding zeros*/ + cs_pad = (rx_fifo[2] != tcb->rx_cs_header); + /*Fall-through the cases is intentional*/ + t1 = t2 = 0; + switch (end_count) { + case 0: + t1 = rx_fifo[2]; + case 4: + t2 = rx_fifo[2]; + cs_pad |= t1; + case 8: + t1 = rx_fifo[2]; + cs_pad |= t2; + case 12: + t2 = rx_fifo[2]; + cs_pad |= t1; + case 16: + t1 = rx_fifo[2]; + cs_pad |= t2; + case 20: + t2 = rx_fifo[2]; + cs_pad |= t1; + case 24: + t1 = rx_fifo[2]; + cs_pad |= t2; + case 28: + t2 = rx_fifo[2]; + cs_pad |= t1; + case 32: + t1 = rx_fifo[2]; + cs_pad |= t2; + case 36: + t2 = rx_fifo[2]; + cs_pad |= t1; + cs_pad |= t2; + } + t1 = rx_fifo[13]; + if (cs_pad != 0) { + /*Errors in CS trailer or pad*/ + cs_trailer_error: + tca_ec[CS_TRAILER]++; + if (tca100_verbose) + printf("CS trailer error ep %d hd %x pad %x\n", ecb->id, + tcb->rx_cs_header, cs_pad); + goto trailer_error; + + } else if ((t1 & SAR_TRAILER_MASK) != predicted_sar_trailer) { + /*Error in SAR trailer or framing*/ + sar_trailer_error: + tca_ec[SAR_TRAILER]++; + if (tca100_verbose) + printf("SAR trailer error ep %d pred %x real %x\n", ecb->id, + predicted_sar_trailer, t1); + goto trailer_error; + + } else if (!nc_deliver_result(tcb->rx_buffer->peer.local_ep, + delivery_type, (int) tcb->rx_buffer)) { + tca_ec[DELIVERY_ERROR]++; + if (tca100_verbose) + printf("Delivery error ep %d\n", ecb->id); + + trailer_error: + if (next_synch >= 0 && !(t1 & HEADER_CRC_ERROR)) { + reply = (msg_count << 16) | TCA_NAK | (predicted_sar_header & MID); + tca100_synch_send(dev, tcb, reply); + } + rx_slot_free(dev, tcb->rx_control); + nc_buffer_deallocate(tcb->rx_buffer->peer.local_ep, + tcb->rx_buffer); + predicted_sar_header = SSM | (predicted_sar_header & MID); + delivery_type = NW_RECEIVE; + } else { + +#ifdef TRACING + printf("Received correctly ep %d\n", ecb->id); +#endif + + if (next_synch == 0) { + reply = TCA_ACK | (predicted_sar_header & MID); + tca100_synch_send(dev, tcb, reply); + } + rx_slot_free(dev, tcb->rx_control); + if (delivery_type != NW_RECEIVE) { + delivery_type = NW_RECEIVE; + predicted_sar_header = SSM | (predicted_sar_header & MID); + } else { + predicted_sar_header = (predicted_sar_header + MID_INC) & MID; + if (predicted_sar_header == 0) + predicted_sar_header = 1; + predicted_sar_header |= SSM; + } + } + } + } + + control = &nw_tx_control[dev][0]; + for (i = 0; i < MAX_LONG_TX; i++) { + if (control->ep != 0 && tct[control->ep].reply != TCA_SYNCH) { + tx_ecb = &ect[control->ep]; + tx_tcb = &tct[control->ep]; + rx_seqno = tx_tcb->reply & MID; + tx_seqno = tx_tcb->tx_sar_header & MID; + rx_count = tx_tcb->reply >> 16; + tx_count = tx_tcb->tx_synch; + reply = tx_tcb->reply & TCA_SYNCH; + if (reply == TCA_ACK) { + if (rx_seqno == tx_seqno && rx_count == tx_count) { + if (rx_count == 0) { +#ifdef TRACING + printf("Received final ack ep %d\n", tx_ecb->id); +#endif + + tx_seqno = (tx_seqno + MID_INC) & MID; + if (tx_seqno == 0) + tx_seqno = 1; + tx_tcb->tx_sar_header = tx_seqno; + tx_slot_free(dev, control); + tx_tcb->reply = NW_SUCCESS; + nc_deliver_result(tx_ecb->id, NW_SEND, NW_SUCCESS); + } else { + if (tca100_window_send(dev, tx_ecb, tx_tcb, + FALSE) == NW_SUCCESS) { + nc_deliver_result(control->ep, NW_SEND, NW_SUCCESS); + tx_tcb->reply = NW_SUCCESS; + tx_slot_free(dev, control); + } else { + control->time_out = tick[dev] + BASE_TIME_OUT; + tx_tcb->reply = TCA_SYNCH; + } + } + } else { + goto synch_error; + } + } else if (reply == TCA_OVR) { + if (rx_seqno == tx_seqno && rx_count == 0xffff && + ((int) tx_ecb->tx_initial->msg_length - + (int) tx_tcb->tx_synch) <= (int) SMALL_WINDOW_SIZE) { + nc_deliver_result(control->ep, NW_SEND, NW_OVERRUN); + tx_tcb->reply = NW_OVERRUN; + tx_slot_free(dev, control); + } else { + goto synch_error; + } + } else if (reply == TCA_NAK) { + if (rx_seqno == tx_seqno && + (rx_count == tx_count || (rx_count == 0xffff && + ((int) tx_ecb->tx_initial->msg_length - + (int) tx_tcb->tx_synch) <= (int) SMALL_WINDOW_SIZE))) { + if (++control->retry < MAX_RETRY) { + if (tca100_verbose) + printf("Sending retransmission ep %d\n", tx_ecb->id); + if (tca100_window_send(dev, tx_ecb, tx_tcb, + TRUE) == NW_SUCCESS) { + nc_deliver_result(control->ep, NW_SEND, NW_SUCCESS); + tx_tcb->reply = NW_SUCCESS; + tx_slot_free(dev, control); + } else { + control->time_out = tick[dev] + BASE_TIME_OUT; + tx_tcb->reply = TCA_SYNCH; + } + tca_ec[TX_RETRANSMISSION]++; + } else { + nc_deliver_result(control->ep, NW_SEND, NW_FAILURE); + tx_tcb->reply = NW_FAILURE; + tx_slot_free(dev, control); + } + } else { + goto synch_error; + } + } else if (reply == TCA_SEQ) { + if (rx_count == 0xffff && tx_ecb->protocol == NW_SEQ_PACKET && + ((int) tx_ecb->tx_initial->msg_length - + (int) tx_tcb->tx_synch) <= (int) SMALL_WINDOW_SIZE && + rx_seqno == ((((tx_seqno + MID_INC) & MID) == 0) ? + 1 : tx_seqno + MID_INC)) { + tx_tcb->tx_sar_header = rx_seqno; + if (tca100_window_send(dev, tx_ecb, tx_tcb, + TRUE) == NW_SUCCESS) { + nc_deliver_result(control->ep, NW_SEND, NW_SUCCESS); + tx_tcb->reply = NW_SUCCESS; + tx_slot_free(dev, control); + } else { + control->time_out = tick[dev] + BASE_TIME_OUT; + tx_tcb->reply = TCA_SYNCH; + } + tca_ec[TX_RETRANSMISSION]++; + if (tca100_verbose) + printf("Sending seq retransmission ep %d\n", tx_ecb->id); + } else { + goto synch_error; + } + } else { + synch_error: + tca_ec[SYNCH_ERROR]++; + tx_tcb->reply = NW_FAILURE; + if (tca100_verbose) + printf("Synch error\n"); + } + } + control++; + } + } + *status = ~(RX_COUNT_INTR | RX_EOM_INTR | RX_TIME_INTR); + tcb->rx_sar_header = predicted_sar_header; + tcb->rx_p = (u_int *) msg; + tcb->rx_count = msg_count; + tcb->rx_next_synch = next_synch; + *ctl_set = RX_COUNT_INTR; + return rx_cell_total; +} + + + +void tca100_timer_sweep(int dev) { + int i, rt; + u_int reply; + nw_control_t control; + nw_ecb_t ecb; + nw_tcb_t tcb; + nw_tx_header_t tx_header; + nw_rx_header_t rx_header; + + tick[dev]++; + control = &nw_rx_control[dev][0]; + for (i = 0; i < MAX_LONG_RX; i++) { + if (control->ep != 0 && control->time_out < tick[dev]) { + rx_slot_free(dev, control); + tcb = &tct[control->ep]; + nc_buffer_deallocate(tcb->rx_buffer->peer.local_ep, tcb->rx_buffer); + tcb->rx_sar_header = SSM | (tcb->rx_sar_header & MID); + } + control++; + } + control = &nw_tx_control[dev][0]; + for (i = 0; i < MAX_LONG_TX; i++) { + if (control->ep != 0 && control->time_out < tick[dev]) { + ecb = &ect[control->ep]; + tcb = &tct[control->ep]; + if (++control->retry < MAX_RETRY) { + if (control->retry == 1) + rt = ( /* random() */ + devct[dev].local_addr_2) & 0x000f; + else + rt = ( /* random() */ + devct[dev].local_addr_1 + + devct[dev].local_addr_2) & 0x00ff; + control->time_out = tick[dev] + BASE_TIME_OUT + rt; + tca100_window_send(dev, ecb, tcb, TRUE); + tca_ec[TX_RETRANSMISSION]++; + } else { + nc_deliver_result(control->ep, NW_SEND, NW_TIME_OUT); + tx_slot_free(dev, control); + } + } + control++; + } + if (long_tx_count[dev] + long_rx_count[dev] > 0) + nc_fast_timer_set(dev); + else + tick[dev] = 0; +} + +nw_buffer_t tca100_rpc(nw_ep ep, nw_tx_header_t header, nw_options options) { + nw_result rc; + nw_buffer_t buf; + nw_ecb_t ecb; + nw_tcb_t tcb; + nw_rx_header_t rx_header; + int dev, poll_time, ncells; + + tcb = &tct[ep]; + ecb = &ect[header->peer.local_ep]; + dev = NW_DEVICE(header->peer.rem_addr_1); + if ((rc = tca100_send(ep, header, options)) == NW_BAD_LENGTH) { + buf = NW_BUFFER_ERROR; + } else if (rc == NW_QUEUED) { + buf = NULL; + } else { + poll_time = 0; + if (rc == NW_SYNCH) { + while (tcb->reply == TCA_SYNCH && poll_time < POLL_LIMIT) { + ncells = tca100_poll(dev); + if (ncells == 0) + poll_time += POLL_IDLE_TIME; + else + poll_time += ncells * POLL_CELL_TIME; + } + } + if (tcb->reply != NW_SUCCESS) { + buf = NW_BUFFER_ERROR; + } else { + while (ecb->rx_first == NULL && poll_time < POLL_LIMIT) { + ncells = tca100_poll(dev); + if (ncells == 0) + poll_time += POLL_IDLE_TIME; + else + poll_time += ncells * POLL_CELL_TIME; + } + if (ecb->rx_first == NULL) { + buf = NULL; + } else { + rx_header = ecb->rx_first; + buf = rx_header->buffer; + ecb->rx_first = rx_header->next; + if (ecb->rx_first == NULL) + ecb->rx_last = NULL; + nc_rx_header_deallocate(rx_header); + } + } + } + + return buf; +} + + + + + + + + + diff --git a/chips/tca100_if.h b/chips/tca100_if.h new file mode 100644 index 0000000..41183ea --- /dev/null +++ b/chips/tca100_if.h @@ -0,0 +1,89 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +/*** TCA 100 ATM NETWORK INTERFACE ***/ + +#ifndef STUB +#include +#include +#include +#else +#include "nc.h" +#include "spans.h" +#include "tca100.h" +#endif + +typedef struct { + nw_ep ep; + int time_out; + int retry; +} nw_control_s, *nw_control_t; + + +typedef struct { + u_int rx_sar_header; + u_int rx_cs_header; + u_int *rx_p; + u_int rx_count; + u_int rx_next_synch; + nw_buffer_t rx_buffer; + nw_control_t rx_control; + u_int tx_atm_header; + u_int tx_sar_header; + u_int tx_cs_header; + u_int *tx_p; + u_int tx_msg_count; + u_int tx_block_count; + u_int tx_synch; + u_int tx_queued_count; + nw_control_t tx_control; + u_int reply; +} nw_tcb, *nw_tcb_t; + +extern nw_tcb tct[MAX_EP]; + +extern nw_dev_entry_s tca100_entry_table; + +extern nw_result tca100_initialize(int dev); + +extern nw_result tca100_status(int dev); + +extern void tca100_timer_sweep(int dev); + +extern int tca100_poll(int dev); + +extern nw_result tca100_send(nw_ep ep, nw_tx_header_t header, + nw_options options); + +extern nw_buffer_t tca100_rpc(nw_ep ep, nw_tx_header_t header, + nw_options options); + + + + + + + diff --git a/chips/vs42x_rb.h b/chips/vs42x_rb.h new file mode 100644 index 0000000..82b89b0 --- /dev/null +++ b/chips/vs42x_rb.h @@ -0,0 +1,267 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: vs42x_rb.h + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 5/91 + * + * This file contains definitions for the VS42X-RB Storage + * controller, which includes a Disk controller and a + * SCSI controller. + */ + +#ifndef _VS42X_RB_H_ +#define _VS42X_RB_H_ + +/* + * Phys addresses for the Vax3100 + */ +#define VAX3100_STC_BASE 0x200c0000 +#define VAX3100_STC_RAM_COMPAT 0x200d0000 +#define VAX3100_STC_RAM 0x202d0000 + +#define VAX3100_STC_HDC9224 0x00000000 /* offsets from BASE */ +#define VAX3100_STC_5380_A 0x00000080 +#define VAX3100_STC_5380_B 0x00000180 +#define VAX3100_STC_DMAREG_A 0x000000a0 +#define VAX3100_STC_DMAREG_B 0x000001a0 +#define VAX3100_STC_RAM_MODE 0x000000e0 + +#define VAX3100_STC_DMAREG_OFF (0xa0-0x80) /* offset from 5380 */ + +#define SCI_REG_SIZE 512 + +/* + * RAM Buffer for this storage system + */ +#define SCI_RAM_SIZE 128*1024 +#define SCI_RAM_COMPATSIZE 32*1024 +#define SCI_RAM_EXPMODE 0x01 /* char-size mode register */ + +/* + * DMA controller for the SCSI subsystem + * (Defines for the NCR 5380 are elsewhere) + */ + +typedef struct { + unsigned int sci_dma_adr; /* +000000a0 */ + char pad0[0xc0-0xa0-4]; + unsigned int sci_dma_count; /* +000000c0 */ + unsigned int sci_dma_dir; /* +000000c4 */ + char pad1[0xe0-0xc4-4]; + unsigned char sci_dma_rammode;/* +000000e0 */ +} *sci_dmaregs_t; + +#define SCI_DMADR_PUT(ptr,adr) (ptr)->sci_dma_adr = (unsigned)(adr) & SCI_DMA_COUNT_MASK; +#define SCI_DMADR_GET(ptr,adr) (adr) = (ptr)->sci_dma_adr; + +#define SCI_DMA_COUNT_MASK 0x0001ffff +#define SCI_TC_GET(ptr,cnt) {\ + (cnt) = (ptr)->sci_dma_count;\ + if ((cnt) & 0x00010000) (cnt) |= ~SCI_DMA_COUNT_MASK;\ + (cnt) = -(cnt);\ + } +#define SCI_TC_PUT(ptr,cnt) (ptr)->sci_dma_count = -(cnt); + +#define SCI_DMA_DIR_READ 0x00000001 +#define SCI_DMA_DIR_WRITE 0x00000000 + +/* + * Disk controller subsytem (ST506/412), uses a + * HDC 9224 Universal Disk Controller chip and + * addresses up to 4 disks. + */ +typedef struct { + unsigned char hdc_rap; /* rw: reg addres ptr */ + char pad0[3]; + unsigned char hdc_cmd; /* w: controller command */ +#define hdc_status hdc_cmd /* r: interrupt status */ + char pad1[3]; +} *sci_hdcregs_t; + +/* + * Register Address Pointer + */ +#define UDC_DMA7 0 /* rw: DMA address bits 7:0 */ +#define UDC_DMA15 1 /* rw: DMA address bits 15:8 */ +#define UDC_DMA23 2 /* rw: DMA address bits 23:16 */ +#define UDC_DSECT 3 /* rw: desired sector */ +#define UDC_DHEAD 4 /* wo: desired head */ +#define UDC_CHEAD 4 /* ro: current head */ +#define UDC_DCYL 5 /* wo: desired cylinder */ +#define UDC_CCYL 5 /* ro: current cylinder */ +#define UDC_SCNT 6 /* wo: sector count */ +#define UDC_RTCNT 7 /* wo: retry count */ +#define UDC_MODE 8 /* wo: operating mode */ +#define UDC_CSTAT 8 /* ro: chip status */ +#define UDC_TERM 9 /* wo: termination conditions */ +#define UDC_DSTAT 9 /* ro: drive status */ +#define UDC_DATA 10 /* rw: data */ + +/* + * Controller Commands + */ +#define HDCC_RESET 0x00 + +#define HDCC_SET_REGP 0x40 /* low 4 bits is regnum */ + +#define HDCC_DESELECT 0x01 + +#define HDCC_SELECT 0x20 +# define HDCC_SELECT_IDMASK 0x03 +# define HDCC_SELECT_DR_HD 0x04 +# define HDCC_SELECT_DR_SD 0x08 +# define HDCC_SELECT_DR_DD 0x0c + +#define HDCC_RESTORE_HD 0x03 + +#define HDCC_RESTORE_RX 0x02 + +#define HDCC_STEP 0x04 +# define HDCC_STEP_OUT 0x02 +# define HDCC_STEP_SKWAIT 0x01 + +#define HDCC_POLL 0x10 /* low 4 bits is drive mask */ + +#define HDCC_SEEK 0x50 +# define HDCC_SEEK_STEP 0x04 +# define HDCC_SEEK_SKWAIT 0x02 +# define HDCC_SEEK_VFY 0x01 + +#define HDCC_FORMAT 0x60 +# define HDCC_FORMAT_DDMARK 0x10 + +#define HDCC_READ_T 0x5a +# define HDCC_READ_XDATA 0x01 + +#define HDCC_READ_P 0x58 + +#define HDCC_READ_L 0x5c +# define HDCC_READ_L_BYPASS 0x02 + +#define HDCC_WRITE_P 0x80 +# define HDCC_WRITE_BYPASS 0x40 +# define HDCC_WRITE_DDMARK 0x10 + +#define HDCC_WRITE_L 0xa0 + +/* + * Interrupt Status Register + */ +#define HDCI_BADSECT 0x01 +#define HDCI_OVRUN 0x02 +#define HDCI_RDYCHNG 0x04 +#define HDCI_TERMCOD 0x18 +# define HDC_T_SUCCESS 0x00 +# define HDC_T_EREAD_ID 0x08 +# define HDC_T_EVFY 0x10 +# define HDC_T_EXFER 0x18 +#define HDCI_DONE 0x20 +#define HDCI_DMAREQ 0x40 +#define HDCI_INT 0x80 /* interrupt pending */ + +/* + * Desired/Current Head + */ +#define UDC_HEAD_HMASK 0x0f /* desired head no */ +#define UDC_HEAD_CMASK 0x70 /* desired cyl 10:8 */ +#define UDC_HEAD_BADSEC 0x80 + +/* + * Sector Count + */ +#define HDC_MAXDATA 256*512 + +/* + * Retry Count + */ +#define UDC_RTCNT_MASK 0xf0 +#define UDC_RTCNT_RXDIS 0x08 /* mbz */ +#define UDC_RTCNT_INVRDY 0x04 +#define UDC_RTCNT_MOTOR 0x02 +#define UDC_RTCNT_LOSPEED 0x01 + +/* + * Mode + */ +#define UDC_MODE_HD 0x80 /* hard disk mode mb1 */ +#define UDC_MODE_CHKCOD 0x60 /* error checkin code */ +# define UDC_MODE_CRC 0x00 +# define UDC_MODE_EECC 0x20 /* NA */ +# define UDC_MODE_IECC 0x40 /* hard disks internal 32 ecc */ +# define UDC_MODE_AECC 0x60 /* NA */ +#define UDC_MODE_DENS 0x10 /* mbz */ +#define UDC_MODE_SRATE 0x07 +# define UDC_MODE_RATE_HD 0x00 /* hard disk */ +# define UDC_MODE_RATE_DD 0x01 /* double den rx23 */ +# define UDC_MODE_RATE_SD 0x02 /* single den rz23 */ +# define UDC_MODE_RATE_RD 0x06 /* restore drive */ + +#define UDC_MODE_RX23_DD 0x81 +#define UDC_MODE_RX23_SD 0x82 +#define UDC_MODE_RDxx 0xc0 +#define UDC_MODE_RD_RESTORE 0xc6 + +/* + * Status + */ +#define UDC_CSTAT_RETRIED 0x80 +#define UDC_CSTAT_ECC 0x40 +#define UDC_CSTAT_ECC_ERR 0x20 +#define UDC_CSTAT_DELDATA 0x10 +#define UDC_CSTAT_SYN_ERR 0x08 +#define UDC_CSTAT_COMP_ERR 0x04 +#define UDC_CSTAT_SELMASK 0x03 +# define UDC_CSTAT_SELHD0 0x00 +# define UDC_CSTAT_SELHD1 0x01 +# define UDC_CSTAT_SELRX 0x02 +# define UDC_CSTAT_SELHD2 0x03 + +/* + * Termination + */ +#define UDC_TERM_CRCPRE 0x80 /* mb1 */ +#define UDC_TERM_IDONE 0x20 +#define UDC_TERM_DELDAT 0x10 +#define UDC_TERM_STAT3 0x08 /* mbz */ +#define UDC_TERM_WPROT 0x04 +#define UDC_TERM_IRDCHNG 0x02 +#define UDC_TERM_WFLT 0x01 + +/* + * Drive status + */ +#define UDC_DSTAT_SELACK 0x80 +#define UDC_DSTAT_INDEX 0x40 +#define UDC_DSTAT_SKCOM 0x20 +#define UDC_DSTAT_TRK0 0x10 +#define UDC_DSTAT_STAT3 0x08 /* mbz */ +#define UDC_DSTAT_WPROT 0x04 +#define UDC_DSTAT_READY 0x02 +#define UDC_DSTAT_WFLT 0x01 + + +#endif _VS42X_RB_H_ diff --git a/chips/xcfb_hdw.c b/chips/xcfb_hdw.c new file mode 100644 index 0000000..b2c67d6 --- /dev/null +++ b/chips/xcfb_hdw.c @@ -0,0 +1,230 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: xcfb_hdw.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 1/92 + * + * Driver for the MAXine Color Frame Buffer Display, + * hardware-level operations. + */ + +#include +#if (NXCFB > 0) + +#include + +#include +#include +#include + +#include +#include +#include + +#ifdef MAXINE + +#include + +#include +#include +#define enable_interrupt(s,o,x) (*tc_enable_interrupt)(s,o,x) + +#else /* MAXINE */ +You must say the magic words to get the coockies: +#define enable_interrupt(slot,on,xx) +#define IMS332_ADDRESS +#define VRAM_OFFSET +#define IMS332_RESET_ADDRESS +#endif /* MAXINE */ + +typedef pm_softc_t xcfb_softc_t; + + +/* + * Definition of the driver for the auto-configuration program. + */ + +int xcfb_probe(), xcfb_intr(); +static void xcfb_attach(); + +vm_offset_t xcfb_std[NXCFB] = { 0 }; +struct bus_device *xcfb_info[NXCFB]; +struct bus_driver xcfb_driver = + { xcfb_probe, 0, xcfb_attach, 0, xcfb_std, "xcfb", xcfb_info, + 0, 0, BUS_INTR_DISABLED}; + +/* + * Probe/Attach functions + */ + +xcfb_probe( /* reg, ui */) +{ + static probed_once = 0; + + /* + * Probing was really done sweeping the TC long ago + */ + if (tc_probe("xcfb") == 0) + return 0; + if (probed_once++ > 1) + printf("[mappable] "); + return 1; +} + +static void +xcfb_attach(ui) + struct bus_device *ui; +{ + /* ... */ + printf(": color display"); +} + + +/* + * Interrupt routine + */ + +xcfb_intr(unit,spllevel) + spl_t spllevel; +{ + /* interrupt has been acknowledge already */ +#if 0 + splx(spllevel); + /* XXX make it load the unsafe things */ +#endif +} + +xcfb_vretrace(xcfb, on) + xcfb_softc_t *xcfb; +{ + int i; + + for (i = 0; i < NXCFB; i++) + if (xcfb_info[i]->address == (vm_offset_t)xcfb->framebuffer) + break; + if (i == NXCFB) return; + + enable_interrupt(xcfb_info[i]->adaptor, on, 0); +} + +/* + * Boot time initialization: must make device + * usable as console asap. + */ + +/* some of these values are made up using ad hocery */ +static struct xcfb_monitor_type monitors[] = { + { "VRM17", 1024, 768, 1024, 1024, 16, 33, + 6, 2, 2, 21, 326, 16, 10, 10 }, + /* XXX Add VRC16 */ + { "VR262", 1024, 864, 1024, 1024, 16, 35, + 5, 3, 3, 37, 330, 16, 10, 10 }, + { "VR299", 1024, 864, 1024, 1024, 16, 35, + 5, 3, 3, 37, 330, 16, 10, 10 }, + { 0 }}; + +/* set from prom command line */ +extern unsigned char *monitor_types[4]; + +xcfb_monitor_type_t xcfb_get_monitor_type() +{ + xcfb_monitor_type_t m; + + m = monitors; + if (monitor_types[3]) + while (m->name) { + /* xcfb is always on the motherboard (slot 3), + fix if you need */ + if (!strcmp(monitor_types[3], m->name)) + break; + m++; + } + if (!m->name) /* the first is the default */ + m = monitors; + return m; +} + + +extern int + xcfb_soft_reset(), xcfb_set_status(), + ims332_pos_cursor(), ims332_video_on(), + ims332_video_off(), xcfb_vretrace(), + pm_get_status(), pm_char_paint(), + pm_insert_line(), pm_remove_line(), + pm_clear_bitmap(), pm_map_page(); + +static struct screen_switch xcfb_sw = { + screen_noop, /* graphic_open */ + xcfb_soft_reset, /* graphic_close */ + xcfb_set_status, /* set_status */ + pm_get_status, /* get_status */ + pm_char_paint, /* char_paint */ + ims332_pos_cursor, /* pos_cursor */ + pm_insert_line, /* insert_line */ + pm_remove_line, /* remove_line */ + pm_clear_bitmap, /* clear_bitmap */ + ims332_video_on, /* video_on */ + ims332_video_off, /* video_off */ + xcfb_vretrace, /* intr_enable */ + pm_map_page /* map_page */ +}; + +xcfb_cold_init(unit, up) + user_info_t *up; +{ + xcfb_softc_t *xcfb; + screen_softc_t sc = screen(unit); + int base = tc_probe("xcfb"); + xcfb_monitor_type_t m = xcfb_get_monitor_type(); + + bcopy(&xcfb_sw, &sc->sw, sizeof(sc->sw)); + + sc->flags |= COLOR_SCREEN; /* XXX should come from m->flags? */ + sc->frame_scanline_width = m->frame_scanline_width; + sc->frame_height = m->frame_height; + sc->frame_visible_width = m->frame_visible_width; + sc->frame_visible_height = m->frame_visible_height; + + pm_init_screen_params(sc, up); + (void) screen_up(unit, up); + + xcfb = pm_alloc(unit, IMS332_ADDRESS, base + VRAM_OFFSET, 0); + xcfb->vdac_registers = (char *)IMS332_RESET_ADDRESS; + + screen_default_colors(up); + + xcfb_soft_reset(sc); + + /* + * Clearing the screen at boot saves from scrolling + * much, and speeds up booting quite a bit. + */ + screen_blitc( unit, 'C'-'@');/* clear screen */ +} + + +#endif (NXCFB > 0) diff --git a/chips/xcfb_misc.c b/chips/xcfb_misc.c new file mode 100644 index 0000000..e7a08c3 --- /dev/null +++ b/chips/xcfb_misc.c @@ -0,0 +1,246 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: xcfb_misc.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 1/92 + * + * Driver for the MAXine color framebuffer + * + */ + +#include +#if (NXCFB > 0) + +/* + * NOTE: This driver relies heavily on the pm one. + */ + +#include + +#include + +#include +#include +typedef pm_softc_t xcfb_softc_t; + +#include +#define ims332 cursor_registers + + +/* + * Initialize color map, for kernel use + */ +xcfb_init_colormap(sc) + screen_softc_t sc; +{ + xcfb_softc_t *xcfb = (xcfb_softc_t*)sc->hw_state; + user_info_t *up = sc->up; + color_map_t Bg_Fg[2]; + register int i; + + ims332_init_colormap( xcfb->ims332 ); + + /* init bg/fg colors */ + for (i = 0; i < 3; i++) { + up->dev_dep_2.pm.Bg_color[i] = 0x00; + up->dev_dep_2.pm.Fg_color[i] = 0xff; + } + + Bg_Fg[0].red = Bg_Fg[0].green = Bg_Fg[0].blue = 0x00; + Bg_Fg[1].red = Bg_Fg[1].green = Bg_Fg[1].blue = 0xff; + ims332_cursor_color( xcfb->ims332, Bg_Fg); +} + +/* + * Large viz small cursor + */ +xcfb_small_cursor_to_large(up, cursor) + user_info_t *up; + cursor_sprite_t cursor; +{ + unsigned short new_cursor[32]; + unsigned char *cursor_bytes; + char *sprite; + register int i; + + /* Clear out old cursor */ + bzero( up->dev_dep_2.pm.cursor_sprite, + sizeof(up->dev_dep_2.pm.cursor_sprite)); + + /* small cursor is 32x2 bytes, fg first */ + cursor_bytes = (unsigned char *) cursor; + + /* use the upper left corner of the large cursor + * as a 64x1 cursor, fg&bg alternated */ + for (i = 0; i < 32; i++) { + register short nc = 0; + register unsigned char fg, bg; + register int j, k; + + fg = cursor_bytes[i]; + bg = cursor_bytes[i + 32]; + bg &= ~fg; + for (j = 1, k = 0; j < 256; j <<= 1) { + nc |= (bg & j) << (k++); + nc |= (fg & j) << (k); + } + new_cursor[i] = nc; + } + + /* Now stick it in the proper place */ + + cursor_bytes = (unsigned char *) new_cursor; + sprite = up->dev_dep_2.pm.cursor_sprite; + for (i = 0; i < 64; i += 4) { + *sprite++ = cursor_bytes[i + 0]; + *sprite++ = cursor_bytes[i + 1]; + *sprite++ = cursor_bytes[i + 2]; + *sprite++ = cursor_bytes[i + 3]; + sprite += 12; /* skip rest of the line */ + } +} + + +/* + * Device-specific set status + */ +xcfb_set_status(sc, flavor, status, status_count) + screen_softc_t sc; + int flavor; + dev_status_t status; + unsigned int status_count; +{ + xcfb_softc_t *xcfb = (xcfb_softc_t*) sc->hw_state; + + switch (flavor) { + + case SCREEN_ADJ_MAPPED_INFO: + return pm_set_status(sc, flavor, status, status_count); + + case SCREEN_LOAD_CURSOR: + + if (status_count < sizeof(cursor_sprite_t)/sizeof(int)) + return D_INVALID_SIZE; + + xcfb_small_cursor_to_large(sc->up, (cursor_sprite_t*) status); + + /* Fall through */ + + case SCREEN_LOAD_CURSOR_LONG: /* 3max only */ + + sc->flags |= SCREEN_BEING_UPDATED; + ims332_cursor_sprite(xcfb->ims332, sc->up->dev_dep_2.pm.cursor_sprite); + sc->flags &= ~SCREEN_BEING_UPDATED; + + break; + + case SCREEN_SET_CURSOR_COLOR: { + color_map_t c[2]; + register cursor_color_t *cc = (cursor_color_t*) status; + + c[0].red = cc->Bg_rgb[0]; + c[0].green = cc->Bg_rgb[1]; + c[0].blue = cc->Bg_rgb[2]; + c[1].red = cc->Fg_rgb[0]; + c[1].green = cc->Fg_rgb[1]; + c[1].blue = cc->Fg_rgb[2]; + + sc->flags |= SCREEN_BEING_UPDATED; + ims332_cursor_color (xcfb->ims332, c ); + sc->flags &= ~SCREEN_BEING_UPDATED; + + break; + } + + case SCREEN_SET_CMAP_ENTRY: { + color_map_entry_t *e = (color_map_entry_t*) status; + + if (e->index < 256) { + sc->flags |= SCREEN_BEING_UPDATED; + ims332_load_colormap_entry( xcfb->ims332, e->index, &e->value); + sc->flags &= ~SCREEN_BEING_UPDATED; + } + break; + } + + default: + return D_INVALID_OPERATION; + } + return D_SUCCESS; +} + +/* + * Hardware initialization + */ +xcfb_init_screen(xcfb) + xcfb_softc_t *xcfb; +{ + extern xcfb_monitor_type_t xcfb_get_monitor_type(); + + ims332_init( xcfb->ims332, xcfb->vdac_registers, xcfb_get_monitor_type()); +} + +/* + * Do what's needed when X exits + */ +xcfb_soft_reset(sc) + screen_softc_t sc; +{ + xcfb_softc_t *xcfb = (xcfb_softc_t*) sc->hw_state; + user_info_t *up = sc->up; + extern cursor_sprite_t dc503_default_cursor; + + /* + * Restore params in mapped structure + */ + pm_init_screen_params(sc,up); + up->row = up->max_row - 1; + + up->dev_dep_2.pm.x26 = 2; /* you do not want to know */ + up->dev_dep_1.pm.x18 = (short*)2; + + /* + * Restore RAMDAC chip to default state + */ + xcfb_init_screen(xcfb); + + /* + * Load kernel's cursor sprite: just use the same pmax one + */ + xcfb_small_cursor_to_large(up, dc503_default_cursor); + ims332_cursor_sprite(xcfb->ims332, up->dev_dep_2.pm.cursor_sprite); + + /* + * Color map and cursor color + */ + xcfb_init_colormap(sc); +} + + + + +#endif (NXCFB > 0) diff --git a/chips/xcfb_monitor.h b/chips/xcfb_monitor.h new file mode 100644 index 0000000..50dc9c9 --- /dev/null +++ b/chips/xcfb_monitor.h @@ -0,0 +1,56 @@ +/* + * Mach Operating System + * Copyright (c) 1992 Carnegie Mellon University + * Copyright (c) 1992 Helsinki University of Technology + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON AND HELSINKI UNIVERSITY OF TECHNOLOGY ALLOW FREE USE + * OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON AND + * HELSINKI UNIVERSITY OF TECHNOLOGY DISCLAIM ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: xcfb_monitor.h + * Author: Jukka Partanen, Helsinki University of Technology 1992. + * + * A type describing the physical properties of a monitor + */ + +#ifndef _XCFB_MONITOR_H_ +#define _XCFB_MONITOR_H_ + +typedef struct xcfb_monitor_type { + char *name; + short frame_visible_width; /* pixels */ + short frame_visible_height; + short frame_scanline_width; + short frame_height; + short half_sync; /* screen units (= 4 pixels) */ + short back_porch; + short v_sync; /* lines */ + short v_pre_equalize; + short v_post_equalize; + short v_blank; + short line_time; /* screen units */ + short line_start; + short mem_init; /* some units */ + short xfer_delay; +} *xcfb_monitor_type_t; + +#endif /* _XCFB_MONITOR_H_ */ -- cgit v1.2.3