Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/dtv Fix a locking problem with the demux, and while ...



details:   https://anonhg.NetBSD.org/src/rev/6b78a5085494
branches:  trunk
changeset: 767340:6b78a5085494
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sat Jul 16 12:20:01 2011 +0000

description:
Fix a locking problem with the demux, and while here do a bit of
housekeeping and documentation.

diffstat:

 sys/dev/dtv/dtv_buffer.c |   11 +-
 sys/dev/dtv/dtv_demux.c  |  376 ++++++++++++++++++++++++++++++++++++----------
 sys/dev/dtv/dtv_device.c |    9 +-
 sys/dev/dtv/dtvvar.h     |    7 +-
 4 files changed, 304 insertions(+), 99 deletions(-)

diffs (truncated from 742 to 300 lines):

diff -r 40fe46bd4662 -r 6b78a5085494 sys/dev/dtv/dtv_buffer.c
--- a/sys/dev/dtv/dtv_buffer.c  Sat Jul 16 11:15:52 2011 +0000
+++ b/sys/dev/dtv/dtv_buffer.c  Sat Jul 16 12:20:01 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: dtv_buffer.c,v 1.5 2011/07/13 22:43:04 jmcneill Exp $ */
+/* $NetBSD: dtv_buffer.c,v 1.6 2011/07/16 12:20:01 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2011 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -33,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dtv_buffer.c,v 1.5 2011/07/13 22:43:04 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dtv_buffer.c,v 1.6 2011/07/16 12:20:01 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -99,7 +99,6 @@
 dtv_submit_payload(device_t self, const struct dtv_payload *payload)
 {
        struct dtv_softc *sc = device_private(self);
-       struct dtv_demux *demux;
        struct dtv_ts *ts = &sc->sc_ts;
        const uint8_t *tspkt;
        unsigned int npkts, i;
@@ -111,11 +110,7 @@
                        if (ts->ts_pidfilter[TS_PID(tspkt)]) {
                                dtv_buffer_write(sc, tspkt, TS_PKTLEN);
                        }
-                       mutex_enter(&sc->sc_demux_lock);
-                       TAILQ_FOREACH(demux, &sc->sc_demux_list, dd_entries) {
-                               dtv_demux_write(demux, tspkt, TS_PKTLEN);
-                       }
-                       mutex_exit(&sc->sc_demux_lock);
+                       dtv_demux_write(sc, tspkt, TS_PKTLEN);
                }
                tspkt += TS_PKTLEN;
        }
diff -r 40fe46bd4662 -r 6b78a5085494 sys/dev/dtv/dtv_demux.c
--- a/sys/dev/dtv/dtv_demux.c   Sat Jul 16 11:15:52 2011 +0000
+++ b/sys/dev/dtv/dtv_demux.c   Sat Jul 16 12:20:01 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: dtv_demux.c,v 1.3 2011/07/14 01:37:09 jmcneill Exp $ */
+/* $NetBSD: dtv_demux.c,v 1.4 2011/07/16 12:20:01 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2011 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -32,8 +32,27 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+/*
+ * This file contains support for the /dev/dvb/adapter<n>/demux0 device.
+ *
+ * The demux device is implemented as a cloning device. Each instance can
+ * be in one of three modes: unconfigured (NONE), section filter (SECTION),
+ * or PID filter (PES).
+ *
+ * An instance in section filter mode extracts PSI sections based on a
+ * filter configured by the DMX_SET_FILTER ioctl. When an entire section is
+ * received, it is made available to userspace via read method. Data is fed
+ * into the section filter using the dtv_demux_write function.
+ *
+ * An instance in PID filter mode extracts TS packets that match the
+ * specified PID filter configured by the DMX_SET_PES_FILTER, DMX_ADD_PID,
+ * and DMX_REMOVE_PID ioctls. As this driver only implements the
+ * DMX_OUT_TS_TAP output, these TS packets are made available to userspace
+ * by calling read on the /dev/dvb/adapter<n>/dvr0 device.
+ */ 
+
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dtv_demux.c,v 1.3 2011/07/14 01:37:09 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dtv_demux.c,v 1.4 2011/07/16 12:20:01 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -47,9 +66,6 @@
 #include <sys/vnode.h>
 #include <sys/queue.h>
 
-#include <net/if.h>
-#include <net/if_ether.h>      /* for ether_crc32_be */
-
 #include <dev/dtv/dtvvar.h>
 
 static int     dtv_demux_read(struct file *, off_t *, struct uio *,
@@ -137,6 +153,7 @@
        0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
 };
 
+/* ISO/IEC 13818-1 Annex A "CRC Decoder Model" */
 static uint32_t
 dtv_demux_crc32(uint8_t *buf, int len)
 {
@@ -150,6 +167,129 @@
        return CRC;
 }
 
+/*
+ * Start running the demux.
+ */
+static int
+dtv_demux_start(struct dtv_demux *demux)
+{
+       struct dtv_softc *sc = demux->dd_sc;
+       int error = 0;
+       bool dostart = false;
+
+       /*
+        * If the demux is not running, mark it as running and update the
+        * global demux run counter.
+        */
+       mutex_enter(&sc->sc_lock);
+       KASSERT(sc->sc_demux_runcnt >= 0);
+       if (demux->dd_running == false) {
+               sc->sc_demux_runcnt++;
+               demux->dd_running = true;
+               /* If this is the first demux running, trigger device start */
+               dostart = sc->sc_demux_runcnt == 1;
+       }
+       mutex_exit(&sc->sc_lock);
+
+       if (dostart) {
+               /* Setup receive buffers and trigger device start */
+               error = dtv_buffer_setup(sc);
+               if (error == 0)
+                       error = dtv_device_start_transfer(sc);
+       }
+
+       /*
+        * If something went wrong, restore the run counter and mark this
+        * demux instance as halted.
+        */
+       if (error) {
+               mutex_enter(&sc->sc_lock);
+               sc->sc_demux_runcnt--;
+               demux->dd_running = false;
+               mutex_exit(&sc->sc_lock);
+       }
+
+       return error;
+}
+
+/*
+ * Stop running the demux.
+ */
+static int
+dtv_demux_stop(struct dtv_demux *demux)
+{
+       struct dtv_softc *sc = demux->dd_sc;
+       int error = 0;
+       bool dostop = false;
+
+       /*
+        * If the demux is running, mark it as halted and update the
+        * global demux run counter.
+        */
+       mutex_enter(&sc->sc_lock);
+       if (demux->dd_running == true) {
+               KASSERT(sc->sc_demux_runcnt > 0);
+               demux->dd_running = false;
+               sc->sc_demux_runcnt--;
+               /* If this was the last demux running, trigger device stop */
+               dostop = sc->sc_demux_runcnt == 0;
+       }
+       mutex_exit(&sc->sc_lock);
+
+       if (dostop) {
+               /* Trigger device stop */
+               error = dtv_device_stop_transfer(sc);
+       }
+
+       /*
+        * If something went wrong, restore the run counter and mark this
+        * demux instance as running.
+        */
+       if (error) {
+               mutex_enter(&sc->sc_lock);
+               sc->sc_demux_runcnt++;
+               demux->dd_running = true;
+               mutex_exit(&sc->sc_lock);
+       }
+
+       return error;
+}
+
+/*
+ * Put the demux into PID filter mode and update the PID filter table.
+ */
+static int
+dtv_demux_set_pidfilter(struct dtv_demux *demux, uint16_t pid, bool onoff)
+{
+       struct dtv_softc *sc = demux->dd_sc;
+
+       /*
+        * TS PID is 13 bits; demux device uses special PID 0x2000 to mean
+        * "all PIDs". Verify that the requested PID is in range.
+        */
+       if (pid > 0x2000)
+               return EINVAL;
+
+       /* Set demux mode */
+       demux->dd_mode = DTV_DEMUX_MODE_PES;
+       /*
+        * If requesting "all PIDs", set the on/off flag for all PIDs in
+        * the PID map, otherwise set the on/off flag for the requested
+        * PID.
+        */
+       if (pid == 0x2000) {
+               memset(sc->sc_ts.ts_pidfilter, onoff,
+                   sizeof(sc->sc_ts.ts_pidfilter));
+       } else {
+               sc->sc_ts.ts_pidfilter[pid] = onoff;
+       }
+
+       return 0;
+}
+
+/*
+ * Open a new instance of the demux cloning device.
+ */
 int
 dtv_demux_open(struct dtv_softc *sc, int flags, int mode, lwp_t *l)
 {
@@ -157,10 +297,12 @@
        struct dtv_demux *demux;
        int error, fd;
 
+       /* Allocate private storage */
        demux = kmem_zalloc(sizeof(*demux), KM_SLEEP);
        if (demux == NULL)
                return ENOMEM;
        demux->dd_sc = sc;
+       /* Default operation mode is unconfigured */
        demux->dd_mode = DTV_DEMUX_MODE_NONE;
        selinit(&demux->dd_sel);
        mutex_init(&demux->dd_lock, MUTEX_DEFAULT, IPL_VM);
@@ -172,6 +314,7 @@
                return error;
        }
 
+       /* Add the demux to the list of demux instances */
        mutex_enter(&sc->sc_demux_lock);
        TAILQ_INSERT_TAIL(&sc->sc_demux_list, demux, dd_entries);
        mutex_exit(&sc->sc_demux_lock);
@@ -179,11 +322,15 @@
        return fd_clone(fp, fd, flags, &dtv_demux_fileops, demux);
 }
 
+/*
+ * Close the instance of the demux cloning device.
+ */
 int
 dtv_demux_close(struct file *fp)
 {
        struct dtv_demux *demux = fp->f_data;
        struct dtv_softc *sc;
+       int error;
 
        if (demux == NULL)
                return ENXIO;
@@ -192,6 +339,14 @@
 
        sc = demux->dd_sc;
 
+       /* If the demux is still running, stop it */
+       if (demux->dd_running) {
+               error = dtv_demux_stop(demux);
+               if (error)
+                       return error;
+       }
+
+       /* Remove the demux from the list of demux instances */
        mutex_enter(&sc->sc_demux_lock);
        TAILQ_REMOVE(&sc->sc_demux_list, demux, dd_entries);
        mutex_exit(&sc->sc_demux_lock);
@@ -200,20 +355,23 @@
        cv_destroy(&demux->dd_section_cv);
        kmem_free(demux, sizeof(*demux));
 
-       dtv_close_common(sc);
+       /* Update the global device open count */
+       dtv_common_close(sc);
 
        return 0;
 }
 
+/*
+ * Handle demux ioctl requests
+ */
 static int
-dtv_demux_ioctl1(struct dtv_demux *demux, u_long cmd, void *data)
+dtv_demux_ioctl(struct file *fp, u_long cmd, void *data)
 {
-       struct dtv_demux *dd;
+       struct dtv_demux *demux = fp->f_data;
        struct dtv_softc *sc;
        struct dmx_pes_filter_params *pesfilt;
        struct dmx_sct_filter_params *sctfilt;



Home | Main Index | Thread Index | Old Index