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