diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c index 0d474c7dd7c9..11919df857b3 100644 --- a/sys/dev/firewire/firewire.c +++ b/sys/dev/firewire/firewire.c @@ -124,8 +124,6 @@ char linkspeed[7][0x10]={"S100","S200","S400","S800","S1600","S3200","Unknown"}; u_int gap_cnt[] = { 5, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40}; -extern struct cdevsw firewire_cdevsw; - static driver_t firewire_driver = { "firewire", firewire_methods, @@ -356,44 +354,22 @@ firewire_watchdog(void *arg) * The attach routine. */ static int -firewire_attach( device_t dev ) +firewire_attach(device_t dev) { - int i, unitmask, mn; + int unit; struct firewire_softc *sc = device_get_softc(dev); device_t pa = device_get_parent(dev); struct firewire_comm *fc; - dev_t d; fc = (struct firewire_comm *)device_get_softc(pa); sc->fc = fc; fc->status = FWBUSNOTREADY; - unitmask = UNIT2MIN(device_get_unit(dev)); - + unit = device_get_unit(dev); if( fc->nisodma > FWMAXNDMA) fc->nisodma = FWMAXNDMA; - for ( i = 0 ; i < fc->nisodma ; i++ ){ - mn = unitmask | i; - /* XXX device name should be improved */ - d = make_dev(&firewire_cdevsw, unit2minor(mn), - UID_ROOT, GID_OPERATOR, 0660, - "fw%x", mn); -#if __FreeBSD_version >= 500000 - if (i == 0) - sc->dev = d; - else - dev_depends(sc->dev, d); -#else - sc->dev[i] = d; -#endif - } - d = make_dev(&firewire_cdevsw, unit2minor(unitmask | FWMEM_FLAG), - UID_ROOT, GID_OPERATOR, 0660, - "fwmem%d", device_get_unit(dev)); -#if __FreeBSD_version >= 500000 - dev_depends(sc->dev, d); -#else - sc->dev[i] = d; -#endif + + fwdev_makedev(sc); + CALLOUT_INIT(&sc->fc->timeout_callout); CALLOUT_INIT(&sc->fc->bmr_callout); CALLOUT_INIT(&sc->fc->retry_probe_callout); @@ -450,30 +426,25 @@ firewire_resume(device_t dev) * Dettach it. */ static int -firewire_detach( device_t dev ) +firewire_detach(device_t dev) { struct firewire_softc *sc; struct csrdir *csrd, *next; struct fw_device *fwdev, *fwdev_next; + int err; sc = (struct firewire_softc *)device_get_softc(dev); + if ((err = fwdev_destroydev(sc)) != 0) + return err; - bus_generic_detach(dev); + if ((err = bus_generic_detach(dev)) != 0) + return err; callout_stop(&sc->fc->timeout_callout); callout_stop(&sc->fc->bmr_callout); callout_stop(&sc->fc->retry_probe_callout); callout_stop(&sc->fc->busprobe_callout); -#if __FreeBSD_version >= 500000 - destroy_dev(sc->dev); -#else - { - int j; - for (j = 0 ; j < sc->fc->nisodma + 1; j++) - destroy_dev(sc->dev[j]); - } -#endif /* XXX xfree_free and untimeout on all xfers */ for (fwdev = STAILQ_FIRST(&sc->fc->devices); fwdev != NULL; fwdev = fwdev_next) { @@ -2197,5 +2168,33 @@ fw_bmr(struct firewire_comm *fc) return 0; } -DRIVER_MODULE(firewire,fwohci,firewire_driver,firewire_devclass,0,0); +static int +fw_modevent(module_t mode, int type, void *data) +{ + int err = 0; +#if __FreeBSD_version >= 500000 + static eventhandler_tag fwdev_ehtag = NULL; +#endif + + switch (type) { + case MOD_LOAD: +#if __FreeBSD_version >= 500000 + fwdev_ehtag = EVENTHANDLER_REGISTER(dev_clone, + fwdev_clone, 0, 1000); +#endif + break; + case MOD_UNLOAD: +#if __FreeBSD_version >= 500000 + if (fwdev_ehtag != NULL) + EVENTHANDLER_DEREGISTER(dev_clone, fwdev_ehtag); +#endif + break; + case MOD_SHUTDOWN: + break; + } + return (err); +} + + +DRIVER_MODULE(firewire,fwohci,firewire_driver,firewire_devclass,fw_modevent,0); MODULE_VERSION(firewire, 1); diff --git a/sys/dev/firewire/firewire.h b/sys/dev/firewire/firewire.h index b3ff16928ca0..b5f6573d6623 100644 --- a/sys/dev/firewire/firewire.h +++ b/sys/dev/firewire/firewire.h @@ -393,7 +393,8 @@ struct fw_crom_buf { #define unit2minor(x) (((x) & 0xff) | (((x) << 8) & ~0xffff)) #endif -#define UNIT2MIN(x) (((x) & 0xff) << 8) +#define MAKEMINOR(f, u, s) \ + unit2minor((f) | (((u) & 0xff) << 8) | (s & 0xff)) #define DEV2UNIT(x) ((dev2unit(x) & 0xff00) >> 8) #define DEV2SUB(x) (dev2unit(x) & 0xff) diff --git a/sys/dev/firewire/firewirereg.h b/sys/dev/firewire/firewirereg.h index 3a69e4eb8921..e90f0c07f526 100644 --- a/sys/dev/firewire/firewirereg.h +++ b/sys/dev/firewire/firewirereg.h @@ -70,8 +70,6 @@ struct fw_device{ struct firewire_softc { #if __FreeBSD_version >= 500000 dev_t dev; -#else - dev_t dev[FWMAXNDMA+1]; #endif struct firewire_comm *fc; }; @@ -290,7 +288,9 @@ struct fw_device *fw_noderesolve_nodeid __P((struct firewire_comm *, int)); struct fw_device *fw_noderesolve_eui64 __P((struct firewire_comm *, struct fw_eui64 *)); struct fw_bind *fw_bindlookup __P((struct firewire_comm *, u_int32_t, u_int32_t)); void fw_drain_txq __P((struct firewire_comm *)); - +int fwdev_makedev __P((struct firewire_softc *)); +int fwdev_destroydev __P((struct firewire_softc *)); +void fwdev_clone __P((void *, char *, int, dev_t *)); extern int firewire_debug; extern devclass_t firewire_devclass; diff --git a/sys/dev/firewire/fwdev.c b/sys/dev/firewire/fwdev.c index abf0e476d8d3..0d61fb7867e7 100644 --- a/sys/dev/firewire/fwdev.c +++ b/sys/dev/firewire/fwdev.c @@ -46,6 +46,7 @@ #include #include +#include #include #include @@ -82,7 +83,8 @@ struct cdevsw firewire_cdevsw = .d_flags = D_MEM #else fw_open, fw_close, fw_read, fw_write, fw_ioctl, - fw_poll, fw_mmap, nostrategy, "fw", CDEV_MAJOR, nodump, nopsize, D_MEM + fw_poll, fw_mmap, nostrategy, "fw", CDEV_MAJOR, + nodump, nopsize, D_MEM, -1 #endif }; @@ -159,9 +161,6 @@ fwdev_freebuf(struct fw_xferq *q) static int fw_open (dev_t dev, int flags, int fmt, fw_proc *td) { - int unit = DEV2UNIT(dev); - int sub = DEV2SUB(dev); - int err = 0; if (dev->si_drv1 != NULL) @@ -171,11 +170,15 @@ fw_open (dev_t dev, int flags, int fmt, fw_proc *td) return fwmem_open(dev, flags, fmt, td); #if __FreeBSD_version >= 500000 - if ((dev->si_flags & SI_NAMED) == 0) -#endif + if ((dev->si_flags & SI_NAMED) == 0) { + int unit = DEV2UNIT(dev); + int sub = DEV2SUB(dev); + make_dev(&firewire_cdevsw, minor(dev), UID_ROOT, GID_OPERATOR, 0660, "fw%d.%d", unit, sub); + } +#endif dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); @@ -718,7 +721,7 @@ fw_mmap (dev_t dev, vm_offset_t offset, int nproto) fw_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto) #endif { - struct firewire_softc *fc; + struct firewire_softc *sc; int unit = DEV2UNIT(dev); if (DEV_FWMEM(dev)) @@ -728,7 +731,91 @@ fw_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto) return fwmem_mmap(dev, offset, paddr, nproto); #endif - fc = devclass_get_softc(firewire_devclass, unit); + sc = devclass_get_softc(firewire_devclass, unit); return EINVAL; } + +int +fwdev_makedev(struct firewire_softc *sc) +{ + int err = 0; + +#if __FreeBSD_version >= 500000 + dev_t d; + int unit; + + unit = device_get_unit(sc->fc->bdev); + sc->dev = make_dev(&firewire_cdevsw, MAKEMINOR(0, unit, 0), + UID_ROOT, GID_OPERATOR, 0660, + "fw%d.%d", unit, 0); + d = make_dev(&firewire_cdevsw, + MAKEMINOR(FWMEM_FLAG, unit, 0), + UID_ROOT, GID_OPERATOR, 0660, + "fwmem%d.%d", unit, 0); + dev_depends(sc->dev, d); + make_dev_alias(sc->dev, "fw%d", unit); + make_dev_alias(d, "fwmem%d", unit); +#else + cdevsw_add(&firewire_cdevsw); +#endif + + return (err); +} + +int +fwdev_destroydev(struct firewire_softc *sc) +{ + int err = 0; + +#if __FreeBSD_version >= 500000 + destroy_dev(sc->dev); +#else + cdevsw_remove(&firewire_cdevsw); +#endif + return (err); +} + +#if __FreeBSD_version >= 500000 +#define NDEVTYPE 2 +void +fwdev_clone(void *arg, char *name, int namelen, dev_t *dev) +{ + struct firewire_softc *sc; + char *devnames[NDEVTYPE] = {"fw", "fwmem"}; + char *subp = NULL; + int devflag[NDEVTYPE] = {0, FWMEM_FLAG}; + int i, unit = 0, sub = 0; + + if (*dev != NODEV) + return; + + for (i = 0; i < NDEVTYPE; i++) + if (dev_stdclone(name, &subp, devnames[i], &unit) != 1) + goto found; + /* not match */ + return; +found: + + if (subp == NULL || *subp++ != '.') + return; + + /* /dev/fwU.S */ + while (isdigit(*subp)) { + sub *= 10; + sub += *subp++ - '0'; + } + if (*subp != '\0') + return; + + sc = devclass_get_softc(firewire_devclass, unit); + if (sc == NULL) + return; + *dev = make_dev(&firewire_cdevsw, MAKEMINOR(devflag[i], unit, sub), + UID_ROOT, GID_OPERATOR, 0660, + "%s%d.%d", devnames[i], unit, sub); + (*dev)->si_flags |= SI_CHEAPCLONE; + dev_depends(sc->dev, *dev); + return; +} +#endif