Module Name: src Committed By: isaki Date: Mon May 6 13:40:03 UTC 2019
Modified Files: src/sys/dev/pad [isaki-audio2]: pad.c Log Message: Revive clonify. XXX should clean code more. To generate a diff of this commit: cvs rdiff -u -r1.58.2.3 -r1.58.2.4 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.58.2.3 src/sys/dev/pad/pad.c:1.58.2.4 --- src/sys/dev/pad/pad.c:1.58.2.3 Sun May 5 02:01:34 2019 +++ src/sys/dev/pad/pad.c Mon May 6 13:40:03 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: pad.c,v 1.58.2.3 2019/05/05 02:01:34 isaki Exp $ */ +/* $NetBSD: pad.c,v 1.58.2.4 2019/05/06 13:40:03 isaki Exp $ */ /*- * Copyright (c) 2007 Jared D. McNeill <jmcne...@invisible.ca> @@ -27,23 +27,25 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.58.2.3 2019/05/05 02:01:34 isaki Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.58.2.4 2019/05/06 13:40:03 isaki Exp $"); #include <sys/types.h> #include <sys/param.h> #include <sys/conf.h> #include <sys/buf.h> +#include <sys/file.h> +#include <sys/filedesc.h> +#include <sys/vnode.h> +#include <sys/kauth.h> #include <sys/kmem.h> #include <sys/kernel.h> #include <sys/device.h> #include <sys/proc.h> #include <sys/condvar.h> #include <sys/select.h> +#include <sys/stat.h> #include <sys/audioio.h> -#include <sys/vnode.h> #include <sys/module.h> -#include <sys/atomic.h> -#include <sys/time.h> #include <dev/audio/audio_if.h> #include <dev/audio/audiovar.h> @@ -57,6 +59,8 @@ __KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.58 #define DPRINTF(fmt...) /**/ #endif +#define MAXDEVS 128 +#define PADCLONER 254 #define PADUNIT(x) minor(x) #define PADFREQ 44100 @@ -64,6 +68,7 @@ __KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.58 #define PADPREC 16 extern struct cfdriver pad_cd; +kmutex_t padconfig; typedef struct pad_block { uint8_t *pb_ptr; @@ -85,8 +90,8 @@ static void pad_childdet(device_t, devic static int pad_query_format(void *, audio_format_query_t *); static int pad_set_format(void *, int, - const audio_params_t *, const audio_params_t *, - audio_filter_reg_t *, audio_filter_reg_t *); + const audio_params_t *, const audio_params_t *, + audio_filter_reg_t *, audio_filter_reg_t *); static int pad_start_output(void *, void *, int, void (*)(void *), void *); static int pad_start_input(void *, void *, int, @@ -103,7 +108,18 @@ static void pad_get_locks(void *, kmutex static void pad_done_output(void *); static void pad_swvol_codec(audio_filter_arg_t *); -static bool pad_is_attached; /* Do we have an audio* child? */ +static int pad_close(struct pad_softc *); +static int pad_read(struct pad_softc *, off_t *, struct uio *, kauth_cred_t, int); + +static int fops_pad_close(struct file *); +static int fops_pad_read(struct file *, off_t *, struct uio *, kauth_cred_t, int); +static int pad_write(struct file *, off_t *, struct uio *, kauth_cred_t, int); +static int pad_ioctl(struct file *, u_long, void *); +static int pad_kqfilter(struct file *, struct knote *); +static int pad_poll(struct file *, int); +static int pad_stat(struct file *, struct stat *); +static int pad_mmap(struct file *, off_t *, size_t, int, int *, int *, + struct uvm_object **, int *); static const struct audio_hw_if pad_hw_if = { .query_format = pad_query_format, @@ -121,14 +137,9 @@ static const struct audio_hw_if pad_hw_i }; #define PAD_NFORMATS 1 -#if defined(PAD_SUPPORT_RECORD) -#define PADMODE (AUMODE_PLAY | AUMODE_RECORD) -#else -#define PADMODE AUMODE_PLAY -#endif static const struct audio_format pad_formats[PAD_NFORMATS] = { { - .mode = PADMODE, + .mode = AUMODE_PLAY, .encoding = AUDIO_ENCODING_SLINEAR_NE, .validbits = PADPREC, .precision = PADPREC, @@ -144,14 +155,14 @@ extern void padattach(int); static int pad_add_block(pad_softc_t *, uint8_t *, int); static int pad_get_block(pad_softc_t *, pad_block_t *, int); -dev_type_open(pad_dev_open); -dev_type_close(pad_dev_close); -dev_type_read(pad_dev_read); +dev_type_open(pad_open); +dev_type_close(cdev_pad_close); +dev_type_read(cdev_pad_read); const struct cdevsw pad_cdevsw = { - .d_open = pad_dev_open, - .d_close = pad_dev_close, - .d_read = pad_dev_read, + .d_open = pad_open, + .d_close = cdev_pad_close, + .d_read = cdev_pad_read, .d_write = nowrite, .d_ioctl = noioctl, .d_stop = nostop, @@ -163,35 +174,36 @@ const struct cdevsw pad_cdevsw = { .d_flag = D_OTHER | D_MPSAFE, }; +const struct fileops pad_fileops = { + .fo_name = "pad", + .fo_read = fops_pad_read, + .fo_write = pad_write, + .fo_ioctl = pad_ioctl, + .fo_fcntl = fnullop_fcntl, + .fo_stat = pad_stat, + .fo_poll = pad_poll, + .fo_close = fops_pad_close, + .fo_mmap = pad_mmap, + .fo_kqfilter = pad_kqfilter, + .fo_restart = fnullop_restart +}; + CFATTACH_DECL2_NEW(pad, sizeof(pad_softc_t), pad_match, pad_attach, pad_detach, NULL, NULL, pad_childdet); void padattach(int n) { - int i, err; - cfdata_t cf; + int error; - aprint_debug("pad: requested %d units\n", n); - DPRINTF("%s: requested %d units\n", __func__, n); - - err = config_cfattach_attach(pad_cd.cd_name, &pad_ca); - if (err) { + error = config_cfattach_attach(pad_cd.cd_name, &pad_ca); + if (error) { aprint_error("%s: couldn't register cfattach: %d\n", - pad_cd.cd_name, err); + pad_cd.cd_name, error); config_cfdriver_detach(&pad_cd); return; } - - for (i = 0; i < n; i++) { - cf = kmem_alloc(sizeof(struct cfdata), KM_SLEEP); - cf->cf_name = pad_cd.cd_name; - cf->cf_atname = pad_cd.cd_name; - cf->cf_unit = i; - cf->cf_fstate = FSTATE_STAR; - - (void)config_attach_pseudo(cf); - } + mutex_init(&padconfig, MUTEX_DEFAULT, IPL_NONE); return; } @@ -260,14 +272,89 @@ pad_childdet(device_t self, device_t chi static void pad_attach(device_t parent, device_t self, void *opaque) { - pad_softc_t *sc = device_private(self); - aprint_normal_dev(self, "outputs: 44100Hz, 16-bit, stereo\n"); - sc->sc_dev = self; - sc->sc_open = 0; + return; +} + +static int +pad_detach(device_t self, int flags) +{ + pad_softc_t *sc; + int cmaj, mn; + + sc = device_private(self); + cmaj = cdevsw_lookup_major(&pad_cdevsw); + mn = device_unit(sc->sc_dev); + if (!sc->sc_dying) + vdevgone(cmaj, mn, mn, VCHR); + + return 0; +} + +int +pad_open(dev_t dev, int flags, int fmt, struct lwp *l) +{ + pad_softc_t *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); + } + + cf = kmem_alloc(sizeof(struct cfdata), KM_SLEEP); + cf->cf_name = pad_cd.cd_name; + cf->cf_atname = pad_cd.cd_name; + cf->cf_unit = i; + 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; + } + + sc->sc_dev = paddev; + sc->sc_dying = false; - cv_init(&sc->sc_condvar, device_xname(self)); + if (PADUNIT(dev) == PADCLONER) { + error = fd_allocfile(&fp, &fd); + if (error) { + if (existing == false) + config_detach(sc->sc_dev, 0); + mutex_exit(&padconfig); + return error; + } + } + + cv_init(&sc->sc_condvar, device_xname(sc->sc_dev)); mutex_init(&sc->sc_cond_lock, MUTEX_DEFAULT, IPL_NONE); mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE); @@ -278,86 +365,172 @@ pad_attach(device_t parent, device_t sel sc->sc_rpos = sc->sc_wpos = 0; sc->sc_audiodev = audio_attach_mi(&pad_hw_if, sc, sc->sc_dev); - if (!pmf_device_register(self, NULL, NULL)) - aprint_error_dev(self, "couldn't establish power handler\n"); + if (!pmf_device_register(sc->sc_dev, NULL, NULL)) + aprint_error_dev(sc->sc_dev, "couldn't establish power handler\n"); - pad_is_attached = true; - return; + if (PADUNIT(dev) == PADCLONER) { + error = fd_clone(fp, fd, flags, &pad_fileops, sc); + KASSERT(error == EMOVEFD); + } + sc->sc_open = 1; + mutex_exit(&padconfig); + + return error; +bad: + mutex_exit(&padconfig); + return ENXIO; } static int -pad_detach(device_t self, int flags) +pad_close(struct pad_softc *sc) { - pad_softc_t *sc = device_private(self); - int cmaj, mn, rc; + int rc; - if (!pad_is_attached) + if (sc == NULL) return ENXIO; - cmaj = cdevsw_lookup_major(&pad_cdevsw); - mn = device_unit(self); - vdevgone(cmaj, mn, mn, VCHR); - - if ((rc = config_detach_children(self, flags)) != 0) + mutex_enter(&padconfig); + config_deactivate(sc->sc_audiodev); + + /* Start draining existing accessors of the device. */ + if ((rc = config_detach_children(sc->sc_dev, + DETACH_SHUTDOWN|DETACH_FORCE)) != 0) { + mutex_exit(&padconfig); return rc; + } + + mutex_enter(&sc->sc_lock); + sc->sc_dying = true; + cv_broadcast(&sc->sc_condvar); + mutex_exit(&sc->sc_lock); - pmf_device_deregister(self); + KASSERT(sc->sc_open > 0); + sc->sc_open = 0; + pmf_device_deregister(sc->sc_dev); + + mutex_destroy(&sc->sc_cond_lock); mutex_destroy(&sc->sc_lock); mutex_destroy(&sc->sc_intr_lock); cv_destroy(&sc->sc_condvar); - callout_destroy(&sc->sc_pcallout); - pad_is_attached = false; - return 0; + rc = config_detach(sc->sc_dev, 0); + mutex_exit(&padconfig); + + return rc; } -int -pad_dev_open(dev_t dev, int flags, int fmt, struct lwp *l) +static int +fops_pad_close(struct file *fp) { pad_softc_t *sc; + int error; - sc = device_lookup_private(&pad_cd, PADUNIT(dev)); - if (sc == NULL) - return ENXIO; + sc = fp->f_pad; - if (atomic_swap_uint(&sc->sc_open, 1) != 0) - return EBUSY; + error = pad_close(sc); - DPRINTF("%s -> %d\n", __func__, sc->sc_open); + if (error == 0) + fp->f_pad = NULL; - return 0; + return error; } int -pad_dev_close(dev_t dev, int flags, int fmt, struct lwp *l) +cdev_pad_close(dev_t dev, int flags, int ifmt, struct lwp *l) { pad_softc_t *sc; + sc = device_private(device_lookup(&pad_cd, PADUNIT(dev))); + + return pad_close(sc); +} - sc = device_lookup_private(&pad_cd, PADUNIT(dev)); +static int +pad_poll(struct file *fp, int events) +{ + return ENODEV; +} + +static int +pad_kqfilter(struct file *fp, struct knote *kn) +{ + struct pad_softc *sc; + dev_t dev; + + sc = fp->f_pad; if (sc == NULL) - return ENXIO; + return EIO; - KASSERT(sc->sc_open > 0); - /* XXX should this be atomic too? */ - sc->sc_open = 0; - DPRINTF("%s -> %d\n", __func__, sc->sc_open); + dev = makedev(cdevsw_lookup_major(&pad_cdevsw), device_unit(sc->sc_dev)); + + return seltrue_kqfilter(dev, kn); +} + +static int +pad_ioctl(struct file *fp, u_long cmd, void *data) +{ + return ENODEV; +} + +static int +pad_stat(struct file *fp, struct stat *st) +{ + struct pad_softc *sc; + + sc = fp->f_pad; + if (sc == NULL) + return EIO; + + memset(st, 0, sizeof(*st)); + + st->st_dev = makedev(cdevsw_lookup_major(&pad_cdevsw), device_unit(sc->sc_dev)); + + st->st_uid = kauth_cred_geteuid(fp->f_cred); + st->st_gid = kauth_cred_getegid(fp->f_cred); + st->st_mode = S_IFCHR; return 0; } +static int +pad_mmap(struct file *fp, off_t *offp, size_t len, int prot, int *flagsp, + int *advicep, struct uvm_object **uobjp, int *maxprotp) +{ + return 1; +} + int -pad_dev_read(dev_t dev, struct uio *uio, int flags) +cdev_pad_read(dev_t dev, struct uio *uio, int ioflag) +{ + pad_softc_t *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) { pad_softc_t *sc; - pad_block_t pb; - int len; - int err; - sc = device_lookup_private(&pad_cd, PADUNIT(dev)); + sc = fp->f_pad; if (sc == NULL) return ENXIO; + return pad_read(sc, offp, uio, cred, ioflag); +} + +static int +pad_read(struct pad_softc *sc, off_t *offp, struct uio *uio, kauth_cred_t cred, + int ioflag) +{ + pad_block_t pb; + int len; + int err; + err = 0; DPRINTF("%s: resid=%zu\n", __func__, uio->uio_resid); while (uio->uio_resid > 0 && !err) { @@ -390,6 +563,13 @@ pad_dev_read(dev_t dev, struct uio *uio, } static int +pad_write(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, + int ioflag) +{ + return EOPNOTSUPP; +} + +static int pad_query_format(void *opaque, audio_format_query_t *afp) { @@ -399,7 +579,7 @@ pad_query_format(void *opaque, audio_for static int pad_set_format(void *opaque, int setmode, const audio_params_t *play, const audio_params_t *rec, - audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) + audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) { pad_softc_t *sc; @@ -606,11 +786,7 @@ pad_get_props(void *opaque) KASSERT(mutex_owned(&sc->sc_lock)); -#if defined(PAD_SUPPORT_RECORD) - return 0; -#else return AUDIO_PROP_PLAYBACK; -#endif } static void @@ -647,95 +823,66 @@ MODULE(MODULE_CLASS_DRIVER, pad, "audio" #ifdef _MODULE -static const struct cfiattrdata audiobuscf_iattrdata = { - "audiobus", 0, { { NULL, NULL, 0 }, } -}; -static const struct cfiattrdata * const pad_attrs[] = { - &audiobuscf_iattrdata, NULL -}; +#include "ioconf.c" -CFDRIVER_DECL(pad, DV_DULL, pad_attrs); -extern struct cfattach pad_ca; -static int padloc[] = { -1, -1 }; +devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR; -static struct cfdata pad_cfdata[] = { - { - .cf_name = "pad", - .cf_atname = "pad", - .cf_unit = 0, - .cf_fstate = FSTATE_STAR, - .cf_loc = padloc, - .cf_flags = 0, - .cf_pspec = NULL, - }, - { NULL, NULL, 0, 0, NULL, 0, NULL } +/* + * We need our own version of cfattach since config(1)'s ioconf does not + * generate what we need + */ + +static struct cfattach *pad_cfattachinit[] = { &pad_ca, NULL }; + +static struct cfattachinit pad_cfattach[] = { + { "pad", pad_cfattachinit }, + { NULL, NULL } }; #endif static int pad_modcmd(modcmd_t cmd, void *arg) { -#ifdef _MODULE - devmajor_t cmajor = NODEVMAJOR, bmajor = NODEVMAJOR; -#endif int error = 0; switch (cmd) { case MODULE_CMD_INIT: #ifdef _MODULE - error = config_cfdriver_attach(&pad_cd); - if (error) { + pad_cfattach[1] = cfattach_ioconf_pad[0]; + error = config_init_component(cfdriver_ioconf_pad, + pad_cfattach, cfdata_ioconf_pad); + if (error) break; - } - - error = config_cfattach_attach(pad_cd.cd_name, &pad_ca); - if (error) { - config_cfdriver_detach(&pad_cd); - aprint_error("%s: unable to register cfattach\n", - pad_cd.cd_name); - - break; - } - - error = config_cfdata_attach(pad_cfdata, 1); - if (error) { - config_cfattach_detach(pad_cd.cd_name, &pad_ca); - config_cfdriver_detach(&pad_cd); - aprint_error("%s: unable to register cfdata\n", - pad_cd.cd_name); - - break; - } error = devsw_attach(pad_cd.cd_name, NULL, &bmajor, - &pad_cdevsw, &cmajor); + &pad_cdevsw, &cmajor); if (error) { - config_cfdata_detach(pad_cfdata); - config_cfattach_detach(pad_cd.cd_name, &pad_ca); - config_cfdriver_detach(&pad_cd); - aprint_error("%s: unable to register devsw\n", - pad_cd.cd_name); - + config_fini_component(cfdriver_ioconf_pad, + pad_cfattach, cfdata_ioconf_pad); break; } + mutex_init(&padconfig, MUTEX_DEFAULT, IPL_NONE); - (void)config_attach_pseudo(pad_cfdata); #endif - break; + case MODULE_CMD_FINI: #ifdef _MODULE - error = config_cfdata_detach(pad_cfdata); + error = devsw_detach(NULL, &pad_cdevsw); + if (error) + break; + + error = config_fini_component(cfdriver_ioconf_pad, + pad_cfattach, cfdata_ioconf_pad); if (error) { + devsw_attach(pad_cd.cd_name, NULL, &bmajor, + &pad_cdevsw, &cmajor); break; } - - config_cfattach_detach(pad_cd.cd_name, &pad_ca); - config_cfdriver_detach(&pad_cd); - devsw_detach(NULL, &pad_cdevsw); + mutex_destroy(&padconfig); #endif - break; + default: error = ENOTTY; }