PERFORCE change 146518 for review
Ed Schouten
ed at FreeBSD.org
Sun Aug 3 12:55:26 UTC 2008
http://perforce.freebsd.org/chv.cgi?CH=146518
Change 146518 by ed at ed_flippo on 2008/08/03 12:54:42
Very first cut to get nmdm(4) working.
Does not compile, but I'd better check it in to make sure it
doesn't get lost.
Affected files ...
.. //depot/projects/mpsafetty/sys/dev/nmdm/nmdm.c#2 edit
Differences ...
==== //depot/projects/mpsafetty/sys/dev/nmdm/nmdm.c#2 (text+ko) ====
@@ -48,154 +48,158 @@
#include <sys/fcntl.h>
#include <sys/poll.h>
#include <sys/kernel.h>
+#include <sys/limits.h>
#include <sys/module.h>
#include <sys/serial.h>
#include <sys/signalvar.h>
#include <sys/malloc.h>
#include <sys/taskqueue.h>
-MALLOC_DEFINE(M_NLMDM, "nullmodem", "nullmodem data structures");
+MALLOC_DEFINE(M_NMDM, "nullmodem", "nullmodem data structures");
-static d_close_t nmdmclose;
-static t_modem_t nmdmmodem;
-static d_open_t nmdmopen;
-static t_oproc_t nmdmoproc;
-static t_param_t nmdmparam;
-static t_stop_t nmdmstop;
+static tsw_outwakeup_t nmdm_outwakeup;
+static tsw_param_t nmdm_param;
+static tsw_modem_t nmdm_modem;
-static struct cdevsw nmdm_cdevsw = {
- .d_version = D_VERSION,
- .d_open = nmdmopen,
- .d_close = nmdmclose,
- .d_name = "nmdn",
- .d_flags = D_TTY | D_PSEUDO | D_NEEDGIANT | D_NEEDMINOR,
+static struct ttydevsw nmdm_class = {
+ .tsw_flags = TF_NOPREFIX,
+ .tsw_outwakeup = nmdm_outwakeup,
+ .tsw_param = nmdm_param,
+ .tsw_modem = nmdm_modem,
};
-#define BUFSIZ 100 /* Chunk size iomoved to/from user */
-#define NMDM_MAX_NUM 128 /* Artificially limit # devices. */
-#define PF_STOPPED 0x10 /* user told stopped */
-#define BFLAG CLONE_FLAG0
+static void nmdm_task_tty(void *, int);
+
+struct nmdmsoftc;
-struct softpart {
- struct tty *nm_tty;
- struct cdev *dev;
- int nm_dcd;
- struct task pt_task;
- struct softpart *other;
- struct callout co;
- u_long quota;
- u_long accumulator;
- int rate;
- int credits;
+struct nmdmpart {
+ struct tty *np_tty;
+ int np_dcd;
+ struct task np_task;
+ struct nmdmpart *np_other;
+ struct nmdmsoftc *np_pair;
+ struct callout np_callout;
+ u_long np_quota;
+ u_long np_accumulator;
+ int np_rate;
+ int np_credits;
#define QS 8 /* Quota shift */
};
-struct nm_softc {
- TAILQ_ENTRY(nm_softc) pt_list;
- int pt_flags;
- struct softpart part1, part2;
- struct prison *pt_prison;
+struct nmdmsoftc {
+ struct nmdmpart ns_part1;
+ struct nmdmpart ns_part2;
+ struct mtx ns_mtx;
};
-static struct clonedevs *nmdmclones;
-static TAILQ_HEAD(,nm_softc) nmdmhead = TAILQ_HEAD_INITIALIZER(nmdmhead);
+static struct nmdmsoftc *
+nmdm_alloc(unsigned long unit, struct ucred *cr)
+{
+ struct nmdmsoftc *ns;
+ struct tty *tp;
+
+ ns = malloc(sizeof(*ns), M_NMDM, M_WAITOK|M_ZERO);
+ mtx_init(&ns->ns_mtx, "nmdm", NULL, MTX_DEF);
+
+ /* Hook the pairs together */
+ ns->ns_part1.np_pair = ns;
+ ns->ns_part1.np_other = &ns->ns_part2;
+ TASK_INIT(&ns->ns_part1.np_task, 0, nmdm_task_tty, &ns->ns_part1);
+ callout_init(&ns->ns_part1.np_callout, 0);
+
+ ns->ns_part2.np_pair = ns;
+ ns->ns_part2.np_other = &ns->ns_part1;
+ TASK_INIT(&ns->ns_part2.np_task, 0, nmdm_task_tty, &ns->ns_part2);
+ callout_init(&ns->ns_part2.np_callout, 0);
+
+ /* Create device nodes */
+ tp = ns->ns_part1.np_tty = tty_alloc(&nmdm_class, &ns->ns_part1,
+ &ns->ns_mtx);
+ tty_makedev(tp, cr, "nmdm%luA", unit);
+
+ tp = ns->ns_part2.np_tty = tty_alloc(&nmdm_class, &ns->ns_part2,
+ &ns->ns_mtx);
+ tty_makedev(tp, cr, "nmdm%luB", unit);
+
+ return (ns);
+}
static void
nmdm_clone(void *arg, struct ucred *cred, char *name, int nameen,
struct cdev **dev)
{
- int i, unit;
- char *p;
- struct cdev *d1, *d2;
+ unsigned long unit;
+ char *end;
+ struct nmdmsoftc *ns;
if (*dev != NULL)
return;
- if (strcmp(name, "nmdm") == 0) {
- p = NULL;
- unit = -1;
- } else {
- i = dev_stdclone(name, &p, "nmdm", &unit);
- if (i == 0)
- return;
- if (p[0] != '\0' && p[0] != 'A' && p[0] != 'B')
- return;
- else if (p[0] != '\0' && p[1] != '\0')
- return;
- }
- i = clone_create(&nmdmclones, &nmdm_cdevsw, &unit, &d1, 0);
- if (i) {
- d1 = make_dev(&nmdm_cdevsw, unit2minor(unit),
- 0, 0, 0666, "nmdm%dA", unit);
- if (d1 == NULL)
- return;
- d2 = make_dev(&nmdm_cdevsw, unit2minor(unit) | BFLAG,
- 0, 0, 0666, "nmdm%dB", unit);
- if (d2 == NULL) {
- destroy_dev(d1);
- return;
- }
- d2->si_drv2 = d1;
- d1->si_drv2 = d2;
- dev_depends(d1, d2);
- dev_depends(d2, d1);
- d1->si_flags |= SI_CHEAPCLONE;
- d2->si_flags |= SI_CHEAPCLONE;
- }
- if (p != NULL && p[0] == 'B')
- *dev = d1->si_drv2;
+ if (strncmp(name, "nmdm", 4) != 0)
+ return;
+
+ /* Device name must be "nmdm%lu%c", where %c is 'A' or 'B' */
+ name += 4;
+ unit = strtoul(name, &end, 10);
+ if (unit == ULONG_MAX || name == end)
+ return;
+ if ((end[0] != 'A' && end[0] != 'B') || end[1] != '\0')
+ return;
+
+ ns = nmdm_alloc(unit, cred);
+
+ if (end[1] == 'A')
+ *dev = ns->ns_part1.np_tty->t_dev;
else
- *dev = d1;
- dev_ref(*dev);
+ *dev = ns->ns_part2.np_tty->t_dev;
}
static void
nmdm_timeout(void *arg)
{
- struct softpart *sp;
+ struct nmdmpart *np = arg;
- sp = arg;
-
- if (sp->rate == 0)
+ if (np->np_rate == 0)
return;
/*
* Do a simple Floyd-Steinberg dither here to avoid FP math.
* Wipe out unused quota from last tick.
*/
- sp->accumulator += sp->credits;
- sp->quota = sp->accumulator >> QS;
- sp->accumulator &= ((1 << QS) - 1);
+ np->np_accumulator += np->np_credits;
+ np->np_quota = np->np_accumulator >> QS;
+ np->np_accumulator &= ((1 << QS) - 1);
- taskqueue_enqueue(taskqueue_swi_giant, &sp->pt_task);
- callout_reset(&sp->co, sp->rate, nmdm_timeout, arg);
+ taskqueue_enqueue(taskqueue_swi, &np->np_task);
+ callout_reset(&np->np_callout, np->np_rate, nmdm_timeout, np);
}
static void
nmdm_task_tty(void *arg, int pending __unused)
{
struct tty *tp, *otp;
- struct softpart *sp;
+ struct nmdmpart *np = tty_softc(tp);
+#if 0
int c;
+#endif
tp = arg;
- sp = tp->t_sc;
- otp = sp->other->nm_tty;
+ otp = np->np_other->np_tty;
KASSERT(otp != NULL, ("NULL otp in nmdmstart"));
KASSERT(otp != tp, ("NULL otp == tp nmdmstart"));
- if (sp->other->nm_dcd) {
- if (!(tp->t_state & TS_ISOPEN)) {
- sp->other->nm_dcd = 0;
- (void)ttyld_modem(otp, 0);
+ if (np->np_other->np_dcd) {
+ if (!tty_opened(tp)) {
+ np->np_other->np_dcd = 0;
+ (void)ttydisc_modem(otp, 0);
}
} else {
- if (tp->t_state & TS_ISOPEN) {
- sp->other->nm_dcd = 1;
- (void)ttyld_modem(otp, 1);
+ if (tty_opened(tp)) {
+ np->np_other->np_dcd = 1;
+ (void)ttydisc_modem(otp, 1);
}
}
- if (tp->t_state & TS_TTSTOP)
- return;
+
+#if 0
while (tp->t_outq.c_cc != 0) {
if (sp->rate && !sp->quota)
return;
@@ -208,92 +212,7 @@
}
if (tp->t_outq.c_cc == 0)
ttwwakeup(tp);
-
-}
-
-/*
- * This function creates and initializes a pair of ttys.
- */
-static void
-nmdminit(struct cdev *dev1)
-{
- struct cdev *dev2;
- struct nm_softc *pt;
-
- dev2 = dev1->si_drv2;
-
- dev1->si_flags &= ~SI_CHEAPCLONE;
- dev2->si_flags &= ~SI_CHEAPCLONE;
-
- pt = malloc(sizeof(*pt), M_NLMDM, M_WAITOK | M_ZERO);
- TAILQ_INSERT_TAIL(&nmdmhead, pt, pt_list);
-
- dev1->si_drv1 = dev2->si_drv1 = pt;
-
- pt->part1.dev = dev1;
- pt->part2.dev = dev2;
-
- pt->part1.nm_tty = ttyalloc();
- pt->part1.nm_tty->t_oproc = nmdmoproc;
- pt->part1.nm_tty->t_stop = nmdmstop;
- pt->part1.nm_tty->t_modem = nmdmmodem;
- pt->part1.nm_tty->t_param = nmdmparam;
- pt->part1.nm_tty->t_dev = dev1;
- pt->part1.nm_tty->t_sc = &pt->part1;
- TASK_INIT(&pt->part1.pt_task, 0, nmdm_task_tty, pt->part1.nm_tty);
- callout_init(&pt->part1.co, 0);
-
- pt->part2.nm_tty = ttyalloc();
- pt->part2.nm_tty->t_oproc = nmdmoproc;
- pt->part2.nm_tty->t_stop = nmdmstop;
- pt->part2.nm_tty->t_modem = nmdmmodem;
- pt->part2.nm_tty->t_param = nmdmparam;
- pt->part2.nm_tty->t_dev = dev2;
- pt->part2.nm_tty->t_sc = &pt->part2;
- TASK_INIT(&pt->part2.pt_task, 0, nmdm_task_tty, pt->part2.nm_tty);
- callout_init(&pt->part2.co, 0);
-
- pt->part1.other = &pt->part2;
- pt->part2.other = &pt->part1;
-
- dev1->si_tty = pt->part1.nm_tty;
- dev1->si_drv1 = pt;
-
- dev2->si_tty = pt->part2.nm_tty;
- dev2->si_drv1 = pt;
-}
-
-/*
- * Device opened from userland
- */
-static int
-nmdmopen(struct cdev *dev, int flag, int devtype, struct thread *td)
-{
- struct tty *tp, *tp2;
- int error;
- struct nm_softc *pti;
- struct softpart *sp;
-
- if (dev->si_drv1 == NULL)
- nmdminit(dev);
- pti = dev->si_drv1;
- if (pti->pt_prison != td->td_ucred->cr_prison)
- return (EBUSY);
-
- tp = dev->si_tty;
- sp = tp->t_sc;
- tp2 = sp->other->nm_tty;
-
- if ((tp->t_state & TS_ISOPEN) == 0) {
- ttyinitmode(tp, 0, 0);
- ttsetwater(tp); /* XXX ? */
- } else if (tp->t_state & TS_XCLUDE &&
- priv_check(td, PRIV_TTY_EXCLUSIVE)) {
- return (EBUSY);
- }
-
- error = ttyld_open(tp, dev);
- return (error);
+#endif
}
static int
@@ -319,16 +238,15 @@
static int
nmdmparam(struct tty *tp, struct termios *t)
{
- struct softpart *sp;
+ struct nmdmpart *np = tty_softc(tp);
struct tty *tp2;
int bpc, rate, speed, i;
- sp = tp->t_sc;
- tp2 = sp->other->nm_tty;
+ tp2 = np->np_other->np_tty;
if (!((t->c_cflag | tp2->t_cflag) & CDSR_OFLOW)) {
- sp->rate = 0;
- sp->other->rate = 0;
+ np->np_rate = 0;
+ np->np_other->np_rate = 0;
return (0);
}
@@ -345,8 +263,8 @@
/* Use the slower of our receive and their transmit rate */
speed = imin(tp2->t_ospeed, t->c_ispeed);
if (speed == 0) {
- sp->rate = 0;
- sp->other->rate = 0;
+ np->np_rate = 0;
+ np->np_other->np_rate = 0;
return (0);
}
@@ -359,28 +277,29 @@
speed *= rate;
speed /= hz; /* [(char/sec)/tick, scaled */
- sp->credits = speed;
- sp->rate = rate;
- callout_reset(&sp->co, rate, nmdm_timeout, sp);
+ np->np_credits = speed;
+ np->np_rate = rate;
+ callout_reset(&np->np_callout, rate, nmdm_timeout, np);
/*
* swap pointers for second pass so the other end gets
* updated as well.
*/
- sp = sp->other;
+ np = np->np_other;
t = &tp2->t_termios;
tp2 = tp;
}
return (0);
}
+#if 0
static int
nmdmmodem(struct tty *tp, int sigon, int sigoff)
{
struct softpart *sp;
int i;
- sp = tp->t_sc;
+ sp = tty_softc(tp);
if (sigon || sigoff) {
if (sigon & SER_DTR)
sp->other->nm_dcd = 1;
@@ -397,35 +316,15 @@
return (i);
}
}
-
-static int
-nmdmclose(struct cdev *dev, int flag, int mode, struct thread *td)
-{
- struct tty *tp = dev->si_tty;
- int error;
-
- error = ttyld_close(tp, flag);
- (void) tty_close(dev->si_tty);
+#endif
- return (error);
-}
-
static void
-nmdmoproc(struct tty *tp)
+nmdm_outwakeup(struct tty *tp)
{
- struct softpart *pt;
+ struct nmdmpart *np = tty_softc(tp);
- pt = tp->t_sc;
- taskqueue_enqueue(taskqueue_swi_giant, &pt->pt_task);
-}
-
-static void
-nmdmstop(struct tty *tp, int flush)
-{
- struct softpart *pt;
-
- pt = tp->t_sc;
- taskqueue_enqueue(taskqueue_swi_giant, &pt->pt_task);
+ np = tty_softc(tp);
+ taskqueue_enqueue(taskqueue_swi, &np->np_task);
}
/*
@@ -435,32 +334,27 @@
nmdm_modevent(module_t mod, int type, void *data)
{
static eventhandler_tag tag;
- struct nm_softc *pt, *tpt;
- int error = 0;
switch(type) {
case MOD_LOAD:
- clone_setup(&nmdmclones);
tag = EVENTHANDLER_REGISTER(dev_clone, nmdm_clone, 0, 1000);
if (tag == NULL)
return (ENOMEM);
break;
case MOD_SHUTDOWN:
- /* FALLTHROUGH */
+ break;
+
case MOD_UNLOAD:
EVENTHANDLER_DEREGISTER(dev_clone, tag);
- TAILQ_FOREACH_SAFE(pt, &nmdmhead, pt_list, tpt) {
- destroy_dev(pt->part1.dev);
- TAILQ_REMOVE(&nmdmhead, pt, pt_list);
- free(pt, M_NLMDM);
- }
- clone_cleanup(&nmdmclones);
+ /* XXX: track counter! */
break;
+
default:
- error = EOPNOTSUPP;
+ return (EOPNOTSUPP);
}
- return (error);
+
+ return (0);
}
DEV_MODULE(nmdm, nmdm_modevent, NULL);
More information about the p4-projects
mailing list