53ac6efbd8
That's EVERY SINGLE driver that has an entry in conf.c.. my next trick will be to define cdevsw[] and bdevsw[] as empty arrays and remove all those DAMNED defines as well.. Each of these drivers has a SYSINIT linker set entry that comes in very early.. and asks teh driver to add it's own entry to the two devsw[] tables. some slight reworking of the commits from yesterday (added the SYSINIT stuff and some usually wrong but token DEVFS entries to all these devices. BTW does anyone know where the 'ata' entries in conf.c actually reside? seems we don't actually have a 'ataopen() etc... If you want to add a new device in conf.c please make sure I know so I can keep it up to date too.. as before, this is all dependent on #if defined(JREMOD) (and #ifdef DEVFS in parts)
534 lines
11 KiB
C
534 lines
11 KiB
C
/*
|
|
* Copyright (c) 1995 Ugen J.S.Antsilevich
|
|
*
|
|
* Redistribution and use in source forms, with and without modification,
|
|
* are permitted provided that this entire comment appears intact.
|
|
*
|
|
* Redistribution in binary form may occur without any restrictions.
|
|
* Obviously, it would be nice if you gave credit where credit is due
|
|
* but requiring it would be too onerous.
|
|
*
|
|
* This software is provided ``AS IS'' without any warranties of any kind.
|
|
*
|
|
* Snoop stuff.
|
|
*/
|
|
|
|
#include "snp.h"
|
|
|
|
#if NSNP > 0
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/ioctl_compat.h> /* Oooh..We need O/NTTYDISC */
|
|
#include <sys/proc.h>
|
|
#define TTYDEFCHARS
|
|
#include <sys/tty.h>
|
|
#undef TTYDEFCHARS
|
|
#include <sys/file.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/uio.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/snoop.h>
|
|
|
|
#ifdef JREMOD
|
|
#ifdef DEVFS
|
|
#include <sys/devfsext.h>
|
|
#endif /*DEVFS*/
|
|
#define CDEV_MAJOR 53
|
|
#endif /*JREMOD*/
|
|
|
|
#ifndef MIN
|
|
#define MIN(a,b) (((a)<(b))?(a):(b))
|
|
#endif
|
|
|
|
static struct snoop snoopsw[NSNP];
|
|
|
|
static struct tty *
|
|
devtotty (dev)
|
|
dev_t dev;
|
|
{
|
|
if (major(dev) > nchrdev)
|
|
return (NULL); /* no such device available */
|
|
|
|
return (*cdevsw[major(dev)].d_devtotty)(dev);
|
|
}
|
|
|
|
#define SNP_INPUT_BUF 5 /* This is even too much,the maximal
|
|
* interactive mode write is 3 bytes
|
|
* length for function keys...
|
|
*/
|
|
|
|
int
|
|
snpwrite(dev, uio, flag)
|
|
dev_t dev;
|
|
struct uio *uio;
|
|
int flag;
|
|
{
|
|
int unit = minor(dev), len, i, error;
|
|
struct snoop *snp = &snoopsw[unit];
|
|
struct tty *tp;
|
|
char c[SNP_INPUT_BUF];
|
|
|
|
if (snp->snp_tty == NULL)
|
|
return (EIO);
|
|
|
|
tp = snp->snp_tty;
|
|
|
|
if ((tp->t_sc == snp) && (tp->t_state & TS_SNOOP) &&
|
|
(tp->t_line == OTTYDISC || tp->t_line == NTTYDISC))
|
|
goto tty_input;
|
|
|
|
printf("Snoop: attempt to write to bad tty.\n");
|
|
return (EIO);
|
|
|
|
tty_input:
|
|
if (!(tp->t_state & TS_ISOPEN))
|
|
return (EIO);
|
|
|
|
while (uio->uio_resid > 0) {
|
|
len = MIN(uio->uio_resid,SNP_INPUT_BUF);
|
|
if ((error = uiomove(c, len, uio)) != 0)
|
|
return (error);
|
|
for (i=0;i<len;i++) {
|
|
if (ttyinput(c[i] , tp))
|
|
return (EIO);
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
int
|
|
snpread(dev, uio, flag)
|
|
dev_t dev;
|
|
struct uio *uio;
|
|
int flag;
|
|
{
|
|
int unit = minor(dev), s;
|
|
struct snoop *snp = &snoopsw[unit];
|
|
int len, n, nblen, error = 0;
|
|
caddr_t from;
|
|
char *nbuf;
|
|
|
|
#ifdef DIAGNOSTIC
|
|
if ((snp->snp_len + snp->snp_base) > snp->snp_blen)
|
|
panic("snoop buffer error");
|
|
#endif
|
|
|
|
if (snp->snp_tty == NULL)
|
|
return (EIO);
|
|
|
|
snp->snp_flags &= ~SNOOP_RWAIT;
|
|
|
|
do {
|
|
if (snp->snp_len == 0) {
|
|
if (snp->snp_flags & SNOOP_NBIO) {
|
|
return EWOULDBLOCK;
|
|
}
|
|
snp->snp_flags |= SNOOP_RWAIT;
|
|
tsleep((caddr_t) snp, (PZERO + 1) | PCATCH, "snoopread", 0);
|
|
}
|
|
} while (snp->snp_len == 0);
|
|
|
|
n = snp->snp_len;
|
|
|
|
while (snp->snp_len > 0 && uio->uio_resid > 0 && error == 0) {
|
|
len = MIN(uio->uio_resid, snp->snp_len);
|
|
from = (caddr_t) (snp->snp_buf + snp->snp_base);
|
|
if (len == 0)
|
|
break;
|
|
|
|
error = uiomove(from, len, uio);
|
|
snp->snp_base += len;
|
|
snp->snp_len -= len;
|
|
}
|
|
if ((snp->snp_flags & SNOOP_OFLOW) && (n < snp->snp_len)) {
|
|
snp->snp_flags &= ~SNOOP_OFLOW;
|
|
}
|
|
s = spltty();
|
|
nblen = snp->snp_blen;
|
|
if (((nblen / 2) >= SNOOP_MINLEN) && (nblen / 2) >= snp->snp_len) {
|
|
while (((nblen / 2) >= snp->snp_len) && ((nblen / 2) >= SNOOP_MINLEN))
|
|
nblen = nblen / 2;
|
|
if (nbuf = malloc(nblen, M_TTYS, M_NOWAIT)) {
|
|
bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len);
|
|
free(snp->snp_buf, M_TTYS);
|
|
snp->snp_buf = nbuf;
|
|
snp->snp_blen = nblen;
|
|
snp->snp_base = 0;
|
|
}
|
|
}
|
|
splx(s);
|
|
|
|
return error;
|
|
}
|
|
|
|
int
|
|
snpinc(snp, c)
|
|
struct snoop *snp;
|
|
char c;
|
|
{
|
|
char buf[1];
|
|
|
|
buf[0]=c;
|
|
return (snpin(snp,buf,1));
|
|
}
|
|
|
|
|
|
int
|
|
snpin(snp, buf, n)
|
|
struct snoop *snp;
|
|
char *buf;
|
|
int n;
|
|
{
|
|
int s_free, s_tail;
|
|
int s, len, nblen;
|
|
caddr_t from, to;
|
|
char *nbuf;
|
|
|
|
|
|
if (n == 0)
|
|
return 0;
|
|
|
|
#ifdef DIAGNOSTIC
|
|
if (n < 0)
|
|
panic("bad snoop char count");
|
|
|
|
if (!(snp->snp_flags & SNOOP_OPEN)) {
|
|
printf("Snoop: data coming to closed device.\n");
|
|
return 0;
|
|
}
|
|
#endif
|
|
if (snp->snp_flags & SNOOP_DOWN) {
|
|
printf("Snoop: more data to down interface.\n");
|
|
return 0;
|
|
}
|
|
|
|
if (snp->snp_flags & SNOOP_OFLOW) {
|
|
printf("Snoop: buffer overflow.\n");
|
|
/*
|
|
* On overflow we just repeat the standart close
|
|
* procedure...yes , this is waste of space but.. Then next
|
|
* read from device will fail if one would recall he is
|
|
* snooping and retry...
|
|
*/
|
|
|
|
return (snpdown(snp));
|
|
}
|
|
s_tail = snp->snp_blen - (snp->snp_len + snp->snp_base);
|
|
s_free = snp->snp_blen - snp->snp_len;
|
|
|
|
|
|
if (n > s_free) {
|
|
s = spltty();
|
|
nblen = snp->snp_blen;
|
|
while ((n > s_free) && ((nblen * 2) <= SNOOP_MAXLEN)) {
|
|
nblen = snp->snp_blen * 2;
|
|
s_free = nblen - (snp->snp_len + snp->snp_base);
|
|
}
|
|
if ((n <= s_free) && (nbuf = malloc(nblen, M_TTYS, M_NOWAIT))) {
|
|
bcopy(snp->snp_buf + snp->snp_base, nbuf, snp->snp_len);
|
|
free(snp->snp_buf, M_TTYS);
|
|
snp->snp_buf = nbuf;
|
|
snp->snp_blen = nblen;
|
|
snp->snp_base = 0;
|
|
} else {
|
|
snp->snp_flags |= SNOOP_OFLOW;
|
|
if (snp->snp_flags & SNOOP_RWAIT) {
|
|
snp->snp_flags &= ~SNOOP_RWAIT;
|
|
wakeup((caddr_t) snp);
|
|
}
|
|
splx(s);
|
|
return 0;
|
|
}
|
|
splx(s);
|
|
}
|
|
if (n > s_tail) {
|
|
from = (caddr_t) (snp->snp_buf + snp->snp_base);
|
|
to = (caddr_t) (snp->snp_buf);
|
|
len = snp->snp_len;
|
|
bcopy(from, to, len);
|
|
snp->snp_base = 0;
|
|
}
|
|
to = (caddr_t) (snp->snp_buf + snp->snp_base + snp->snp_len);
|
|
bcopy(buf, to, n);
|
|
snp->snp_len += n;
|
|
|
|
if (snp->snp_flags & SNOOP_RWAIT) {
|
|
snp->snp_flags &= ~SNOOP_RWAIT;
|
|
wakeup((caddr_t) snp);
|
|
}
|
|
selwakeup(&snp->snp_sel);
|
|
snp->snp_sel.si_pid = 0;
|
|
|
|
return n;
|
|
}
|
|
|
|
int
|
|
snpopen(dev, flag, mode, p)
|
|
dev_t dev;
|
|
int flag, mode;
|
|
struct proc *p;
|
|
{
|
|
struct snoop *snp;
|
|
register int unit, error;
|
|
|
|
if (error = suser(p->p_ucred, &p->p_acflag))
|
|
return (error);
|
|
|
|
if ((unit = minor(dev)) >= NSNP)
|
|
return (ENXIO);
|
|
|
|
snp = &snoopsw[unit];
|
|
|
|
if (snp->snp_flags & SNOOP_OPEN)
|
|
return (ENXIO);
|
|
|
|
/*
|
|
* We intentionally do not OR flags with SNOOP_OPEN,but set them so
|
|
* all previous settings (especially SNOOP_OFLOW) will be cleared.
|
|
*/
|
|
snp->snp_flags = SNOOP_OPEN;
|
|
|
|
snp->snp_buf = malloc(SNOOP_MINLEN, M_TTYS, M_WAITOK);
|
|
snp->snp_blen = SNOOP_MINLEN;
|
|
snp->snp_base = 0;
|
|
snp->snp_len = 0;
|
|
|
|
/*
|
|
* snp_tty == NULL is for inactive snoop devices.
|
|
*/
|
|
snp->snp_tty = NULL;
|
|
snp->snp_target = -1;
|
|
return (0);
|
|
}
|
|
|
|
|
|
int
|
|
snp_detach(snp)
|
|
struct snoop *snp;
|
|
{
|
|
struct tty *tp;
|
|
|
|
snp->snp_base = 0;
|
|
snp->snp_len = 0;
|
|
|
|
/*
|
|
* If line disc. changed we do not touch this pointer,SLIP/PPP will
|
|
* change it anyway.
|
|
*/
|
|
|
|
if (snp->snp_tty == NULL)
|
|
goto detach_notty;
|
|
|
|
tp = snp->snp_tty;
|
|
|
|
if (tp && (tp->t_sc == snp) && (tp->t_state & TS_SNOOP) &&
|
|
(tp->t_line == OTTYDISC || tp->t_line == NTTYDISC)) {
|
|
tp->t_sc = NULL;
|
|
tp->t_state &= ~TS_SNOOP;
|
|
} else
|
|
printf("Snoop: bad attached tty data.\n");
|
|
|
|
snp->snp_tty = NULL;
|
|
snp->snp_target = -1;
|
|
|
|
detach_notty:
|
|
selwakeup(&snp->snp_sel);
|
|
snp->snp_sel.si_pid = 0;
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
snpclose(dev, flags, fmt, p)
|
|
dev_t dev;
|
|
int flags;
|
|
int fmt;
|
|
struct proc *p;
|
|
{
|
|
register int unit = minor(dev);
|
|
struct snoop *snp = &snoopsw[unit];
|
|
|
|
snp->snp_blen = 0;
|
|
free(snp->snp_buf, M_TTYS);
|
|
snp->snp_flags &= ~SNOOP_OPEN;
|
|
|
|
return (snp_detach(snp));
|
|
}
|
|
|
|
int
|
|
snpdown(snp)
|
|
struct snoop *snp;
|
|
{
|
|
snp->snp_blen = SNOOP_MINLEN;
|
|
free(snp->snp_buf, M_TTYS);
|
|
snp->snp_buf = malloc(SNOOP_MINLEN, M_TTYS, M_WAITOK);
|
|
snp->snp_flags |= SNOOP_DOWN;
|
|
|
|
return (snp_detach(snp));
|
|
}
|
|
|
|
|
|
int
|
|
snpioctl(dev, cmd, data, flags, p)
|
|
dev_t dev;
|
|
int cmd;
|
|
caddr_t data;
|
|
int flags;
|
|
struct proc *p;
|
|
{
|
|
int unit = minor(dev), s;
|
|
dev_t tdev;
|
|
struct snoop *snp = &snoopsw[unit];
|
|
struct tty *tp, *tpo;
|
|
|
|
switch (cmd) {
|
|
case SNPSTTY:
|
|
tdev = *((dev_t *) data);
|
|
if (tdev == -1)
|
|
return (snpdown(snp));
|
|
|
|
tp = devtotty(tdev);
|
|
if (!tp)
|
|
return (EINVAL);
|
|
|
|
if ((tp->t_sc != (caddr_t) snp) && (tp->t_state & TS_SNOOP))
|
|
return (EBUSY);
|
|
|
|
if ((tp->t_line != OTTYDISC) && (tp->t_line != NTTYDISC))
|
|
return (EBUSY);
|
|
|
|
s = spltty();
|
|
|
|
if (snp->snp_target == -1) {
|
|
tpo = snp->snp_tty;
|
|
if (tpo)
|
|
tpo->t_state &= ~TS_SNOOP;
|
|
}
|
|
|
|
tp->t_sc = (caddr_t) snp;
|
|
tp->t_state |= TS_SNOOP;
|
|
snp->snp_tty = tp;
|
|
snp->snp_target = tdev;
|
|
|
|
/*
|
|
* Clean overflow and down flags -
|
|
* we'll have a chance to get them in the future :)))
|
|
*/
|
|
snp->snp_flags &= ~SNOOP_OFLOW;
|
|
snp->snp_flags &= ~SNOOP_DOWN;
|
|
splx(s);
|
|
break;
|
|
|
|
case SNPGTTY:
|
|
/*
|
|
* We keep snp_target field specially to make
|
|
* SNPGTTY happy,else we can't know what is device
|
|
* major/minor for tty.
|
|
*/
|
|
*((dev_t *) data) = snp->snp_target;
|
|
break;
|
|
|
|
case FIONBIO:
|
|
if (*(int *) data)
|
|
snp->snp_flags |= SNOOP_NBIO;
|
|
else
|
|
snp->snp_flags &= ~SNOOP_NBIO;
|
|
break;
|
|
|
|
case FIOASYNC:
|
|
if (*(int *) data)
|
|
snp->snp_flags |= SNOOP_ASYNC;
|
|
else
|
|
snp->snp_flags &= ~SNOOP_ASYNC;
|
|
break;
|
|
|
|
case FIONREAD:
|
|
s = spltty();
|
|
if (snp->snp_tty != NULL)
|
|
*(int *) data = snp->snp_len;
|
|
else
|
|
if (snp->snp_flags & SNOOP_DOWN) {
|
|
if (snp->snp_flags & SNOOP_OFLOW)
|
|
*(int *) data = SNP_OFLOW;
|
|
else
|
|
*(int *) data = SNP_TTYCLOSE;
|
|
} else {
|
|
*(int *) data = SNP_DETACH;
|
|
}
|
|
splx(s);
|
|
break;
|
|
|
|
default:
|
|
return (ENOTTY);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
|
|
int
|
|
snpselect(dev, rw, p)
|
|
dev_t dev;
|
|
int rw;
|
|
struct proc *p;
|
|
{
|
|
int unit = minor(dev);
|
|
struct snoop *snp = &snoopsw[unit];
|
|
|
|
if (rw != FREAD)
|
|
return 1;
|
|
|
|
if (snp->snp_len > 0)
|
|
return 1;
|
|
|
|
/*
|
|
* If snoop is down,we don't want to select() forever so we return 1.
|
|
* Caller should see if we down via FIONREAD ioctl().The last should
|
|
* return -1 to indicate down state.
|
|
*/
|
|
if (snp->snp_flags & SNOOP_DOWN)
|
|
return 1;
|
|
|
|
selrecord(p, &snp->snp_sel);
|
|
return 0;
|
|
}
|
|
|
|
#ifdef JREMOD
|
|
struct cdevsw snp_cdevsw =
|
|
{ snpopen, snpclose, snpread, snpwrite, /*53*/
|
|
snpioctl, nostop, nullreset, nodevtotty,/* snoop */
|
|
snpselect, nommap, NULL };
|
|
|
|
static snp_devsw_installed = 0;
|
|
|
|
static void snp_drvinit(void *unused)
|
|
{
|
|
dev_t dev;
|
|
|
|
if( ! snp_devsw_installed ) {
|
|
dev = makedev(CDEV_MAJOR,0);
|
|
cdevsw_add(&dev,&snp_cdevsw,NULL);
|
|
snp_devsw_installed = 1;
|
|
#ifdef DEVFS
|
|
{
|
|
int x;
|
|
/* default for a simple device with no probe routine (usually delete this) */
|
|
x=devfs_add_devsw(
|
|
/* path name devsw minor type uid gid perm*/
|
|
"/", "snp", major(dev), 0, DV_CHR, 0, 0, 0600);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
SYSINIT(snpdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,snp_drvinit,NULL)
|
|
|
|
#endif /* JREMOD */
|
|
|
|
#endif
|