Module Name: src Committed By: nat Date: Sat Jul 1 23:31:19 UTC 2017
Modified Files: src/sys/dev/pad: pad.c padvar.h src/sys/sys: file.h Log Message: Pad is now clones its device, attaching upon open and detaching upon close. This means that only one pad device is required in /dev. The code contains a compile time limit of 128 units. Ok christos@. To generate a diff of this commit: cvs rdiff -u -r1.38 -r1.39 src/sys/dev/pad/pad.c cvs rdiff -u -r1.10 -r1.11 src/sys/dev/pad/padvar.h cvs rdiff -u -r1.81 -r1.82 src/sys/sys/file.h 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.38 src/sys/dev/pad/pad.c:1.39 --- src/sys/dev/pad/pad.c:1.38 Sat Jul 1 05:50:10 2017 +++ src/sys/dev/pad/pad.c Sat Jul 1 23:31:19 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: pad.c,v 1.38 2017/07/01 05:50:10 nat Exp $ */ +/* $NetBSD: pad.c,v 1.39 2017/07/01 23:31:19 nat Exp $ */ /*- * Copyright (c) 2007 Jared D. McNeill <jmcne...@invisible.ca> @@ -27,18 +27,23 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.38 2017/07/01 05:50:10 nat Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.39 2017/07/01 23:31:19 nat 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> @@ -52,6 +57,7 @@ __KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.38 #include <dev/pad/padvar.h> +#define MAXDEVS 128 #define PADUNIT(x) minor(x) #define PADFREQ 44100 @@ -104,7 +110,15 @@ static stream_filter_t *pad_swvol_filter const audio_params_t *, const audio_params_t *); static void pad_swvol_dtor(stream_filter_t *); -static bool pad_is_attached; /* Do we have an audio* child? */ +static int pad_close(struct file *); +static int 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 = { .open = pad_audio_open, @@ -135,13 +149,11 @@ static int pad_add_block(pad_softc_t *, static int pad_get_block(pad_softc_t *, pad_block_t *, int); dev_type_open(pad_open); -dev_type_close(pad_close); -dev_type_read(pad_read); const struct cdevsw pad_cdevsw = { .d_open = pad_open, - .d_close = pad_close, - .d_read = pad_read, + .d_close = noclose, + .d_read = noread, .d_write = nowrite, .d_ioctl = noioctl, .d_stop = nostop, @@ -153,35 +165,35 @@ const struct cdevsw pad_cdevsw = { .d_flag = D_OTHER | D_MPSAFE, }; +const struct fileops pad_fileops = { + .fo_read = pad_read, + .fo_write = pad_write, + .fo_ioctl = pad_ioctl, + .fo_fcntl = fnullop_fcntl, + .fo_stat = pad_stat, + .fo_poll = pad_poll, + .fo_close = 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; - - aprint_debug("pad: requested %d units\n", n); + int error; - 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); - } - return; } @@ -258,51 +270,37 @@ 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; - if (auconv_create_encodings(pad_formats, PAD_NFORMATS, - &sc->sc_encodings) != 0) { - aprint_error_dev(self, "couldn't create encodings\n"); - return; - } - - cv_init(&sc->sc_condvar, device_xname(self)); - mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); - mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE); - - sc->sc_swvol = 255; - sc->sc_buflen = 0; - 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"); - - pad_is_attached = true; return; } static int pad_detach(device_t self, int flags) { - pad_softc_t *sc = device_private(self); + pad_softc_t *sc; int cmaj, mn, rc; - if (!pad_is_attached) - return ENXIO; + sc = device_private(self); + config_deactivate(sc->sc_audiodev); + + /* Start draining existing accessors of the device. */ + if ((rc = config_detach_children(self, flags)) != 0) + return rc; + + mutex_enter(&sc->sc_lock); + sc->sc_dying = true; + cv_broadcast(&sc->sc_condvar); + mutex_exit(&sc->sc_lock); + + KASSERT(sc->sc_open > 0); + sc->sc_open = 0; cmaj = cdevsw_lookup_major(&pad_cdevsw); - mn = device_unit(self); + mn = device_unit(sc->sc_dev); vdevgone(cmaj, mn, mn, VCHR); - if ((rc = config_detach_children(self, flags)) != 0) - return rc; - - pmf_device_deregister(self); + pmf_device_deregister(sc->sc_dev); mutex_destroy(&sc->sc_lock); mutex_destroy(&sc->sc_intr_lock); @@ -310,46 +308,149 @@ pad_detach(device_t self, int flags) auconv_delete_encodings(sc->sc_encodings); - pad_is_attached = false; - return 0; + return rc; } 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; - sc = device_lookup_private(&pad_cd, PADUNIT(dev)); - if (sc == NULL) + for (i = 0; i < MAXDEVS; i++) { + if (device_lookup(&pad_cd, i) == NULL) + break; + } + if (i == MAXDEVS) return ENXIO; - if (atomic_swap_uint(&sc->sc_open, 1) != 0) + 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; + + paddev = config_attach_pseudo(cf); + sc = device_private(paddev); + sc->sc_dev = paddev; + sc->sc_dying = false; + + if (sc->sc_open == 1) return EBUSY; + + error = fd_allocfile(&fp, &fd); + if (error) { + config_detach(sc->sc_dev, 0); + return error; + } + + if (auconv_create_encodings(pad_formats, PAD_NFORMATS, + &sc->sc_encodings) != 0) { + aprint_error_dev(sc->sc_dev, "couldn't create encodings\n"); + config_detach(sc->sc_dev, 0); + return EINVAL; + } + + cv_init(&sc->sc_condvar, device_xname(sc->sc_dev)); + mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); + mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NONE); + + sc->sc_swvol = 255; + sc->sc_buflen = 0; + sc->sc_rpos = sc->sc_wpos = 0; + sc->sc_audiodev = audio_attach_mi(&pad_hw_if, sc, sc->sc_dev); + + if (!pmf_device_register(sc->sc_dev, NULL, NULL)) + aprint_error_dev(sc->sc_dev, "couldn't establish power handler\n"); + + error = fd_clone(fp, fd, flags, &pad_fileops, sc); + KASSERT(error == EMOVEFD); - return 0; + sc->sc_open = 1; + + return error; } -int -pad_close(dev_t dev, int flags, int fmt, struct lwp *l) +static int +pad_close(struct file *fp) { pad_softc_t *sc; - sc = device_lookup_private(&pad_cd, PADUNIT(dev)); + sc = fp->f_pad; if (sc == NULL) return ENXIO; - KASSERT(sc->sc_open > 0); - sc->sc_open = 0; + config_detach(sc->sc_dev, DETACH_FORCE); + + fp->f_pad = NULL; + + return 0; +} + +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 EIO; + + 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; +} + #define PAD_BYTES_PER_SEC (PADFREQ * PADPREC / NBBY * PADCHAN) #define BYTESTOSLEEP (int64_t)(PAD_BLKSIZE) #define TIMENEXTREAD (int64_t)(BYTESTOSLEEP * 1000000 / PAD_BYTES_PER_SEC) -int -pad_read(dev_t dev, struct uio *uio, int flags) +static int +pad_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, + int ioflag) { struct timeval now; uint64_t nowusec, lastusec; @@ -359,7 +460,7 @@ pad_read(dev_t dev, struct uio *uio, int void *intrarg; int err, wait_ticks; - sc = device_lookup_private(&pad_cd, PADUNIT(dev)); + sc = fp->f_pad; if (sc == NULL) return ENXIO; @@ -367,6 +468,10 @@ pad_read(dev_t dev, struct uio *uio, int while (uio->uio_resid > 0 && !err) { mutex_enter(&sc->sc_lock); + if (sc->sc_dying == true) { + mutex_exit(&sc->sc_lock); + return EIO; + } intr = sc->sc_intr; intrarg = sc->sc_intrarg; @@ -425,6 +530,13 @@ pad_read(dev_t dev, struct uio *uio, int } static int +pad_write(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, + int ioflag) +{ + return EOPNOTSUPP; +} + +static int pad_audio_open(void *opaque, int flags) { pad_softc_t *sc; Index: src/sys/dev/pad/padvar.h diff -u src/sys/dev/pad/padvar.h:1.10 src/sys/dev/pad/padvar.h:1.11 --- src/sys/dev/pad/padvar.h:1.10 Sat Jul 1 05:50:10 2017 +++ src/sys/dev/pad/padvar.h Sat Jul 1 23:31:19 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: padvar.h,v 1.10 2017/07/01 05:50:10 nat Exp $ */ +/* $NetBSD: padvar.h,v 1.11 2017/07/01 23:31:19 nat Exp $ */ /*- * Copyright (c) 2007 Jared D. McNeill <jmcne...@invisible.ca> @@ -40,6 +40,7 @@ typedef struct pad_softc { kcondvar_t sc_condvar; kmutex_t sc_lock; kmutex_t sc_intr_lock; + bool sc_dying; device_t sc_audiodev; int sc_blksize; Index: src/sys/sys/file.h diff -u src/sys/sys/file.h:1.81 src/sys/sys/file.h:1.82 --- src/sys/sys/file.h:1.81 Fri Feb 10 19:31:42 2017 +++ src/sys/sys/file.h Sat Jul 1 23:31:19 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: file.h,v 1.81 2017/02/10 19:31:42 nat Exp $ */ +/* $NetBSD: file.h,v 1.82 2017/07/01 23:31:19 nat Exp $ */ /*- * Copyright (c) 2009 The NetBSD Foundation, Inc. @@ -104,6 +104,7 @@ union file_data { void *fd_data; // DTYPE_MISC struct rnd_ctx *fd_rndctx; // DTYPE_MISC (rnd) struct audio_chan *fd_audioctx; // DTYPE_MISC (audio) + struct pad_softc *fd_pad; // DTYPE_MISC (pad) int fd_devunit; // DTYPE_MISC (tap) struct bpf_d *fd_bpf; // DTYPE_MISC (bpf) struct fcrypt *fd_fcrypt; // DTYPE_CRYPTO is not used @@ -146,6 +147,7 @@ struct file { #define f_rndctx f_undata.fd_rndctx #define f_audioctx f_undata.fd_audioctx +#define f_pad f_undata.fd_pad #define f_devunit f_undata.fd_devunit #define f_bpf f_undata.fd_bpf #define f_fcrypt f_undata.fd_fcrypt