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 <[email protected]>
@@ -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;
}