+/*
+ * DM-11 driver.
+ */
+
+/*
+ * Definition of the controller for the auto-configuration program.
+ */
+int dmcntrlr(), dmslave(), dmintr();
+struct uba_dinfo *dminfo[NDH11];
+u_short dmstd[] = { 0 };
+struct uba_driver dmdriver =
+ { dmcntrlr, dmslave, 0, 0, dmstd, "dm", dminfo };
+
+/* hardware bits */
+#define DM_CARRTRANS 040000 /* carrier transition */
+#define DM_CLSCAN 004000 /* clear scan */
+#define DM_DONE 000200
+#define DM_CARRON 000100 /* carrier on */
+#define DM_SCENABLE 000040 /* scan enable */
+#define DM_SCBUSY 000020 /* scan busy */
+
+struct dmdevice
+{
+ short dmcsr;
+ short dmlstat;
+ short dmpad1[2];
+};
+
+dmcntrlr(um, addr)
+ struct uba_minfo *um;
+ caddr_t addr;
+{
+
+}
+
+dmslave()
+{
+
+}
+
+/*
+ * Turn on the line associated with the dh device dev.
+ */
+dmopen(dev)
+ dev_t dev;
+{
+ register struct tty *tp;
+ register struct dmdevice *addr;
+ register struct uba_dinfo *ui;
+ register int unit;
+ register int dm;
+
+ unit = minor(dev);
+ dm = unit >> 8;
+ tp = &dh11[unit];
+ if (dm >= NDH11 || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0) {
+ tp->t_state |= CARR_ON;
+ return;
+ }
+ addr = (struct dmdevice *)ui->ui_addr;
+ spl5();
+ addr->dmcsr &= ~DM_SCENABLE;
+ while (addr->dmcsr & DM_SCBUSY)
+ ;
+ addr->dmcsr = unit & 0xf;
+ addr->dmlstat = DM_ON;
+ if (addr->dmlstat&DM_CARRON)
+ tp->t_state |= CARR_ON;
+ addr->dmcsr = DH_IE|DM_SCENABLE;
+ while ((tp->t_state&CARR_ON)==0)
+ sleep((caddr_t)&tp->t_rawq, TTIPRI);
+ spl0();
+}
+
+/*
+ * Dump control bits into the DM registers.
+ */
+dmctl(dev, bits, how)
+ dev_t dev;
+ int bits, how;
+{
+ register struct uba_dinfo *ui;
+ register struct dmdevice *addr;
+ register int unit, s;
+ int dm;
+
+ unit = minor(dev);
+ dm = unit >> 4;
+ if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0)
+ return;
+ addr = (struct dmdevice *)ui->ui_addr;
+ s = spl5();
+ addr->dmcsr &= ~DM_SCENABLE;
+ while (addr->dmcsr & DM_SCBUSY)
+ ;
+ addr->dmcsr = unit & 0xf;
+ switch(how) {
+ case DMSET:
+ addr->dmlstat = bits;
+ break;
+ case DMBIS:
+ addr->dmlstat |= bits;
+ break;
+ case DMBIC:
+ addr->dmlstat &= ~bits;
+ break;
+ }
+ addr->dmcsr = DH_IE|DM_SCENABLE;
+ splx(s);
+}
+
+/*
+ * DM11 interrupt; deal with carrier transitions.
+ */
+dmintr(dm)
+ register int dm;
+{
+ register struct uba_dinfo *ui;
+ register struct tty *tp;
+ register struct dmdevice *addr;
+
+ ui = dminfo[dm];
+ addr = (struct dmdevice *)ui->ui_addr;
+ if (addr->dmcsr&DM_DONE && addr->dmcsr&DM_CARRTRANS) {
+ tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)];
+ wakeup((caddr_t)&tp->t_rawq);
+ if ((tp->t_state&WOPEN)==0 &&
+ (tp->t_local&LMDMBUF)) {
+ if (addr->dmlstat & DM_CARRON) {
+ tp->t_state &= ~TTSTOP;
+ ttstart(tp);
+ } else if ((tp->t_state&TTSTOP) == 0) {
+ tp->t_state |= TTSTOP;
+ dhstop(tp, 0);
+ }
+ } else if ((addr->dmlstat&DM_CARRON)==0) {
+ if ((tp->t_state&WOPEN)==0 &&
+ (tp->t_local&LNOHANG)==0) {
+ gsignal(tp->t_pgrp, SIGHUP);
+ gsignal(tp->t_pgrp, SIGCONT);
+ addr->dmlstat = 0;
+ flushtty(tp, FREAD|FWRITE);
+ }
+ tp->t_state &= ~CARR_ON;
+ } else
+ tp->t_state |= CARR_ON;
+ addr->dmcsr = DH_IE|DM_SCENABLE;
+ }
+}