summaryrefslogtreecommitdiffstats
path: root/sys/dev/nmdm
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2004-02-21 20:29:52 +0000
committerphk <phk@FreeBSD.org>2004-02-21 20:29:52 +0000
commit32b7c9a433930842533064d829ba214aadf6a67d (patch)
treec97716bebd5c7c784bf841850192a5addeaf0347 /sys/dev/nmdm
parentdf397dedeab80f98300da9e5999d17a57c01b19f (diff)
downloadFreeBSD-src-32b7c9a433930842533064d829ba214aadf6a67d.zip
FreeBSD-src-32b7c9a433930842533064d829ba214aadf6a67d.tar.gz
Device megapatch 2/6:
This commit adds a couple of functions for pseudodrivers to use for implementing cloning in a manner we will be able to lock down (shortly). Basically what happens is that pseudo drivers get a way to ask for "give me the dev_t with this unit number" or alternatively "give me a dev_t with the lowest guaranteed free unit number" (there is unfortunately a lot of non-POLA in the exact numeric value of this number, just live with it for now) Managing the unit number space this way removes the need to use rman(9) to do so in the drivers this greatly simplifies the code in the drivers because even using rman(9) they still needed to manage their dev_t's anyway. I have taken the if_tun, if_tap, snp and nmdm drivers through the mill, partly because they (ab)used makedev(), but mostly because together they represent three different problems for device-cloning: if_tun and snp is the plain case: just give me a device. if_tap has two kinds of devices, with a flag for device type. nmdm has paired devices (ala pty) can you can clone either of them.
Diffstat (limited to 'sys/dev/nmdm')
-rw-r--r--sys/dev/nmdm/nmdm.c169
1 files changed, 85 insertions, 84 deletions
diff --git a/sys/dev/nmdm/nmdm.c b/sys/dev/nmdm/nmdm.c
index 3227b11..f3440dd 100644
--- a/sys/dev/nmdm/nmdm.c
+++ b/sys/dev/nmdm/nmdm.c
@@ -63,8 +63,7 @@ MALLOC_DEFINE(M_NLMDM, "nullmodem", "nullmodem data structures");
static void nmdmstart(struct tty *tp);
static void nmdmstop(struct tty *tp, int rw);
static void wakeup_other(struct tty *tp, int flag);
-static void nmdminit(int);
-static int nmdmshutdown(void);
+static void nmdminit(dev_t dev);
static d_open_t nmdmopen;
static d_close_t nmdmclose;
@@ -72,7 +71,6 @@ static d_read_t nmdmread;
static d_write_t nmdmwrite;
static d_ioctl_t nmdmioctl;
-#define CDEV_MAJOR 18
static struct cdevsw nmdm_cdevsw = {
.d_open = nmdmopen,
.d_close = nmdmclose,
@@ -80,14 +78,14 @@ static struct cdevsw nmdm_cdevsw = {
.d_write = nmdmwrite,
.d_ioctl = nmdmioctl,
.d_poll = ttypoll,
- .d_name = "pts",
- .d_maj = CDEV_MAJOR,
- .d_flags = D_TTY,
+ .d_name = "nmdm",
+ .d_flags = D_TTY | D_PSEUDO,
};
#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
struct softpart {
struct tty nm_tty;
@@ -97,11 +95,61 @@ struct softpart {
};
struct nm_softc {
- int pt_flags;
- struct softpart part1, part2;
- struct prison *pt_prison;
+ TAILQ_ENTRY(nm_softc) pt_list;
+ int pt_flags;
+ struct softpart part1, part2;
+ struct prison *pt_prison;
};
+static struct clonedevs *nmdmclones;
+static TAILQ_HEAD(,nm_softc) nmdmhead = TAILQ_HEAD_INITIALIZER(nmdmhead);
+
+static void
+nmdm_clone(void *arg, char *name, int nameen, dev_t *dev)
+{
+ int i, unit;
+ char *p;
+ dev_t d1, d2;
+
+ if (*dev != NODEV)
+ 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;
+ else
+ *dev = d1;
+}
+
static void
nmdm_crossover(struct nm_softc *pti,
struct softpart *ourpart,
@@ -123,24 +171,22 @@ do { \
* This function creates and initializes a pair of ttys.
*/
static void
-nmdminit(n)
- int n;
+nmdminit(dev_t dev1)
{
- dev_t dev1, dev2;
+ dev_t dev2;
struct nm_softc *pt;
- /* For now we only map the lower 8 bits of the minor */
- if (n & ~0xff)
- return;
+ dev2 = dev1->si_drv2;
- pt = malloc(sizeof(*pt), M_NLMDM, M_WAITOK);
- bzero(pt, sizeof(*pt));
- pt->part1.dev = dev1 = make_dev(&nmdm_cdevsw, n+n,
- 0, 0, 0666, "nmdm%dA", n);
- pt->part2.dev = dev2 = make_dev(&nmdm_cdevsw, n+n+1,
- 0, 0, 0666, "nmdm%dB", n);
+ 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;
dev1->si_tty = &pt->part1.nm_tty;
dev2->si_tty = &pt->part2.nm_tty;
ttyregister(&pt->part1.nm_tty);
@@ -148,9 +194,9 @@ nmdminit(n)
pt->part1.nm_tty.t_oproc = nmdmstart;
pt->part2.nm_tty.t_oproc = nmdmstart;
pt->part1.nm_tty.t_stop = nmdmstop;
+ pt->part2.nm_tty.t_stop = nmdmstop;
pt->part2.nm_tty.t_dev = dev1;
pt->part1.nm_tty.t_dev = dev2;
- pt->part2.nm_tty.t_stop = nmdmstop;
}
/*
@@ -161,39 +207,14 @@ nmdmopen(dev_t dev, int flag, int devtype, struct thread *td)
{
register struct tty *tp, *tp2;
int error;
- int minr;
- dev_t nextdev;
struct nm_softc *pti;
- int is_b;
- int pair;
struct softpart *ourpart, *otherpart;
- /*
- * XXX: Gross hack for DEVFS:
- * If we openned this device, ensure we have the
- * next one too, so people can open it.
- */
- minr = dev2unit(dev);
- pair = minr >> 1;
- is_b = minr & 1;
-
- if (pair < (NMDM_MAX_NUM - 1)) {
- nextdev = makedev(major(dev), minr + 2);
- if (!nextdev->si_drv1) {
- nmdminit(pair + 1);
- }
- } else { /* Limit ourselves to 128 of them for now */
- if (pair > (NMDM_MAX_NUM - 1))
- return (ENXIO);
- }
- if (!dev->si_drv1)
- nmdminit(pair);
-
- if (!dev->si_drv1)
- return(ENXIO);
-
+ if (dev->si_drv1 == NULL)
+ nmdminit(dev);
pti = dev->si_drv1;
- if (is_b)
+
+ if (minor(dev) & BFLAG)
tp = &pti->part2.nm_tty;
else
tp = &pti->part1.nm_tty;
@@ -567,20 +588,27 @@ nmdm_crossover(struct nm_softc *pti, struct softpart *ourpart,
static int
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: /* start with 4 of them */
- nmdminit(0);
- nmdminit(1);
- nmdminit(2);
- nmdminit(3);
+ case MOD_LOAD:
+ tag = EVENTHANDLER_REGISTER(dev_clone, nmdm_clone, 0, 1000);
+ if (tag == NULL)
+ return (ENOMEM);
break;
case MOD_SHUTDOWN:
/* FALLTHROUGH */
case MOD_UNLOAD:
- nmdmshutdown();
+ 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);
break;
default:
error = EOPNOTSUPP;
@@ -588,31 +616,4 @@ nmdm_modevent(module_t mod, int type, void *data)
return (error);
}
-/*
- * Handle teardown of device
- */
-static int
-nmdmshutdown(void)
-{
- int i;
- dev_t nextdev1;
- dev_t nextdev2;
- void * ptr1;
-
- for(i = 0;( i < NMDM_MAX_NUM) ;i++) {
- nextdev1 = makedev(CDEV_MAJOR, (i+i) );
- nextdev2 = makedev(CDEV_MAJOR, (i+i) + 1);
- ptr1 = nextdev1->si_drv1;
- if (ptr1) {
- destroy_dev(nextdev1);
- destroy_dev(nextdev2);
- free(ptr1, M_NLMDM);
- } else {
- freedev(nextdev1);
- freedev(nextdev2);
- }
- }
- return(0);
-}
-
DEV_MODULE(nmdm, nmdm_modevent, NULL);
OpenPOWER on IntegriCloud