V4L/DVB (4228a): pvrusb2 to kernel 2.6.18

Implement V4L2 driver for the Hauppauge PVR USB2 TV tuner.

The Hauppauge PVR USB2 is a USB connected TV tuner with an embedded
cx23416 hardware MPEG2 encoder.  There are two major variants of this
device; this driver handles both.  Any V4L2 application which
understands MPEG2 video stream data should be able to work with this
device.

Signed-off-by: Mike Isely <isely@pobox.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
new file mode 100644
index 0000000..3577d5b
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -0,0 +1,544 @@
+/*
+ *
+ *  $Id$
+ *
+ *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "pvrusb2-ctrl.h"
+#include "pvrusb2-hdw-internal.h"
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mutex.h>
+
+
+/* Set the given control. */
+int pvr2_ctrl_set_value(struct pvr2_ctrl *cptr,int val)
+{
+	return pvr2_ctrl_set_mask_value(cptr,~0,val);
+}
+
+
+/* Set/clear specific bits of the given control. */
+int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val)
+{
+	int ret = 0;
+	if (!cptr) return -EINVAL;
+	LOCK_TAKE(cptr->hdw->big_lock); do {
+		if (cptr->info->set_value != 0) {
+			if (cptr->info->type == pvr2_ctl_bitmask) {
+				mask &= cptr->info->def.type_bitmask.valid_bits;
+			} else if (cptr->info->type == pvr2_ctl_int) {
+				if (val < cptr->info->def.type_int.min_value) {
+					break;
+				}
+				if (val > cptr->info->def.type_int.max_value) {
+					break;
+				}
+			} else if (cptr->info->type == pvr2_ctl_enum) {
+				if (val >= cptr->info->def.type_enum.count) {
+					break;
+				}
+			}
+			ret = cptr->info->set_value(cptr,mask,val);
+		} else {
+			ret = -EPERM;
+		}
+	} while(0); LOCK_GIVE(cptr->hdw->big_lock);
+	return ret;
+}
+
+
+/* Get the current value of the given control. */
+int pvr2_ctrl_get_value(struct pvr2_ctrl *cptr,int *valptr)
+{
+	int ret = 0;
+	if (!cptr) return -EINVAL;
+	LOCK_TAKE(cptr->hdw->big_lock); do {
+		ret = cptr->info->get_value(cptr,valptr);
+	} while(0); LOCK_GIVE(cptr->hdw->big_lock);
+	return ret;
+}
+
+
+/* Retrieve control's type */
+enum pvr2_ctl_type pvr2_ctrl_get_type(struct pvr2_ctrl *cptr)
+{
+	if (!cptr) return pvr2_ctl_int;
+	return cptr->info->type;
+}
+
+
+/* Retrieve control's maximum value (int type) */
+int pvr2_ctrl_get_max(struct pvr2_ctrl *cptr)
+{
+	int ret = 0;
+	if (!cptr) return 0;
+	LOCK_TAKE(cptr->hdw->big_lock); do {
+		if (cptr->info->type == pvr2_ctl_int) {
+			ret = cptr->info->def.type_int.max_value;
+		}
+	} while(0); LOCK_GIVE(cptr->hdw->big_lock);
+	return ret;
+}
+
+
+/* Retrieve control's minimum value (int type) */
+int pvr2_ctrl_get_min(struct pvr2_ctrl *cptr)
+{
+	int ret = 0;
+	if (!cptr) return 0;
+	LOCK_TAKE(cptr->hdw->big_lock); do {
+		if (cptr->info->type == pvr2_ctl_int) {
+			ret = cptr->info->def.type_int.min_value;
+		}
+	} while(0); LOCK_GIVE(cptr->hdw->big_lock);
+	return ret;
+}
+
+
+/* Retrieve control's default value (any type) */
+int pvr2_ctrl_get_def(struct pvr2_ctrl *cptr)
+{
+	int ret = 0;
+	if (!cptr) return 0;
+	LOCK_TAKE(cptr->hdw->big_lock); do {
+		if (cptr->info->type == pvr2_ctl_int) {
+			ret = cptr->info->default_value;
+		}
+	} while(0); LOCK_GIVE(cptr->hdw->big_lock);
+	return ret;
+}
+
+
+/* Retrieve control's enumeration count (enum only) */
+int pvr2_ctrl_get_cnt(struct pvr2_ctrl *cptr)
+{
+	int ret = 0;
+	if (!cptr) return 0;
+	LOCK_TAKE(cptr->hdw->big_lock); do {
+		if (cptr->info->type == pvr2_ctl_enum) {
+			ret = cptr->info->def.type_enum.count;
+		}
+	} while(0); LOCK_GIVE(cptr->hdw->big_lock);
+	return ret;
+}
+
+
+/* Retrieve control's valid mask bits (bit mask only) */
+int pvr2_ctrl_get_mask(struct pvr2_ctrl *cptr)
+{
+	int ret = 0;
+	if (!cptr) return 0;
+	LOCK_TAKE(cptr->hdw->big_lock); do {
+		if (cptr->info->type == pvr2_ctl_bitmask) {
+			ret = cptr->info->def.type_bitmask.valid_bits;
+		}
+	} while(0); LOCK_GIVE(cptr->hdw->big_lock);
+	return ret;
+}
+
+
+/* Retrieve the control's name */
+const char *pvr2_ctrl_get_name(struct pvr2_ctrl *cptr)
+{
+	if (!cptr) return 0;
+	return cptr->info->name;
+}
+
+
+/* Retrieve the control's desc */
+const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *cptr)
+{
+	if (!cptr) return 0;
+	return cptr->info->desc;
+}
+
+
+/* Retrieve a control enumeration or bit mask value */
+int pvr2_ctrl_get_valname(struct pvr2_ctrl *cptr,int val,
+			  char *bptr,unsigned int bmax,
+			  unsigned int *blen)
+{
+	int ret = -EINVAL;
+	if (!cptr) return 0;
+	*blen = 0;
+	LOCK_TAKE(cptr->hdw->big_lock); do {
+		if (cptr->info->type == pvr2_ctl_enum) {
+			const char **names;
+			names = cptr->info->def.type_enum.value_names;
+			if ((val >= 0) &&
+			    (val < cptr->info->def.type_enum.count)) {
+				if (names[val]) {
+					*blen = scnprintf(
+						bptr,bmax,"%s",
+						names[val]);
+				} else {
+					*blen = 0;
+				}
+				ret = 0;
+			}
+		} else if (cptr->info->type == pvr2_ctl_bitmask) {
+			const char **names;
+			unsigned int idx;
+			int msk;
+			names = cptr->info->def.type_bitmask.bit_names;
+			val &= cptr->info->def.type_bitmask.valid_bits;
+			for (idx = 0, msk = 1; val; idx++, msk <<= 1) {
+				if (val & msk) {
+					*blen = scnprintf(bptr,bmax,"%s",
+							  names[idx]);
+					ret = 0;
+					break;
+				}
+			}
+		}
+	} while(0); LOCK_GIVE(cptr->hdw->big_lock);
+	return ret;
+}
+
+
+/* Return true if control is writable */
+int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr)
+{
+	if (!cptr) return 0;
+	return cptr->info->set_value != 0;
+}
+
+
+/* Return true if control has custom symbolic representation */
+int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *cptr)
+{
+	if (!cptr) return 0;
+	if (!cptr->info->val_to_sym) return 0;
+	if (!cptr->info->sym_to_val) return 0;
+	return !0;
+}
+
+
+/* Convert a given mask/val to a custom symbolic value */
+int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *cptr,
+				  int mask,int val,
+				  char *buf,unsigned int maxlen,
+				  unsigned int *len)
+{
+	if (!cptr) return -EINVAL;
+	if (!cptr->info->val_to_sym) return -EINVAL;
+	return cptr->info->val_to_sym(cptr,mask,val,buf,maxlen,len);
+}
+
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *cptr,
+				  const char *buf,unsigned int len,
+				  int *maskptr,int *valptr)
+{
+	if (!cptr) return -EINVAL;
+	if (!cptr->info->sym_to_val) return -EINVAL;
+	return cptr->info->sym_to_val(cptr,buf,len,maskptr,valptr);
+}
+
+
+static unsigned int gen_bitmask_string(int msk,int val,int msk_only,
+				       const char **names,
+				       char *ptr,unsigned int len)
+{
+	unsigned int idx;
+	long sm,um;
+	int spcFl;
+	unsigned int uc,cnt;
+	const char *idStr;
+
+	spcFl = 0;
+	uc = 0;
+	um = 0;
+	for (idx = 0, sm = 1; msk; idx++, sm <<= 1) {
+		if (sm & msk) {
+			msk &= ~sm;
+			idStr = names[idx];
+			if (idStr) {
+				cnt = scnprintf(ptr,len,"%s%s%s",
+						(spcFl ? " " : ""),
+						(msk_only ? "" :
+						 ((val & sm) ? "+" : "-")),
+						idStr);
+				ptr += cnt; len -= cnt; uc += cnt;
+				spcFl = !0;
+			} else {
+				um |= sm;
+			}
+		}
+	}
+	if (um) {
+		if (msk_only) {
+			cnt = scnprintf(ptr,len,"%s0x%lx",
+					(spcFl ? " " : ""),
+					um);
+			ptr += cnt; len -= cnt; uc += cnt;
+			spcFl = !0;
+		} else if (um & val) {
+			cnt = scnprintf(ptr,len,"%s+0x%lx",
+					(spcFl ? " " : ""),
+					um & val);
+			ptr += cnt; len -= cnt; uc += cnt;
+			spcFl = !0;
+		} else if (um & ~val) {
+			cnt = scnprintf(ptr,len,"%s+0x%lx",
+					(spcFl ? " " : ""),
+					um & ~val);
+			ptr += cnt; len -= cnt; uc += cnt;
+			spcFl = !0;
+		}
+	}
+	return uc;
+}
+
+
+static int parse_token(const char *ptr,unsigned int len,
+		       int *valptr,
+		       const char **names,unsigned int namecnt)
+{
+	char buf[33];
+	unsigned int slen;
+	unsigned int idx;
+	int negfl;
+	char *p2;
+	*valptr = 0;
+	if (!names) namecnt = 0;
+	for (idx = 0; idx < namecnt; idx++) {
+		if (!names[idx]) continue;
+		slen = strlen(names[idx]);
+		if (slen != len) continue;
+		if (memcmp(names[idx],ptr,slen)) continue;
+		*valptr = idx;
+		return 0;
+	}
+	negfl = 0;
+	if ((*ptr == '-') || (*ptr == '+')) {
+		negfl = (*ptr == '-');
+		ptr++; len--;
+	}
+	if (len >= sizeof(buf)) return -EINVAL;
+	memcpy(buf,ptr,len);
+	buf[len] = 0;
+	*valptr = simple_strtol(buf,&p2,0);
+	if (negfl) *valptr = -(*valptr);
+	if (*p2) return -EINVAL;
+	return 0;
+}
+
+
+static int parse_mtoken(const char *ptr,unsigned int len,
+			int *valptr,
+			const char **names,int valid_bits)
+{
+	char buf[33];
+	unsigned int slen;
+	unsigned int idx;
+	char *p2;
+	int msk;
+	*valptr = 0;
+	for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) {
+		if (!msk & valid_bits) continue;
+		valid_bits &= ~msk;
+		if (!names[idx]) continue;
+		slen = strlen(names[idx]);
+		if (slen != len) continue;
+		if (memcmp(names[idx],ptr,slen)) continue;
+		*valptr = msk;
+		return 0;
+	}
+	if (len >= sizeof(buf)) return -EINVAL;
+	memcpy(buf,ptr,len);
+	buf[len] = 0;
+	*valptr = simple_strtol(buf,&p2,0);
+	if (*p2) return -EINVAL;
+	return 0;
+}
+
+
+static int parse_tlist(const char *ptr,unsigned int len,
+		       int *maskptr,int *valptr,
+		       const char **names,int valid_bits)
+{
+	unsigned int cnt;
+	int mask,val,kv,mode,ret;
+	mask = 0;
+	val = 0;
+	ret = 0;
+	while (len) {
+		cnt = 0;
+		while ((cnt < len) &&
+		       ((ptr[cnt] <= 32) ||
+			(ptr[cnt] >= 127))) cnt++;
+		ptr += cnt;
+		len -= cnt;
+		mode = 0;
+		if ((*ptr == '-') || (*ptr == '+')) {
+			mode = (*ptr == '-') ? -1 : 1;
+			ptr++;
+			len--;
+		}
+		cnt = 0;
+		while (cnt < len) {
+			if (ptr[cnt] <= 32) break;
+			if (ptr[cnt] >= 127) break;
+			cnt++;
+		}
+		if (!cnt) break;
+		if (parse_mtoken(ptr,cnt,&kv,names,valid_bits)) {
+			ret = -EINVAL;
+			break;
+		}
+		ptr += cnt;
+		len -= cnt;
+		switch (mode) {
+		case 0:
+			mask = valid_bits;
+			val |= kv;
+			break;
+		case -1:
+			mask |= kv;
+			val &= ~kv;
+			break;
+		case 1:
+			mask |= kv;
+			val |= kv;
+			break;
+		default:
+			break;
+		}
+	}
+	*maskptr = mask;
+	*valptr = val;
+	return ret;
+}
+
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
+			   const char *ptr,unsigned int len,
+			   int *maskptr,int *valptr)
+{
+	int ret = -EINVAL;
+	unsigned int cnt;
+
+	*maskptr = 0;
+	*valptr = 0;
+
+	cnt = 0;
+	while ((cnt < len) && ((ptr[cnt] <= 32) || (ptr[cnt] >= 127))) cnt++;
+	len -= cnt; ptr += cnt;
+	cnt = 0;
+	while ((cnt < len) && ((ptr[len-(cnt+1)] <= 32) ||
+			       (ptr[len-(cnt+1)] >= 127))) cnt++;
+	len -= cnt;
+
+	if (!len) return -EINVAL;
+
+	LOCK_TAKE(cptr->hdw->big_lock); do {
+		if (cptr->info->type == pvr2_ctl_int) {
+			ret = parse_token(ptr,len,valptr,0,0);
+			if ((ret == 0) &&
+			    ((*valptr < cptr->info->def.type_int.min_value) ||
+			     (*valptr > cptr->info->def.type_int.max_value))) {
+				ret = -EINVAL;
+			}
+			if (maskptr) *maskptr = ~0;
+		} else if (cptr->info->type == pvr2_ctl_enum) {
+			ret = parse_token(
+				ptr,len,valptr,
+				cptr->info->def.type_enum.value_names,
+				cptr->info->def.type_enum.count);
+			if ((ret == 0) &&
+			    ((*valptr < 0) ||
+			     (*valptr >= cptr->info->def.type_enum.count))) {
+				ret = -EINVAL;
+			}
+			if (maskptr) *maskptr = ~0;
+		} else if (cptr->info->type == pvr2_ctl_bitmask) {
+			ret = parse_tlist(
+				ptr,len,maskptr,valptr,
+				cptr->info->def.type_bitmask.bit_names,
+				cptr->info->def.type_bitmask.valid_bits);
+		}
+	} while(0); LOCK_GIVE(cptr->hdw->big_lock);
+	return ret;
+}
+
+
+/* Convert a given mask/val to a symbolic value */
+int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr,
+				    int mask,int val,
+				    char *buf,unsigned int maxlen,
+				    unsigned int *len)
+{
+	int ret = -EINVAL;
+
+	*len = 0;
+	if (cptr->info->type == pvr2_ctl_int) {
+		*len = scnprintf(buf,maxlen,"%d",val);
+		ret = 0;
+	} else if (cptr->info->type == pvr2_ctl_enum) {
+		const char **names;
+		names = cptr->info->def.type_enum.value_names;
+		if ((val >= 0) &&
+		    (val < cptr->info->def.type_enum.count)) {
+			if (names[val]) {
+				*len = scnprintf(
+					buf,maxlen,"%s",
+					names[val]);
+			} else {
+				*len = 0;
+			}
+			ret = 0;
+		}
+	} else if (cptr->info->type == pvr2_ctl_bitmask) {
+		*len = gen_bitmask_string(
+			val & mask & cptr->info->def.type_bitmask.valid_bits,
+			~0,!0,
+			cptr->info->def.type_bitmask.bit_names,
+			buf,maxlen);
+	}
+	return ret;
+}
+
+
+/* Convert a given mask/val to a symbolic value */
+int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr,
+			   int mask,int val,
+			   char *buf,unsigned int maxlen,
+			   unsigned int *len)
+{
+	int ret;
+	LOCK_TAKE(cptr->hdw->big_lock); do {
+		ret = pvr2_ctrl_value_to_sym_internal(cptr,mask,val,
+						      buf,maxlen,len);
+	} while(0); LOCK_GIVE(cptr->hdw->big_lock);
+	return ret;
+}
+
+
+/*
+  Stuff for Emacs to see, in order to encourage consistent editing style:
+  *** Local Variables: ***
+  *** mode: c ***
+  *** fill-column: 75 ***
+  *** tab-width: 8 ***
+  *** c-basic-offset: 8 ***
+  *** End: ***
+  */