|
|
GNU Mach 1.0
/*
* 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 [email protected]
* 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 <dz_.h>
#if NDZ_ > 0
#include <bm.h>
#include <platforms.h>
#include <mach_kdb.h>
#include <machine/machspl.h> /* spl definitions */
#include <device/io_req.h>
#include <device/tty.h>
#include <chips/busses.h>
#include <chips/screen_defs.h>
#include <chips/serial_defs.h>
#include <chips/dz_7085.h>
#ifdef DECSTATION
#include <mips/mips_cpu.h>
#include <mips/PMAX/kn01.h>
#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<<line;
else
dz7085_softc[unit]->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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.