1dde8a05bSUgen J.S. Antsilevich /* 2dde8a05bSUgen J.S. Antsilevich * Copyright (c) 1995 Ugen J.S.Antsilevich 3dde8a05bSUgen J.S. Antsilevich * 4dde8a05bSUgen J.S. Antsilevich * Redistribution and use in source forms, with and without modification, 5dde8a05bSUgen J.S. Antsilevich * are permitted provided that this entire comment appears intact. 6dde8a05bSUgen J.S. Antsilevich * 7dde8a05bSUgen J.S. Antsilevich * Redistribution in binary form may occur without any restrictions. 8dde8a05bSUgen J.S. Antsilevich * Obviously, it would be nice if you gave credit where credit is due 9dde8a05bSUgen J.S. Antsilevich * but requiring it would be too onerous. 10dde8a05bSUgen J.S. Antsilevich * 11dde8a05bSUgen J.S. Antsilevich * This software is provided ``AS IS'' without any warranties of any kind. 12dde8a05bSUgen J.S. Antsilevich * 13dde8a05bSUgen J.S. Antsilevich * Snoop stuff. 14dde8a05bSUgen J.S. Antsilevich */ 15dde8a05bSUgen J.S. Antsilevich 16dde8a05bSUgen J.S. Antsilevich #include "snp.h" 17dde8a05bSUgen J.S. Antsilevich 18019b4d63SUgen J.S. Antsilevich #if NSNP > 0 19dde8a05bSUgen J.S. Antsilevich 205591b823SEivind Eklund #include "opt_compat.h" 217b778b5eSEivind Eklund #include "opt_devfs.h" 225591b823SEivind Eklund 23dde8a05bSUgen J.S. Antsilevich #include <sys/param.h> 24dde8a05bSUgen J.S. Antsilevich #include <sys/systm.h> 2571455815SBruce Evans #include <sys/filio.h> 26d96bc99dSBruce Evans #if defined(COMPAT_43) || defined(COMPAT_SUNOS) 27d96bc99dSBruce Evans #include <sys/ioctl_compat.h> 28d96bc99dSBruce Evans #endif 29dde8a05bSUgen J.S. Antsilevich #include <sys/proc.h> 30a1c995b6SPoul-Henning Kamp #include <sys/malloc.h> 31dde8a05bSUgen J.S. Antsilevich #include <sys/tty.h> 32dde8a05bSUgen J.S. Antsilevich #include <sys/conf.h> 33659ffb48SPeter Wemm #include <sys/poll.h> 34dde8a05bSUgen J.S. Antsilevich #include <sys/kernel.h> 3553ac6efbSJulian Elischer #ifdef DEVFS 3653ac6efbSJulian Elischer #include <sys/devfsext.h> 3753ac6efbSJulian Elischer #endif /*DEVFS*/ 3887f6c662SJulian Elischer #include <sys/snoop.h> 39d96bc99dSBruce Evans #include <sys/vnode.h> 4087f6c662SJulian Elischer 4187f6c662SJulian Elischer static d_open_t snpopen; 4287f6c662SJulian Elischer static d_close_t snpclose; 4387f6c662SJulian Elischer static d_read_t snpread; 4487f6c662SJulian Elischer static d_write_t snpwrite; 4587f6c662SJulian Elischer static d_ioctl_t snpioctl; 46659ffb48SPeter Wemm static d_poll_t snppoll; 4787f6c662SJulian Elischer 4853ac6efbSJulian Elischer #define CDEV_MAJOR 53 49d2f265faSPoul-Henning Kamp static struct cdevsw snp_cdevsw = 5087f6c662SJulian Elischer { snpopen, snpclose, snpread, snpwrite, /*53*/ 5187f6c662SJulian Elischer snpioctl, nostop, nullreset, nodevtotty,/* snoop */ 52659ffb48SPeter Wemm snppoll, nommap, NULL, "snp", NULL, -1 }; 5387f6c662SJulian Elischer 5453ac6efbSJulian Elischer 55dde8a05bSUgen J.S. Antsilevich #ifndef MIN 56dde8a05bSUgen J.S. Antsilevich #define MIN(a,b) (((a)<(b))?(a):(b)) 57dde8a05bSUgen J.S. Antsilevich #endif 58dde8a05bSUgen J.S. Antsilevich 59dde8a05bSUgen J.S. Antsilevich static struct snoop snoopsw[NSNP]; 60dde8a05bSUgen J.S. Antsilevich 61444f003cSBruce Evans static struct tty *snpdevtotty __P((dev_t dev)); 6287b6de2bSPoul-Henning Kamp static int snp_detach __P((struct snoop *snp)); 6398d93822SBruce Evans 6477f77631SPaul Traina static struct tty * 65444f003cSBruce Evans snpdevtotty (dev) 6677f77631SPaul Traina dev_t dev; 6777f77631SPaul Traina { 68444f003cSBruce Evans struct cdevsw *cdp; 69444f003cSBruce Evans int maj; 7077f77631SPaul Traina 71444f003cSBruce Evans maj = major(dev); 72444f003cSBruce Evans if ((u_int)maj >= nchrdev) 73444f003cSBruce Evans return (NULL); 74444f003cSBruce Evans cdp = cdevsw[maj]; 75444f003cSBruce Evans if (cdp == NULL) 76444f003cSBruce Evans return (NULL); 77444f003cSBruce Evans return ((*cdp->d_devtotty)(dev)); 7877f77631SPaul Traina } 7977f77631SPaul Traina 800739a0dcSUgen J.S. Antsilevich #define SNP_INPUT_BUF 5 /* This is even too much,the maximal 810739a0dcSUgen J.S. Antsilevich * interactive mode write is 3 bytes 820739a0dcSUgen J.S. Antsilevich * length for function keys... 830739a0dcSUgen J.S. Antsilevich */ 840739a0dcSUgen J.S. Antsilevich 8587f6c662SJulian Elischer static int 860739a0dcSUgen J.S. Antsilevich snpwrite(dev, uio, flag) 870739a0dcSUgen J.S. Antsilevich dev_t dev; 880739a0dcSUgen J.S. Antsilevich struct uio *uio; 890739a0dcSUgen J.S. Antsilevich int flag; 900739a0dcSUgen J.S. Antsilevich { 910739a0dcSUgen J.S. Antsilevich int unit = minor(dev), len, i, error; 920739a0dcSUgen J.S. Antsilevich struct snoop *snp = &snoopsw[unit]; 930739a0dcSUgen J.S. Antsilevich struct tty *tp; 940739a0dcSUgen J.S. Antsilevich char c[SNP_INPUT_BUF]; 950739a0dcSUgen J.S. Antsilevich 960739a0dcSUgen J.S. Antsilevich if (snp->snp_tty == NULL) 970739a0dcSUgen J.S. Antsilevich return (EIO); 980739a0dcSUgen J.S. Antsilevich 990739a0dcSUgen J.S. Antsilevich tp = snp->snp_tty; 1000739a0dcSUgen J.S. Antsilevich 1010739a0dcSUgen J.S. Antsilevich if ((tp->t_sc == snp) && (tp->t_state & TS_SNOOP) && 1020739a0dcSUgen J.S. Antsilevich (tp->t_line == OTTYDISC || tp->t_line == NTTYDISC)) 1030739a0dcSUgen J.S. Antsilevich goto tty_input; 1040739a0dcSUgen J.S. Antsilevich 1050739a0dcSUgen J.S. Antsilevich printf("Snoop: attempt to write to bad tty.\n"); 1060739a0dcSUgen J.S. Antsilevich return (EIO); 1070739a0dcSUgen J.S. Antsilevich 1080739a0dcSUgen J.S. Antsilevich tty_input: 1090739a0dcSUgen J.S. Antsilevich if (!(tp->t_state & TS_ISOPEN)) 1100739a0dcSUgen J.S. Antsilevich return (EIO); 1110739a0dcSUgen J.S. Antsilevich 1120739a0dcSUgen J.S. Antsilevich while (uio->uio_resid > 0) { 1130739a0dcSUgen J.S. Antsilevich len = MIN(uio->uio_resid,SNP_INPUT_BUF); 1140739a0dcSUgen J.S. Antsilevich if ((error = uiomove(c, len, uio)) != 0) 1150739a0dcSUgen J.S. Antsilevich return (error); 1160739a0dcSUgen J.S. Antsilevich for (i=0;i<len;i++) { 1170739a0dcSUgen J.S. Antsilevich if (ttyinput(c[i] , tp)) 1180739a0dcSUgen J.S. Antsilevich return (EIO); 1190739a0dcSUgen J.S. Antsilevich } 1200739a0dcSUgen J.S. Antsilevich } 1210739a0dcSUgen J.S. Antsilevich return 0; 1220739a0dcSUgen J.S. Antsilevich 1230739a0dcSUgen J.S. Antsilevich } 1240739a0dcSUgen J.S. Antsilevich 1250739a0dcSUgen J.S. Antsilevich 12687f6c662SJulian Elischer static int 127dde8a05bSUgen J.S. Antsilevich snpread(dev, uio, flag) 128dde8a05bSUgen J.S. Antsilevich dev_t dev; 129dde8a05bSUgen J.S. Antsilevich struct uio *uio; 130dde8a05bSUgen J.S. Antsilevich int flag; 131dde8a05bSUgen J.S. Antsilevich { 132dde8a05bSUgen J.S. Antsilevich int unit = minor(dev), s; 133dde8a05bSUgen J.S. Antsilevich struct snoop *snp = &snoopsw[unit]; 134dde8a05bSUgen J.S. Antsilevich int len, n, nblen, error = 0; 135dde8a05bSUgen J.S. Antsilevich caddr_t from; 136dde8a05bSUgen J.S. Antsilevich char *nbuf; 137dde8a05bSUgen J.S. Antsilevich 1385526d2d9SEivind Eklund KASSERT(snp->snp_len + snp->snp_base <= snp->snp_blen, 1395526d2d9SEivind Eklund ("snoop buffer error")); 14077f77631SPaul Traina 1410739a0dcSUgen J.S. Antsilevich if (snp->snp_tty == NULL) 142dde8a05bSUgen J.S. Antsilevich return (EIO); 143dde8a05bSUgen J.S. Antsilevich 144dde8a05bSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_RWAIT; 145dde8a05bSUgen J.S. Antsilevich 146dde8a05bSUgen J.S. Antsilevich do { 147dde8a05bSUgen J.S. Antsilevich if (snp->snp_len == 0) { 148d96bc99dSBruce Evans if (flag & IO_NDELAY) 149d96bc99dSBruce Evans return (EWOULDBLOCK); 150dde8a05bSUgen J.S. Antsilevich snp->snp_flags |= SNOOP_RWAIT; 151dde8a05bSUgen J.S. Antsilevich tsleep((caddr_t) snp, (PZERO + 1) | PCATCH, "snoopread", 0); 152dde8a05bSUgen J.S. Antsilevich } 153dde8a05bSUgen J.S. Antsilevich } while (snp->snp_len == 0); 154dde8a05bSUgen J.S. Antsilevich 155019b4d63SUgen J.S. Antsilevich n = snp->snp_len; 156dde8a05bSUgen J.S. Antsilevich 157dde8a05bSUgen J.S. Antsilevich while (snp->snp_len > 0 && uio->uio_resid > 0 && error == 0) { 158dde8a05bSUgen J.S. Antsilevich len = MIN(uio->uio_resid, snp->snp_len); 159dde8a05bSUgen J.S. Antsilevich from = (caddr_t) (snp->snp_buf + snp->snp_base); 160dde8a05bSUgen J.S. Antsilevich if (len == 0) 161dde8a05bSUgen J.S. Antsilevich break; 162dde8a05bSUgen J.S. Antsilevich 163dde8a05bSUgen J.S. Antsilevich error = uiomove(from, len, uio); 164dde8a05bSUgen J.S. Antsilevich snp->snp_base += len; 165dde8a05bSUgen J.S. Antsilevich snp->snp_len -= len; 166dde8a05bSUgen J.S. Antsilevich } 167019b4d63SUgen J.S. Antsilevich if ((snp->snp_flags & SNOOP_OFLOW) && (n < snp->snp_len)) { 168dde8a05bSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_OFLOW; 169019b4d63SUgen J.S. Antsilevich } 170dde8a05bSUgen J.S. Antsilevich s = spltty(); 171dde8a05bSUgen J.S. Antsilevich nblen = snp->snp_blen; 172dde8a05bSUgen J.S. Antsilevich if (((nblen / 2) >= SNOOP_MINLEN) && (nblen / 2) >= snp->snp_len) { 173dde8a05bSUgen J.S. Antsilevich while (((nblen / 2) >= snp->snp_len) && ((nblen / 2) >= SNOOP_MINLEN)) 174dde8a05bSUgen J.S. Antsilevich nblen = nblen / 2; 175d254af07SMatthew Dillon if ((nbuf = malloc(nblen, M_TTYS, M_NOWAIT)) != NULL) { 176dde8a05bSUgen J.S. Antsilevich bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len); 177dde8a05bSUgen J.S. Antsilevich free(snp->snp_buf, M_TTYS); 178dde8a05bSUgen J.S. Antsilevich snp->snp_buf = nbuf; 179dde8a05bSUgen J.S. Antsilevich snp->snp_blen = nblen; 180dde8a05bSUgen J.S. Antsilevich snp->snp_base = 0; 181dde8a05bSUgen J.S. Antsilevich } 182dde8a05bSUgen J.S. Antsilevich } 183dde8a05bSUgen J.S. Antsilevich splx(s); 184dde8a05bSUgen J.S. Antsilevich 185dde8a05bSUgen J.S. Antsilevich return error; 186dde8a05bSUgen J.S. Antsilevich } 187dde8a05bSUgen J.S. Antsilevich 1880739a0dcSUgen J.S. Antsilevich int 189d96bc99dSBruce Evans snpinc(struct snoop *snp, char c) 1900739a0dcSUgen J.S. Antsilevich { 1910739a0dcSUgen J.S. Antsilevich char buf[1]; 1920739a0dcSUgen J.S. Antsilevich 1930739a0dcSUgen J.S. Antsilevich buf[0]=c; 1940739a0dcSUgen J.S. Antsilevich return (snpin(snp,buf,1)); 1950739a0dcSUgen J.S. Antsilevich } 1960739a0dcSUgen J.S. Antsilevich 197dde8a05bSUgen J.S. Antsilevich 198dde8a05bSUgen J.S. Antsilevich int 199dde8a05bSUgen J.S. Antsilevich snpin(snp, buf, n) 200dde8a05bSUgen J.S. Antsilevich struct snoop *snp; 201dde8a05bSUgen J.S. Antsilevich char *buf; 202dde8a05bSUgen J.S. Antsilevich int n; 203dde8a05bSUgen J.S. Antsilevich { 204dde8a05bSUgen J.S. Antsilevich int s_free, s_tail; 205dde8a05bSUgen J.S. Antsilevich int s, len, nblen; 206dde8a05bSUgen J.S. Antsilevich caddr_t from, to; 207dde8a05bSUgen J.S. Antsilevich char *nbuf; 208dde8a05bSUgen J.S. Antsilevich 209219cbf59SEivind Eklund KASSERT(n >= 0, ("negative snoop char count")); 210dde8a05bSUgen J.S. Antsilevich 211dde8a05bSUgen J.S. Antsilevich if (n == 0) 212dde8a05bSUgen J.S. Antsilevich return 0; 213dde8a05bSUgen J.S. Antsilevich 2145526d2d9SEivind Eklund #ifdef DIAGNOSTIC 215019b4d63SUgen J.S. Antsilevich if (!(snp->snp_flags & SNOOP_OPEN)) { 216019b4d63SUgen J.S. Antsilevich printf("Snoop: data coming to closed device.\n"); 217019b4d63SUgen J.S. Antsilevich return 0; 218dde8a05bSUgen J.S. Antsilevich } 219019b4d63SUgen J.S. Antsilevich #endif 220019b4d63SUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_DOWN) { 221019b4d63SUgen J.S. Antsilevich printf("Snoop: more data to down interface.\n"); 222019b4d63SUgen J.S. Antsilevich return 0; 223019b4d63SUgen J.S. Antsilevich } 224964587caSUgen J.S. Antsilevich 225019b4d63SUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_OFLOW) { 226019b4d63SUgen J.S. Antsilevich printf("Snoop: buffer overflow.\n"); 227019b4d63SUgen J.S. Antsilevich /* 228019b4d63SUgen J.S. Antsilevich * On overflow we just repeat the standart close 229019b4d63SUgen J.S. Antsilevich * procedure...yes , this is waste of space but.. Then next 230019b4d63SUgen J.S. Antsilevich * read from device will fail if one would recall he is 231019b4d63SUgen J.S. Antsilevich * snooping and retry... 232019b4d63SUgen J.S. Antsilevich */ 233dde8a05bSUgen J.S. Antsilevich 234964587caSUgen J.S. Antsilevich return (snpdown(snp)); 235019b4d63SUgen J.S. Antsilevich } 236019b4d63SUgen J.S. Antsilevich s_tail = snp->snp_blen - (snp->snp_len + snp->snp_base); 237019b4d63SUgen J.S. Antsilevich s_free = snp->snp_blen - snp->snp_len; 238dde8a05bSUgen J.S. Antsilevich 239dde8a05bSUgen J.S. Antsilevich 240dde8a05bSUgen J.S. Antsilevich if (n > s_free) { 241dde8a05bSUgen J.S. Antsilevich s = spltty(); 242dde8a05bSUgen J.S. Antsilevich nblen = snp->snp_blen; 243dde8a05bSUgen J.S. Antsilevich while ((n > s_free) && ((nblen * 2) <= SNOOP_MAXLEN)) { 244dde8a05bSUgen J.S. Antsilevich nblen = snp->snp_blen * 2; 245dde8a05bSUgen J.S. Antsilevich s_free = nblen - (snp->snp_len + snp->snp_base); 246dde8a05bSUgen J.S. Antsilevich } 247dde8a05bSUgen J.S. Antsilevich if ((n <= s_free) && (nbuf = malloc(nblen, M_TTYS, M_NOWAIT))) { 248dde8a05bSUgen J.S. Antsilevich bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len); 249dde8a05bSUgen J.S. Antsilevich free(snp->snp_buf, M_TTYS); 250dde8a05bSUgen J.S. Antsilevich snp->snp_buf = nbuf; 251dde8a05bSUgen J.S. Antsilevich snp->snp_blen = nblen; 252dde8a05bSUgen J.S. Antsilevich snp->snp_base = 0; 253dde8a05bSUgen J.S. Antsilevich } else { 254dde8a05bSUgen J.S. Antsilevich snp->snp_flags |= SNOOP_OFLOW; 255dde8a05bSUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_RWAIT) { 256dde8a05bSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_RWAIT; 257dde8a05bSUgen J.S. Antsilevich wakeup((caddr_t) snp); 258dde8a05bSUgen J.S. Antsilevich } 259dde8a05bSUgen J.S. Antsilevich splx(s); 260dde8a05bSUgen J.S. Antsilevich return 0; 261dde8a05bSUgen J.S. Antsilevich } 262dde8a05bSUgen J.S. Antsilevich splx(s); 263dde8a05bSUgen J.S. Antsilevich } 264dde8a05bSUgen J.S. Antsilevich if (n > s_tail) { 265dde8a05bSUgen J.S. Antsilevich from = (caddr_t) (snp->snp_buf + snp->snp_base); 266dde8a05bSUgen J.S. Antsilevich to = (caddr_t) (snp->snp_buf); 267dde8a05bSUgen J.S. Antsilevich len = snp->snp_len; 268dde8a05bSUgen J.S. Antsilevich bcopy(from, to, len); 269dde8a05bSUgen J.S. Antsilevich snp->snp_base = 0; 270dde8a05bSUgen J.S. Antsilevich } 271dde8a05bSUgen J.S. Antsilevich to = (caddr_t) (snp->snp_buf + snp->snp_base + snp->snp_len); 272dde8a05bSUgen J.S. Antsilevich bcopy(buf, to, n); 273dde8a05bSUgen J.S. Antsilevich snp->snp_len += n; 274dde8a05bSUgen J.S. Antsilevich 275dde8a05bSUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_RWAIT) { 276dde8a05bSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_RWAIT; 277dde8a05bSUgen J.S. Antsilevich wakeup((caddr_t) snp); 278dde8a05bSUgen J.S. Antsilevich } 279dde8a05bSUgen J.S. Antsilevich selwakeup(&snp->snp_sel); 280dde8a05bSUgen J.S. Antsilevich snp->snp_sel.si_pid = 0; 281dde8a05bSUgen J.S. Antsilevich 282dde8a05bSUgen J.S. Antsilevich return n; 283dde8a05bSUgen J.S. Antsilevich } 284dde8a05bSUgen J.S. Antsilevich 28587f6c662SJulian Elischer static int 286dde8a05bSUgen J.S. Antsilevich snpopen(dev, flag, mode, p) 287dde8a05bSUgen J.S. Antsilevich dev_t dev; 288dde8a05bSUgen J.S. Antsilevich int flag, mode; 289dde8a05bSUgen J.S. Antsilevich struct proc *p; 290dde8a05bSUgen J.S. Antsilevich { 291dde8a05bSUgen J.S. Antsilevich struct snoop *snp; 292dde8a05bSUgen J.S. Antsilevich register int unit, error; 293dde8a05bSUgen J.S. Antsilevich 294f711d546SPoul-Henning Kamp if ((error = suser(p)) != 0) 295dde8a05bSUgen J.S. Antsilevich return (error); 296dde8a05bSUgen J.S. Antsilevich 297dde8a05bSUgen J.S. Antsilevich if ((unit = minor(dev)) >= NSNP) 298dde8a05bSUgen J.S. Antsilevich return (ENXIO); 29977f77631SPaul Traina 300dde8a05bSUgen J.S. Antsilevich snp = &snoopsw[unit]; 30177f77631SPaul Traina 302dde8a05bSUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_OPEN) 303dde8a05bSUgen J.S. Antsilevich return (ENXIO); 30477f77631SPaul Traina 305019b4d63SUgen J.S. Antsilevich /* 306019b4d63SUgen J.S. Antsilevich * We intentionally do not OR flags with SNOOP_OPEN,but set them so 307019b4d63SUgen J.S. Antsilevich * all previous settings (especially SNOOP_OFLOW) will be cleared. 308019b4d63SUgen J.S. Antsilevich */ 309019b4d63SUgen J.S. Antsilevich snp->snp_flags = SNOOP_OPEN; 310dde8a05bSUgen J.S. Antsilevich 311dde8a05bSUgen J.S. Antsilevich snp->snp_buf = malloc(SNOOP_MINLEN, M_TTYS, M_WAITOK); 312dde8a05bSUgen J.S. Antsilevich snp->snp_blen = SNOOP_MINLEN; 313dde8a05bSUgen J.S. Antsilevich snp->snp_base = 0; 314dde8a05bSUgen J.S. Antsilevich snp->snp_len = 0; 315dde8a05bSUgen J.S. Antsilevich 316dde8a05bSUgen J.S. Antsilevich /* 3170739a0dcSUgen J.S. Antsilevich * snp_tty == NULL is for inactive snoop devices. 318dde8a05bSUgen J.S. Antsilevich */ 3190739a0dcSUgen J.S. Antsilevich snp->snp_tty = NULL; 32077f77631SPaul Traina snp->snp_target = -1; 321dde8a05bSUgen J.S. Antsilevich return (0); 322dde8a05bSUgen J.S. Antsilevich } 323dde8a05bSUgen J.S. Antsilevich 324019b4d63SUgen J.S. Antsilevich 32587b6de2bSPoul-Henning Kamp static int 326019b4d63SUgen J.S. Antsilevich snp_detach(snp) 327019b4d63SUgen J.S. Antsilevich struct snoop *snp; 328019b4d63SUgen J.S. Antsilevich { 329019b4d63SUgen J.S. Antsilevich struct tty *tp; 330019b4d63SUgen J.S. Antsilevich 331019b4d63SUgen J.S. Antsilevich snp->snp_base = 0; 332019b4d63SUgen J.S. Antsilevich snp->snp_len = 0; 333019b4d63SUgen J.S. Antsilevich 334019b4d63SUgen J.S. Antsilevich /* 335019b4d63SUgen J.S. Antsilevich * If line disc. changed we do not touch this pointer,SLIP/PPP will 336019b4d63SUgen J.S. Antsilevich * change it anyway. 337019b4d63SUgen J.S. Antsilevich */ 338019b4d63SUgen J.S. Antsilevich 3390739a0dcSUgen J.S. Antsilevich if (snp->snp_tty == NULL) 340964587caSUgen J.S. Antsilevich goto detach_notty; 341019b4d63SUgen J.S. Antsilevich 3420739a0dcSUgen J.S. Antsilevich tp = snp->snp_tty; 343019b4d63SUgen J.S. Antsilevich 34477f77631SPaul Traina if (tp && (tp->t_sc == snp) && (tp->t_state & TS_SNOOP) && 345019b4d63SUgen J.S. Antsilevich (tp->t_line == OTTYDISC || tp->t_line == NTTYDISC)) { 346019b4d63SUgen J.S. Antsilevich tp->t_sc = NULL; 347019b4d63SUgen J.S. Antsilevich tp->t_state &= ~TS_SNOOP; 348019b4d63SUgen J.S. Antsilevich } else 349019b4d63SUgen J.S. Antsilevich printf("Snoop: bad attached tty data.\n"); 350019b4d63SUgen J.S. Antsilevich 3510739a0dcSUgen J.S. Antsilevich snp->snp_tty = NULL; 35277f77631SPaul Traina snp->snp_target = -1; 353019b4d63SUgen J.S. Antsilevich 354964587caSUgen J.S. Antsilevich detach_notty: 355019b4d63SUgen J.S. Antsilevich selwakeup(&snp->snp_sel); 356019b4d63SUgen J.S. Antsilevich snp->snp_sel.si_pid = 0; 357019b4d63SUgen J.S. Antsilevich 358019b4d63SUgen J.S. Antsilevich return (0); 359019b4d63SUgen J.S. Antsilevich } 360019b4d63SUgen J.S. Antsilevich 36187f6c662SJulian Elischer static int 36260039670SBruce Evans snpclose(dev, flags, fmt, p) 363dde8a05bSUgen J.S. Antsilevich dev_t dev; 36460039670SBruce Evans int flags; 36560039670SBruce Evans int fmt; 36660039670SBruce Evans struct proc *p; 367dde8a05bSUgen J.S. Antsilevich { 368dde8a05bSUgen J.S. Antsilevich register int unit = minor(dev); 369dde8a05bSUgen J.S. Antsilevich struct snoop *snp = &snoopsw[unit]; 370dde8a05bSUgen J.S. Antsilevich 371dde8a05bSUgen J.S. Antsilevich snp->snp_blen = 0; 372dde8a05bSUgen J.S. Antsilevich free(snp->snp_buf, M_TTYS); 373019b4d63SUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_OPEN; 374dde8a05bSUgen J.S. Antsilevich 375019b4d63SUgen J.S. Antsilevich return (snp_detach(snp)); 376dde8a05bSUgen J.S. Antsilevich } 377dde8a05bSUgen J.S. Antsilevich 378964587caSUgen J.S. Antsilevich int 379964587caSUgen J.S. Antsilevich snpdown(snp) 380964587caSUgen J.S. Antsilevich struct snoop *snp; 381964587caSUgen J.S. Antsilevich { 382964587caSUgen J.S. Antsilevich snp->snp_blen = SNOOP_MINLEN; 383964587caSUgen J.S. Antsilevich free(snp->snp_buf, M_TTYS); 384964587caSUgen J.S. Antsilevich snp->snp_buf = malloc(SNOOP_MINLEN, M_TTYS, M_WAITOK); 385964587caSUgen J.S. Antsilevich snp->snp_flags |= SNOOP_DOWN; 386dde8a05bSUgen J.S. Antsilevich 387964587caSUgen J.S. Antsilevich return (snp_detach(snp)); 388964587caSUgen J.S. Antsilevich } 389dde8a05bSUgen J.S. Antsilevich 390dde8a05bSUgen J.S. Antsilevich 39187f6c662SJulian Elischer static int 39260039670SBruce Evans snpioctl(dev, cmd, data, flags, p) 393dde8a05bSUgen J.S. Antsilevich dev_t dev; 394ecbb00a2SDoug Rabson u_long cmd; 395dde8a05bSUgen J.S. Antsilevich caddr_t data; 39660039670SBruce Evans int flags; 39760039670SBruce Evans struct proc *p; 398dde8a05bSUgen J.S. Antsilevich { 399dde8a05bSUgen J.S. Antsilevich int unit = minor(dev), s; 40077f77631SPaul Traina dev_t tdev; 401dde8a05bSUgen J.S. Antsilevich struct snoop *snp = &snoopsw[unit]; 402dde8a05bSUgen J.S. Antsilevich struct tty *tp, *tpo; 403dde8a05bSUgen J.S. Antsilevich 404dde8a05bSUgen J.S. Antsilevich switch (cmd) { 405dde8a05bSUgen J.S. Antsilevich case SNPSTTY: 40677f77631SPaul Traina tdev = *((dev_t *) data); 40777f77631SPaul Traina if (tdev == -1) 408964587caSUgen J.S. Antsilevich return (snpdown(snp)); 409964587caSUgen J.S. Antsilevich 410444f003cSBruce Evans tp = snpdevtotty(tdev); 41177f77631SPaul Traina if (!tp) 412dde8a05bSUgen J.S. Antsilevich return (EINVAL); 413dde8a05bSUgen J.S. Antsilevich 41477f77631SPaul Traina if ((tp->t_sc != (caddr_t) snp) && (tp->t_state & TS_SNOOP)) 415dde8a05bSUgen J.S. Antsilevich return (EBUSY); 416dde8a05bSUgen J.S. Antsilevich 41777f77631SPaul Traina if ((tp->t_line != OTTYDISC) && (tp->t_line != NTTYDISC)) 418dde8a05bSUgen J.S. Antsilevich return (EBUSY); 419dde8a05bSUgen J.S. Antsilevich 420dde8a05bSUgen J.S. Antsilevich s = spltty(); 42177f77631SPaul Traina 42277f77631SPaul Traina if (snp->snp_target == -1) { 4230739a0dcSUgen J.S. Antsilevich tpo = snp->snp_tty; 42477f77631SPaul Traina if (tpo) 425dde8a05bSUgen J.S. Antsilevich tpo->t_state &= ~TS_SNOOP; 426dde8a05bSUgen J.S. Antsilevich } 42777f77631SPaul Traina 428dde8a05bSUgen J.S. Antsilevich tp->t_sc = (caddr_t) snp; 429dde8a05bSUgen J.S. Antsilevich tp->t_state |= TS_SNOOP; 4300739a0dcSUgen J.S. Antsilevich snp->snp_tty = tp; 43177f77631SPaul Traina snp->snp_target = tdev; 43277f77631SPaul Traina 433964587caSUgen J.S. Antsilevich /* 434964587caSUgen J.S. Antsilevich * Clean overflow and down flags - 435964587caSUgen J.S. Antsilevich * we'll have a chance to get them in the future :))) 436964587caSUgen J.S. Antsilevich */ 437964587caSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_OFLOW; 438019b4d63SUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_DOWN; 439dde8a05bSUgen J.S. Antsilevich splx(s); 440dde8a05bSUgen J.S. Antsilevich break; 44177f77631SPaul Traina 442dde8a05bSUgen J.S. Antsilevich case SNPGTTY: 4430739a0dcSUgen J.S. Antsilevich /* 4440739a0dcSUgen J.S. Antsilevich * We keep snp_target field specially to make 4450739a0dcSUgen J.S. Antsilevich * SNPGTTY happy,else we can't know what is device 4460739a0dcSUgen J.S. Antsilevich * major/minor for tty. 4470739a0dcSUgen J.S. Antsilevich */ 44877f77631SPaul Traina *((dev_t *) data) = snp->snp_target; 449dde8a05bSUgen J.S. Antsilevich break; 450dde8a05bSUgen J.S. Antsilevich 451dde8a05bSUgen J.S. Antsilevich case FIONBIO: 452dde8a05bSUgen J.S. Antsilevich break; 45377f77631SPaul Traina 454dde8a05bSUgen J.S. Antsilevich case FIOASYNC: 455dde8a05bSUgen J.S. Antsilevich if (*(int *) data) 456dde8a05bSUgen J.S. Antsilevich snp->snp_flags |= SNOOP_ASYNC; 457dde8a05bSUgen J.S. Antsilevich else 458dde8a05bSUgen J.S. Antsilevich snp->snp_flags &= ~SNOOP_ASYNC; 459dde8a05bSUgen J.S. Antsilevich break; 46077f77631SPaul Traina 461dde8a05bSUgen J.S. Antsilevich case FIONREAD: 462dde8a05bSUgen J.S. Antsilevich s = spltty(); 4630739a0dcSUgen J.S. Antsilevich if (snp->snp_tty != NULL) 464dde8a05bSUgen J.S. Antsilevich *(int *) data = snp->snp_len; 465dde8a05bSUgen J.S. Antsilevich else 466964587caSUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_DOWN) { 467964587caSUgen J.S. Antsilevich if (snp->snp_flags & SNOOP_OFLOW) 468964587caSUgen J.S. Antsilevich *(int *) data = SNP_OFLOW; 469964587caSUgen J.S. Antsilevich else 470964587caSUgen J.S. Antsilevich *(int *) data = SNP_TTYCLOSE; 471964587caSUgen J.S. Antsilevich } else { 472964587caSUgen J.S. Antsilevich *(int *) data = SNP_DETACH; 473964587caSUgen J.S. Antsilevich } 474dde8a05bSUgen J.S. Antsilevich splx(s); 475dde8a05bSUgen J.S. Antsilevich break; 47677f77631SPaul Traina 477dde8a05bSUgen J.S. Antsilevich default: 478dde8a05bSUgen J.S. Antsilevich return (ENOTTY); 479dde8a05bSUgen J.S. Antsilevich } 480dde8a05bSUgen J.S. Antsilevich return (0); 481dde8a05bSUgen J.S. Antsilevich } 482dde8a05bSUgen J.S. Antsilevich 483dde8a05bSUgen J.S. Antsilevich 48487f6c662SJulian Elischer static int 485659ffb48SPeter Wemm snppoll(dev, events, p) 486dde8a05bSUgen J.S. Antsilevich dev_t dev; 487659ffb48SPeter Wemm int events; 488dde8a05bSUgen J.S. Antsilevich struct proc *p; 489dde8a05bSUgen J.S. Antsilevich { 490a98ca469SPoul-Henning Kamp int unit = minor(dev); 491dde8a05bSUgen J.S. Antsilevich struct snoop *snp = &snoopsw[unit]; 492659ffb48SPeter Wemm int revents = 0; 493dde8a05bSUgen J.S. Antsilevich 49477f77631SPaul Traina 495019b4d63SUgen J.S. Antsilevich /* 496659ffb48SPeter Wemm * If snoop is down,we don't want to poll() forever so we return 1. 497019b4d63SUgen J.S. Antsilevich * Caller should see if we down via FIONREAD ioctl().The last should 498019b4d63SUgen J.S. Antsilevich * return -1 to indicate down state. 499019b4d63SUgen J.S. Antsilevich */ 500dfd5dee1SPeter Wemm if (events & (POLLIN | POLLRDNORM)) { 501659ffb48SPeter Wemm if (snp->snp_flags & SNOOP_DOWN || snp->snp_len > 0) 502659ffb48SPeter Wemm revents |= events & (POLLIN | POLLRDNORM); 503659ffb48SPeter Wemm else 504dde8a05bSUgen J.S. Antsilevich selrecord(p, &snp->snp_sel); 505dfd5dee1SPeter Wemm } 506659ffb48SPeter Wemm return (revents); 507dde8a05bSUgen J.S. Antsilevich } 508dde8a05bSUgen J.S. Antsilevich 509734daefcSMarc G. Fournier #ifdef DEVFS 51087f6c662SJulian Elischer static void *snp_devfs_token[NSNP]; 511734daefcSMarc G. Fournier #endif 512e31abedeSBruce Evans static int snp_devsw_installed; 51353ac6efbSJulian Elischer 514514ede09SBruce Evans static void snp_drvinit __P((void *unused)); 51587f6c662SJulian Elischer static void 516514ede09SBruce Evans snp_drvinit(unused) 517514ede09SBruce Evans void *unused; 51853ac6efbSJulian Elischer { 51953ac6efbSJulian Elischer dev_t dev; 520734daefcSMarc G. Fournier #ifdef DEVFS 52187f6c662SJulian Elischer int i; 522734daefcSMarc G. Fournier #endif 52353ac6efbSJulian Elischer 52453ac6efbSJulian Elischer if( ! snp_devsw_installed ) { 52553ac6efbSJulian Elischer dev = makedev(CDEV_MAJOR, 0); 52653ac6efbSJulian Elischer cdevsw_add(&dev,&snp_cdevsw, NULL); 52753ac6efbSJulian Elischer snp_devsw_installed = 1; 52853ac6efbSJulian Elischer #ifdef DEVFS 52987f6c662SJulian Elischer for ( i = 0 ; i < NSNP ; i++) { 53087f6c662SJulian Elischer snp_devfs_token[i] = 531734daefcSMarc G. Fournier devfs_add_devswf(&snp_cdevsw, i, DV_CHR, 0, 0, 532734daefcSMarc G. Fournier 0600, "snp%d", i); 53353ac6efbSJulian Elischer } 53453ac6efbSJulian Elischer #endif 53553ac6efbSJulian Elischer } 5367198bf47SJulian Elischer } 53753ac6efbSJulian Elischer 53853ac6efbSJulian Elischer SYSINIT(snpdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,snp_drvinit,NULL) 53953ac6efbSJulian Elischer 54053ac6efbSJulian Elischer 541dde8a05bSUgen J.S. Antsilevich #endif 542