123325Smckusick /*
229218Smckusick * Copyright (c) 1982, 1986 Regents of the University of California.
323325Smckusick * All rights reserved. The Berkeley software License Agreement
423325Smckusick * specifies the terms and conditions for redistribution.
523325Smckusick *
6*45804Sbostic * @(#)dn.c 7.7 (Berkeley) 12/16/90
723325Smckusick */
84737Swnj
94737Swnj #include "dn.h"
104737Swnj #if NDN > 0
114737Swnj /*
124737Swnj * DN-11 ACU interface
134737Swnj */
14*45804Sbostic #include "../include/pte.h"
154737Swnj
16*45804Sbostic #include "sys/param.h"
17*45804Sbostic #include "sys/systm.h"
18*45804Sbostic #include "sys/user.h"
19*45804Sbostic #include "sys/buf.h"
20*45804Sbostic #include "sys/map.h"
21*45804Sbostic #include "sys/conf.h"
22*45804Sbostic #include "sys/uio.h"
234737Swnj
2417073Sbloom #include "ubavar.h"
258474Sroot
264737Swnj struct dndevice {
276593Ssam u_short dn_reg[4];
284737Swnj };
294737Swnj
304737Swnj struct uba_device *dninfo[NDN];
318779Sroot int dnprobe(), dnattach(), dnintr();
3225521Stef u_short dnstd[] = { 0175200, 0 };
334737Swnj struct uba_driver dndriver =
344737Swnj { dnprobe, 0, dnattach, 0, dnstd, "dn", dninfo };
354737Swnj
366593Ssam #define CRQ 0x001 /* call request */
376593Ssam #define DPR 0x002 /* digit present */
386593Ssam #define MENABLE 0x004 /* master enable */
396593Ssam #define MAINT 0x008 /* maintenance mode */
406593Ssam #define PND 0x010 /* present next digit */
416593Ssam #define DSS 0x020 /* data set status */
426593Ssam #define IENABLE 0x040 /* interrupt enable */
436593Ssam #define DONE 0x080 /* operation complete */
446593Ssam #define DLO 0x1000 /* data line occupied */
456593Ssam #define ACR 0x4000 /* abandon call and retry */
466593Ssam #define PWI 0x8000 /* power indicate */
474737Swnj
484737Swnj #define DNPRI (PZERO+5)
494737Swnj #define DNUNIT(dev) (minor(dev)>>2)
504737Swnj #define DNREG(dev) ((dev)&03)
514737Swnj
524737Swnj #define OBUFSIZ 40 /* largest phone # dialer can handle */
534737Swnj
544737Swnj /*
554737Swnj * There's no good way to determine the correct number of dialers attached
564933Swnj * to a single device (especially when dialers such as Vadic-821 MACS
576593Ssam * exist which can address four chassis, each with its own dialer).
584737Swnj */
dnprobe(reg)594737Swnj dnprobe(reg)
604737Swnj caddr_t reg;
614737Swnj {
626593Ssam register int br, cvec; /* value-result, must be r11, r10 */
634737Swnj register struct dndevice *dnaddr = (struct dndevice *)reg;
644737Swnj
658608Sroot #ifdef lint
668608Sroot br = 0; cvec = 0; br = cvec; cvec = br;
678779Sroot dnintr(0);
688608Sroot #endif
694737Swnj /*
704737Swnj * If there's at least one dialer out there it better be
718608Sroot * at chassis 0.
724737Swnj */
734737Swnj dnaddr->dn_reg[0] = MENABLE|IENABLE|DONE;
744737Swnj DELAY(5);
754737Swnj dnaddr->dn_reg[0] = 0;
767409Skre return (sizeof (struct dndevice));
774737Swnj }
784737Swnj
798608Sroot /*ARGSUSED*/
804737Swnj dnattach(ui)
814737Swnj struct uba_device *ui;
828568Sroot {
834933Swnj
848568Sroot }
858568Sroot
864737Swnj /*ARGSUSED*/
dnopen(dev,flag)874737Swnj dnopen(dev, flag)
884737Swnj dev_t dev;
898647Sroot int flag;
904737Swnj {
914737Swnj register struct dndevice *dp;
926593Ssam register u_short unit, *dnreg;
934737Swnj register struct uba_device *ui;
944737Swnj register short dialer;
954737Swnj
964737Swnj if ((unit = DNUNIT(dev)) >= NDN || (ui = dninfo[unit]) == 0 ||
978568Sroot ui->ui_alive == 0)
988568Sroot return (ENXIO);
996593Ssam dialer = DNREG(dev);
1006593Ssam dp = (struct dndevice *)ui->ui_addr;
1018568Sroot if (dp->dn_reg[dialer] & PWI)
1028568Sroot return (ENXIO);
1034737Swnj dnreg = &(dp->dn_reg[dialer]);
1048568Sroot if (*dnreg&(DLO|CRQ))
1058568Sroot return (EBUSY);
1064737Swnj dp->dn_reg[0] |= MENABLE;
1074737Swnj *dnreg = IENABLE|MENABLE|CRQ;
1088568Sroot return (0);
1094737Swnj }
1104737Swnj
1114737Swnj /*ARGSUSED*/
dnclose(dev,flag)1124737Swnj dnclose(dev, flag)
1134737Swnj dev_t dev;
1144737Swnj {
1154737Swnj register struct dndevice *dp;
1164737Swnj
1174737Swnj dp = (struct dndevice *)dninfo[DNUNIT(dev)]->ui_addr;
1184737Swnj dp->dn_reg[DNREG(dev)] = MENABLE;
11940728Skarels return (0);
1204737Swnj }
1214737Swnj
dnwrite(dev,uio)1227833Sroot dnwrite(dev, uio)
1234737Swnj dev_t dev;
1247833Sroot struct uio *uio;
1254737Swnj {
1266593Ssam register u_short *dnreg;
1276593Ssam register int cc;
1284737Swnj register struct dndevice *dp;
1298608Sroot char obuf[OBUFSIZ];
1304737Swnj register char *cp;
1314737Swnj extern lbolt;
1328491Sroot int error;
1334737Swnj
1344737Swnj dp = (struct dndevice *)dninfo[DNUNIT(dev)]->ui_addr;
1354737Swnj dnreg = &(dp->dn_reg[DNREG(dev)]);
1367833Sroot cc = MIN(uio->uio_resid, OBUFSIZ);
1378608Sroot cp = obuf;
13837762Smckusick error = uiomove(cp, cc, uio);
1398491Sroot if (error)
1408491Sroot return (error);
14140728Skarels while ((*dnreg & (PWI|ACR|DSS)) == 0 && cc >= 0 && error == 0) {
1428715Sroot (void) spl4();
1436593Ssam if ((*dnreg & PND) == 0 || cc == 0)
14440728Skarels error = tsleep((caddr_t)dnreg, DNPRI | PCATCH,
14540728Skarels devout, 0);
1464737Swnj else switch(*cp) {
1474737Swnj
1484737Swnj case '-':
14940728Skarels error = tsleep((caddr_t)&lbolt, DNPRI | PCATCH,
15040728Skarels devout, 0);
15140728Skarels if (error == 0)
15240728Skarels error = tsleep((caddr_t)&lbolt, DNPRI | PCATCH,
15340728Skarels devout, 0);
1544737Swnj break;
1554737Swnj
1564737Swnj case 'f':
1574737Swnj *dnreg &= ~CRQ;
15840728Skarels error = tsleep((caddr_t)&lbolt, DNPRI | PCATCH,
15940728Skarels devout, 0);
1604737Swnj *dnreg |= CRQ;
1614737Swnj break;
1624737Swnj
1634737Swnj case '*': case ':':
1644737Swnj *cp = 012;
1654737Swnj goto dial;
1664737Swnj
1674737Swnj case '#': case ';':
1684737Swnj *cp = 013;
1694737Swnj goto dial;
1704737Swnj
1714737Swnj case 'e': case '<':
1724737Swnj *cp = 014;
1734737Swnj goto dial;
1744737Swnj
1754737Swnj case 'w': case '=':
1764737Swnj *cp = 015;
1774737Swnj goto dial;
1784737Swnj
1794737Swnj default:
1804737Swnj if (*cp < '0' || *cp > '9')
1814737Swnj break;
1824737Swnj dial:
1836593Ssam *dnreg = (*cp << 8) | (IENABLE|MENABLE|DPR|CRQ);
18440728Skarels error = tsleep((caddr_t)dnreg, DNPRI | PCATCH,
18540728Skarels devout, 0);
1864737Swnj }
1874737Swnj cp++, cc--;
1884737Swnj spl0();
1894737Swnj }
19040728Skarels if (error)
19140728Skarels return (error);
1926593Ssam if (*dnreg & (PWI|ACR))
1938491Sroot return (EIO);
1948491Sroot return (0);
1954737Swnj }
1964737Swnj
dnintr(dev)1974737Swnj dnintr(dev)
1984737Swnj dev_t dev;
1994737Swnj {
2006593Ssam register u_short *basereg, *dnreg;
2014737Swnj
2026593Ssam basereg = (u_short *)dninfo[dev]->ui_addr;
2034737Swnj *basereg &= ~MENABLE;
2046593Ssam for (dnreg = basereg; dnreg < basereg + 4; dnreg++)
2056593Ssam if (*dnreg & DONE) {
2064737Swnj *dnreg &= ~(DONE|DPR);
2074737Swnj wakeup((caddr_t)dnreg);
2084737Swnj }
2094737Swnj *basereg |= MENABLE;
2104737Swnj }
2114737Swnj #endif
212