Module Name:    src
Committed By:   jmcneill
Date:           Sat Jul 16 12:20:01 UTC 2011

Modified Files:
        src/sys/dev/dtv: dtv_buffer.c dtv_demux.c dtv_device.c dtvvar.h

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


To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/dtv/dtv_buffer.c
cvs rdiff -u -r1.3 -r1.4 src/sys/dev/dtv/dtv_demux.c
cvs rdiff -u -r1.6 -r1.7 src/sys/dev/dtv/dtv_device.c
cvs rdiff -u -r1.4 -r1.5 src/sys/dev/dtv/dtvvar.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/dtv/dtv_buffer.c
diff -u src/sys/dev/dtv/dtv_buffer.c:1.5 src/sys/dev/dtv/dtv_buffer.c:1.6
--- src/sys/dev/dtv/dtv_buffer.c:1.5	Wed Jul 13 22:43:04 2011
+++ src/sys/dev/dtv/dtv_buffer.c	Sat Jul 16 12:20:01 2011
@@ -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 <[email protected]>
@@ -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;
 	}

Index: src/sys/dev/dtv/dtv_demux.c
diff -u src/sys/dev/dtv/dtv_demux.c:1.3 src/sys/dev/dtv/dtv_demux.c:1.4
--- src/sys/dev/dtv/dtv_demux.c:1.3	Thu Jul 14 01:37:09 2011
+++ src/sys/dev/dtv/dtv_demux.c	Sat Jul 16 12:20:01 2011
@@ -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 <[email protected]>
@@ -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;
 	uint16_t pid;
-	unsigned int demux_running;
 	int error;
 
 	if (demux == NULL)
@@ -222,56 +380,40 @@
 
 	switch (cmd) {
 	case DMX_START:
-		error = 0;
-		demux_running = 0;
-
-		mutex_enter(&sc->sc_demux_lock);
-		TAILQ_FOREACH(dd, &sc->sc_demux_list, dd_entries) {
-			if (dd->dd_running)
-				demux_running++;
-		}
-		if (demux_running == 0) {
-			error = dtv_buffer_setup(sc);
-			if (error)
-				return error;
-			error = dtv_device_start_transfer(sc);
-		}
-		if (error == 0)
-			demux->dd_running = true;
-		mutex_exit(&sc->sc_demux_lock);
-
-		return error;
+		return dtv_demux_start(demux);
 	case DMX_STOP:
-		error = 0;
-		demux_running = 0;
-
-		mutex_enter(&sc->sc_demux_lock);
-		demux->dd_running = false;
-		TAILQ_FOREACH(dd, &sc->sc_demux_list, dd_entries) {
-			if (dd->dd_running)
-				demux_running++;
-		}
-		if (demux_running == 0)
-			error = dtv_device_stop_transfer(sc);
-		mutex_exit(&sc->sc_demux_lock);
-
-		return error;
+		return dtv_demux_stop(demux);
 	case DMX_SET_BUFFER_SIZE:
+		/*
+		 * The demux driver doesn't support configurable buffer sizes,
+		 * but software relies on this command succeeding.
+		 */
 		return 0;
 	case DMX_SET_FILTER:
 		sctfilt = data;
 
+		/* Verify that the requested PID is in range. */
 		if (sctfilt->pid >= 0x2000)
 			return EINVAL;
 
+		/*
+		 * Update section filter parameters, reset read/write ptrs,
+		 * clear section count and overflow flag, and set the
+		 * demux instance mode to section filter.
+		 */
 		demux->dd_secfilt.params = *sctfilt;
 		demux->dd_secfilt.rp = demux->dd_secfilt.wp = 0;
 		demux->dd_secfilt.nsections = 0;
 		demux->dd_secfilt.overflow = false;
 		demux->dd_mode = DTV_DEMUX_MODE_SECTION;
 
+		/*
+		 * If the DMX_IMMEDIATE_START flag is present in the request,
+		 * start running the demux immediately (no need for a
+		 * subsequent DMX_START ioctl).
+		 */
 		if (sctfilt->flags & DMX_IMMEDIATE_START) {
-			error = dtv_demux_ioctl1(demux, DMX_START, NULL);
+			error = dtv_demux_start(demux);
 			if (error)
 				return error;
 		}
@@ -280,60 +422,46 @@
 	case DMX_SET_PES_FILTER:
 		pesfilt = data;
 
+		/* The driver only supports input from the frontend */
 		if (pesfilt->input != DMX_IN_FRONTEND)
 			return EINVAL;
+		/*
+		 * The driver only supports output to the TS TAP in PID
+		 * filter mode.
+		 */
 		if (pesfilt->output != DMX_OUT_TS_TAP)
 			return EINVAL;
-		if (pesfilt->pes_type != DMX_PES_OTHER)
-			return EINVAL;
 
-		error = dtv_demux_ioctl1(demux, DMX_ADD_PID, &pesfilt->pid);
+		/* Update PID filter table */
+		error = dtv_demux_set_pidfilter(demux, pesfilt->pid, true);
 		if (error)
 			return error;
 
+		/*
+		 * If the DMX_IMMEDIATE_START flag is present in the request,
+		 * start running the demux immediately (no need for a
+		 * subsequent DMX_START ioctl).
+		 */
 		if (pesfilt->flags & DMX_IMMEDIATE_START) {
-			error = dtv_demux_ioctl1(demux, DMX_START, NULL);
+			error = dtv_demux_start(demux);
 			if (error)
 				return error;
 		}
 		return 0;
 	case DMX_ADD_PID:
 		pid = *(uint16_t *)data;
-		if (pid > 0x2000)
-			return EINVAL;
-
-		demux->dd_mode = DTV_DEMUX_MODE_PES;
-		if (pid == 0x2000) {
-			memset(sc->sc_ts.ts_pidfilter, 1,
-			    sizeof(sc->sc_ts.ts_pidfilter));
-		} else {
-			sc->sc_ts.ts_pidfilter[pid] = 1;
-		}
-		return 0;
+		return dtv_demux_set_pidfilter(demux, pid, true);
 	case DMX_REMOVE_PID:
 		pid = *(uint16_t *)data;
-		if (pid > 0x2000)
-			return EINVAL;
-
-		demux->dd_mode = DTV_DEMUX_MODE_PES;
-		if (pid == 0x2000) {
-			memset(sc->sc_ts.ts_pidfilter, 0,
-			    sizeof(sc->sc_ts.ts_pidfilter));
-		} else {
-			sc->sc_ts.ts_pidfilter[pid] = 0;
-		}
-		return 0;
+		return dtv_demux_set_pidfilter(demux, pid, false);
 	default:
 		return EINVAL;
 	}
 }
 
-int
-dtv_demux_ioctl(struct file *fp, u_long cmd, void *data)
-{
-	return dtv_demux_ioctl1(fp->f_data, cmd, data);
-}
-
+/*
+ * Test for I/O readiness
+ */
 static int
 dtv_demux_poll(struct file *fp, int events)
 {
@@ -343,8 +471,13 @@
 	if (demux == NULL)
 		return POLLERR;
 
+	/*
+	 * If the demux instance is in section filter mode, wait for an
+	 * entire section to become ready.
+	 */
 	mutex_enter(&demux->dd_lock);
-	if (demux->dd_secfilt.nsections > 0) {
+	if (demux->dd_mode == DTV_DEMUX_MODE_SECTION &&
+	    demux->dd_secfilt.nsections > 0) {
 		revents |= POLLIN;
 	} else {
 		selrecord(curlwp, &demux->dd_sel);
@@ -354,6 +487,9 @@
 	return revents;
 }
 
+/*
+ * Read from the demux instance
+ */
 static int
 dtv_demux_read(struct file *fp, off_t *offp, struct uio *uio,
     kauth_cred_t cred, int flags)
@@ -365,13 +501,16 @@
 	if (demux == NULL)
 		return ENXIO;
 
+	/* Only support read if the instance is in section filter mode */
 	if (demux->dd_mode != DTV_DEMUX_MODE_SECTION)
 		return EIO;
 
+	/* Wait for a complete PSI section */
 	mutex_enter(&demux->dd_lock);
 	while (demux->dd_secfilt.nsections == 0) {
 		if (flags & IO_NDELAY) {
 			mutex_exit(&demux->dd_lock);
+			/* No data available */
 			return EWOULDBLOCK;
 		}
 		error = cv_wait_sig(&demux->dd_section_cv, &demux->dd_lock);
@@ -380,22 +519,45 @@
 			return error;
 		}
 	}
+	/* Copy the completed PSI section */
 	sec = demux->dd_secfilt.section[demux->dd_secfilt.rp];
+	/* Update read pointer */
 	demux->dd_secfilt.rp++;
 	if (demux->dd_secfilt.rp >= __arraycount(demux->dd_secfilt.section))
 		demux->dd_secfilt.rp = 0;
+	/* Update section count */
 	demux->dd_secfilt.nsections--;
 	mutex_exit(&demux->dd_lock);
 
+	/*
+	 * If the filter parameters specify the DMX_ONESHOT flag, stop
+	 * the demux after one PSI section is received.
+	 */
+	if (demux->dd_secfilt.params.flags & DMX_ONESHOT)
+		dtv_demux_stop(demux);
+
+	/*
+	 * Copy the PSI section to userspace. If the receiving buffer is
+	 * too small, the rest of the payload will be discarded. Although
+	 * this behaviour differs from the Linux implementation, in practice
+	 * it should not be an issue as PSI sections have a max size of 4KB
+	 * (and callers will generally provide a big enough buffer).
+	 */
 	return uiomove(sec.sec_buf, sec.sec_length, uio);
 }
 
+/*
+ * Verify the CRC of a PSI section.
+ */
 static bool
 dtv_demux_check_crc(struct dtv_demux *demux, struct dtv_ts_section *sec)
 {
 	uint32_t crc, sec_crc;
 
-	/* if section_syntax_indicator is not set, there is no CRC */
+	/*
+	 * If section_syntax_indicator is not set, the PSI section does
+	 * not include a CRC field.
+	 */
 	if ((sec->sec_buf[1] & 0x80) == 0)
 		return false;
 
@@ -405,8 +567,13 @@
 	return crc == sec_crc;
 }
 
-int
-dtv_demux_write(struct dtv_demux *demux, const uint8_t *tspkt, size_t tspktlen)
+/*
+ * Process a single TS packet and extract PSI sections based on the
+ * instance's section filter.
+ */
+static int
+dtv_demux_process(struct dtv_demux *demux, const uint8_t *tspkt,
+    size_t tspktlen)
 {
 	struct dtv_ts_section *sec;
 	dmx_filter_t *dmxfilt = &demux->dd_secfilt.params.filter;
@@ -416,14 +583,31 @@
 
 	KASSERT(tspktlen == TS_PKTLEN);
 
+	/* If the demux instance is not running, ignore the packet */
+	if (demux->dd_running == false)
+		return 0;
+
+	/*
+	 * If the demux instance is not in section filter mode, ignore
+	 * the packet
+	 */
 	if (demux->dd_mode != DTV_DEMUX_MODE_SECTION)
 		return 0;
+	/*
+	 * If the packet's TS PID does not match the section filter PID,
+	 * ignore the packet
+	 */
 	if (TS_PID(tspkt) != demux->dd_secfilt.params.pid)
 		return 0;
+	/*
+	 * If the TS packet does not contain a payload, ignore the packet
+	 */
 	if (TS_HAS_PAYLOAD(tspkt) == 0)
 		return 0;
 
 	mutex_enter(&demux->dd_lock);
+
+	/* If the section buffer is full, set the overflow flag and return */
 	if (demux->dd_secfilt.nsections ==
 	    __arraycount(demux->dd_secfilt.section)) {
 		demux->dd_secfilt.overflow = true;
@@ -460,6 +644,10 @@
 		}
 		/* table_id_ext filter */
 		if (dmxfilt->mask[1] && dmxfilt->mask[2]) {
+			/*
+			 * table_id_ext is only valid if
+			 * section_syntax_indicator is set
+			 */
 			if (section_length < 2 || (p[1] & 0x80) == 0)
 				goto done;
 			if ((p[3] & dmxfilt->mask[1]) != dmxfilt->filter[1])
@@ -482,17 +670,26 @@
 	if (sec->sec_bytesused > 0 && TS_HAS_PUSI(tspkt))
 		sec->sec_bytesused = sec->sec_length = 0;
 
+	/* Copy data into section buffer */
 	avail = min(sec->sec_length - sec->sec_bytesused, brem);
 	if (avail < 0)
 		goto done;
-
 	memcpy(&sec->sec_buf[sec->sec_bytesused], p, avail);
 	sec->sec_bytesused += avail;
 
+	/*
+	 * If a complete section has been received, update section count
+	 * and notify readers.
+	 */
 	if (sec->sec_bytesused == sec->sec_length) {
+		/*
+		 * If the DMX_CHECK_CRC flag was present in the DMX_SET_FILTER
+		 * parameters, verify the PSI section checksum. If the
+		 * checksum is invalid, discard the entire corrupt section.
+		 */
 		if ((demux->dd_secfilt.params.flags & DMX_CHECK_CRC) &&
 		    dtv_demux_check_crc(demux, sec) == false) {
-			/* discard packet */
+			/* discard section */
 			sec->sec_bytesused = sec->sec_length = 0;
 			goto done;
 		}
@@ -504,9 +701,6 @@
 		demux->dd_secfilt.nsections++;
 		cv_broadcast(&demux->dd_section_cv);
 		selnotify(&demux->dd_sel, 0, 0);
-
-		if (demux->dd_secfilt.params.flags & DMX_ONESHOT)
-			dtv_demux_ioctl1(demux, DMX_STOP, NULL);
 	}
 
 done:
@@ -514,3 +708,17 @@
 	return 0;
 }
 
+/*
+ * Submit TS data to all demux instances
+ */
+void
+dtv_demux_write(struct dtv_softc *sc, const uint8_t *tspkt, size_t tspktlen)
+{
+	struct dtv_demux *demux;
+
+	mutex_enter(&sc->sc_demux_lock);
+	TAILQ_FOREACH(demux, &sc->sc_demux_list, dd_entries) {
+		dtv_demux_process(demux, tspkt, tspktlen);
+	}
+	mutex_exit(&sc->sc_demux_lock);
+}

Index: src/sys/dev/dtv/dtv_device.c
diff -u src/sys/dev/dtv/dtv_device.c:1.6 src/sys/dev/dtv/dtv_device.c:1.7
--- src/sys/dev/dtv/dtv_device.c:1.6	Wed Jul 13 22:51:10 2011
+++ src/sys/dev/dtv/dtv_device.c	Sat Jul 16 12:20:01 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: dtv_device.c,v 1.6 2011/07/13 22:51:10 jmcneill Exp $ */
+/* $NetBSD: dtv_device.c,v 1.7 2011/07/16 12:20:01 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2011 Jared D. McNeill <[email protected]>
@@ -33,7 +33,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dtv_device.c,v 1.6 2011/07/13 22:51:10 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dtv_device.c,v 1.7 2011/07/16 12:20:01 jmcneill Exp $");
 
 #include <sys/types.h>
 #include <sys/conf.h>
@@ -118,6 +118,7 @@
 
 	mutex_init(&sc->sc_demux_lock, MUTEX_DEFAULT, IPL_VM);
 	TAILQ_INIT(&sc->sc_demux_list);
+	sc->sc_demux_runcnt = 0;
 
 	dtv_device_get_devinfo(sc, &info);
 
@@ -237,7 +238,7 @@
 	if ((sc = device_lookup_private(&dtv_cd, DTVUNIT(dev))) == NULL)
 		return ENXIO;
 
-	dtv_close_common(sc);
+	dtv_common_close(sc);
 
 	return 0;
 }
@@ -289,7 +290,7 @@
 }
 
 void
-dtv_close_common(struct dtv_softc *sc)
+dtv_common_close(struct dtv_softc *sc)
 {
 	mutex_enter(&sc->sc_lock);
 	KASSERT(sc->sc_open > 0);

Index: src/sys/dev/dtv/dtvvar.h
diff -u src/sys/dev/dtv/dtvvar.h:1.4 src/sys/dev/dtv/dtvvar.h:1.5
--- src/sys/dev/dtv/dtvvar.h:1.4	Wed Jul 13 22:43:04 2011
+++ src/sys/dev/dtv/dtvvar.h	Sat Jul 16 12:20:01 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: dtvvar.h,v 1.4 2011/07/13 22:43:04 jmcneill Exp $ */
+/* $NetBSD: dtvvar.h,v 1.5 2011/07/16 12:20:01 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2011 Jared D. McNeill <[email protected]>
@@ -124,6 +124,7 @@
 
 	TAILQ_HEAD(, dtv_demux) sc_demux_list;
 	kmutex_t	sc_demux_lock;
+	int		sc_demux_runcnt;
 };
 
 #define	dtv_device_get_devinfo(sc, info)	\
@@ -148,7 +149,7 @@
 int	dtv_frontend_ioctl(struct dtv_softc *, u_long, void *, int);
 
 int	dtv_demux_open(struct dtv_softc *, int, int, lwp_t *);
-int	dtv_demux_write(struct dtv_demux *, const uint8_t *, size_t);
+void	dtv_demux_write(struct dtv_softc *, const uint8_t *, size_t);
 
 int	dtv_buffer_realloc(struct dtv_softc *, size_t);
 int	dtv_buffer_setup(struct dtv_softc *);
@@ -156,6 +157,6 @@
 int	dtv_buffer_read(struct dtv_softc *, struct uio *, int);
 int	dtv_buffer_poll(struct dtv_softc *, int, lwp_t *);
 
-void	dtv_close_common(struct dtv_softc *);
+void	dtv_common_close(struct dtv_softc *);
 
 #endif /* !_DEV_DTV_DTVVAR_H */

Reply via email to