summaryrefslogtreecommitdiff
path: root/sys/dev/pad
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pad')
-rw-r--r--sys/dev/pad/pad.c131
1 files changed, 95 insertions, 36 deletions
diff --git a/sys/dev/pad/pad.c b/sys/dev/pad/pad.c
index a53162fba08..9e92a90f0a0 100644
--- a/sys/dev/pad/pad.c
+++ b/sys/dev/pad/pad.c
@@ -1,4 +1,4 @@
-/* $NetBSD: pad.c,v 1.40 2017/07/02 05:59:27 nat Exp $ */
+/* $NetBSD: pad.c,v 1.41 2017/07/02 13:32:50 nat Exp $ */
/*-
* Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.40 2017/07/02 05:59:27 nat Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.41 2017/07/02 13:32:50 nat Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -58,6 +58,7 @@ __KERNEL_RCSID(0, "$NetBSD: pad.c,v 1.40 2017/07/02 05:59:27 nat Exp $");
#include <dev/pad/padvar.h>
#define MAXDEVS 128
+#define PADCLONER 254
#define PADUNIT(x) minor(x)
#define PADFREQ 44100
@@ -110,8 +111,11 @@ static stream_filter_t *pad_swvol_filter_be(struct audio_softc *,
const audio_params_t *, const audio_params_t *);
static void pad_swvol_dtor(stream_filter_t *);
-static int pad_close(struct file *);
-static int pad_read(struct file *, off_t *, struct uio *, kauth_cred_t, int);
+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 *);
@@ -149,11 +153,13 @@ 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_open);
+dev_type_close(cdev_pad_close);
+dev_type_read(cdev_pad_read);
const struct cdevsw pad_cdevsw = {
.d_open = pad_open,
- .d_close = noclose,
- .d_read = noread,
+ .d_close = cdev_pad_close,
+ .d_read = cdev_pad_read,
.d_write = nowrite,
.d_ioctl = noioctl,
.d_stop = nostop,
@@ -166,13 +172,13 @@ const struct cdevsw pad_cdevsw = {
};
const struct fileops pad_fileops = {
- .fo_read = pad_read,
+ .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 = pad_close,
+ .fo_close = fops_pad_close,
.fo_mmap = pad_mmap,
.fo_kqfilter = pad_kqfilter,
.fo_restart = fnullop_restart
@@ -308,7 +314,7 @@ pad_detach(device_t self, int flags)
auconv_delete_encodings(sc->sc_encodings);
- return rc;
+ return 0;
}
int
@@ -320,12 +326,18 @@ pad_open(dev_t dev, int flags, int fmt, struct lwp *l)
cfdata_t cf;
int error, fd, i;
- for (i = 0; i < MAXDEVS; i++) {
- if (device_lookup(&pad_cd, i) == NULL)
- break;
+ if (PADUNIT(dev) == PADCLONER) {
+ for (i = 0; i < MAXDEVS; i++) {
+ if (device_lookup(&pad_cd, i) == NULL)
+ break;
+ }
+ if (i == MAXDEVS)
+ return ENXIO;
+ } else {
+ if (PADUNIT(dev) >= MAXDEVS)
+ return ENXIO;
+ i = PADUNIT(dev);
}
- if (i == MAXDEVS)
- return ENXIO;
cf = kmem_alloc(sizeof(struct cfdata), KM_SLEEP);
cf->cf_name = pad_cd.cd_name;
@@ -333,18 +345,27 @@ pad_open(dev_t dev, int flags, int fmt, struct lwp *l)
cf->cf_unit = i;
cf->cf_fstate = FSTATE_STAR;
- paddev = config_attach_pseudo(cf);
+ if (device_lookup(&pad_cd, minor(dev)) == NULL)
+ paddev = config_attach_pseudo(cf);
+ else
+ paddev = device_lookup(&pad_cd, minor(dev));
+
sc = device_private(paddev);
- sc->sc_dev = paddev;
- sc->sc_dying = false;
+ if (sc == NULL)
+ return ENXIO;
if (sc->sc_open == 1)
return EBUSY;
- error = fd_allocfile(&fp, &fd);
- if (error) {
- config_detach(sc->sc_dev, 0);
- return error;
+ sc->sc_dev = paddev;
+ sc->sc_dying = false;
+
+ if (PADUNIT(dev) == PADCLONER) {
+ error = fd_allocfile(&fp, &fd);
+ if (error) {
+ config_detach(sc->sc_dev, 0);
+ return error;
+ }
}
if (auconv_create_encodings(pad_formats, PAD_NFORMATS,
@@ -366,28 +387,47 @@ pad_open(dev_t dev, int flags, int fmt, struct lwp *l)
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);
-
+ if (PADUNIT(dev) == PADCLONER) {
+ error = fd_clone(fp, fd, flags, &pad_fileops, sc);
+ KASSERT(error == EMOVEFD);
+ }
sc->sc_open = 1;
return error;
}
static int
-pad_close(struct file *fp)
+pad_close(struct pad_softc *sc)
+{
+ if (sc == NULL)
+ return ENXIO;
+
+ return config_detach(sc->sc_dev, DETACH_FORCE);
+}
+
+static int
+fops_pad_close(struct file *fp)
{
pad_softc_t *sc;
+ int error;
sc = fp->f_pad;
- if (sc == NULL)
- return ENXIO;
- config_detach(sc->sc_dev, DETACH_FORCE);
+ error = pad_close(sc);
- fp->f_pad = NULL;
+ if (error == 0)
+ fp->f_pad = NULL;
- return 0;
+ return error;
+}
+
+int
+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);
}
static int
@@ -448,22 +488,41 @@ pad_mmap(struct file *fp, off_t *offp, size_t len, int prot, int *flagsp,
#define BYTESTOSLEEP (int64_t)(PAD_BLKSIZE)
#define TIMENEXTREAD (int64_t)(BYTESTOSLEEP * 1000000 / PAD_BYTES_PER_SEC)
+int
+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
-pad_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
+fops_pad_read(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred,
+ int ioflag)
+{
+ pad_softc_t *sc;
+
+ 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)
{
struct timeval now;
uint64_t nowusec, lastusec;
- pad_softc_t *sc;
pad_block_t pb;
void (*intr)(void *);
void *intrarg;
int err, wait_ticks;
- sc = fp->f_pad;
- if (sc == NULL)
- return ENXIO;
-
err = 0;
while (uio->uio_resid > 0 && !err) {