Module Name: src Committed By: riastradh Date: Mon Jun 14 10:14:58 UTC 2021
Modified Files: src/sys/dev/pad: pad.c Log Message: pad(4): Make this exclusively a cloning device. padN numbering never corresponded with audioM numbering except by accident, so the non-cloning device never worked reliably for scripting. This simplifies the logic substantially. While here, fix drvctl detach race. To generate a diff of this commit: cvs rdiff -u -r1.70 -r1.71 src/sys/dev/pad/pad.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pad/pad.c diff -u src/sys/dev/pad/pad.c:1.70 src/sys/dev/pad/pad.c:1.71 --- src/sys/dev/pad/pad.c:1.70 Mon Jun 14 10:14:46 2021 +++ src/sys/dev/pad/pad.c Mon Jun 14 10:14:58 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: pad.c,v 1.70 2021/06/14 10:14:46 riastradh Exp $ */ +/* $NetBSD: pad.c,v 1.71 2021/06/14 10:14:58 riastradh Exp $ */ /*- * Copyright (c) 2007 Jared D. McNeill <jmcne...@invisible.ca> @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.70 2021/06/14 10:14:46 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.71 2021/06/14 10:14:58 riastradh Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -54,6 +54,8 @@ __KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.70 #include <dev/pad/padvar.h> +#include "ioconf.h" + /* #define PAD_DEBUG */ #ifdef PAD_DEBUG #define DPRINTF(fmt...) printf(fmt) @@ -61,17 +63,10 @@ __KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.70 #define DPRINTF(fmt...) /**/ #endif -#define MAXDEVS 128 -#define PADCLONER 254 -#define PADUNIT(x) minor(x) - #define PADFREQ 44100 #define PADCHAN 2 #define PADPREC 16 -extern struct cfdriver pad_cd; -kmutex_t padconfig; - typedef struct pad_block { uint8_t *pb_ptr; int pb_len; @@ -107,7 +102,7 @@ static void pad_get_locks(void *, kmutex static void pad_done_output(void *); static void pad_swvol_codec(audio_filter_arg_t *); -static int pad_close(struct pad_softc *); +static void pad_close(struct pad_softc *); static int pad_read(struct pad_softc *, off_t *, struct uio *, kauth_cred_t, int); @@ -155,14 +150,12 @@ extern void padattach(int); static int pad_add_block(struct pad_softc *, uint8_t *, int); static int pad_get_block(struct pad_softc *, pad_block_t *, int); -dev_type_open(cdev_pad_open); -dev_type_close(cdev_pad_close); -dev_type_read(cdev_pad_read); +static dev_type_open(pad_open); const struct cdevsw pad_cdevsw = { - .d_open = cdev_pad_open, - .d_close = cdev_pad_close, - .d_read = cdev_pad_read, + .d_open = pad_open, + .d_close = noclose, + .d_read = noread, .d_write = nowrite, .d_ioctl = noioctl, .d_stop = nostop, @@ -204,9 +197,6 @@ padattach(int n) config_cfdriver_detach(&pad_cd); return; } - mutex_init(&padconfig, MUTEX_DEFAULT, IPL_NONE); - - return; } static int @@ -221,6 +211,8 @@ pad_attach(device_t parent, device_t sel { struct pad_softc *sc = device_private(self); + KASSERT(KERNEL_LOCKED_P()); + aprint_normal_dev(self, "outputs: 44100Hz, 16-bit, stereo\n"); sc->sc_dev = self; @@ -239,6 +231,8 @@ pad_attach(device_t parent, device_t sel if (!pmf_device_register(sc->sc_dev, NULL, NULL)) aprint_error_dev(sc->sc_dev, "couldn't establish power handler\n"); + + sc->sc_open = 1; } static int @@ -248,6 +242,12 @@ pad_detach(device_t self, int flags) int cmaj, mn; int error; + KASSERT(KERNEL_LOCKED_P()); + + /* Prevent detach without going through close -- e.g., drvctl. */ + if (sc->sc_open) + return EBUSY; + error = config_detach_children(self, flags); if (error) return error; @@ -320,85 +320,61 @@ pad_get_block(struct pad_softc *sc, pad_ return 0; } -int -cdev_pad_open(dev_t dev, int flags, int fmt, struct lwp *l) +static int +pad_open(dev_t dev, int flags, int fmt, struct lwp *l) { - struct pad_softc *sc; - struct file *fp; - device_t paddev; - cfdata_t cf; - int error, fd, i; - - error = 0; - - mutex_enter(&padconfig); - if (PADUNIT(dev) == PADCLONER) { - for (i = 0; i < MAXDEVS; i++) { - if (device_lookup(&pad_cd, i) == NULL) - break; - } - if (i == MAXDEVS) - goto bad; - } else { - if (PADUNIT(dev) >= MAXDEVS) - goto bad; - i = PADUNIT(dev); - } + struct file *fp = NULL; + device_t self; + struct pad_softc *sc = NULL; + cfdata_t cf = NULL; + int error, fd; + + error = fd_allocfile(&fp, &fd); + if (error) + goto out; - cf = kmem_alloc(sizeof(struct cfdata), KM_SLEEP); + cf = kmem_alloc(sizeof(*cf), KM_SLEEP); cf->cf_name = pad_cd.cd_name; cf->cf_atname = pad_cd.cd_name; - cf->cf_unit = i; + cf->cf_unit = 0; cf->cf_fstate = FSTATE_STAR; - bool existing = false; - paddev = device_lookup(&pad_cd, minor(dev)); - if (paddev == NULL) - paddev = config_attach_pseudo(cf); - else - existing = true; - if (paddev == NULL) - goto bad; - - sc = device_private(paddev); - if (sc == NULL) - goto bad; - - if (sc->sc_open == 1) { - mutex_exit(&padconfig); - return EBUSY; - } - - if (PADUNIT(dev) == PADCLONER) { - error = fd_allocfile(&fp, &fd); - if (error) { - if (existing == false) - config_detach(paddev, 0); - mutex_exit(&padconfig); - return error; - } - error = fd_clone(fp, fd, flags, &pad_fileops, sc); - KASSERT(error == EMOVEFD); - } - sc->sc_open = 1; - mutex_exit(&padconfig); - + self = config_attach_pseudo(cf); + if (self == NULL) { + error = ENXIO; + goto out; + } + sc = device_private(self); + KASSERT(sc->sc_dev == self); + cf = NULL; + + error = fd_clone(fp, fd, flags, &pad_fileops, sc); + KASSERT(error == EMOVEFD); + fp = NULL; + sc = NULL; + +out: if (sc) + pad_close(sc); + if (cf) + kmem_free(cf, sizeof(*cf)); + if (fp) + fd_abort(curproc, fp, fd); return error; -bad: - mutex_exit(&padconfig); - return ENXIO; } -static int +static void pad_close(struct pad_softc *sc) { - int rc __diagused; + device_t self = sc->sc_dev; + cfdata_t cf = device_cfdata(self); - /* XXX Defend against concurrent drvctl detach. */ - rc = config_detach(sc->sc_dev, DETACH_FORCE); - KASSERT(rc == 0); + KERNEL_LOCK(1, NULL); + KASSERT(sc->sc_open); + sc->sc_open = 0; + (void)config_detach(self, DETACH_FORCE); + KERNEL_UNLOCK_ONE(NULL); - return 0; + kmem_free(cf, sizeof(*cf)); } static int @@ -407,25 +383,6 @@ fops_pad_close(struct file *fp) struct pad_softc *sc = fp->f_pad; pad_close(sc); - fp->f_pad = NULL; - - return 0; -} - -int -cdev_pad_close(dev_t dev, int flags, int ifmt, struct lwp *l) -{ - struct pad_softc *sc; - - /* - * XXX Defend against concurrent drvctl detach. Simply testing - * sc == NULL here is not enough -- it could be detached after - * we look it up but before we've issued our own config_detach. - */ - sc = device_lookup_private(&pad_cd, PADUNIT(dev)); - if (sc == NULL) - return 0; - pad_close(sc); return 0; } @@ -481,18 +438,6 @@ fops_pad_mmap(struct file *fp, off_t *of return 1; } -int -cdev_pad_read(dev_t dev, struct uio *uio, int ioflag) -{ - struct pad_softc *sc; - - sc = device_private(device_lookup(&pad_cd, PADUNIT(dev))); - if (sc == NULL) - return ENXIO; - - return pad_read(sc, NULL, uio, NULL, ioflag); -} - static int fops_pad_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, int ioflag) @@ -795,7 +740,6 @@ pad_modcmd(modcmd_t cmd, void *arg) pad_cfattach, cfdata_ioconf_pad); break; } - mutex_init(&padconfig, MUTEX_DEFAULT, IPL_NONE); #endif break; @@ -813,7 +757,6 @@ pad_modcmd(modcmd_t cmd, void *arg) &pad_cdevsw, &cmajor); break; } - mutex_destroy(&padconfig); #endif break;